core: Send FPU interrupts to writeback rather than execute1
authorPaul Mackerras <paulus@ozlabs.org>
Wed, 23 Dec 2020 02:57:40 +0000 (13:57 +1100)
committerPaul Mackerras <paulus@ozlabs.org>
Tue, 19 Jan 2021 01:16:19 +0000 (12:16 +1100)
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
common.vhdl
execute1.vhdl
fpu.vhdl
loadstore1.vhdl
writeback.vhdl

index 48ba46f27ad181b44223f533a9b4de8cd9c4ac34..e79bcb5c2e0bed6319a0674b0e27bee755047eb0 100644 (file)
@@ -139,6 +139,8 @@ package common is
     constant instr_tag_init : instr_tag_t := (tag => 0, valid => '0');
     function tag_match(tag1 : instr_tag_t; tag2 : instr_tag_t) return boolean;
 
+    subtype intr_vector_t is integer range 0 to 16#fff#;
+
     -- For now, fixed 16 sources, make this either a parametric
     -- package of some sort or an unconstrainted array.
     type ics_to_icp_t is record
@@ -449,9 +451,9 @@ package common is
         rc : std_ulogic;
         store_done : std_ulogic;
         interrupt : std_ulogic;
-        intr_vec : integer range 0 to 16#fff#;
+        intr_vec : intr_vector_t;
         srr0: std_ulogic_vector(63 downto 0);
-        srr1: std_ulogic_vector(31 downto 0);
+        srr1: std_ulogic_vector(15 downto 0);
     end record;
     constant Loadstore1ToWritebackInit : Loadstore1ToWritebackType :=
         (valid => '0', instr_tag => instr_tag_init, write_enable => '0',
@@ -474,7 +476,7 @@ package common is
        write_xerc_enable : std_ulogic;
        xerc : xer_common_t;
         interrupt : std_ulogic;
-        intr_vec : integer range 0 to 16#fff#;
+        intr_vec : intr_vector_t;
        redirect: std_ulogic;
         redir_mode: std_ulogic_vector(3 downto 0);
         last_nia: std_ulogic_vector(63 downto 0);
@@ -482,7 +484,7 @@ package common is
         br_last: std_ulogic;
         br_taken: std_ulogic;
         abs_br: std_ulogic;
-        srr1: std_ulogic_vector(31 downto 0);
+        srr1: std_ulogic_vector(15 downto 0);
         msr: std_ulogic_vector(63 downto 0);
     end record;
     constant Execute1ToWritebackInit : Execute1ToWritebackType :=
@@ -521,13 +523,12 @@ package common is
     type FPUToExecute1Type is record
         busy      : std_ulogic;
         exception : std_ulogic;
-        interrupt : std_ulogic;
-        illegal   : std_ulogic;
     end record;
     constant FPUToExecute1Init : FPUToExecute1Type := (others => '0');
 
     type FPUToWritebackType is record
         valid           : std_ulogic;
+        interrupt       : std_ulogic;
         instr_tag       : instr_tag_t;
         write_enable    : std_ulogic;
         write_reg       : gspr_index_t;
@@ -535,10 +536,17 @@ package common is
         write_cr_enable : std_ulogic;
         write_cr_mask   : std_ulogic_vector(7 downto 0);
         write_cr_data   : std_ulogic_vector(31 downto 0);
-    end record;
-    constant FPUToWritebackInit : FPUToWritebackType :=  (valid => '0', instr_tag => instr_tag_init,
-                                                          write_enable => '0', write_cr_enable => '0',
-                                                          others => (others => '0'));
+        intr_vec        : intr_vector_t;
+        srr0            : std_ulogic_vector(63 downto 0);
+        srr1            : std_ulogic_vector(15 downto 0);
+    end record;
+    constant FPUToWritebackInit : FPUToWritebackType :=
+        (valid => '0', interrupt => '0', instr_tag => instr_tag_init,
+         write_enable => '0', write_reg => (others => '0'),
+         write_cr_enable => '0', write_cr_mask => (others => '0'),
+         write_cr_data => (others => '0'),
+         intr_vec => 0, srr1 => (others => '0'),
+         others => (others => '0'));
 
     type DividerToExecute1Type is record
        valid: std_ulogic;
index f8507bba3ffeac9d3d05359096936733a93d009b..0eaf55aa49b554f078658d1f98802e046dc793ee 100644 (file)
@@ -750,19 +750,19 @@ begin
                 -- become pending due to MSR[FE0,FE1] changing from 00 to non-zero.
                 exception := '1';
                 v.e.intr_vec := 16#700#;
-                v.e.srr1(63 - 43) := '1';
-                v.e.srr1(63 - 47) := '1';
+                v.e.srr1(47 - 43) := '1';
+                v.e.srr1(47 - 47) := '1';
             elsif r.trace_next = '1' then
                 -- Generate a trace interrupt rather than executing the next instruction
                 -- or taking any asynchronous interrupt
                 exception := '1';
                 v.e.intr_vec := 16#d00#;
-                v.e.srr1(63 - 33) := '1';
+                v.e.srr1(47 - 33) := '1';
                 if r.prev_op = OP_LOAD or r.prev_op = OP_ICBI or r.prev_op = OP_ICBT or
                     r.prev_op = OP_DCBT or r.prev_op = OP_DCBST or r.prev_op = OP_DCBF then
-                    v.e.srr1(63 - 35) := '1';
+                    v.e.srr1(47 - 35) := '1';
                 elsif r.prev_op = OP_STORE or r.prev_op = OP_DCBZ or r.prev_op = OP_DCBTST then
-                    v.e.srr1(63 - 36) := '1';
+                    v.e.srr1(47 - 36) := '1';
                 end if;
 
             elsif irq_valid = '1' then
@@ -775,7 +775,7 @@ begin
                 exception := '1';
                 v.e.intr_vec := 16#700#;
                 -- set bit 45 to indicate privileged instruction type interrupt
-                v.e.srr1(63 - 45) := '1';
+                v.e.srr1(47 - 45) := '1';
                 report "privileged instruction";
 
             elsif not HAS_FPU and e_in.fac = FPU then
@@ -840,7 +840,7 @@ begin
                 -- trap instructions (tw, twi, td, tdi)
                 v.e.intr_vec := 16#700#;
                 -- set bit 46 to say trap occurred
-                v.e.srr1(63 - 46) := '1';
+                v.e.srr1(47 - 46) := '1';
                 if or (trapval and insn_to(e_in.insn)) = '1' then
                     -- generate trap-type program interrupt
                     exception := '1';
@@ -1124,22 +1124,12 @@ begin
             v.e.valid := '1';
        end if;
 
-        -- Generate FP-type program interrupt.  fp_in.interrupt will only
-        -- be set during the execution of a FP instruction.
-        -- The case where MSR[FE0,FE1] goes from zero to non-zero is
-        -- handled above by mtmsrd and rfid setting v.fp_exception_next.
-        if HAS_FPU and fp_in.interrupt = '1' then
-            v.e.intr_vec := 16#700#;
-            v.e.srr1(63 - 43) := '1';
-            exception := '1';
-        end if;
-
-        if illegal = '1' or (HAS_FPU and fp_in.illegal = '1') then
+        if illegal = '1' then
             exception := '1';
             v.e.intr_vec := 16#700#;
             -- Since we aren't doing Hypervisor emulation assist (0xe40) we
             -- set bit 44 to indicate we have an illegal
-            v.e.srr1(63 - 44) := '1';
+            v.e.srr1(47 - 44) := '1';
             report "illegal";
         end if;
 
index 5e5c7d6eafa73f7247209e2c2ff289df772e2b89..93fa9d68880c996be4aefcdb961bd9430284222f 100644 (file)
--- a/fpu.vhdl
+++ b/fpu.vhdl
@@ -73,8 +73,10 @@ architecture behaviour of fpu is
         busy         : std_ulogic;
         instr_done   : std_ulogic;
         do_intr      : std_ulogic;
+        illegal      : std_ulogic;
         op           : insn_type_t;
         insn         : std_ulogic_vector(31 downto 0);
+        nia          : std_ulogic_vector(63 downto 0);
         instr_tag    : instr_tag_t;
         dest_fpr     : gspr_index_t;
         fe_mode      : std_ulogic;
@@ -572,7 +574,6 @@ begin
 
     e_out.busy <= r.busy;
     e_out.exception <= r.fpscr(FPSCR_FEX);
-    e_out.interrupt <= r.do_intr;
 
     w_out.valid <= r.instr_done and not r.do_intr;
     w_out.instr_tag <= r.instr_tag;
@@ -583,6 +584,10 @@ begin
     w_out.write_cr_mask <= r.cr_mask;
     w_out.write_cr_data <= r.cr_result & r.cr_result & r.cr_result & r.cr_result &
                            r.cr_result & r.cr_result & r.cr_result & r.cr_result;
+    w_out.interrupt <= r.do_intr;
+    w_out.intr_vec <= 16#700#;
+    w_out.srr0 <= r.nia;
+    w_out.srr1 <= (47-44 => r.illegal, 47-43 => not r.illegal, others => '0');
 
     fpu_1: process(all)
         variable v           : reg_type;
@@ -644,6 +649,7 @@ begin
         -- capture incoming instruction
         if e_in.valid = '1' then
             v.insn := e_in.insn;
+            v.nia := e_in.nia;
             v.op := e_in.op;
             v.instr_tag := e_in.itag;
             v.fe_mode := or (e_in.fe_mode);
@@ -2543,9 +2549,10 @@ begin
             v.cr_result := v.fpscr(FPSCR_FX downto FPSCR_OX);
         end if;
 
+        v.illegal := illegal;
         if illegal = '1' then
             v.instr_done := '0';
-            v.do_intr := '0';
+            v.do_intr := '1';
             v.writing_back := '0';
             v.busy := '0';
             v.state := IDLE;
@@ -2557,7 +2564,6 @@ begin
         end if;
 
         rin <= v;
-        e_out.illegal <= illegal;
     end process;
 
 end architecture behaviour;
index f4f4f4a83fbdbafe0853caffe434f1caa44ea315..a754cc4efd61b0c63f0cae59381a859433d090b9 100644 (file)
@@ -108,7 +108,7 @@ architecture behave of loadstore1 is
         interrupt    : std_ulogic;
         intr_vec     : integer range 0 to 16#fff#;
         nia          : std_ulogic_vector(63 downto 0);
-        srr1         : std_ulogic_vector(31 downto 0);
+        srr1         : std_ulogic_vector(15 downto 0);
     end record;
 
     signal r, rin : reg_stage_t;
@@ -721,10 +721,10 @@ begin
                 end if;
             else
                 if m_in.segerr = '0' then
-                    v.srr1(63 - 33) := m_in.invalid;
-                    v.srr1(63 - 35) := m_in.perm_error; -- noexec fault
-                    v.srr1(63 - 44) := m_in.badtree;
-                    v.srr1(63 - 45) := m_in.rc_error;
+                    v.srr1(47 - 33) := m_in.invalid;
+                    v.srr1(47 - 35) := m_in.perm_error; -- noexec fault
+                    v.srr1(47 - 44) := m_in.badtree;
+                    v.srr1(47 - 45) := m_in.rc_error;
                     v.intr_vec := 16#400#;
                 else
                     v.intr_vec := 16#480#;
index 40cd5b401e2cdf149ba3f4f35cd61db09ea3f83e..65da537e19b3a05270c9b71efed215a669cdb9bb 100644 (file)
@@ -82,6 +82,8 @@ begin
         variable sign : std_ulogic;
        variable scf  : std_ulogic_vector(3 downto 0);
         variable vec  : integer range 0 to 16#fff#;
+        variable srr1 : std_ulogic_vector(15 downto 0);
+        variable intr : std_ulogic;
     begin
         w_out <= WritebackToRegisterFileInit;
         c_out <= WritebackToCrFileInit;
@@ -99,6 +101,8 @@ begin
             complete_out <= fp_in.instr_tag;
         end if;
 
+        intr := e_in.interrupt or l_in.interrupt or fp_in.interrupt;
+
         if r.state = WRITE_SRR1 then
             w_out.write_reg <= fast_spr_num(SPR_SRR1);
             w_out.write_data <= r.srr1;
@@ -106,23 +110,29 @@ begin
             interrupt_out <= '1';
             v.state := WRITE_SRR0;
 
-        elsif e_in.interrupt = '1' then
-            w_out.write_reg <= fast_spr_num(SPR_SRR0);
-            w_out.write_data <= e_in.last_nia;
-            w_out.write_enable <= '1';
-            v.state := WRITE_SRR1;
-            v.srr1(63 downto 32) := e_in.msr(63 downto 32);
-            v.srr1(31 downto 0) := e_in.msr(31 downto 0) or e_in.srr1;
-            vec := e_in.intr_vec;
-
-        elsif l_in.interrupt = '1' then
+        elsif intr = '1' then
             w_out.write_reg <= fast_spr_num(SPR_SRR0);
-            w_out.write_data <= l_in.srr0;
             w_out.write_enable <= '1';
             v.state := WRITE_SRR1;
-            v.srr1(63 downto 32) := e_in.msr(63 downto 32);
-            v.srr1(31 downto 0) := e_in.msr(31 downto 0) or l_in.srr1;
-            vec := l_in.intr_vec;
+            srr1 := (others => '0');
+            if e_in.interrupt = '1' then
+                vec := e_in.intr_vec;
+                w_out.write_data <= e_in.last_nia;
+                srr1 := e_in.srr1;
+            elsif l_in.interrupt = '1' then
+                vec := l_in.intr_vec;
+                w_out.write_data <= l_in.srr0;
+                srr1 := l_in.srr1;
+            elsif fp_in.interrupt = '1' then
+                vec := fp_in.intr_vec;
+                w_out.write_data <= fp_in.srr0;
+                srr1 := fp_in.srr1;
+            end if;
+            v.srr1(63 downto 31) := e_in.msr(63 downto 31);
+            v.srr1(30 downto 27) := srr1(14 downto 11);
+            v.srr1(26 downto 22) := e_in.msr(26 downto 22);
+            v.srr1(21 downto 16) := srr1(5 downto 0);
+            v.srr1(15 downto 0) := e_in.msr(15 downto 0);
 
         else
             if e_in.write_enable = '1' then
@@ -196,7 +206,7 @@ begin
         f.br_nia := e_in.last_nia;
         f.br_last := e_in.br_last;
         f.br_taken := e_in.br_taken;
-        if e_in.interrupt = '1' or l_in.interrupt = '1' then
+        if intr = '1' then
             f.redirect := '1';
             f.br_last := '0';
             f.redirect_nia := std_ulogic_vector(to_unsigned(vec, 64));