|
|
|
library ieee;
|
|
|
|
use ieee.std_logic_1164.all;
|
|
|
|
|
|
|
|
library work;
|
|
|
|
use work.common.all;
|
|
|
|
use work.wishbone_types.all;
|
|
|
|
|
|
|
|
entity icache_tb is
|
|
|
|
end icache_tb;
|
|
|
|
|
|
|
|
architecture behave of icache_tb is
|
|
|
|
signal clk : std_ulogic;
|
|
|
|
signal rst : std_ulogic;
|
|
|
|
|
|
|
|
signal i_out : Fetch1ToIcacheType;
|
|
|
|
signal i_in : IcacheToDecode1Type;
|
|
|
|
|
|
|
|
signal wb_bram_in : wishbone_master_out;
|
|
|
|
signal wb_bram_out : wishbone_slave_out;
|
|
|
|
|
|
|
|
constant clk_period : time := 10 ns;
|
|
|
|
begin
|
|
|
|
icache0: entity work.icache
|
|
|
|
generic map(
|
|
|
|
LINE_SIZE => 64,
|
|
|
|
NUM_LINES => 4
|
|
|
|
)
|
|
|
|
port map(
|
|
|
|
clk => clk,
|
|
|
|
rst => rst,
|
|
|
|
i_in => i_out,
|
|
|
|
i_out => i_in,
|
|
|
|
stall_in => '0',
|
|
|
|
flush_in => '0',
|
|
|
|
inval_in => '0',
|
|
|
|
wishbone_out => wb_bram_in,
|
|
|
|
wishbone_in => wb_bram_out
|
|
|
|
);
|
|
|
|
|
|
|
|
-- BRAM Memory slave
|
|
|
|
bram0: entity work.wishbone_bram_wrapper
|
|
|
|
generic map(
|
|
|
|
MEMORY_SIZE => 1024,
|
|
|
|
RAM_INIT_FILE => "icache_test.bin"
|
|
|
|
)
|
|
|
|
port map(
|
|
|
|
clk => clk,
|
|
|
|
rst => rst,
|
|
|
|
wishbone_in => wb_bram_in,
|
|
|
|
wishbone_out => wb_bram_out
|
|
|
|
);
|
|
|
|
|
|
|
|
clk_process: process
|
|
|
|
begin
|
|
|
|
clk <= '0';
|
|
|
|
wait for clk_period/2;
|
|
|
|
clk <= '1';
|
|
|
|
wait for clk_period/2;
|
|
|
|
end process;
|
|
|
|
|
|
|
|
rst_process: process
|
|
|
|
begin
|
|
|
|
rst <= '1';
|
|
|
|
wait for 2*clk_period;
|
|
|
|
rst <= '0';
|
|
|
|
wait;
|
|
|
|
end process;
|
|
|
|
|
|
|
|
stim: process
|
|
|
|
begin
|
|
|
|
i_out.req <= '0';
|
|
|
|
i_out.nia <= (others => '0');
|
|
|
|
i_out.stop_mark <= '0';
|
|
|
|
i_out.priv_mode <= '1';
|
|
|
|
i_out.virt_mode <= '0';
|
|
|
|
i_out.big_endian <= '0';
|
|
|
|
i_out.fetch_fail <= '0';
|
|
|
|
i_out.predicted <= '0';
|
|
|
|
i_out.pred_ntaken <= '0';
|
Add TLB to icache
This adds a direct-mapped TLB to the icache, with 64 entries by default.
Execute1 now sends a "virt_mode" signal from MSR[IR] to fetch1 along
with redirects to indicate whether instruction addresses should be
translated through the TLB, and fetch1 sends that on to icache.
Similarly a "priv_mode" signal is sent to indicate the privilege
mode for instruction fetches. This means that changes to MSR[IR]
or MSR[PR] don't take effect until the next redirect, meaning an
isync, rfid, branch, etc.
The icache uses a hash of the effective address (i.e. next instruction
address) to index the TLB. The hash is an XOR of three fields of the
address; with a 64-entry TLB, the fields are bits 12--17, 18--23 and
24--29 of the address. TLB invalidations simply invalidate the
indexed TLB entry without checking the contents.
If the icache detects a TLB miss with virt_mode=1, it will send a
fetch_failed indication through fetch2 to decode1, which will turn it
into a special OP_FETCH_FAILED opcode with unit=LDST. That will get
sent down to loadstore1 which will currently just raise a Instruction
Storage Interrupt (0x400) exception.
One bit in the PTE obtained from the TLB is used to check whether an
instruction access is allowed -- the privilege bit (bit 3). If bit 3
is 1 and priv_mode=0, then a fetch_failed indication is sent down to
fetch2 and to decode1, which generates an OP_FETCH_FAILED. Any PTEs
with PTE bit 0 (EAA[3]) clear or bit 8 (R) clear should not be put
into the iTLB since such PTEs would not allow execution by any
context.
Tlbie operations get sent from mmu to icache over a new connection.
Unfortunately the privileged instruction tests are broken for now.
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
5 years ago
|
|
|
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
|
|
|
|
i_out.next_nia <= x"0000000000000004";
|
|
|
|
i_out.next_rpn <= (others => '0');
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
|
|
|
|
i_out.req <= '1';
|
|
|
|
i_out.nia <= x"0000000000000004";
|
|
|
|
i_out.rpn <= (others => '0');
|
|
|
|
|
|
|
|
wait for 30*clk_period;
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
|
|
|
|
assert i_in.valid = '1' severity failure;
|
|
|
|
assert i_in.insn = x"00000001"
|
|
|
|
report "insn @" & to_hstring(i_out.nia) &
|
|
|
|
"=" & to_hstring(i_in.insn) &
|
|
|
|
" expected 00000001"
|
|
|
|
severity failure;
|
|
|
|
|
|
|
|
i_out.req <= '0';
|
|
|
|
i_out.next_nia <= x"0000000000000008";
|
|
|
|
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
|
|
|
|
-- hit
|
|
|
|
i_out.req <= '1';
|
|
|
|
i_out.nia <= x"0000000000000008";
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
assert i_in.valid = '1' severity failure;
|
|
|
|
assert i_in.insn = x"00000002"
|
|
|
|
report "insn @" & to_hstring(i_out.nia) &
|
|
|
|
"=" & to_hstring(i_in.insn) &
|
|
|
|
" expected 00000002"
|
|
|
|
severity failure;
|
|
|
|
|
|
|
|
i_out.next_nia <= x"0000000000000040";
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
|
|
|
|
-- another miss
|
|
|
|
i_out.req <= '1';
|
|
|
|
i_out.nia <= x"0000000000000040";
|
|
|
|
|
|
|
|
wait for 30*clk_period;
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
|
|
|
|
assert i_in.valid = '1' severity failure;
|
|
|
|
assert i_in.insn = x"00000010"
|
|
|
|
report "insn @" & to_hstring(i_out.nia) &
|
|
|
|
"=" & to_hstring(i_in.insn) &
|
|
|
|
" expected 00000010"
|
|
|
|
severity failure;
|
|
|
|
|
|
|
|
-- test something that aliases
|
|
|
|
i_out.next_nia <= x"0000000000000100";
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
|
|
|
|
i_out.req <= '1';
|
|
|
|
i_out.nia <= x"0000000000000100";
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
assert i_in.valid = '0' severity failure;
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
|
|
|
|
wait for 30*clk_period;
|
|
|
|
wait until rising_edge(clk);
|
|
|
|
|
|
|
|
assert i_in.valid = '1' severity failure;
|
|
|
|
assert i_in.insn = x"00000040"
|
|
|
|
report "insn @" & to_hstring(i_out.nia) &
|
|
|
|
"=" & to_hstring(i_in.insn) &
|
|
|
|
" expected 00000040"
|
|
|
|
severity failure;
|
|
|
|
|
|
|
|
i_out.req <= '0';
|
|
|
|
|
|
|
|
std.env.finish;
|
|
|
|
end process;
|
|
|
|
end;
|