icache: Snoop writes to memory by other agents

This makes the icache snoop writes to memory in the same way that the
dcache does, thus making DMA cache-coherent for the icache as well as
the dcache.

This also simplifies the logic for the WAIT_ACK state by removing the
stbs_done variable, since is_last_row(r.store_row, r.end_row_ix) can
only be true when stbs_done is true.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
remove-potato-uart
Paul Mackerras 3 years ago
parent 4c11c9c661
commit 231003f7c7

@ -243,6 +243,7 @@ begin
stall_out => icache_stall_out, stall_out => icache_stall_out,
wishbone_out => wishbone_insn_out, wishbone_out => wishbone_insn_out,
wishbone_in => wishbone_insn_in, wishbone_in => wishbone_insn_in,
wb_snoop_in => wb_snoop_in,
log_out => log_data(96 downto 43) log_out => log_data(96 downto 43)
); );



@ -68,6 +68,8 @@ entity icache is
wishbone_out : out wishbone_master_out; wishbone_out : out wishbone_master_out;
wishbone_in : in wishbone_slave_out; wishbone_in : in wishbone_slave_out;


wb_snoop_in : in wishbone_master_out := wishbone_master_out_init;

log_out : out std_ulogic_vector(53 downto 0) log_out : out std_ulogic_vector(53 downto 0)
); );
end entity icache; end entity icache;
@ -220,8 +222,13 @@ architecture rtl of icache is
signal plru_victim : plru_out_t; signal plru_victim : plru_out_t;
signal replace_way : way_t; signal replace_way : way_t;


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

-- 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(63 downto 0)) 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 to_integer(unsigned(addr(SET_SIZE_BITS - 1 downto LINE_OFF_BITS)));
end; end;
@ -614,7 +621,10 @@ begin
-- Cache miss/reload synchronous machine -- Cache miss/reload synchronous machine
icache_miss : process(clk) icache_miss : process(clk)
variable tagset : cache_tags_set_t; variable tagset : cache_tags_set_t;
variable stbs_done : boolean; variable tag : cache_tag_t;
variable snoop_addr : std_ulogic_vector(REAL_ADDR_BITS - 1 downto 0);
variable snoop_tag : cache_tag_t;
variable snoop_cache_tags : cache_tags_set_t;
begin begin
if rising_edge(clk) then if rising_edge(clk) then
-- On reset, clear all valid bits to force misses -- On reset, clear all valid bits to force misses
@ -633,13 +643,43 @@ begin


-- Not useful normally but helps avoiding tons of sim warnings -- Not useful normally but helps avoiding tons of sim warnings
r.wb.adr <= (others => '0'); r.wb.adr <= (others => '0');

snoop_valid <= '0';
snoop_index <= 0;
snoop_hits <= (others => '0');
else else
-- Detect snooped writes and decode address into index and tag
-- Since we never write, any write should be snooped
snoop_valid <= wb_snoop_in.cyc and wb_snoop_in.stb and wb_snoop_in.we;
snoop_addr := (others => '0');
snoop_addr(wb_snoop_in.adr'left downto 0) := wb_snoop_in.adr;
snoop_index <= get_index(snoop_addr);
snoop_cache_tags := cache_tags(get_index(snoop_addr));
snoop_tag := get_tag(snoop_addr, '0');
snoop_hits <= (others => '0');
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;

-- Process cache invalidations -- Process cache invalidations
if inval_in = '1' then if inval_in = '1' then
for i in index_t loop for i in index_t loop
cache_valids(i) <= (others => '0'); cache_valids(i) <= (others => '0');
end loop; end loop;
r.store_valid <= '0'; r.store_valid <= '0';
else
-- Do invalidations from snooped stores to memory, one
-- cycle after the address appears on wb_snoop_in.
for i in way_t loop
if snoop_valid = '1' and snoop_hits(i) = '1' then
cache_valids(snoop_index)(i) <= '0';
end if;
end loop;
end if; end if;


-- Main state machine -- Main state machine
@ -697,18 +737,13 @@ begin


r.state <= WAIT_ACK; r.state <= WAIT_ACK;
end if; end if;
-- Requests are all sent if stb is 0
stbs_done := r.wb.stb = '0';


-- If we are still sending requests, was one accepted ? -- If we are still sending requests, was one accepted ?
if wishbone_in.stall = '0' and not stbs_done then if wishbone_in.stall = '0' and r.wb.stb = '1' then
-- That was the last word ? We are done sending. Clear -- That was the last word ? We are done sending. Clear stb.
-- stb and set stbs_done so we can handle an eventual last
-- ack on the same cycle.
-- --
if is_last_row_addr(r.wb.adr, r.end_row_ix) then if is_last_row_addr(r.wb.adr, r.end_row_ix) then
r.wb.stb <= '0'; r.wb.stb <= '0';
stbs_done := true;
end if; end if;


-- Calculate the next row address -- Calculate the next row address
@ -719,7 +754,7 @@ begin
if wishbone_in.ack = '1' then if wishbone_in.ack = '1' then
r.rows_valid(r.store_row mod ROW_PER_LINE) <= '1'; r.rows_valid(r.store_row mod ROW_PER_LINE) <= '1';
-- Check for completion -- Check for completion
if stbs_done and is_last_row(r.store_row, r.end_row_ix) then if is_last_row(r.store_row, r.end_row_ix) then
-- Complete wishbone cycle -- Complete wishbone cycle
r.wb.cyc <= '0'; r.wb.cyc <= '0';



Loading…
Cancel
Save