dcache: Fix bug causing load to return incorrect data

If a touch is immediately followed by a load to a different address
which has the same index as the touch address, and both are cache
misses, it is possible for the load to be treated as if it is to the
same cache line as the touch, and thus return data from the line being
touched rather than the line being loaded from.  For example, if the
touch is to 0x1c20 and the load is to 0x2c20, and the state left in
r1.store_ways by an earlier operation happens to match the PLRU victim
way, the load will return data from 0x1c20.

This happens because the touch completes immediately, meaning that the
load gets processed before r1.store_ways and the cache tag for the
line being touched have been set correctly, leading to a chance that
the load can match when it shouldn't (or not match when it should).
To fix this, complete the touch after one cycle, in RELOAD_WAIT_ACK
state, rather than immediately.

Also, for touches, consider hit_reload = 1 equivalent to a cache hit.
If the line is being reloaded then the touch doesn't need to do
anything.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/458/head
Paul Mackerras 2 weeks ago
parent c78d9b32ef
commit a7420c2a4d

@ -1121,9 +1121,9 @@ begin
if r0.req.sync = '1' then
req_op_sync <= '1';
elsif r0.req.touch = '1' then
if access_ok = '1' and is_hit = '0' and nc = '0' then
if access_ok = '1' and (is_hit or hit_reload) = '0' and nc = '0' then
req_op_load_miss <= '1';
elsif access_ok = '1' and is_hit = '1' and nc = '0' then
elsif access_ok = '1' and (is_hit or hit_reload) = '1' and nc = '0' then
-- Make this OP_LOAD_HIT so the PLRU gets updated
req_op_load_hit <= '1';
else
@ -1632,13 +1632,6 @@ begin
r1.reloading <= '1';
r1.write_tag <= '1';
ev.load_miss <= '1';

-- If this is a touch, complete the instruction
if req.touch = '1' then
r1.full <= '0';
r1.slow_valid <= '1';
r1.ls_valid <= '1';
end if;
else
r1.state <= NC_LOAD_WAIT_ACK;
end if;
@ -1710,6 +1703,13 @@ begin
r1.wb.adr <= next_row_wb_addr(r1.wb.adr);
end if;

-- If this is a touch, complete the instruction
if r1.full = '1' and r1.req.touch = '1' then
r1.full <= '0';
r1.slow_valid <= '1';
r1.ls_valid <= '1';
end if;

-- Incoming acks processing
if wishbone_in.ack = '1' then
r1.rows_valid(to_integer(r1.store_row(ROW_LINEBITS-1 downto 0))) <= '1';

Loading…
Cancel
Save