dcache: Output separate done-without-error and error-done signals

This reduces the complexity of the logic in the places where these
signals are used.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
jtag-port
Paul Mackerras 4 years ago
parent 56420e74f3
commit c180ed0af0

@ -287,8 +287,9 @@ architecture rtl of dcache is


-- Signals to complete (possibly with error) -- Signals to complete (possibly with error)
ls_valid : std_ulogic; ls_valid : std_ulogic;
ls_error : std_ulogic;
mmu_done : std_ulogic; mmu_done : std_ulogic;
error_done : std_ulogic; mmu_error : std_ulogic;
cache_paradox : std_ulogic; cache_paradox : std_ulogic;


-- Signal to complete a failed stcx. -- Signal to complete a failed stcx.
@ -739,7 +740,7 @@ begin
req_row <= get_row(r0.req.addr); req_row <= get_row(r0.req.addr);
req_tag <= get_tag(ra); req_tag <= get_tag(ra);


go := r0_valid and not (r0.tlbie or r0.tlbld) and not r1.error_done; go := r0_valid and not (r0.tlbie or r0.tlbld) and not r1.ls_error;


-- Test if pending request is a hit on any way -- Test if pending request is a hit on any way
-- In order to make timing in virtual mode, when we are using the TLB, -- In order to make timing in virtual mode, when we are using the TLB,
@ -945,12 +946,12 @@ begin
d_out.valid <= r1.ls_valid; d_out.valid <= r1.ls_valid;
d_out.data <= data_out; d_out.data <= data_out;
d_out.store_done <= not r1.stcx_fail; d_out.store_done <= not r1.stcx_fail;
d_out.error <= r1.error_done; d_out.error <= r1.ls_error;
d_out.cache_paradox <= r1.cache_paradox; d_out.cache_paradox <= r1.cache_paradox;


-- Outputs to MMU -- Outputs to MMU
m_out.done <= r1.mmu_done; m_out.done <= r1.mmu_done;
m_out.err <= r1.error_done; m_out.err <= r1.mmu_error;
m_out.data <= data_out; m_out.data <= data_out;


-- We have a valid load or store hit or we just completed a slow -- We have a valid load or store hit or we just completed a slow
@ -979,7 +980,7 @@ begin
end if; end if;


-- error cases complete without stalling -- error cases complete without stalling
if r1.error_done = '1' then if r1.ls_error = '1' then
report "completing ld/st with error"; report "completing ld/st with error";
end if; end if;


@ -995,7 +996,7 @@ begin
end if; end if;


-- error cases complete without stalling -- error cases complete without stalling
if r1.error_done = '1' then if r1.mmu_error = '1' then
report "completing MMU ld with error"; report "completing MMU ld with error";
end if; end if;


@ -1128,10 +1129,12 @@ begin
if req_op = OP_BAD then if req_op = OP_BAD then
report "Signalling ld/st error valid_ra=" & std_ulogic'image(valid_ra) & report "Signalling ld/st error valid_ra=" & std_ulogic'image(valid_ra) &
" rc_ok=" & std_ulogic'image(rc_ok) & " perm_ok=" & std_ulogic'image(perm_ok); " rc_ok=" & std_ulogic'image(rc_ok) & " perm_ok=" & std_ulogic'image(perm_ok);
r1.error_done <= '1'; r1.ls_error <= not r0.mmu_req;
r1.mmu_error <= r0.mmu_req;
r1.cache_paradox <= access_ok; r1.cache_paradox <= access_ok;
else else
r1.error_done <= '0'; r1.ls_error <= '0';
r1.mmu_error <= '0';
r1.cache_paradox <= '0'; r1.cache_paradox <= '0';
end if; end if;


@ -1217,7 +1220,7 @@ begin
r1.ls_valid <= '0'; r1.ls_valid <= '0';
-- complete tlbies and TLB loads in the third cycle -- complete tlbies and TLB loads in the third cycle
r1.mmu_done <= r0_valid and (r0.tlbie or r0.tlbld); r1.mmu_done <= r0_valid and (r0.tlbie or r0.tlbld);
if req_op = OP_LOAD_HIT or req_op = OP_BAD or req_op = OP_STCX_FAIL then if req_op = OP_LOAD_HIT or req_op = OP_STCX_FAIL then
if r0.mmu_req = '0' then if r0.mmu_req = '0' then
r1.ls_valid <= '1'; r1.ls_valid <= '1';
else else

@ -241,47 +241,46 @@ begin
v.last_dword := '0'; v.last_dword := '0';


when ACK_WAIT => when ACK_WAIT =>
if d_in.error = '1' then
-- dcache will discard the second request if it
-- gets an error on the 1st of two requests
if r.dwords_done = '1' then
addr := next_addr;
else
addr := r.addr;
end if;
if d_in.cache_paradox = '1' then
-- signal an interrupt straight away
exception := '1';
dsisr(63 - 38) := not r.load;
-- XXX there is no architected bit for this
dsisr(63 - 35) := d_in.cache_paradox;
v.state := IDLE;
else
-- Look up the translation for TLB miss
-- and also for permission error and RC error
-- in case the PTE has been updated.
mmureq := '1';
v.state := MMU_LOOKUP;
end if;
end if;
if d_in.valid = '1' then if d_in.valid = '1' then
if d_in.error = '1' then if r.last_dword = '0' then
-- dcache will discard the second request if it v.dwords_done := '1';
-- gets an error on the 1st of two requests v.last_dword := '1';
if r.dwords_done = '1' then if r.load = '1' then
addr := next_addr; v.load_data := data_permuted;
else
addr := r.addr;
end if;
if d_in.cache_paradox = '1' then
-- signal an interrupt straight away
exception := '1';
dsisr(63 - 38) := not r.load;
-- XXX there is no architected bit for this
dsisr(63 - 35) := d_in.cache_paradox;
v.state := IDLE;
else
-- Look up the translation for TLB miss
-- and also for permission error and RC error
-- in case the PTE has been updated.
mmureq := '1';
v.state := MMU_LOOKUP;
end if; end if;
else else
if r.last_dword = '0' then write_enable := r.load;
v.dwords_done := '1'; if r.load = '1' and r.update = '1' then
v.last_dword := '1'; -- loads with rA update need an extra cycle
if r.load = '1' then v.state := LD_UPDATE;
v.load_data := data_permuted;
end if;
else else
write_enable := r.load; -- stores write back rA update in this cycle
if r.load = '1' and r.update = '1' then do_update := r.update;
-- loads with rA update need an extra cycle done := '1';
v.state := LD_UPDATE; v.state := IDLE;
else
-- stores write back rA update in this cycle
do_update := r.update;
done := '1';
v.state := IDLE;
end if;
end if; end if;
end if; end if;
end if; end if;

@ -301,33 +301,32 @@ begin


when PROC_TBL_WAIT => when PROC_TBL_WAIT =>
if d_in.done = '1' then if d_in.done = '1' then
if d_in.err = '0' then if r.addr(63) = '1' then
if r.addr(63) = '1' then v.pgtbl3 := data;
v.pgtbl3 := data; v.pt3_valid := '1';
v.pt3_valid := '1';
else
v.pgtbl0 := data;
v.pt0_valid := '1';
end if;
-- rts == radix tree size, # address bits being translated
rts := unsigned('0' & data(62 downto 61) & data(7 downto 5));
-- mbits == # address bits to index top level of tree
mbits := unsigned('0' & data(4 downto 0));
-- set v.shift to rts so that we can use finalmask for the segment check
v.shift := rts;
v.mask_size := mbits(4 downto 0);
v.pgbase := data(55 downto 8) & x"00";
if mbits = 0 then
v.state := RADIX_FINISH;
v.invalid := '1';
else
v.state := SEGMENT_CHECK;
end if;
else else
v.pgtbl0 := data;
v.pt0_valid := '1';
end if;
-- rts == radix tree size, # address bits being translated
rts := unsigned('0' & data(62 downto 61) & data(7 downto 5));
-- mbits == # address bits to index top level of tree
mbits := unsigned('0' & data(4 downto 0));
-- set v.shift to rts so that we can use finalmask for the segment check
v.shift := rts;
v.mask_size := mbits(4 downto 0);
v.pgbase := data(55 downto 8) & x"00";
if mbits = 0 then
v.state := RADIX_FINISH; v.state := RADIX_FINISH;
v.badtree := '1'; v.invalid := '1';
else
v.state := SEGMENT_CHECK;
end if; end if;
end if; end if;
if d_in.err = '1' then
v.state := RADIX_FINISH;
v.badtree := '1';
end if;


when SEGMENT_CHECK => when SEGMENT_CHECK =>
mbits := '0' & r.mask_size; mbits := '0' & r.mask_size;
@ -349,54 +348,53 @@ begin


when RADIX_READ_WAIT => when RADIX_READ_WAIT =>
if d_in.done = '1' then if d_in.done = '1' then
if d_in.err = '0' then v.pde := data;
v.pde := data; -- test valid bit
-- test valid bit if data(63) = '1' then
if data(63) = '1' then -- test leaf bit
-- test leaf bit if data(62) = '1' then
if data(62) = '1' then -- check permissions and RC bits
-- check permissions and RC bits perm_ok := '0';
perm_ok := '0'; if r.priv = '1' or data(3) = '0' then
if r.priv = '1' or data(3) = '0' then if r.iside = '0' then
if r.iside = '0' then perm_ok := data(1) or (data(2) and not r.store);
perm_ok := data(1) or (data(2) and not r.store);
else
-- no IAMR, so no KUEP support for now
-- deny execute permission if cache inhibited
perm_ok := data(0) and not data(5);
end if;
end if;
rc_ok := data(8) and (data(7) or not r.store);
if perm_ok = '1' and rc_ok = '1' then
v.state := RADIX_LOAD_TLB;
else else
v.state := RADIX_FINISH; -- no IAMR, so no KUEP support for now
v.perm_err := not perm_ok; -- deny execute permission if cache inhibited
-- permission error takes precedence over RC error perm_ok := data(0) and not data(5);
v.rc_error := perm_ok;
end if; end if;
end if;
rc_ok := data(8) and (data(7) or not r.store);
if perm_ok = '1' and rc_ok = '1' then
v.state := RADIX_LOAD_TLB;
else else
mbits := unsigned('0' & data(4 downto 0)); v.state := RADIX_FINISH;
if mbits < 5 or mbits > 16 or mbits > r.shift then v.perm_err := not perm_ok;
v.state := RADIX_FINISH; -- permission error takes precedence over RC error
v.badtree := '1'; v.rc_error := perm_ok;
else
v.shift := v.shift - mbits;
v.mask_size := mbits(4 downto 0);
v.pgbase := data(55 downto 8) & x"00";
v.state := RADIX_LOOKUP;
end if;
end if; end if;
else else
-- non-present PTE, generate a DSI mbits := unsigned('0' & data(4 downto 0));
v.state := RADIX_FINISH; if mbits < 5 or mbits > 16 or mbits > r.shift then
v.invalid := '1'; v.state := RADIX_FINISH;
v.badtree := '1';
else
v.shift := v.shift - mbits;
v.mask_size := mbits(4 downto 0);
v.pgbase := data(55 downto 8) & x"00";
v.state := RADIX_LOOKUP;
end if;
end if; end if;
else else
-- non-present PTE, generate a DSI
v.state := RADIX_FINISH; v.state := RADIX_FINISH;
v.badtree := '1'; v.invalid := '1';
end if; end if;
end if; end if;
if d_in.err = '1' then
v.state := RADIX_FINISH;
v.badtree := '1';
end if;


when RADIX_LOAD_TLB => when RADIX_LOAD_TLB =>
tlb_load := '1'; tlb_load := '1';

Loading…
Cancel
Save