From a7420c2a4d69cc2a57625fad9b96105d14a08e3d Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 27 Dec 2025 15:22:09 +1100 Subject: [PATCH] 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 --- dcache.vhdl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dcache.vhdl b/dcache.vhdl index a0fec63..58c464b 100644 --- a/dcache.vhdl +++ b/dcache.vhdl @@ -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';