diff --git a/dcache.vhdl b/dcache.vhdl index a98dde2..cf72927 100644 --- a/dcache.vhdl +++ b/dcache.vhdl @@ -416,7 +416,6 @@ architecture rtl of dcache is signal reservation : reservation_t; signal kill_rsrv : std_ulogic; - signal kill_rsrv2 : std_ulogic; -- Async signals on incoming request signal req_index : index_t; @@ -936,9 +935,6 @@ begin snoop_addr <= addr_to_real(wb_to_addr(snoop_in.adr)); snoop_active <= snoop_in.cyc and snoop_in.stb and snoop_in.we and not (r1.wb.cyc and not wishbone_in.stall); - kill_rsrv <= '1' when (snoop_active = '1' and reservation.valid = '1' and - snoop_addr(REAL_ADDR_BITS - 1 downto LINE_OFF_BITS) = reservation.addr) - else '0'; -- Cache tag RAM second read port, for snooping cache_tag_read_2 : process(clk) @@ -954,10 +950,9 @@ begin end if; end process; - -- Compare the previous cycle's snooped store address to the reservation, - -- to catch the case where a write happens on cycle 1 of a cached larx - kill_rsrv2 <= '1' when (snoop_valid = '1' and reservation.valid = '1' and - snoop_paddr(REAL_ADDR_BITS - 1 downto LINE_OFF_BITS) = reservation.addr) + -- Compare the previous cycle's snooped store address to the reservation + kill_rsrv <= '1' when (snoop_valid = '1' and reservation.valid = '1' and + snoop_paddr(REAL_ADDR_BITS - 1 downto LINE_OFF_BITS) = reservation.addr) else '0'; snoop_tag_match : process(all) @@ -1493,10 +1488,8 @@ begin r1.mmu_done <= (r0_valid and (r0.tlbie or r0.tlbld)) or (req_op_load_hit and r0.mmu_req); - -- The kill_rsrv2 term covers the case where the reservation - -- address was set at the beginning of this cycle, and a store - -- to that address happened in the previous cycle. - if kill_rsrv = '1' or kill_rsrv2 = '1' then + -- Clear the reservation if another entity writes to that line + if kill_rsrv = '1' then reservation.valid <= '0'; end if; if req_go = '1' and access_ok = '1' and r0.req.load = '1' and @@ -1689,9 +1682,18 @@ begin if req.op_store = '1' then if req.reserve = '1' then - -- stcx needs to wait until next cycle - -- for the reservation address check - r1.state <= DO_STCX; + if reservation.valid = '0' or kill_rsrv = '1' then + -- someone else has stored to the reservation granule + r1.stcx_fail <= '1'; + r1.full <= '0'; + r1.ls_valid <= '1'; + else + r1.wb.we <= '1'; + r1.wb.cyc <= '1'; + -- stcx needs to wait to assert stb until next cycle + -- for the reservation address check + r1.state <= DO_STCX; + end if; elsif req.dcbz = '0' then r1.state <= STORE_WAIT_ACK; r1.full <= '0'; @@ -1876,28 +1878,21 @@ begin if reservation.valid = '0' or kill_rsrv = '1' or r1.req.real_addr(REAL_ADDR_BITS - 1 downto LINE_OFF_BITS) /= reservation.addr then -- Wrong address, didn't have reservation, or lost reservation - -- Abandon the wishbone cycle if started and fail the stcx. + -- Abandon the wishbone cycle and fail the stcx. r1.stcx_fail <= '1'; r1.full <= '0'; r1.ls_valid <= '1'; r1.state <= IDLE; r1.wb.cyc <= '0'; - r1.wb.stb <= '0'; reservation.valid <= '0'; -- If this is the first half of a stqcx., the second half -- will fail also because the reservation is not valid. r1.state <= IDLE; - elsif r1.wb.cyc = '0' then - -- Right address and have reservation, so start the - -- wishbone cycle - r1.wb.we <= '1'; - r1.wb.cyc <= '1'; - r1.wb.stb <= '1'; - elsif r1.wb.stb = '1' and wishbone_in.stall = '0' then - -- Store has been accepted, so now we can write the - -- cache data RAM and complete the request + elsif wishbone_in.stall = '0' then + -- We have the wishbone, so now we can assert stb, + -- write the cache data RAM and complete the request r1.write_bram <= r1.req.is_hit; - r1.wb.stb <= '0'; + r1.wb.stb <= '1'; r1.full <= '0'; r1.slow_valid <= '1'; r1.ls_valid <= '1';