dcache: Output separate done-without-error and error-done signals
authorPaul Mackerras <paulus@ozlabs.org>
Sun, 12 Jul 2020 10:05:53 +0000 (20:05 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Mon, 20 Jul 2020 04:28:18 +0000 (14:28 +1000)
This reduces the complexity of the logic in the places where these
signals are used.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
dcache.vhdl
loadstore1.vhdl
mmu.vhdl

index a24dc15af28a403671133f9c3dede98d2d838019..08b16641dca5e5eaec285e56b1cca9f53280939a 100644 (file)
@@ -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
index 0387e40dff69f54cbc4a538524660f002f04bc36..4e1f9436732e4f32f19e8033da0c8b05c7790c53 100644 (file)
@@ -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;
index f1d69e240b81ca392206abae536d8a5befb7b0fc..6458a6ea1eab3a5d87b32fbf168658890aa6381d 100644 (file)
--- 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';