dcache: Simplify reservation logic

With some slight arrangement of the state machine in the dcache_slow
process, we can remove one of the two comparators that detect writes
by other entities to the reservation granule.  The state machine now
sets the wishbone cyc signal on the transition from IDLE to DO_STCX
state.  Once we see the wishbone stall signal at 0, we consider we
have the wishbone and we can assert stb to do the write provided that
the stcx is to the reservation address and we haven't seen another
write to the reservation granule.  We keep the comparator that
compares the snoop address delayed by one cycle, in order to make
timing easier, and the one (or more) cycle delay between cyc and stb
covers that one cycle delay in the kill_rsrv signal.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/441/head
Paul Mackerras 1 month ago
parent 26507450b7
commit 4278387b21

@ -416,7 +416,6 @@ architecture rtl of dcache is


signal reservation : reservation_t; signal reservation : reservation_t;
signal kill_rsrv : std_ulogic; signal kill_rsrv : std_ulogic;
signal kill_rsrv2 : std_ulogic;


-- Async signals on incoming request -- Async signals on incoming request
signal req_index : index_t; signal req_index : index_t;
@ -936,9 +935,6 @@ begin
snoop_addr <= addr_to_real(wb_to_addr(snoop_in.adr)); 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 snoop_active <= snoop_in.cyc and snoop_in.stb and snoop_in.we and
not (r1.wb.cyc and not wishbone_in.stall); 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 RAM second read port, for snooping
cache_tag_read_2 : process(clk) cache_tag_read_2 : process(clk)
@ -954,9 +950,8 @@ begin
end if; end if;
end process; end process;


-- Compare the previous cycle's snooped store address to the reservation, -- 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_rsrv <= '1' when (snoop_valid = '1' and reservation.valid = '1' and
kill_rsrv2 <= '1' when (snoop_valid = '1' and reservation.valid = '1' and
snoop_paddr(REAL_ADDR_BITS - 1 downto LINE_OFF_BITS) = reservation.addr) snoop_paddr(REAL_ADDR_BITS - 1 downto LINE_OFF_BITS) = reservation.addr)
else '0'; else '0';


@ -1493,10 +1488,8 @@ begin
r1.mmu_done <= (r0_valid and (r0.tlbie or r0.tlbld)) or r1.mmu_done <= (r0_valid and (r0.tlbie or r0.tlbld)) or
(req_op_load_hit and r0.mmu_req); (req_op_load_hit and r0.mmu_req);


-- The kill_rsrv2 term covers the case where the reservation -- Clear the reservation if another entity writes to that line
-- address was set at the beginning of this cycle, and a store if kill_rsrv = '1' then
-- to that address happened in the previous cycle.
if kill_rsrv = '1' or kill_rsrv2 = '1' then
reservation.valid <= '0'; reservation.valid <= '0';
end if; end if;
if req_go = '1' and access_ok = '1' and r0.req.load = '1' and 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.op_store = '1' then
if req.reserve = '1' then if req.reserve = '1' then
-- stcx needs to wait until next cycle 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 -- for the reservation address check
r1.state <= DO_STCX; r1.state <= DO_STCX;
end if;
elsif req.dcbz = '0' then elsif req.dcbz = '0' then
r1.state <= STORE_WAIT_ACK; r1.state <= STORE_WAIT_ACK;
r1.full <= '0'; r1.full <= '0';
@ -1876,28 +1878,21 @@ begin
if reservation.valid = '0' or kill_rsrv = '1' or if reservation.valid = '0' or kill_rsrv = '1' or
r1.req.real_addr(REAL_ADDR_BITS - 1 downto LINE_OFF_BITS) /= reservation.addr then r1.req.real_addr(REAL_ADDR_BITS - 1 downto LINE_OFF_BITS) /= reservation.addr then
-- Wrong address, didn't have reservation, or lost reservation -- 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.stcx_fail <= '1';
r1.full <= '0'; r1.full <= '0';
r1.ls_valid <= '1'; r1.ls_valid <= '1';
r1.state <= IDLE; r1.state <= IDLE;
r1.wb.cyc <= '0'; r1.wb.cyc <= '0';
r1.wb.stb <= '0';
reservation.valid <= '0'; reservation.valid <= '0';
-- If this is the first half of a stqcx., the second half -- If this is the first half of a stqcx., the second half
-- will fail also because the reservation is not valid. -- will fail also because the reservation is not valid.
r1.state <= IDLE; r1.state <= IDLE;
elsif r1.wb.cyc = '0' then elsif wishbone_in.stall = '0' then
-- Right address and have reservation, so start the -- We have the wishbone, so now we can assert stb,
-- wishbone cycle -- write the cache data RAM and complete the request
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
r1.write_bram <= r1.req.is_hit; r1.write_bram <= r1.req.is_hit;
r1.wb.stb <= '0'; r1.wb.stb <= '1';
r1.full <= '0'; r1.full <= '0';
r1.slow_valid <= '1'; r1.slow_valid <= '1';
r1.ls_valid <= '1'; r1.ls_valid <= '1';

Loading…
Cancel
Save