|
|
|
@ -207,7 +207,6 @@ architecture rtl of icache is
|
|
|
|
|
signal req_is_miss : std_ulogic;
|
|
|
|
|
signal req_raddr : real_addr_t;
|
|
|
|
|
|
|
|
|
|
signal tlb_req_index : tlb_index_t;
|
|
|
|
|
signal real_addr : real_addr_t;
|
|
|
|
|
signal ra_valid : std_ulogic;
|
|
|
|
|
signal priv_fault : std_ulogic;
|
|
|
|
@ -317,14 +316,15 @@ architecture rtl of icache is
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
-- Simple hash for direct-mapped TLB index
|
|
|
|
|
function hash_ea(addr: std_ulogic_vector(63 downto 0)) return tlb_index_t is
|
|
|
|
|
function hash_ea(addr: std_ulogic_vector(63 downto 0)) return std_ulogic_vector is
|
|
|
|
|
variable hash : std_ulogic_vector(TLB_BITS - 1 downto 0);
|
|
|
|
|
begin
|
|
|
|
|
hash := addr(TLB_LG_PGSZ + TLB_BITS - 1 downto TLB_LG_PGSZ)
|
|
|
|
|
xor addr(TLB_LG_PGSZ + 2 * TLB_BITS - 1 downto TLB_LG_PGSZ + TLB_BITS)
|
|
|
|
|
xor addr(TLB_LG_PGSZ + 3 * TLB_BITS - 1 downto TLB_LG_PGSZ + 2 * TLB_BITS);
|
|
|
|
|
return to_integer(unsigned(hash));
|
|
|
|
|
return hash;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
begin
|
|
|
|
|
|
|
|
|
|
assert LINE_SIZE mod ROW_SIZE = 0;
|
|
|
|
@ -435,7 +435,9 @@ begin
|
|
|
|
|
process(all)
|
|
|
|
|
begin
|
|
|
|
|
-- PLRU interface
|
|
|
|
|
if get_index(r.hit_nia) = i then
|
|
|
|
|
if is_X(r.hit_nia) then
|
|
|
|
|
plru_acc_en <= 'X';
|
|
|
|
|
elsif get_index(r.hit_nia) = i then
|
|
|
|
|
plru_acc_en <= r.hit_valid;
|
|
|
|
|
else
|
|
|
|
|
plru_acc_en <= '0';
|
|
|
|
@ -450,15 +452,25 @@ begin
|
|
|
|
|
itlb_lookup : process(all)
|
|
|
|
|
variable pte : tlb_pte_t;
|
|
|
|
|
variable ttag : tlb_tag_t;
|
|
|
|
|
variable tlb_req_index : std_ulogic_vector(TLB_BITS - 1 downto 0);
|
|
|
|
|
begin
|
|
|
|
|
tlb_req_index <= hash_ea(i_in.nia);
|
|
|
|
|
pte := itlb_ptes(tlb_req_index);
|
|
|
|
|
ttag := itlb_tags(tlb_req_index);
|
|
|
|
|
tlb_req_index := hash_ea(i_in.nia);
|
|
|
|
|
if is_X(tlb_req_index) then
|
|
|
|
|
pte := (others => 'X');
|
|
|
|
|
ttag := (others => 'X');
|
|
|
|
|
else
|
|
|
|
|
pte := itlb_ptes(to_integer(unsigned(tlb_req_index)));
|
|
|
|
|
ttag := itlb_tags(to_integer(unsigned(tlb_req_index)));
|
|
|
|
|
end if;
|
|
|
|
|
if i_in.virt_mode = '1' then
|
|
|
|
|
real_addr <= pte(REAL_ADDR_BITS - 1 downto TLB_LG_PGSZ) &
|
|
|
|
|
i_in.nia(TLB_LG_PGSZ - 1 downto 0);
|
|
|
|
|
if ttag = i_in.nia(63 downto TLB_LG_PGSZ + TLB_BITS) then
|
|
|
|
|
ra_valid <= itlb_valids(tlb_req_index);
|
|
|
|
|
if is_X(tlb_req_index) then
|
|
|
|
|
ra_valid <= 'X';
|
|
|
|
|
else
|
|
|
|
|
ra_valid <= itlb_valids(to_integer(unsigned(tlb_req_index)));
|
|
|
|
|
end if;
|
|
|
|
|
else
|
|
|
|
|
ra_valid <= '0';
|
|
|
|
|
end if;
|
|
|
|
@ -476,7 +488,7 @@ begin
|
|
|
|
|
|
|
|
|
|
-- iTLB update
|
|
|
|
|
itlb_update: process(clk)
|
|
|
|
|
variable wr_index : tlb_index_t;
|
|
|
|
|
variable wr_index : std_ulogic_vector(TLB_BITS - 1 downto 0);
|
|
|
|
|
begin
|
|
|
|
|
if rising_edge(clk) then
|
|
|
|
|
wr_index := hash_ea(m_in.addr);
|
|
|
|
@ -486,12 +498,14 @@ begin
|
|
|
|
|
itlb_valids(i) <= '0';
|
|
|
|
|
end loop;
|
|
|
|
|
elsif m_in.tlbie = '1' then
|
|
|
|
|
assert not is_X(wr_index) report "icache index invalid on write" severity FAILURE;
|
|
|
|
|
-- clear entry regardless of hit or miss
|
|
|
|
|
itlb_valids(wr_index) <= '0';
|
|
|
|
|
itlb_valids(to_integer(unsigned(wr_index))) <= '0';
|
|
|
|
|
elsif m_in.tlbld = '1' then
|
|
|
|
|
itlb_tags(wr_index) <= m_in.addr(63 downto TLB_LG_PGSZ + TLB_BITS);
|
|
|
|
|
itlb_ptes(wr_index) <= m_in.pte;
|
|
|
|
|
itlb_valids(wr_index) <= '1';
|
|
|
|
|
assert not is_X(wr_index) report "icache index invalid on write" severity FAILURE;
|
|
|
|
|
itlb_tags(to_integer(unsigned(wr_index))) <= m_in.addr(63 downto TLB_LG_PGSZ + TLB_BITS);
|
|
|
|
|
itlb_ptes(to_integer(unsigned(wr_index))) <= m_in.pte;
|
|
|
|
|
itlb_valids(to_integer(unsigned(wr_index))) <= '1';
|
|
|
|
|
end if;
|
|
|
|
|
ev.itlb_miss_resolved <= m_in.tlbld and not rst;
|
|
|
|
|
end if;
|
|
|
|
@ -503,8 +517,10 @@ begin
|
|
|
|
|
variable hit_way : way_t;
|
|
|
|
|
begin
|
|
|
|
|
-- Extract line, row and tag from request
|
|
|
|
|
if not is_X(i_in.nia) then
|
|
|
|
|
req_index <= get_index(i_in.nia);
|
|
|
|
|
req_row <= get_row(i_in.nia);
|
|
|
|
|
end if;
|
|
|
|
|
req_tag <= get_tag(real_addr, i_in.big_endian);
|
|
|
|
|
|
|
|
|
|
-- Calculate address of beginning of cache row, will be
|
|
|
|
@ -517,7 +533,11 @@ begin
|
|
|
|
|
hit_way := 0;
|
|
|
|
|
is_hit := '0';
|
|
|
|
|
for i in way_t loop
|
|
|
|
|
if i_in.req = '1' and
|
|
|
|
|
if is_X(i_in.nia) then
|
|
|
|
|
-- FIXME: This is fragile
|
|
|
|
|
-- req_index or req_row could be a metavalue
|
|
|
|
|
is_hit := 'X';
|
|
|
|
|
elsif i_in.req = '1' and
|
|
|
|
|
(cache_valids(req_index)(i) = '1' or
|
|
|
|
|
(r.state = WAIT_ACK and
|
|
|
|
|
req_index = r.store_index and
|
|
|
|
@ -592,6 +612,8 @@ begin
|
|
|
|
|
r.hit_valid <= req_is_hit;
|
|
|
|
|
if req_is_hit = '1' then
|
|
|
|
|
r.hit_way <= req_hit_way;
|
|
|
|
|
-- this is a bit fragile but better than propogating bad values
|
|
|
|
|
assert not is_X(i_in.nia) report "metavalue in NIA" severity FAILURE;
|
|
|
|
|
|
|
|
|
|
report "cache hit nia:" & to_hstring(i_in.nia) &
|
|
|
|
|
" IR:" & std_ulogic'image(i_in.virt_mode) &
|
|
|
|
@ -648,6 +670,9 @@ begin
|
|
|
|
|
snoop_addr := addr_to_real(wb_to_addr(wb_snoop_in.adr));
|
|
|
|
|
snoop_index <= get_index(snoop_addr);
|
|
|
|
|
snoop_cache_tags := cache_tags(get_index(snoop_addr));
|
|
|
|
|
if snoop_valid = '1' and is_X(snoop_addr) then
|
|
|
|
|
report "metavalue in snoop_addr" severity FAILURE;
|
|
|
|
|
end if;
|
|
|
|
|
snoop_tag := get_tag(snoop_addr, '0');
|
|
|
|
|
snoop_hits <= (others => '0');
|
|
|
|
|
for i in way_t loop
|
|
|
|
|