Merge pull request #396 from paulusmack/reduce-meta

Reduce metavalue warnings
pull/397/head
Michael Neuling 2 years ago committed by GitHub
commit 5c6d57de30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -53,12 +53,14 @@ begin
for i in 0 to WIDTH/BYTEWID-1 loop for i in 0 to WIDTH/BYTEWID-1 loop
lbit := i * BYTEWID; lbit := i * BYTEWID;
mbit := lbit + BYTEWID - 1; mbit := lbit + BYTEWID - 1;
widx := to_integer(unsigned(wr_addr));
if wr_sel(i) = '1' then if wr_sel(i) = '1' then
assert not is_X(wr_addr);
widx := to_integer(unsigned(wr_addr));
ram(widx)(mbit downto lbit) <= wr_data(mbit downto lbit); ram(widx)(mbit downto lbit) <= wr_data(mbit downto lbit);
end if; end if;
end loop; end loop;
if rd_en = '1' then if rd_en = '1' then
assert not is_X(rd_addr);
rd_data0 <= ram(to_integer(unsigned(rd_addr))); rd_data0 <= ram(to_integer(unsigned(rd_addr)));
if TRACE then if TRACE then
report "read a:" & to_hstring(rd_addr) & report "read a:" & to_hstring(rd_addr) &

@ -173,6 +173,7 @@ begin
terminated <= '0'; terminated <= '0';
log_trigger_delay <= 0; log_trigger_delay <= 0;
gspr_index <= (others => '0'); gspr_index <= (others => '0');
log_dmi_addr <= (others => '0');
else else
if do_log_trigger = '1' or log_trigger_delay /= 0 then if do_log_trigger = '1' or log_trigger_delay /= 0 then
if log_trigger_delay = 255 or if log_trigger_delay = 255 or
@ -334,6 +335,7 @@ begin
addr : std_ulogic_vector(31 downto 0)) return std_ulogic_vector is addr : std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
variable firstbit : integer; variable firstbit : integer;
begin begin
assert not is_X(addr);
firstbit := to_integer(unsigned(addr(1 downto 0))) * 64; firstbit := to_integer(unsigned(addr(1 downto 0))) * 64;
return data(firstbit + 63 downto firstbit); return data(firstbit + 63 downto firstbit);
end; end;
@ -351,9 +353,14 @@ begin
begin begin
if rising_edge(clk) then if rising_edge(clk) then
if log_wr_enable = '1' then if log_wr_enable = '1' then
assert not is_X(log_wr_ptr);
log_array(to_integer(log_wr_ptr)) <= log_data; log_array(to_integer(log_wr_ptr)) <= log_data;
end if; end if;
log_rd <= log_array(to_integer(log_rd_ptr_latched)); if is_X(log_rd_ptr_latched) then
log_rd <= (others => 'X');
else
log_rd <= log_array(to_integer(log_rd_ptr_latched));
end if;
end if; end if;
end process; end process;


@ -366,6 +373,7 @@ begin
if rst = '1' then if rst = '1' then
log_wr_ptr <= (others => '0'); log_wr_ptr <= (others => '0');
log_toggle <= '0'; log_toggle <= '0';
log_rd_ptr_latched <= (others => '0');
elsif log_wr_enable = '1' then elsif log_wr_enable = '1' then
if log_wr_ptr = to_unsigned(LOG_LENGTH - 1, LOG_INDEX_BITS) then if log_wr_ptr = to_unsigned(LOG_LENGTH - 1, LOG_INDEX_BITS) then
log_toggle <= not log_toggle; log_toggle <= not log_toggle;

@ -97,9 +97,9 @@ architecture rtl of dcache is
-- .. |-----| | INDEX_BITS (5) -- .. |-----| | INDEX_BITS (5)
-- .. --------| | TAG_BITS (45) -- .. --------| | TAG_BITS (45)


subtype row_t is integer range 0 to BRAM_ROWS-1; subtype row_t is unsigned(ROW_BITS-1 downto 0);
subtype index_t is integer range 0 to NUM_LINES-1; subtype index_t is unsigned(INDEX_BITS-1 downto 0);
subtype way_t is integer range 0 to NUM_WAYS-1; subtype way_t is unsigned(WAY_BITS-1 downto 0);
subtype row_in_line_t is unsigned(ROW_LINEBITS-1 downto 0); subtype row_in_line_t is unsigned(ROW_LINEBITS-1 downto 0);


-- The cache data BRAM organized as described above for each way -- The cache data BRAM organized as described above for each way
@ -110,14 +110,14 @@ architecture rtl of dcache is
-- memory. For now, work around it by putting all the tags -- memory. For now, work around it by putting all the tags
subtype cache_tag_t is std_logic_vector(TAG_BITS-1 downto 0); subtype cache_tag_t is std_logic_vector(TAG_BITS-1 downto 0);
-- type cache_tags_set_t is array(way_t) of cache_tag_t; -- type cache_tags_set_t is array(way_t) of cache_tag_t;
-- type cache_tags_array_t is array(index_t) of cache_tags_set_t; -- type cache_tags_array_t is array(0 to NUM_LINES-1) of cache_tags_set_t;
constant TAG_RAM_WIDTH : natural := TAG_WIDTH * NUM_WAYS; constant TAG_RAM_WIDTH : natural := TAG_WIDTH * NUM_WAYS;
subtype cache_tags_set_t is std_logic_vector(TAG_RAM_WIDTH-1 downto 0); subtype cache_tags_set_t is std_logic_vector(TAG_RAM_WIDTH-1 downto 0);
type cache_tags_array_t is array(index_t) of cache_tags_set_t; type cache_tags_array_t is array(0 to NUM_LINES-1) of cache_tags_set_t;


-- The cache valid bits -- The cache valid bits
subtype cache_way_valids_t is std_ulogic_vector(NUM_WAYS-1 downto 0); subtype cache_way_valids_t is std_ulogic_vector(NUM_WAYS-1 downto 0);
type cache_valids_t is array(index_t) of cache_way_valids_t; type cache_valids_t is array(0 to NUM_LINES-1) of cache_way_valids_t;
type row_per_line_valid_t is array(0 to ROW_PER_LINE - 1) of std_ulogic; type row_per_line_valid_t is array(0 to ROW_PER_LINE - 1) of std_ulogic;


-- Storage. Hopefully implemented in LUTs -- Storage. Hopefully implemented in LUTs
@ -137,7 +137,9 @@ architecture rtl of dcache is
constant TLB_PTE_WAY_BITS : natural := TLB_NUM_WAYS * TLB_PTE_BITS; constant TLB_PTE_WAY_BITS : natural := TLB_NUM_WAYS * TLB_PTE_BITS;


subtype tlb_way_t is integer range 0 to TLB_NUM_WAYS - 1; subtype tlb_way_t is integer range 0 to TLB_NUM_WAYS - 1;
subtype tlb_way_sig_t is unsigned(TLB_WAY_BITS-1 downto 0);
subtype tlb_index_t is integer range 0 to TLB_SET_SIZE - 1; subtype tlb_index_t is integer range 0 to TLB_SET_SIZE - 1;
subtype tlb_index_sig_t is unsigned(TLB_SET_BITS-1 downto 0);
subtype tlb_way_valids_t is std_ulogic_vector(TLB_NUM_WAYS-1 downto 0); subtype tlb_way_valids_t is std_ulogic_vector(TLB_NUM_WAYS-1 downto 0);
type tlb_valids_t is array(tlb_index_t) of tlb_way_valids_t; type tlb_valids_t is array(tlb_index_t) of tlb_way_valids_t;
subtype tlb_tag_t is std_ulogic_vector(TLB_EA_TAG_BITS - 1 downto 0); subtype tlb_tag_t is std_ulogic_vector(TLB_EA_TAG_BITS - 1 downto 0);
@ -312,8 +314,8 @@ architecture rtl of dcache is


-- TLB hit state -- TLB hit state
tlb_hit : std_ulogic; tlb_hit : std_ulogic;
tlb_hit_way : tlb_way_t; tlb_hit_way : tlb_way_sig_t;
tlb_hit_index : tlb_index_t; tlb_hit_index : tlb_index_sig_t;


-- data buffer for data forwarded from writes to reads -- data buffer for data forwarded from writes to reads
forward_data : std_ulogic_vector(63 downto 0); forward_data : std_ulogic_vector(63 downto 0);
@ -366,7 +368,6 @@ architecture rtl of dcache is


-- Async signals on incoming request -- Async signals on incoming request
signal req_index : index_t; signal req_index : index_t;
signal req_row : row_t;
signal req_hit_way : way_t; signal req_hit_way : way_t;
signal req_tag : cache_tag_t; signal req_tag : cache_tag_t;
signal req_op : op_t; signal req_op : op_t;
@ -375,6 +376,7 @@ architecture rtl of dcache is
signal req_go : std_ulogic; signal req_go : std_ulogic;


signal early_req_row : row_t; signal early_req_row : row_t;
signal early_rd_valid : std_ulogic;


signal cancel_store : std_ulogic; signal cancel_store : std_ulogic;
signal set_rsrv : std_ulogic; signal set_rsrv : std_ulogic;
@ -389,13 +391,13 @@ architecture rtl of dcache is
signal use_forward2 : std_ulogic; signal use_forward2 : std_ulogic;


-- Cache RAM interface -- Cache RAM interface
type cache_ram_out_t is array(way_t) of cache_row_t; type cache_ram_out_t is array(0 to NUM_WAYS-1) of cache_row_t;
signal cache_out : cache_ram_out_t; signal cache_out : cache_ram_out_t;
signal ram_wr_data : cache_row_t; signal ram_wr_data : cache_row_t;
signal ram_wr_select : std_ulogic_vector(ROW_SIZE - 1 downto 0); signal ram_wr_select : std_ulogic_vector(ROW_SIZE - 1 downto 0);


-- PLRU output interface -- PLRU output interface
type plru_out_t is array(index_t) of std_ulogic_vector(WAY_BITS-1 downto 0); type plru_out_t is array(0 to NUM_LINES-1) of std_ulogic_vector(WAY_BITS-1 downto 0);
signal plru_victim : plru_out_t; signal plru_victim : plru_out_t;
signal replace_way : way_t; signal replace_way : way_t;


@ -406,9 +408,10 @@ architecture rtl of dcache is
signal tlb_tag_way : tlb_way_tags_t; signal tlb_tag_way : tlb_way_tags_t;
signal tlb_pte_way : tlb_way_ptes_t; signal tlb_pte_way : tlb_way_ptes_t;
signal tlb_valid_way : tlb_way_valids_t; signal tlb_valid_way : tlb_way_valids_t;
signal tlb_req_index : tlb_index_t; signal tlb_req_index : tlb_index_sig_t;
signal tlb_read_valid : std_ulogic;
signal tlb_hit : std_ulogic; signal tlb_hit : std_ulogic;
signal tlb_hit_way : tlb_way_t; signal tlb_hit_way : tlb_way_sig_t;
signal pte : tlb_pte_t; signal pte : tlb_pte_t;
signal ra : real_addr_t; signal ra : real_addr_t;
signal valid_ra : std_ulogic; signal valid_ra : std_ulogic;
@ -434,21 +437,19 @@ architecture rtl of dcache is
-- Return the cache line index (tag index) for an address -- Return the cache line index (tag index) for an address
function get_index(addr: std_ulogic_vector) return index_t is function get_index(addr: std_ulogic_vector) return index_t is
begin begin
return to_integer(unsigned(addr(SET_SIZE_BITS - 1 downto LINE_OFF_BITS))); return unsigned(addr(SET_SIZE_BITS - 1 downto LINE_OFF_BITS));
end; end;


-- Return the cache row index (data memory) for an address -- Return the cache row index (data memory) for an address
function get_row(addr: std_ulogic_vector) return row_t is function get_row(addr: std_ulogic_vector) return row_t is
begin begin
return to_integer(unsigned(addr(SET_SIZE_BITS - 1 downto ROW_OFF_BITS))); return unsigned(addr(SET_SIZE_BITS - 1 downto ROW_OFF_BITS));
end; end;


-- Return the index of a row within a line -- Return the index of a row within a line
function get_row_of_line(row: row_t) return row_in_line_t is function get_row_of_line(row: row_t) return row_in_line_t is
variable row_v : unsigned(ROW_BITS-1 downto 0);
begin begin
row_v := to_unsigned(row, ROW_BITS); return row(ROW_LINEBITS-1 downto 0);
return row_v(ROW_LINEBITS-1 downto 0);
end; end;


-- Returns whether this is the last row of a line -- Returns whether this is the last row of a line
@ -485,10 +486,10 @@ architecture rtl of dcache is
variable row_idx : std_ulogic_vector(ROW_LINEBITS-1 downto 0); variable row_idx : std_ulogic_vector(ROW_LINEBITS-1 downto 0);
variable result : std_ulogic_vector(ROW_BITS-1 downto 0); variable result : std_ulogic_vector(ROW_BITS-1 downto 0);
begin begin
row_v := std_ulogic_vector(to_unsigned(row, ROW_BITS)); row_v := std_ulogic_vector(row);
row_idx := row_v(ROW_LINEBITS-1 downto 0); row_idx := row_v(ROW_LINEBITS-1 downto 0);
row_v(ROW_LINEBITS-1 downto 0) := std_ulogic_vector(unsigned(row_idx) + 1); row_v(ROW_LINEBITS-1 downto 0) := std_ulogic_vector(unsigned(row_idx) + 1);
return to_integer(unsigned(row_v)); return unsigned(row_v);
end; end;


-- Get the tag value from the address -- Get the tag value from the address
@ -498,7 +499,7 @@ architecture rtl of dcache is
end; end;


-- Read a tag from a tag memory row -- Read a tag from a tag memory row
function read_tag(way: way_t; tagset: cache_tags_set_t) return cache_tag_t is function read_tag(way: integer; tagset: cache_tags_set_t) return cache_tag_t is
begin begin
return tagset(way * TAG_WIDTH + TAG_BITS - 1 downto way * TAG_WIDTH); return tagset(way * TAG_WIDTH + TAG_BITS - 1 downto way * TAG_WIDTH);
end; end;
@ -586,6 +587,9 @@ begin
r.mmu_req := '0'; r.mmu_req := '0';
r.d_valid := '0'; r.d_valid := '0';
end if; end if;
if r.req.valid = '1' and r.doall = '0' then
assert not is_X(r.req.addr) severity failure;
end if;
if rst = '1' then if rst = '1' then
r0_full <= '0'; r0_full <= '0';
elsif r1.full = '0' and d_in.hold = '0' then elsif r1.full = '0' and d_in.hold = '0' then
@ -617,21 +621,30 @@ begin
tlb_read : process(clk) tlb_read : process(clk)
variable index : tlb_index_t; variable index : tlb_index_t;
variable addrbits : std_ulogic_vector(TLB_SET_BITS - 1 downto 0); variable addrbits : std_ulogic_vector(TLB_SET_BITS - 1 downto 0);
variable valid : std_ulogic;
begin begin
if rising_edge(clk) then if rising_edge(clk) then
if m_in.valid = '1' then if m_in.valid = '1' then
addrbits := m_in.addr(TLB_LG_PGSZ + TLB_SET_BITS - 1 downto TLB_LG_PGSZ); addrbits := m_in.addr(TLB_LG_PGSZ + TLB_SET_BITS - 1 downto TLB_LG_PGSZ);
valid := not (m_in.tlbie and m_in.doall);
else else
addrbits := d_in.addr(TLB_LG_PGSZ + TLB_SET_BITS - 1 downto TLB_LG_PGSZ); addrbits := d_in.addr(TLB_LG_PGSZ + TLB_SET_BITS - 1 downto TLB_LG_PGSZ);
valid := d_in.valid;
end if; end if;
index := to_integer(unsigned(addrbits));
-- If we have any op and the previous op isn't finished, -- If we have any op and the previous op isn't finished,
-- then keep the same output for next cycle. -- then keep the same output for next cycle.
if r0_stall = '0' then if r0_stall = '0' and valid = '1' then
assert not is_X(addrbits);
index := to_integer(unsigned(addrbits));
tlb_valid_way <= dtlb_valids(index); tlb_valid_way <= dtlb_valids(index);
tlb_tag_way <= dtlb_tags(index); tlb_tag_way <= dtlb_tags(index);
tlb_pte_way <= dtlb_ptes(index); tlb_pte_way <= dtlb_ptes(index);
end if; end if;
if rst = '1' then
tlb_read_valid <= '0';
elsif r0_stall = '0' then
tlb_read_valid <= valid;
end if;
end if; end if;
end process; end process;


@ -659,38 +672,39 @@ begin
process(all) process(all)
begin begin
-- PLRU interface -- PLRU interface
if r1.tlb_hit_index = i then if not is_X(r1.tlb_hit_index) and r1.tlb_hit_index = i then
tlb_plru_acc_en <= r1.tlb_hit; tlb_plru_acc_en <= r1.tlb_hit;
assert not is_X(r1.tlb_hit_way);
else else
tlb_plru_acc_en <= '0'; tlb_plru_acc_en <= '0';
end if; end if;
tlb_plru_acc <= std_ulogic_vector(to_unsigned(r1.tlb_hit_way, TLB_WAY_BITS)); tlb_plru_acc <= std_ulogic_vector(r1.tlb_hit_way);
tlb_plru_victim(i) <= tlb_plru_out; tlb_plru_victim(i) <= tlb_plru_out;
end process; end process;
end generate; end generate;
end generate; end generate;


tlb_search : process(all) tlb_search : process(all)
variable hitway : tlb_way_t; variable hitway : tlb_way_sig_t;
variable hit : std_ulogic; variable hit : std_ulogic;
variable eatag : tlb_tag_t; variable eatag : tlb_tag_t;
begin begin
tlb_req_index <= to_integer(unsigned(r0.req.addr(TLB_LG_PGSZ + TLB_SET_BITS - 1 tlb_req_index <= unsigned(r0.req.addr(TLB_LG_PGSZ + TLB_SET_BITS - 1
downto TLB_LG_PGSZ))); downto TLB_LG_PGSZ));
hitway := 0; hitway := to_unsigned(0, TLB_WAY_BITS);
hit := '0'; hit := '0';
eatag := r0.req.addr(63 downto TLB_LG_PGSZ + TLB_SET_BITS); eatag := r0.req.addr(63 downto TLB_LG_PGSZ + TLB_SET_BITS);
for i in tlb_way_t loop for i in tlb_way_t loop
if tlb_valid_way(i) = '1' and if tlb_read_valid = '1' and tlb_valid_way(i) = '1' and
read_tlb_tag(i, tlb_tag_way) = eatag then read_tlb_tag(i, tlb_tag_way) = eatag then
hitway := i; hitway := to_unsigned(i, TLB_WAY_BITS);
hit := '1'; hit := '1';
end if; end if;
end loop; end loop;
tlb_hit <= hit and r0_valid; tlb_hit <= hit and r0_valid;
tlb_hit_way <= hitway; tlb_hit_way <= hitway;
if tlb_hit = '1' then if tlb_hit = '1' then
pte <= read_tlb_pte(hitway, tlb_pte_way); pte <= read_tlb_pte(to_integer(hitway), tlb_pte_way);
else else
pte <= (others => '0'); pte <= (others => '0');
end if; end if;
@ -711,7 +725,7 @@ begin
tlb_update : process(clk) tlb_update : process(clk)
variable tlbie : std_ulogic; variable tlbie : std_ulogic;
variable tlbwe : std_ulogic; variable tlbwe : std_ulogic;
variable repl_way : tlb_way_t; variable repl_way : tlb_way_sig_t;
variable eatag : tlb_tag_t; variable eatag : tlb_tag_t;
variable tagset : tlb_way_tags_t; variable tagset : tlb_way_tags_t;
variable pteset : tlb_way_ptes_t; variable pteset : tlb_way_ptes_t;
@ -727,22 +741,27 @@ begin
end loop; end loop;
elsif tlbie = '1' then elsif tlbie = '1' then
if tlb_hit = '1' then if tlb_hit = '1' then
dtlb_valids(tlb_req_index)(tlb_hit_way) <= '0'; assert not is_X(tlb_req_index);
assert not is_X(tlb_hit_way);
dtlb_valids(to_integer(tlb_req_index))(to_integer(tlb_hit_way)) <= '0';
end if; end if;
elsif tlbwe = '1' then elsif tlbwe = '1' then
assert not is_X(tlb_req_index);
if tlb_hit = '1' then if tlb_hit = '1' then
repl_way := tlb_hit_way; repl_way := tlb_hit_way;
else else
repl_way := to_integer(unsigned(tlb_plru_victim(tlb_req_index))); assert not is_X(tlb_plru_victim(to_integer(tlb_req_index)));
repl_way := unsigned(tlb_plru_victim(to_integer(tlb_req_index)));
end if; end if;
assert not is_X(repl_way);
eatag := r0.req.addr(63 downto TLB_LG_PGSZ + TLB_SET_BITS); eatag := r0.req.addr(63 downto TLB_LG_PGSZ + TLB_SET_BITS);
tagset := tlb_tag_way; tagset := tlb_tag_way;
write_tlb_tag(repl_way, tagset, eatag); write_tlb_tag(to_integer(repl_way), tagset, eatag);
dtlb_tags(tlb_req_index) <= tagset; dtlb_tags(to_integer(tlb_req_index)) <= tagset;
pteset := tlb_pte_way; pteset := tlb_pte_way;
write_tlb_pte(repl_way, pteset, r0.req.data); write_tlb_pte(to_integer(repl_way), pteset, r0.req.data);
dtlb_ptes(tlb_req_index) <= pteset; dtlb_ptes(to_integer(tlb_req_index)) <= pteset;
dtlb_valids(tlb_req_index)(repl_way) <= '1'; dtlb_valids(to_integer(tlb_req_index))(to_integer(repl_way)) <= '1';
end if; end if;
end if; end if;
end process; end process;
@ -772,12 +791,12 @@ begin
process(all) process(all)
begin begin
-- PLRU interface -- PLRU interface
if r1.hit_index = i then if not is_X(r1.hit_index) and r1.hit_index = to_unsigned(i, INDEX_BITS) then
plru_acc_en <= r1.cache_hit; plru_acc_en <= r1.cache_hit;
else else
plru_acc_en <= '0'; plru_acc_en <= '0';
end if; end if;
plru_acc <= std_ulogic_vector(to_unsigned(r1.hit_way, WAY_BITS)); plru_acc <= std_ulogic_vector(r1.hit_way);
plru_victim(i) <= plru_out; plru_victim(i) <= plru_out;
end process; end process;
end generate; end generate;
@ -786,16 +805,24 @@ begin
-- Cache tag RAM read port -- Cache tag RAM read port
cache_tag_read : process(clk) cache_tag_read : process(clk)
variable index : index_t; variable index : index_t;
variable valid : std_ulogic;
begin begin
if rising_edge(clk) then if rising_edge(clk) then
if r0_stall = '1' then if r0_stall = '1' then
index := req_index; index := req_index;
valid := r0.req.valid and not (r0.tlbie or r0.tlbld);
elsif m_in.valid = '1' then elsif m_in.valid = '1' then
index := get_index(m_in.addr); index := get_index(m_in.addr);
valid := not (m_in.tlbie or m_in.tlbld);
else else
index := get_index(d_in.addr); index := get_index(d_in.addr);
valid := d_in.valid;
end if;
if valid = '1' then
cache_tag_set <= cache_tags(to_integer(index));
else
cache_tag_set <= (others => '0');
end if; end if;
cache_tag_set <= cache_tags(index);
end if; end if;
end process; end process;


@ -804,20 +831,25 @@ begin
variable addr : real_addr_t; variable addr : real_addr_t;
begin begin
if rising_edge(clk) then if rising_edge(clk) then
addr := addr_to_real(wb_to_addr(snoop_in.adr));
snoop_tag_set <= cache_tags(get_index(addr));
snoop_wrtag <= get_tag(addr);
snoop_index <= get_index(addr);
-- Don't snoop our own cycles -- Don't snoop our own cycles
snoop_valid <= '0'; snoop_valid <= '0';
if not (r1.wb.cyc = '1' and wishbone_in.stall = '0') then if not (r1.wb.cyc = '1' and wishbone_in.stall = '0') then
snoop_valid <= snoop_in.cyc and snoop_in.stb and snoop_in.we; if (snoop_in.cyc and snoop_in.stb and snoop_in.we) = '1' then
snoop_valid <= '1';
addr := addr_to_real(wb_to_addr(snoop_in.adr));
assert not is_X(addr);
snoop_tag_set <= cache_tags(to_integer(get_index(addr)));
snoop_wrtag <= get_tag(addr);
snoop_index <= get_index(addr);
end if;
end if; end if;
end if; end if;
end process; end process;


-- Cache request parsing and hit detection -- Cache request parsing and hit detection
dcache_request : process(all) dcache_request : process(all)
variable req_row : row_t;
variable rindex : index_t;
variable is_hit : std_ulogic; variable is_hit : std_ulogic;
variable hit_way : way_t; variable hit_way : way_t;
variable op : op_t; variable op : op_t;
@ -836,17 +868,24 @@ begin
variable fwd_match : std_ulogic; variable fwd_match : std_ulogic;
begin begin
-- Extract line, row and tag from request -- Extract line, row and tag from request
req_index <= get_index(r0.req.addr); rindex := get_index(r0.req.addr);
req_row <= get_row(r0.req.addr); req_index <= rindex;
req_row := get_row(r0.req.addr);
req_tag <= get_tag(ra); req_tag <= get_tag(ra);


go := r0_valid and not (r0.tlbie or r0.tlbld) and not r1.ls_error; go := r0_valid and not (r0.tlbie or r0.tlbld) and not r1.ls_error;
if is_X(r0.req.addr) then
go := '0';
end if;
if go = '1' then
assert not is_X(r1.forward_tag);
end if;


-- Test if pending request is a hit on any way -- Test if pending request is a hit on any way
-- In order to make timing in virtual mode, when we are using the TLB, -- In order to make timing in virtual mode, when we are using the TLB,
-- we compare each way with each of the real addresses from each way of -- we compare each way with each of the real addresses from each way of
-- the TLB, and then decide later which match to use. -- the TLB, and then decide later which match to use.
hit_way := 0; hit_way := to_unsigned(0, WAY_BITS);
is_hit := '0'; is_hit := '0';
rel_match := '0'; rel_match := '0';
fwd_match := '0'; fwd_match := '0';
@ -854,47 +893,54 @@ begin
rel_matches := (others => '0'); rel_matches := (others => '0');
fwd_matches := (others => '0'); fwd_matches := (others => '0');
for j in tlb_way_t loop for j in tlb_way_t loop
hit_way_set(j) := 0; hit_way_set(j) := to_unsigned(0, WAY_BITS);
s_hit := '0'; s_hit := '0';
s_pte := read_tlb_pte(j, tlb_pte_way); s_pte := read_tlb_pte(j, tlb_pte_way);
s_ra := s_pte(REAL_ADDR_BITS - 1 downto TLB_LG_PGSZ) & s_ra := s_pte(REAL_ADDR_BITS - 1 downto TLB_LG_PGSZ) &
r0.req.addr(TLB_LG_PGSZ - 1 downto 0); r0.req.addr(TLB_LG_PGSZ - 1 downto 0);
s_tag := get_tag(s_ra); s_tag := get_tag(s_ra);
for i in way_t loop if go = '1' then
if go = '1' and cache_valids(req_index)(i) = '1' and assert not is_X(s_tag);
end if;
for i in 0 to NUM_WAYS-1 loop
if go = '1' and cache_valids(to_integer(rindex))(i) = '1' and
read_tag(i, cache_tag_set) = s_tag and read_tag(i, cache_tag_set) = s_tag and
tlb_valid_way(j) = '1' then tlb_valid_way(j) = '1' then
hit_way_set(j) := i; hit_way_set(j) := to_unsigned(i, WAY_BITS);
s_hit := '1'; s_hit := '1';
end if; end if;
end loop; end loop;
hit_set(j) := s_hit; hit_set(j) := s_hit;
if s_tag = r1.reload_tag then if go = '1' and not is_X(r1.reload_tag) and s_tag = r1.reload_tag then
rel_matches(j) := '1'; rel_matches(j) := '1';
end if; end if;
if s_tag = r1.forward_tag then if go = '1' and s_tag = r1.forward_tag then
fwd_matches(j) := '1'; fwd_matches(j) := '1';
end if; end if;
end loop; end loop;
if tlb_hit = '1' then if tlb_hit = '1' and go = '1' then
is_hit := hit_set(tlb_hit_way); assert not is_X(tlb_hit_way);
hit_way := hit_way_set(tlb_hit_way); is_hit := hit_set(to_integer(tlb_hit_way));
rel_match := rel_matches(tlb_hit_way); hit_way := hit_way_set(to_integer(tlb_hit_way));
fwd_match := fwd_matches(tlb_hit_way); rel_match := rel_matches(to_integer(tlb_hit_way));
fwd_match := fwd_matches(to_integer(tlb_hit_way));
end if; end if;
else else
s_tag := get_tag(r0.req.addr); s_tag := get_tag(r0.req.addr);
for i in way_t loop if go = '1' then
if go = '1' and cache_valids(req_index)(i) = '1' and assert not is_X(s_tag);
end if;
for i in 0 to NUM_WAYS-1 loop
if go = '1' and cache_valids(to_integer(rindex))(i) = '1' and
read_tag(i, cache_tag_set) = s_tag then read_tag(i, cache_tag_set) = s_tag then
hit_way := i; hit_way := to_unsigned(i, WAY_BITS);
is_hit := '1'; is_hit := '1';
end if; end if;
end loop; end loop;
if s_tag = r1.reload_tag then if go = '1' and not is_X(r1.reload_tag) and s_tag = r1.reload_tag then
rel_match := '1'; rel_match := '1';
end if; end if;
if s_tag = r1.forward_tag then if go = '1' and s_tag = r1.forward_tag then
fwd_match := '1'; fwd_match := '1';
end if; end if;
end if; end if;
@ -904,7 +950,11 @@ begin
-- Whether to use forwarded data for a load or not -- Whether to use forwarded data for a load or not
use_forward_st <= '0'; use_forward_st <= '0';
use_forward_rl <= '0'; use_forward_rl <= '0';
if r1.store_row = req_row and rel_match = '1' then if rel_match = '1' then
assert not is_X(r1.store_row);
assert not is_X(req_row);
end if;
if rel_match = '1' and r1.store_row = req_row then
-- Use the forwarding path if this cycle is a write to this row -- Use the forwarding path if this cycle is a write to this row
use_forward_st <= r1.write_bram; use_forward_st <= r1.write_bram;
if r1.state = RELOAD_WAIT_ACK and wishbone_in.ack = '1' then if r1.state = RELOAD_WAIT_ACK and wishbone_in.ack = '1' then
@ -912,27 +962,39 @@ begin
end if; end if;
end if; end if;
use_forward2 <= '0'; use_forward2 <= '0';
if r1.forward_row = req_row and fwd_match = '1' then if fwd_match = '1' then
assert not is_X(r1.forward_row);
if is_X(req_row) then
report "req_row=" & to_hstring(req_row) & " addr=" & to_hstring(r0.req.addr) & " go=" & std_ulogic'image(go);
end if;
assert not is_X(req_row);
end if;
if fwd_match = '1' and r1.forward_row = req_row then
use_forward2 <= r1.forward_valid; use_forward2 <= r1.forward_valid;
end if; end if;


-- The way to replace on a miss -- The way to replace on a miss
if r1.write_tag = '1' then if r1.write_tag = '1' then
replace_way <= to_integer(unsigned(plru_victim(r1.store_index))); assert not is_X(r1.store_index);
replace_way <= unsigned(plru_victim(to_integer(r1.store_index)));
else else
replace_way <= r1.store_way; replace_way <= r1.store_way;
end if; end if;


-- See if the request matches the line currently being reloaded -- See if the request matches the line currently being reloaded
if r1.state = RELOAD_WAIT_ACK and req_index = r1.store_index and if r1.state = RELOAD_WAIT_ACK and rel_match = '1' then
rel_match = '1' then assert not is_X(rindex);
assert not is_X(r1.store_index);
end if;
if r1.state = RELOAD_WAIT_ACK and rel_match = '1' and
rindex = r1.store_index then
-- Ignore is_hit from above, because a load miss writes the new tag -- Ignore is_hit from above, because a load miss writes the new tag
-- but doesn't clear the valid bit on the line before refilling it. -- but doesn't clear the valid bit on the line before refilling it.
-- For a store, consider this a hit even if the row isn't valid -- For a store, consider this a hit even if the row isn't valid
-- since it will be by the time we perform the store. -- since it will be by the time we perform the store.
-- For a load, check the appropriate row valid bit; but also, -- For a load, check the appropriate row valid bit; but also,
-- if use_forward_rl is 1 then we can consider this a hit. -- if use_forward_rl is 1 then we can consider this a hit.
is_hit := not r0.req.load or r1.rows_valid(req_row mod ROW_PER_LINE) or is_hit := not r0.req.load or r1.rows_valid(to_integer(req_row(ROW_LINEBITS-1 downto 0))) or
use_forward_rl; use_forward_rl;
hit_way := replace_way; hit_way := replace_way;
end if; end if;
@ -982,11 +1044,14 @@ begin
if r0_stall = '0' then if r0_stall = '0' then
if m_in.valid = '1' then if m_in.valid = '1' then
early_req_row <= get_row(m_in.addr); early_req_row <= get_row(m_in.addr);
early_rd_valid <= not (m_in.tlbie or m_in.tlbld);
else else
early_req_row <= get_row(d_in.addr); early_req_row <= get_row(d_in.addr);
early_rd_valid <= d_in.valid and d_in.load;
end if; end if;
else else
early_req_row <= req_row; early_req_row <= req_row;
early_rd_valid <= r0.req.valid and r0.req.load;
end if; end if;
end process; end process;


@ -1145,8 +1210,8 @@ begin
process(all) process(all)
begin begin
-- Cache hit reads -- Cache hit reads
do_read <= '1'; do_read <= early_rd_valid;
rd_addr <= std_ulogic_vector(to_unsigned(early_req_row, ROW_BITS)); rd_addr <= std_ulogic_vector(early_req_row);
cache_out(i) <= dout; cache_out(i) <= dout;


-- Write mux: -- Write mux:
@ -1156,13 +1221,15 @@ begin
-- For timing, the mux on wr_data/sel/addr is not dependent on anything -- For timing, the mux on wr_data/sel/addr is not dependent on anything
-- other than the current state. -- other than the current state.
-- --
wr_addr <= std_ulogic_vector(to_unsigned(r1.store_row, ROW_BITS)); wr_addr <= std_ulogic_vector(r1.store_row);


wr_sel_m <= (others => '0'); wr_sel_m <= (others => '0');
if i = replace_way and if r1.write_bram = '1' or
(r1.write_bram = '1' or (r1.state = RELOAD_WAIT_ACK and wishbone_in.ack = '1') then
(r1.state = RELOAD_WAIT_ACK and wishbone_in.ack = '1')) then assert not is_X(replace_way);
wr_sel_m <= ram_wr_select; if to_unsigned(i, WAY_BITS) = replace_way then
wr_sel_m <= ram_wr_select;
end if;
end if; end if;


end process; end process;
@ -1182,9 +1249,9 @@ begin
report "op:" & op_t'image(req_op) & report "op:" & op_t'image(req_op) &
" addr:" & to_hstring(r0.req.addr) & " addr:" & to_hstring(r0.req.addr) &
" nc:" & std_ulogic'image(r0.req.nc) & " nc:" & std_ulogic'image(r0.req.nc) &
" idx:" & integer'image(req_index) & " idx:" & to_hstring(req_index) &
" tag:" & to_hstring(req_tag) & " tag:" & to_hstring(req_tag) &
" way: " & integer'image(req_hit_way); " way: " & to_hstring(req_hit_way);
end if; end if;
if r0_valid = '1' then if r0_valid = '1' then
r1.mmu_req <= r0.mmu_req; r1.mmu_req <= r0.mmu_req;
@ -1213,7 +1280,11 @@ begin
when "10" => when "10" =>
data_out(j + 7 downto j) := r1.forward_data(j + 7 downto j); data_out(j + 7 downto j) := r1.forward_data(j + 7 downto j);
when others => when others =>
data_out(j + 7 downto j) := cache_out(req_hit_way)(j + 7 downto j); if is_X(req_hit_way) then
data_out(j + 7 downto j) := (others => 'X');
else
data_out(j + 7 downto j) := cache_out(to_integer(req_hit_way))(j + 7 downto j);
end if;
end case; end case;
end loop; end loop;
r1.data_out <= data_out; r1.data_out <= data_out;
@ -1290,7 +1361,7 @@ begin


-- On reset, clear all valid bits to force misses -- On reset, clear all valid bits to force misses
if rst = '1' then if rst = '1' then
for i in index_t loop for i in 0 to NUM_LINES-1 loop
cache_valids(i) <= (others => '0'); cache_valids(i) <= (others => '0');
end loop; end loop;
r1.state <= IDLE; r1.state <= IDLE;
@ -1322,17 +1393,24 @@ begin
end if; end if;


-- Do invalidations from snooped stores to memory -- Do invalidations from snooped stores to memory
for i in way_t loop if snoop_valid = '1' then
assert not is_X(snoop_tag_set);
assert not is_X(snoop_wrtag);
end if;
for i in 0 to NUM_WAYS-1 loop
if snoop_valid = '1' and read_tag(i, snoop_tag_set) = snoop_wrtag then if snoop_valid = '1' and read_tag(i, snoop_tag_set) = snoop_wrtag then
cache_valids(snoop_index)(i) <= '0'; assert not is_X(snoop_index);
cache_valids(to_integer(snoop_index))(i) <= '0';
end if; end if;
end loop; end loop;


if r1.write_tag = '1' then if r1.write_tag = '1' then
-- Store new tag in selected way -- Store new tag in selected way
assert not is_X(r1.store_index);
assert not is_X(replace_way);
for i in 0 to NUM_WAYS-1 loop for i in 0 to NUM_WAYS-1 loop
if i = replace_way then if to_unsigned(i, WAY_BITS) = replace_way then
cache_tags(r1.store_index)((i + 1) * TAG_WIDTH - 1 downto i * TAG_WIDTH) <= cache_tags(to_integer(r1.store_index))((i + 1) * TAG_WIDTH - 1 downto i * TAG_WIDTH) <=
(TAG_WIDTH - 1 downto TAG_BITS => '0') & r1.reload_tag; (TAG_WIDTH - 1 downto TAG_BITS => '0') & r1.reload_tag;
end if; end if;
end loop; end loop;
@ -1408,7 +1486,7 @@ begin
-- Normal load cache miss, start the reload machine -- Normal load cache miss, start the reload machine
-- --
report "cache miss real addr:" & to_hstring(req.real_addr) & report "cache miss real addr:" & to_hstring(req.real_addr) &
" idx:" & integer'image(get_index(req.real_addr)) & " idx:" & to_hstring(get_index(req.real_addr)) &
" tag:" & to_hstring(get_tag(req.real_addr)); " tag:" & to_hstring(get_tag(req.real_addr));


-- Start the wishbone cycle -- Start the wishbone cycle
@ -1467,6 +1545,8 @@ begin
-- If we are still sending requests, was one accepted ? -- If we are still sending requests, was one accepted ?
if wishbone_in.stall = '0' and r1.wb.stb = '1' then if wishbone_in.stall = '0' and r1.wb.stb = '1' then
-- That was the last word ? We are done sending. Clear stb. -- That was the last word ? We are done sending. Clear stb.
assert not is_X(r1.wb.adr);
assert not is_X(r1.end_row_ix);
if is_last_row_wb_addr(r1.wb.adr, r1.end_row_ix) then if is_last_row_wb_addr(r1.wb.adr, r1.end_row_ix) then
r1.wb.stb <= '0'; r1.wb.stb <= '0';
end if; end if;
@ -1477,13 +1557,17 @@ begin


-- Incoming acks processing -- Incoming acks processing
if wishbone_in.ack = '1' then if wishbone_in.ack = '1' then
r1.rows_valid(r1.store_row mod ROW_PER_LINE) <= '1'; r1.rows_valid(to_integer(r1.store_row(ROW_LINEBITS-1 downto 0))) <= '1';
-- If this is the data we were looking for, we can -- If this is the data we were looking for, we can
-- complete the request next cycle. -- complete the request next cycle.
-- Compare the whole address in case the request in -- Compare the whole address in case the request in
-- r1.req is not the one that started this refill. -- r1.req is not the one that started this refill.
-- (Cases where req comes from r0 are handled as a load -- (Cases where req comes from r0 are handled as a load
-- hit.) -- hit.)
if r1.full = '1' then
assert not is_X(r1.store_row);
assert not is_X(r1.req.real_addr);
end if;
if r1.full = '1' and r1.req.same_tag = '1' and if r1.full = '1' and r1.req.same_tag = '1' and
((r1.dcbz = '1' and req.dcbz = '1') or r1.req.op = OP_LOAD_MISS) and ((r1.dcbz = '1' and req.dcbz = '1') or r1.req.op = OP_LOAD_MISS) and
r1.store_row = get_row(r1.req.real_addr) then r1.store_row = get_row(r1.req.real_addr) then
@ -1497,12 +1581,16 @@ begin
end if; end if;


-- Check for completion -- Check for completion
assert not is_X(r1.store_row);
assert not is_X(r1.end_row_ix);
if is_last_row(r1.store_row, r1.end_row_ix) then if is_last_row(r1.store_row, r1.end_row_ix) then
-- Complete wishbone cycle -- Complete wishbone cycle
r1.wb.cyc <= '0'; r1.wb.cyc <= '0';


-- Cache line is now valid -- Cache line is now valid
cache_valids(r1.store_index)(r1.store_way) <= '1'; assert not is_X(r1.store_index);
assert not is_X(r1.store_way);
cache_valids(to_integer(r1.store_index))(to_integer(r1.store_way)) <= '1';


ev.dcache_refill <= not r1.dcbz; ev.dcache_refill <= not r1.dcbz;
r1.state <= IDLE; r1.state <= IDLE;
@ -1533,6 +1621,7 @@ begin
r1.wb.dat <= req.data; r1.wb.dat <= req.data;
r1.wb.sel <= req.byte_sel; r1.wb.sel <= req.byte_sel;
end if; end if;
assert not is_X(acks);
if acks < 7 and req.same_tag = '1' and req.dcbz = '0' and if acks < 7 and req.same_tag = '1' and req.dcbz = '0' and
(req.op = OP_STORE_MISS or req.op = OP_STORE_HIT) then (req.op = OP_STORE_MISS or req.op = OP_STORE_HIT) then
r1.wb.stb <= '1'; r1.wb.stb <= '1';
@ -1556,6 +1645,7 @@ begin


-- Got ack ? See if complete. -- Got ack ? See if complete.
if wishbone_in.ack = '1' then if wishbone_in.ack = '1' then
assert not is_X(acks);
if stbs_done and acks = 1 then if stbs_done and acks = 1 then
r1.state <= IDLE; r1.state <= IDLE;
r1.wb.cyc <= '0'; r1.wb.cyc <= '0';
@ -1602,7 +1692,7 @@ begin
d_out.valid & d_out.valid &
std_ulogic_vector(to_unsigned(op_t'pos(req_op), 3)) & std_ulogic_vector(to_unsigned(op_t'pos(req_op), 3)) &
stall_out & stall_out &
std_ulogic_vector(to_unsigned(tlb_hit_way, 3)) & std_ulogic_vector(resize(tlb_hit_way, 3)) &
valid_ra & valid_ra &
std_ulogic_vector(to_unsigned(state_t'pos(r1.state), 3)); std_ulogic_vector(to_unsigned(state_t'pos(r1.state), 3));
end if; end if;

@ -434,27 +434,37 @@ begin
v.input_ov := '1'; -- need SO state if setting OV to 0 v.input_ov := '1'; -- need SO state if setting OV to 0
end if; end if;
when OP_MFSPR => when OP_MFSPR =>
case decode_spr_num(d_in.insn) is if is_X(d_in.insn) then
when SPR_XER => v.input_ov := 'X';
v.input_ov := '1'; else
when SPR_DAR | SPR_DSISR | SPR_PID | SPR_PTCR => case decode_spr_num(d_in.insn) is
unit := LDST; when SPR_XER =>
when others => v.input_ov := '1';
end case; when SPR_DAR | SPR_DSISR | SPR_PID | SPR_PTCR =>
unit := LDST;
when others =>
end case;
end if;
when OP_MTSPR => when OP_MTSPR =>
case decode_spr_num(d_in.insn) is if is_X(d_in.insn) then
when SPR_XER => v.e.output_xer := 'X';
v.e.output_xer := '1'; v.output_ov := 'X';
v.output_ov := '1'; v.sgl_pipe := 'X';
when SPR_DAR | SPR_DSISR | SPR_PID | SPR_PTCR => else
unit := LDST; case decode_spr_num(d_in.insn) is
if d_in.valid = '1' then when SPR_XER =>
v.sgl_pipe := '1'; v.e.output_xer := '1';
end if; v.output_ov := '1';
when others => when SPR_DAR | SPR_DSISR | SPR_PID | SPR_PTCR =>
end case; unit := LDST;
if d_in.spr_info.valid = '1' and d_in.valid = '1' then if d_in.valid = '1' then
v.sgl_pipe := '1'; v.sgl_pipe := '1';
end if;
when others =>
end case;
if d_in.spr_info.valid = '1' and d_in.valid = '1' then
v.sgl_pipe := '1';
end if;
end if; end if;
when OP_CMP | OP_MCRXRX => when OP_CMP | OP_MCRXRX =>
v.input_ov := '1'; v.input_ov := '1';

@ -863,11 +863,16 @@ begin
else else
a_lt_lo := '0'; a_lt_lo := '0';
a_lt_hi := '0'; a_lt_hi := '0';
if unsigned(a_in(30 downto 0)) < unsigned(b_in(30 downto 0)) then if is_X(a_in) or is_X(b_in) then
a_lt_lo := '1'; a_lt_lo := 'X';
end if; a_lt_hi := 'X';
if unsigned(a_in(62 downto 31)) < unsigned(b_in(62 downto 31)) then else
a_lt_hi := '1'; if unsigned(a_in(30 downto 0)) < unsigned(b_in(30 downto 0)) then
a_lt_lo := '1';
end if;
if unsigned(a_in(62 downto 31)) < unsigned(b_in(62 downto 31)) then
a_lt_hi := '1';
end if;
end if; end if;
if l = '1' then if l = '1' then
-- 64-bit comparison -- 64-bit comparison
@ -893,7 +898,6 @@ begin


-- CR result mux -- CR result mux
bf := insn_bf(e_in.insn); bf := insn_bf(e_in.insn);
crnum := to_integer(unsigned(bf));
newcrf := (others => '0'); newcrf := (others => '0');
case e_in.sub_select is case e_in.sub_select is
when "000" => when "000" =>
@ -908,8 +912,11 @@ begin
when "010" => when "010" =>
newcrf := ppc_cmpeqb(a_in, b_in); newcrf := ppc_cmpeqb(a_in, b_in);
when "011" => when "011" =>
if e_in.insn(1) = '1' then if is_X(e_in.insn) then
newcrf := (others => 'X');
elsif e_in.insn(1) = '1' then
-- CR logical instructions -- CR logical instructions
crnum := to_integer(unsigned(bf));
j := (7 - crnum) * 4; j := (7 - crnum) * 4;
newcrf := cr_in(j + 3 downto j); newcrf := cr_in(j + 3 downto j);
bt := insn_bt(e_in.insn); bt := insn_bt(e_in.insn);
@ -948,7 +955,8 @@ begin
crnum := fxm_to_num(insn_fxm(e_in.insn)); crnum := fxm_to_num(insn_fxm(e_in.insn));
write_cr_mask <= num_to_fxm(crnum); write_cr_mask <= num_to_fxm(crnum);
end if; end if;
elsif e_in.output_cr = '1' then elsif e_in.output_cr = '1' and not is_X(bf) then
crnum := to_integer(unsigned(bf));
write_cr_mask <= num_to_fxm(crnum); write_cr_mask <= num_to_fxm(crnum);
else else
write_cr_mask <= (others => '0'); write_cr_mask <= (others => '0');

@ -4,9 +4,7 @@
-- TODO (in no specific order): -- TODO (in no specific order):
-- --
-- * Add debug interface to inspect cache content -- * Add debug interface to inspect cache content
-- * Add snoop/invalidate path
-- * Add multi-hit error detection -- * Add multi-hit error detection
-- * Pipelined bus interface (wb or axi)
-- * Maybe add parity ? There's a few bits free in each BRAM row on Xilinx -- * Maybe add parity ? There's a few bits free in each BRAM row on Xilinx
-- * Add optimization: service hits on partially loaded lines -- * Add optimization: service hits on partially loaded lines
-- * Add optimization: (maybe) interrupt reload on fluch/redirect -- * Add optimization: (maybe) interrupt reload on fluch/redirect
@ -119,9 +117,11 @@ architecture rtl of icache is
-- .. |-----| | INDEX_BITS (5) -- .. |-----| | INDEX_BITS (5)
-- .. --------| | TAG_BITS (53) -- .. --------| | TAG_BITS (53)


subtype row_t is integer range 0 to BRAM_ROWS-1; subtype row_t is unsigned(ROW_BITS-1 downto 0);
subtype index_t is integer range 0 to NUM_LINES-1; subtype index_t is integer range 0 to NUM_LINES-1;
subtype index_sig_t is unsigned(INDEX_BITS-1 downto 0);
subtype way_t is integer range 0 to NUM_WAYS-1; subtype way_t is integer range 0 to NUM_WAYS-1;
subtype way_sig_t is unsigned(WAY_BITS-1 downto 0);
subtype row_in_line_t is unsigned(ROW_LINEBITS-1 downto 0); subtype row_in_line_t is unsigned(ROW_LINEBITS-1 downto 0);


-- We store a pre-decoded 10-bit insn_code along with the bottom 26 bits of -- We store a pre-decoded 10-bit insn_code along with the bottom 26 bits of
@ -187,7 +187,7 @@ architecture rtl of icache is


type reg_internal_t is record type reg_internal_t is record
-- Cache hit state (Latches for 1 cycle BRAM access) -- Cache hit state (Latches for 1 cycle BRAM access)
hit_way : way_t; hit_way : way_sig_t;
hit_nia : std_ulogic_vector(63 downto 0); hit_nia : std_ulogic_vector(63 downto 0);
hit_smark : std_ulogic; hit_smark : std_ulogic;
hit_valid : std_ulogic; hit_valid : std_ulogic;
@ -196,8 +196,8 @@ architecture rtl of icache is
-- Cache miss state (reload state machine) -- Cache miss state (reload state machine)
state : state_t; state : state_t;
wb : wishbone_master_out; wb : wishbone_master_out;
store_way : way_t; store_way : way_sig_t;
store_index : index_t; store_index : index_sig_t;
recv_row : row_t; recv_row : row_t;
recv_valid : std_ulogic; recv_valid : std_ulogic;
store_row : row_t; store_row : row_t;
@ -215,9 +215,9 @@ architecture rtl of icache is
signal ev : IcacheEventType; signal ev : IcacheEventType;


-- Async signals on incoming request -- Async signals on incoming request
signal req_index : index_t; signal req_index : index_sig_t;
signal req_row : row_t; signal req_row : row_t;
signal req_hit_way : way_t; signal req_hit_way : way_sig_t;
signal req_tag : cache_tag_t; signal req_tag : cache_tag_t;
signal req_is_hit : std_ulogic; signal req_is_hit : std_ulogic;
signal req_is_miss : std_ulogic; signal req_is_miss : std_ulogic;
@ -237,33 +237,30 @@ architecture rtl of icache is
-- PLRU output interface -- PLRU output interface
type plru_out_t is array(index_t) of std_ulogic_vector(WAY_BITS-1 downto 0); type plru_out_t is array(index_t) of std_ulogic_vector(WAY_BITS-1 downto 0);
signal plru_victim : plru_out_t; signal plru_victim : plru_out_t;
signal replace_way : way_t;


-- Memory write snoop signals -- Memory write snoop signals
signal snoop_valid : std_ulogic; signal snoop_valid : std_ulogic;
signal snoop_index : index_t; signal snoop_index : index_sig_t;
signal snoop_hits : cache_way_valids_t; signal snoop_hits : cache_way_valids_t;


signal log_insn : std_ulogic_vector(35 downto 0); signal log_insn : std_ulogic_vector(35 downto 0);


-- Return the cache line index (tag index) for an address -- Return the cache line index (tag index) for an address
function get_index(addr: std_ulogic_vector) return index_t is function get_index(addr: std_ulogic_vector) return index_sig_t is
begin begin
return to_integer(unsigned(addr(SET_SIZE_BITS - 1 downto LINE_OFF_BITS))); return unsigned(addr(SET_SIZE_BITS - 1 downto LINE_OFF_BITS));
end; end;


-- Return the cache row index (data memory) for an address -- Return the cache row index (data memory) for an address
function get_row(addr: std_ulogic_vector) return row_t is function get_row(addr: std_ulogic_vector) return row_t is
begin begin
return to_integer(unsigned(addr(SET_SIZE_BITS - 1 downto ROW_OFF_BITS))); return unsigned(addr(SET_SIZE_BITS - 1 downto ROW_OFF_BITS));
end; end;


-- Return the index of a row within a line -- Return the index of a row within a line
function get_row_of_line(row: row_t) return row_in_line_t is function get_row_of_line(row: row_t) return row_in_line_t is
variable row_v : unsigned(ROW_BITS-1 downto 0);
begin begin
row_v := to_unsigned(row, ROW_BITS); return row(ROW_LINEBITS-1 downto 0);
return row_v(ROW_LINEBITS-1 downto 0);
end; end;


-- Returns whether this is the last row of a line -- Returns whether this is the last row of a line
@ -298,13 +295,13 @@ architecture rtl of icache is
-- --
function next_row(row: row_t) return row_t is function next_row(row: row_t) return row_t is
variable row_v : std_ulogic_vector(ROW_BITS-1 downto 0); variable row_v : std_ulogic_vector(ROW_BITS-1 downto 0);
variable row_idx : std_ulogic_vector(ROW_LINEBITS-1 downto 0); variable row_idx : unsigned(ROW_LINEBITS-1 downto 0);
variable result : std_ulogic_vector(ROW_BITS-1 downto 0); variable result : std_ulogic_vector(ROW_BITS-1 downto 0);
begin begin
row_v := std_ulogic_vector(to_unsigned(row, ROW_BITS)); row_v := std_ulogic_vector(row);
row_idx := row_v(ROW_LINEBITS-1 downto 0); row_idx := row(ROW_LINEBITS-1 downto 0);
row_v(ROW_LINEBITS-1 downto 0) := std_ulogic_vector(unsigned(row_idx) + 1); row_v(ROW_LINEBITS-1 downto 0) := std_ulogic_vector(row_idx + 1);
return to_integer(unsigned(row_v)); return unsigned(row_v);
end; end;


-- Read the instruction word for the given address in the current cache row -- Read the instruction word for the given address in the current cache row
@ -312,6 +309,7 @@ architecture rtl of icache is
data: cache_row_t) return std_ulogic_vector is data: cache_row_t) return std_ulogic_vector is
variable word: integer range 0 to INSN_PER_ROW-1; variable word: integer range 0 to INSN_PER_ROW-1;
begin begin
assert not is_X(addr) severity failure;
word := to_integer(unsigned(addr(INSN_BITS+2-1 downto 2))); word := to_integer(unsigned(addr(INSN_BITS+2-1 downto 2)));
return data(word * ICWORDLEN + ICWORDLEN - 1 downto word * ICWORDLEN); return data(word * ICWORDLEN + ICWORDLEN - 1 downto word * ICWORDLEN);
end; end;
@ -436,12 +434,12 @@ begin
begin begin
do_read <= not stall_in; do_read <= not stall_in;
do_write <= '0'; do_write <= '0';
if r.recv_valid = '1' and r.store_way = i then if r.recv_valid = '1' and r.store_way = to_unsigned(i, WAY_BITS) then
do_write <= '1'; do_write <= '1';
end if; end if;
cache_out(i) <= dout; cache_out(i) <= dout;
rd_addr <= std_ulogic_vector(to_unsigned(req_row, ROW_BITS)); rd_addr <= std_ulogic_vector(req_row);
wr_addr <= std_ulogic_vector(to_unsigned(r.store_row, ROW_BITS)); wr_addr <= std_ulogic_vector(r.store_row);
wr_sel(0) <= do_write; wr_sel(0) <= do_write;
end process; end process;
end generate; end generate;
@ -478,7 +476,7 @@ begin
else else
plru_acc_en <= '0'; plru_acc_en <= '0';
end if; end if;
plru_acc <= std_ulogic_vector(to_unsigned(r.hit_way, WAY_BITS)); plru_acc <= std_ulogic_vector(r.hit_way);
plru_victim(i) <= plru_out; plru_victim(i) <= plru_out;
end process; end process;
end generate; end generate;
@ -550,15 +548,13 @@ begin
-- Cache hit detection, output to fetch2 and other misc logic -- Cache hit detection, output to fetch2 and other misc logic
icache_comb : process(all) icache_comb : process(all)
variable is_hit : std_ulogic; variable is_hit : std_ulogic;
variable hit_way : way_t; variable hit_way : way_sig_t;
variable insn : std_ulogic_vector(ICWORDLEN - 1 downto 0); variable insn : std_ulogic_vector(ICWORDLEN - 1 downto 0);
variable icode : insn_code; variable icode : insn_code;
begin begin
-- Extract line, row and tag from request -- Extract line, row and tag from request
if not is_X(i_in.nia) then req_index <= get_index(i_in.nia);
req_index <= get_index(i_in.nia); req_row <= get_row(i_in.nia);
req_row <= get_row(i_in.nia);
end if;
req_tag <= get_tag(real_addr, i_in.big_endian); req_tag <= get_tag(real_addr, i_in.big_endian);


-- Calculate address of beginning of cache row, will be -- Calculate address of beginning of cache row, will be
@ -568,21 +564,20 @@ begin
(ROW_OFF_BITS-1 downto 0 => '0'); (ROW_OFF_BITS-1 downto 0 => '0');


-- Test if pending request is a hit on any way -- Test if pending request is a hit on any way
hit_way := 0; hit_way := to_unsigned(0, WAY_BITS);
is_hit := '0'; is_hit := '0';
if i_in.req = '1' then
assert not is_X(req_index) and not is_X(req_row) severity failure;
end if;
for i in way_t loop for i in way_t loop
if is_X(i_in.nia) then if i_in.req = '1' and
-- FIXME: This is fragile (cache_valids(to_integer(req_index))(i) = '1' or
-- 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 (r.state = WAIT_ACK and
req_index = r.store_index and req_index = r.store_index and
i = r.store_way and to_unsigned(i, WAY_BITS) = r.store_way and
r.rows_valid(req_row mod ROW_PER_LINE) = '1')) then r.rows_valid(to_integer(req_row(ROW_LINEBITS-1 downto 0))) = '1')) then
if read_tag(i, cache_tags(req_index)) = req_tag then if read_tag(i, cache_tags(to_integer(req_index))) = req_tag then
hit_way := i; hit_way := to_unsigned(i, WAY_BITS);
is_hit := '1'; is_hit := '1';
end if; end if;
end if; end if;
@ -598,13 +593,6 @@ begin
end if; end if;
req_hit_way <= hit_way; req_hit_way <= hit_way;


-- The way to replace on a miss
if r.state = CLR_TAG then
replace_way <= to_integer(unsigned(plru_victim(r.store_index)));
else
replace_way <= r.store_way;
end if;

-- Output instruction from current cache row -- Output instruction from current cache row
-- --
-- Note: This is a mild violation of our design principle of having pipeline -- Note: This is a mild violation of our design principle of having pipeline
@ -616,10 +604,13 @@ begin
insn := (others => '0'); insn := (others => '0');
icode := INSN_illegal; icode := INSN_illegal;
if r.hit_valid = '1' then if r.hit_valid = '1' then
insn := read_insn_word(r.hit_nia, cache_out(r.hit_way)); assert not is_X(r.hit_way) severity failure;
insn := read_insn_word(r.hit_nia, cache_out(to_integer(r.hit_way)));
-- Currently we use only the top bit for indicating illegal -- Currently we use only the top bit for indicating illegal
-- instructions because we know that insn_codes fit into 9 bits. -- instructions because we know that insn_codes fit into 9 bits.
if insn(ICWORDLEN - 1) = '0' then if is_X(insn) then
insn := (others => '0');
elsif insn(ICWORDLEN - 1) = '0' then
icode := insn_code'val(to_integer(unsigned(insn(ICWORDLEN-1 downto INSN_IMAGE_BITS)))); icode := insn_code'val(to_integer(unsigned(insn(ICWORDLEN-1 downto INSN_IMAGE_BITS))));
end if; end if;
end if; end if;
@ -664,9 +655,9 @@ begin
report "cache hit nia:" & to_hstring(i_in.nia) & report "cache hit nia:" & to_hstring(i_in.nia) &
" IR:" & std_ulogic'image(i_in.virt_mode) & " IR:" & std_ulogic'image(i_in.virt_mode) &
" SM:" & std_ulogic'image(i_in.stop_mark) & " SM:" & std_ulogic'image(i_in.stop_mark) &
" idx:" & integer'image(req_index) & " idx:" & to_hstring(req_index) &
" tag:" & to_hstring(req_tag) & " tag:" & to_hstring(req_tag) &
" way:" & integer'image(req_hit_way) & " way:" & to_hstring(req_hit_way) &
" RA:" & to_hstring(real_addr); " RA:" & to_hstring(real_addr);
end if; end if;
end if; end if;
@ -676,6 +667,9 @@ begin
r.hit_nia <= i_in.nia; r.hit_nia <= i_in.nia;
r.big_endian <= i_in.big_endian; r.big_endian <= i_in.big_endian;
end if; end if;
if i_out.valid = '1' then
assert not is_X(i_out.insn) severity failure;
end if;
end if; end if;
end process; end process;


@ -686,7 +680,7 @@ begin
variable snoop_addr : real_addr_t; variable snoop_addr : real_addr_t;
variable snoop_tag : cache_tag_t; variable snoop_tag : cache_tag_t;
variable snoop_cache_tags : cache_tags_set_t; variable snoop_cache_tags : cache_tags_set_t;
variable replace_way : way_t; variable replace_way : way_sig_t;
begin begin
if rising_edge(clk) then if rising_edge(clk) then
ev.icache_miss <= '0'; ev.icache_miss <= '0';
@ -709,7 +703,7 @@ begin
r.wb.adr <= (others => '0'); r.wb.adr <= (others => '0');


snoop_valid <= '0'; snoop_valid <= '0';
snoop_index <= 0; snoop_index <= to_unsigned(0, INDEX_BITS);
snoop_hits <= (others => '0'); snoop_hits <= (others => '0');
else else
-- Detect snooped writes and decode address into index and tag -- Detect snooped writes and decode address into index and tag
@ -717,20 +711,22 @@ begin
snoop_valid <= wb_snoop_in.cyc and wb_snoop_in.stb and wb_snoop_in.we; snoop_valid <= wb_snoop_in.cyc and wb_snoop_in.stb and wb_snoop_in.we;
snoop_addr := addr_to_real(wb_to_addr(wb_snoop_in.adr)); snoop_addr := addr_to_real(wb_to_addr(wb_snoop_in.adr));
snoop_index <= get_index(snoop_addr); 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_tag := get_tag(snoop_addr, '0');
snoop_hits <= (others => '0'); snoop_hits <= (others => '0');
for i in way_t loop if snoop_valid = '1' then
tag := read_tag(i, snoop_cache_tags); if is_X(snoop_addr) then
-- Ignore endian bit in comparison report "metavalue in snoop_addr" severity FAILURE;
tag(TAG_BITS - 1) := '0';
if tag = snoop_tag then
snoop_hits(i) <= '1';
end if; end if;
end loop; snoop_cache_tags := cache_tags(to_integer(get_index(snoop_addr)));
for i in way_t loop
tag := read_tag(i, snoop_cache_tags);
-- Ignore endian bit in comparison
tag(TAG_BITS - 1) := '0';
if tag = snoop_tag then
snoop_hits(i) <= '1';
end if;
end loop;
end if;


-- Process cache invalidations -- Process cache invalidations
if inval_in = '1' then if inval_in = '1' then
@ -742,8 +738,9 @@ begin
-- Do invalidations from snooped stores to memory, one -- Do invalidations from snooped stores to memory, one
-- cycle after the address appears on wb_snoop_in. -- cycle after the address appears on wb_snoop_in.
for i in way_t loop for i in way_t loop
if snoop_valid = '1' and snoop_hits(i) = '1' then if snoop_hits(i) = '1' then
cache_valids(snoop_index)(i) <= '0'; assert not is_X(snoop_index) severity failure;
cache_valids(to_integer(snoop_index))(i) <= '0';
end if; end if;
end loop; end loop;
end if; end if;
@ -761,7 +758,7 @@ begin
report "cache miss nia:" & to_hstring(i_in.nia) & report "cache miss nia:" & to_hstring(i_in.nia) &
" IR:" & std_ulogic'image(i_in.virt_mode) & " IR:" & std_ulogic'image(i_in.virt_mode) &
" SM:" & std_ulogic'image(i_in.stop_mark) & " SM:" & std_ulogic'image(i_in.stop_mark) &
" idx:" & integer'image(req_index) & " idx:" & to_hstring(req_index) &
" tag:" & to_hstring(req_tag) & " tag:" & to_hstring(req_tag) &
" RA:" & to_hstring(real_addr); " RA:" & to_hstring(real_addr);
ev.icache_miss <= '1'; ev.icache_miss <= '1';
@ -786,20 +783,24 @@ begin
end if; end if;


when CLR_TAG | WAIT_ACK => when CLR_TAG | WAIT_ACK =>
assert not is_X(r.store_index) severity failure;
assert not is_X(r.store_row) severity failure;
assert not is_X(r.recv_row) severity failure;
if r.state = CLR_TAG then if r.state = CLR_TAG then
-- Get victim way from plru -- Get victim way from plru
replace_way := to_integer(unsigned(plru_victim(r.store_index))); replace_way := unsigned(plru_victim(to_integer(r.store_index)));
r.store_way <= replace_way; r.store_way <= replace_way;


-- Force misses on that way while reloading that line -- Force misses on that way while reloading that line
cache_valids(req_index)(replace_way) <= '0'; assert not is_X(replace_way) severity failure;
cache_valids(to_integer(r.store_index))(to_integer(replace_way)) <= '0';


-- Store new tag in selected way -- Store new tag in selected way
for i in 0 to NUM_WAYS-1 loop for i in 0 to NUM_WAYS-1 loop
if i = replace_way then if to_unsigned(i, WAY_BITS) = replace_way then
tagset := cache_tags(r.store_index); tagset := cache_tags(to_integer(r.store_index));
write_tag(i, tagset, r.store_tag); write_tag(i, tagset, r.store_tag);
cache_tags(r.store_index) <= tagset; cache_tags(to_integer(r.store_index)) <= tagset;
end if; end if;
end loop; end loop;


@ -808,10 +809,11 @@ begin


-- If we are writing in this cycle, mark row valid and see if we are done -- If we are writing in this cycle, mark row valid and see if we are done
if r.recv_valid = '1' then if r.recv_valid = '1' then
r.rows_valid(r.store_row mod ROW_PER_LINE) <= not inval_in; r.rows_valid(to_integer(r.store_row(ROW_LINEBITS-1 downto 0))) <= not inval_in;
if is_last_row(r.store_row, r.end_row_ix) then if is_last_row(r.store_row, r.end_row_ix) then
-- Cache line is now valid -- Cache line is now valid
cache_valids(r.store_index)(r.store_way) <= r.store_valid and not inval_in; cache_valids(to_integer(r.store_index))(to_integer(r.store_way)) <=
r.store_valid and not inval_in;
-- We are done -- We are done
r.state <= IDLE; r.state <= IDLE;
end if; end if;
@ -878,7 +880,7 @@ begin
signal log_data : std_ulogic_vector(57 downto 0); signal log_data : std_ulogic_vector(57 downto 0);
begin begin
data_log: process(clk) data_log: process(clk)
variable lway: way_t; variable lway: way_sig_t;
variable wstate: std_ulogic; variable wstate: std_ulogic;
begin begin
if rising_edge(clk) then if rising_edge(clk) then
@ -897,7 +899,7 @@ begin
r.fetch_failed & r.fetch_failed &
r.hit_nia(5 downto 2) & r.hit_nia(5 downto 2) &
wstate & wstate &
std_ulogic_vector(to_unsigned(lway, 3)) & std_ulogic_vector(resize(lway, 3)) &
req_is_hit & req_is_miss & req_is_hit & req_is_miss &
access_ok & access_ok &
ra_valid; ra_valid;

@ -199,9 +199,14 @@ architecture behave of loadstore1 is
return std_ulogic_vector is return std_ulogic_vector is
variable longsel : std_ulogic_vector(15 downto 0); variable longsel : std_ulogic_vector(15 downto 0);
begin begin
longsel := "00000000" & length_to_sel(size); if is_X(address) then
return std_ulogic_vector(shift_left(unsigned(longsel), longsel := (others => 'X');
to_integer(unsigned(address)))); return longsel;
else
longsel := "00000000" & length_to_sel(size);
return std_ulogic_vector(shift_left(unsigned(longsel),
to_integer(unsigned(address))));
end if;
end function xfer_data_sel; end function xfer_data_sel;


-- 23-bit right shifter for DP -> SP float conversions -- 23-bit right shifter for DP -> SP float conversions
@ -401,7 +406,7 @@ begin
variable addr_mask : std_ulogic_vector(2 downto 0); variable addr_mask : std_ulogic_vector(2 downto 0);
begin begin
v := request_init; v := request_init;
sprn := std_ulogic_vector(to_unsigned(decode_spr_num(l_in.insn), 10)); sprn := l_in.insn(15 downto 11) & l_in.insn(20 downto 16);


v.valid := l_in.valid; v.valid := l_in.valid;
v.instr_tag := l_in.instr_tag; v.instr_tag := l_in.instr_tag;

Loading…
Cancel
Save