mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-04-12 14:53:10 +00:00
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>
This commit is contained in:
21
dcache.vhdl
21
dcache.vhdl
@@ -287,8 +287,9 @@ architecture rtl of dcache is
|
||||
|
||||
-- Signals to complete (possibly with error)
|
||||
ls_valid : std_ulogic;
|
||||
ls_error : std_ulogic;
|
||||
mmu_done : std_ulogic;
|
||||
error_done : std_ulogic;
|
||||
mmu_error : std_ulogic;
|
||||
cache_paradox : std_ulogic;
|
||||
|
||||
-- Signal to complete a failed stcx.
|
||||
@@ -739,7 +740,7 @@ begin
|
||||
req_row <= get_row(r0.req.addr);
|
||||
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
|
||||
-- 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.data <= data_out;
|
||||
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;
|
||||
|
||||
-- Outputs to MMU
|
||||
m_out.done <= r1.mmu_done;
|
||||
m_out.err <= r1.error_done;
|
||||
m_out.err <= r1.mmu_error;
|
||||
m_out.data <= data_out;
|
||||
|
||||
-- We have a valid load or store hit or we just completed a slow
|
||||
@@ -979,7 +980,7 @@ begin
|
||||
end if;
|
||||
|
||||
-- error cases complete without stalling
|
||||
if r1.error_done = '1' then
|
||||
if r1.ls_error = '1' then
|
||||
report "completing ld/st with error";
|
||||
end if;
|
||||
|
||||
@@ -995,7 +996,7 @@ begin
|
||||
end if;
|
||||
|
||||
-- error cases complete without stalling
|
||||
if r1.error_done = '1' then
|
||||
if r1.mmu_error = '1' then
|
||||
report "completing MMU ld with error";
|
||||
end if;
|
||||
|
||||
@@ -1128,10 +1129,12 @@ begin
|
||||
if req_op = OP_BAD then
|
||||
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);
|
||||
r1.error_done <= '1';
|
||||
r1.ls_error <= not r0.mmu_req;
|
||||
r1.mmu_error <= r0.mmu_req;
|
||||
r1.cache_paradox <= access_ok;
|
||||
else
|
||||
r1.error_done <= '0';
|
||||
r1.ls_error <= '0';
|
||||
r1.mmu_error <= '0';
|
||||
r1.cache_paradox <= '0';
|
||||
end if;
|
||||
|
||||
@@ -1217,7 +1220,7 @@ begin
|
||||
r1.ls_valid <= '0';
|
||||
-- complete tlbies and TLB loads in the third cycle
|
||||
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
|
||||
r1.ls_valid <= '1';
|
||||
else
|
||||
|
||||
@@ -241,47 +241,46 @@ begin
|
||||
v.last_dword := '0';
|
||||
|
||||
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.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;
|
||||
if r.last_dword = '0' then
|
||||
v.dwords_done := '1';
|
||||
v.last_dword := '1';
|
||||
if r.load = '1' then
|
||||
v.load_data := data_permuted;
|
||||
end if;
|
||||
else
|
||||
if r.last_dword = '0' then
|
||||
v.dwords_done := '1';
|
||||
v.last_dword := '1';
|
||||
if r.load = '1' then
|
||||
v.load_data := data_permuted;
|
||||
end if;
|
||||
write_enable := r.load;
|
||||
if r.load = '1' and r.update = '1' then
|
||||
-- loads with rA update need an extra cycle
|
||||
v.state := LD_UPDATE;
|
||||
else
|
||||
write_enable := r.load;
|
||||
if r.load = '1' and r.update = '1' then
|
||||
-- loads with rA update need an extra cycle
|
||||
v.state := LD_UPDATE;
|
||||
else
|
||||
-- stores write back rA update in this cycle
|
||||
do_update := r.update;
|
||||
done := '1';
|
||||
v.state := IDLE;
|
||||
end if;
|
||||
-- stores write back rA update in this cycle
|
||||
do_update := r.update;
|
||||
done := '1';
|
||||
v.state := IDLE;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
124
mmu.vhdl
124
mmu.vhdl
@@ -301,32 +301,31 @@ begin
|
||||
|
||||
when PROC_TBL_WAIT =>
|
||||
if d_in.done = '1' then
|
||||
if d_in.err = '0' then
|
||||
if r.addr(63) = '1' then
|
||||
v.pgtbl3 := data;
|
||||
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;
|
||||
if r.addr(63) = '1' then
|
||||
v.pgtbl3 := data;
|
||||
v.pt3_valid := '1';
|
||||
else
|
||||
v.state := RADIX_FINISH;
|
||||
v.badtree := '1';
|
||||
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;
|
||||
end if;
|
||||
if d_in.err = '1' then
|
||||
v.state := RADIX_FINISH;
|
||||
v.badtree := '1';
|
||||
end if;
|
||||
|
||||
when SEGMENT_CHECK =>
|
||||
@@ -349,54 +348,53 @@ begin
|
||||
|
||||
when RADIX_READ_WAIT =>
|
||||
if d_in.done = '1' then
|
||||
if d_in.err = '0' then
|
||||
v.pde := data;
|
||||
-- test valid bit
|
||||
if data(63) = '1' then
|
||||
-- test leaf bit
|
||||
if data(62) = '1' then
|
||||
-- check permissions and RC bits
|
||||
perm_ok := '0';
|
||||
if r.priv = '1' or data(3) = '0' then
|
||||
if r.iside = '0' then
|
||||
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;
|
||||
v.pde := data;
|
||||
-- test valid bit
|
||||
if data(63) = '1' then
|
||||
-- test leaf bit
|
||||
if data(62) = '1' then
|
||||
-- check permissions and RC bits
|
||||
perm_ok := '0';
|
||||
if r.priv = '1' or data(3) = '0' then
|
||||
if r.iside = '0' then
|
||||
perm_ok := data(1) or (data(2) and not r.store);
|
||||
else
|
||||
v.state := RADIX_FINISH;
|
||||
v.perm_err := not perm_ok;
|
||||
-- permission error takes precedence over RC error
|
||||
v.rc_error := perm_ok;
|
||||
end if;
|
||||
else
|
||||
mbits := unsigned('0' & data(4 downto 0));
|
||||
if mbits < 5 or mbits > 16 or mbits > r.shift then
|
||||
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;
|
||||
-- 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
|
||||
v.state := RADIX_FINISH;
|
||||
v.perm_err := not perm_ok;
|
||||
-- permission error takes precedence over RC error
|
||||
v.rc_error := perm_ok;
|
||||
end if;
|
||||
else
|
||||
-- non-present PTE, generate a DSI
|
||||
v.state := RADIX_FINISH;
|
||||
v.invalid := '1';
|
||||
mbits := unsigned('0' & data(4 downto 0));
|
||||
if mbits < 5 or mbits > 16 or mbits > r.shift then
|
||||
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;
|
||||
else
|
||||
-- non-present PTE, generate a DSI
|
||||
v.state := RADIX_FINISH;
|
||||
v.badtree := '1';
|
||||
v.invalid := '1';
|
||||
end if;
|
||||
end if;
|
||||
if d_in.err = '1' then
|
||||
v.state := RADIX_FINISH;
|
||||
v.badtree := '1';
|
||||
end if;
|
||||
|
||||
when RADIX_LOAD_TLB =>
|
||||
tlb_load := '1';
|
||||
|
||||
Reference in New Issue
Block a user