execute1: Simplify the interrupt logic a little
authorPaul Mackerras <paulus@ozlabs.org>
Tue, 7 Apr 2020 08:38:18 +0000 (18:38 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Tue, 7 Apr 2020 10:04:00 +0000 (20:04 +1000)
This makes some simplifications to the interrupt logic which will
help with later commits.

- When irq_valid is set, don't set exception to 1 until we have a
  valid instruction.  That means we can remove the if e_in.valid = '1'
  test from the exception = '1' block.

- Don't assert stall_out on the first cycle of delivering an
  interrupt.  If we do get another instruction in the next cycle,
  nothing will happen because we have ctrl.irq_state set and we
  will just continue writing the interrupt registers.

- Make sure we deliver as many completions as we got instructions,
  otherwise the outstanding instruction count in control.vhdl gets
  out of sync.

- In writeback, make sure all of the other write enables are ignored
  when e_in.exc_write_enable is set.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
execute1.vhdl
writeback.vhdl

index ffa9048b37e75003ab752853f0115b3deab70efd..6c195592024c03735311031b5ea5c4de8cae4370 100644 (file)
@@ -399,13 +399,15 @@ begin
            ctrl_tmp.msr(63 - 48) <= '0'; -- clear EE
            f_out.redirect <= '1';
            f_out.redirect_nia <= ctrl.irq_nia;
-           v.e.valid := '1';
+           v.e.valid := e_in.valid;
            report "Writing SRR1: " & to_hstring(ctrl.srr1);
 
        elsif irq_valid = '1' then
            -- we need two cycles to write srr0 and 1
            -- will need more when we have to write DSISR, DAR and HIER
-           exception := '1';
+            -- Don't deliver the interrupt until we have a valid instruction
+            -- coming in, so we have a valid NIA to put in SRR0.
+           exception := e_in.valid;
            ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#900#, 64));
            ctrl_tmp.srr1 <= msr_copy(ctrl.msr);
 
@@ -821,16 +823,12 @@ begin
        end if;
 
        if exception = '1' then
-           if e_in.valid = '1' then
-               v.e.exc_write_enable := '1';
-                if exception_nextpc = '1' then
-                    v.e.exc_write_data := std_logic_vector(unsigned(e_in.nia) + 4);
-                end if;
-               ctrl_tmp.irq_state <= WRITE_SRR1;
-               stall_out <= '1';
-               v.e.valid := '0';
-                result_en := '0';
-           end if;
+            v.e.exc_write_enable := '1';
+            if exception_nextpc = '1' then
+                v.e.exc_write_data := next_nia;
+            end if;
+            ctrl_tmp.irq_state <= WRITE_SRR1;
+            v.e.valid := '1';
        end if;
 
        v.e.write_data := result;
index 71870c25f7d4aab02fb0aca07cbbce652fccc3d4..60afebbe14ba5432e79161b4010f733ad01916cb 100644 (file)
@@ -55,52 +55,54 @@ begin
             w_out.write_reg <= e_in.exc_write_reg;
             w_out.write_data <= e_in.exc_write_data;
             w_out.write_enable <= '1';
-        elsif e_in.write_enable = '1' then
-            w_out.write_reg <= e_in.write_reg;
-            w_out.write_data <= e_in.write_data;
-            w_out.write_enable <= '1';
-        end if;
-
-        if e_in.write_cr_enable = '1' then
-            c_out.write_cr_enable <= '1';
-            c_out.write_cr_mask <= e_in.write_cr_mask;
-            c_out.write_cr_data <= e_in.write_cr_data;
-        end if;
-
-       if e_in.write_xerc_enable = '1' then
-            c_out.write_xerc_enable <= '1';
-            c_out.write_xerc_data <= e_in.xerc;
-       end if;
-
-       if l_in.write_enable = '1' then
-            w_out.write_reg <= gpr_to_gspr(l_in.write_reg);
-            w_out.write_data <= l_in.write_data;
-            w_out.write_enable <= '1';
-        end if;
-
-        if l_in.rc = '1' then
-            -- st*cx. instructions
-            scf(3) := '0';
-            scf(2) := '0';
-            scf(1) := l_in.store_done;
-            scf(0) := l_in.xerc.so;
-            c_out.write_cr_enable <= '1';
-            c_out.write_cr_mask <= num_to_fxm(0);
-            c_out.write_cr_data(31 downto 28) <= scf;
-        end if;
-
-        -- Perform CR0 update for RC forms
-        -- Note that loads never have a form with an RC bit, therefore this can test e_in.write_data
-        if e_in.rc = '1' and e_in.write_enable = '1' then
-            sign := e_in.write_data(63);
-            zero := not (or e_in.write_data);
-            c_out.write_cr_enable <= '1';
-            c_out.write_cr_mask <= num_to_fxm(0);
-           cf(3) := sign;
-           cf(2) := not sign and not zero;
-           cf(1) := zero;
-           cf(0) := e_in.xerc.so;
-           c_out.write_cr_data(31 downto 28) <= cf;
+        else
+            if e_in.write_enable = '1' then
+                w_out.write_reg <= e_in.write_reg;
+                w_out.write_data <= e_in.write_data;
+                w_out.write_enable <= '1';
+            end if;
+
+            if e_in.write_cr_enable = '1' then
+                c_out.write_cr_enable <= '1';
+                c_out.write_cr_mask <= e_in.write_cr_mask;
+                c_out.write_cr_data <= e_in.write_cr_data;
+            end if;
+
+            if e_in.write_xerc_enable = '1' then
+                c_out.write_xerc_enable <= '1';
+                c_out.write_xerc_data <= e_in.xerc;
+            end if;
+
+            if l_in.write_enable = '1' then
+                w_out.write_reg <= gpr_to_gspr(l_in.write_reg);
+                w_out.write_data <= l_in.write_data;
+                w_out.write_enable <= '1';
+            end if;
+
+            if l_in.rc = '1' then
+                -- st*cx. instructions
+                scf(3) := '0';
+                scf(2) := '0';
+                scf(1) := l_in.store_done;
+                scf(0) := l_in.xerc.so;
+                c_out.write_cr_enable <= '1';
+                c_out.write_cr_mask <= num_to_fxm(0);
+                c_out.write_cr_data(31 downto 28) <= scf;
+            end if;
+
+            -- Perform CR0 update for RC forms
+            -- Note that loads never have a form with an RC bit, therefore this can test e_in.write_data
+            if e_in.rc = '1' and e_in.write_enable = '1' then
+                sign := e_in.write_data(63);
+                zero := not (or e_in.write_data);
+                c_out.write_cr_enable <= '1';
+                c_out.write_cr_mask <= num_to_fxm(0);
+                cf(3) := sign;
+                cf(2) := not sign and not zero;
+                cf(1) := zero;
+                cf(0) := e_in.xerc.so;
+                c_out.write_cr_data(31 downto 28) <= cf;
+            end if;
         end if;
     end process;
 end;