From: Paul Mackerras Date: Sun, 12 Jul 2020 10:05:53 +0000 (+1000) Subject: dcache: Output separate done-without-error and error-done signals X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c180ed0af0f2cee202ae81df75c89b81341c150c;p=microwatt.git 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 --- diff --git a/dcache.vhdl b/dcache.vhdl index a24dc15..08b1664 100644 --- a/dcache.vhdl +++ b/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 diff --git a/loadstore1.vhdl b/loadstore1.vhdl index 0387e40..4e1f943 100644 --- a/loadstore1.vhdl +++ b/loadstore1.vhdl @@ -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; diff --git a/mmu.vhdl b/mmu.vhdl index f1d69e2..6458a6e 100644 --- a/mmu.vhdl +++ b/mmu.vhdl @@ -301,33 +301,32 @@ 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.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.badtree := '1'; + 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 => mbits := '0' & r.mask_size; @@ -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; + -- 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 - 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; + 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';