core: Send loadstore1 interrupts to writeback rather than execute1
authorPaul Mackerras <paulus@ozlabs.org>
Wed, 23 Dec 2020 01:27:22 +0000 (12:27 +1100)
committerPaul Mackerras <paulus@ozlabs.org>
Mon, 18 Jan 2021 22:27:29 +0000 (09:27 +1100)
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
common.vhdl
execute1.vhdl
loadstore1.vhdl
writeback.vhdl

index b2d6b134e98bec7b0f151d07104a2a588ee20050..48ba46f27ad181b44223f533a9b4de8cd9c4ac34 100644 (file)
@@ -349,6 +349,7 @@ package common is
         is_32bit : std_ulogic;
         repeat : std_ulogic;
         second : std_ulogic;
+        msr : std_ulogic_vector(63 downto 0);
     end record;
     constant Execute1ToLoadstore1Init : Execute1ToLoadstore1Type :=
         (valid => '0', op => OP_ILLEGAL, ci => '0', byte_reverse => '0',
@@ -360,18 +361,11 @@ package common is
          write_reg => (others => '0'),
          length => (others => '0'),
          mode_32bit => '0', is_32bit => '0',
-         repeat => '0', second => '0');
+         repeat => '0', second => '0',
+         msr => (others => '0'));
 
     type Loadstore1ToExecute1Type is record
         busy : std_ulogic;
-        exception : std_ulogic;
-        alignment : std_ulogic;
-        invalid : std_ulogic;
-        perm_error : std_ulogic;
-        rc_error : std_ulogic;
-        badtree : std_ulogic;
-        segment_fault : std_ulogic;
-        instr_fault : std_ulogic;
     end record;
 
     type Loadstore1ToDcacheType is record
@@ -454,10 +448,17 @@ package common is
        xerc : xer_common_t;
         rc : std_ulogic;
         store_done : std_ulogic;
+        interrupt : std_ulogic;
+        intr_vec : integer range 0 to 16#fff#;
+        srr0: std_ulogic_vector(63 downto 0);
+        srr1: std_ulogic_vector(31 downto 0);
     end record;
     constant Loadstore1ToWritebackInit : Loadstore1ToWritebackType :=
-        (valid => '0', instr_tag => instr_tag_init, write_enable => '0', xerc => xerc_init,
-         rc => '0', store_done => '0', write_data => (others => '0'), others => (others => '0'));
+        (valid => '0', instr_tag => instr_tag_init, write_enable => '0',
+         write_reg => (others => '0'), write_data => (others => '0'),
+         xerc => xerc_init, rc => '0', store_done => '0',
+         interrupt => '0', intr_vec => 0,
+         srr0 => (others => '0'), srr1 => (others => '0'));
 
     type Execute1ToWritebackType is record
        valid: std_ulogic;
@@ -481,7 +482,8 @@ package common is
         br_last: std_ulogic;
         br_taken: std_ulogic;
         abs_br: std_ulogic;
-        srr1: std_ulogic_vector(63 downto 0);
+        srr1: std_ulogic_vector(31 downto 0);
+        msr: std_ulogic_vector(63 downto 0);
     end record;
     constant Execute1ToWritebackInit : Execute1ToWritebackType :=
         (valid => '0', instr_tag => instr_tag_init, rc => '0', mode_32bit => '0',
@@ -491,7 +493,8 @@ package common is
          write_cr_data => (others => '0'), write_reg => (others => '0'),
          interrupt => '0', intr_vec => 0, redirect => '0', redir_mode => "0000",
          last_nia => (others => '0'), br_offset => (others => '0'),
-         br_last => '0', br_taken => '0', abs_br => '0', srr1 => (others => '0'));
+         br_last => '0', br_taken => '0', abs_br => '0',
+         srr1 => (others => '0'), msr => (others => '0'));
 
     type Execute1ToFPUType is record
         valid   : std_ulogic;
index 875e22c95919ce4e8438bd52c8b597da0447243c..f8507bba3ffeac9d3d05359096936733a93d009b 100644 (file)
@@ -725,7 +725,7 @@ begin
        rot_clear_right <= '1' when e_in.insn_type = OP_RLC or e_in.insn_type = OP_RLCR else '0';
         rot_sign_ext <= '1' when e_in.insn_type = OP_EXTSWSLI else '0';
 
-        v.e.srr1 := msr_copy(ctrl.msr);
+        v.e.srr1 := (others => '0');
        exception := '0';
         illegal := '0';
         if valid_in = '1' then
@@ -1143,31 +1143,7 @@ begin
             report "illegal";
         end if;
 
-        -- generate DSI or DSegI for load/store exceptions
-        -- or ISI or ISegI for instruction fetch exceptions
-        if l_in.exception = '1' then
-            if l_in.alignment = '1' then
-                v.e.intr_vec := 16#600#;
-            elsif l_in.instr_fault = '0' then
-                if l_in.segment_fault = '0' then
-                    v.e.intr_vec := 16#300#;
-                else
-                    v.e.intr_vec := 16#380#;
-                end if;
-            else
-                if l_in.segment_fault = '0' then
-                    v.e.srr1(63 - 33) := l_in.invalid;
-                    v.e.srr1(63 - 35) := l_in.perm_error; -- noexec fault
-                    v.e.srr1(63 - 44) := l_in.badtree;
-                    v.e.srr1(63 - 45) := l_in.rc_error;
-                    v.e.intr_vec := 16#400#;
-                else
-                    v.e.intr_vec := 16#480#;
-                end if;
-            end if;
-        end if;
-
-        v.e.interrupt := exception or l_in.exception;
+        v.e.interrupt := exception;
 
         if do_trace = '1' then
             v.trace_next := '1';
@@ -1265,6 +1241,7 @@ begin
        -- update outputs
         l_out <= lv;
        e_out <= r.e;
+        e_out.msr <= msr_copy(ctrl.msr);
         fp_out <= fv;
 
         exception_log <= exception;
index 935ce5fce7891cc07ae2da883baa8d72662d9dbc..f4f4f4a83fbdbafe0853caffe434f1caa44ea315 100644 (file)
@@ -105,6 +105,10 @@ architecture behave of loadstore1 is
         ld_sp_nz     : std_ulogic;
         ld_sp_lz     : std_ulogic_vector(5 downto 0);
         wr_sel       : std_ulogic_vector(1 downto 0);
+        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);
     end record;
 
     signal r, rin : reg_stage_t;
@@ -220,6 +224,7 @@ begin
                 r.state <= IDLE;
                 r.busy <= '0';
                 r.do_update <= '0';
+                r.interrupt <= '0';
             else
                 r <= rin;
             end if;
@@ -520,6 +525,8 @@ begin
             v.wait_dcache := '0';
             v.wait_mmu := '0';
             v.extra_cycle := '0';
+            v.nia := l_in.nia;
+            v.srr1 := (others => '0');
 
             if HAS_FPU and l_in.is_32bit = '1' then
                 v.store_data := x"00000000" & store_sp_data;
@@ -697,6 +704,34 @@ begin
             end if;
         end loop;
 
+        -- generate DSI or DSegI for load/store exceptions
+        -- or ISI or ISegI for instruction fetch exceptions
+        v.interrupt := exception;
+        if exception = '1' then
+            if r.align_intr = '1' then
+                v.intr_vec := 16#600#;
+                v.dar := addr;
+            elsif r.instr_fault = '0' then
+                v.dar := addr;
+                if m_in.segerr = '0' then
+                    v.intr_vec := 16#300#;
+                    v.dsisr := dsisr;
+                else
+                    v.intr_vec := 16#380#;
+                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.intr_vec := 16#400#;
+                else
+                    v.intr_vec := 16#480#;
+                end if;
+            end if;
+        end if;
+
         -- Update outputs to dcache
         d_out.valid <= req and not v.align_intr;
         d_out.load <= v.load;
@@ -746,23 +781,13 @@ begin
         l_out.xerc <= r.xerc;
         l_out.rc <= r.rc and done;
         l_out.store_done <= d_in.store_done;
+        l_out.interrupt <= r.interrupt;
+        l_out.intr_vec <= r.intr_vec;
+        l_out.srr0 <= r.nia;
+        l_out.srr1 <= r.srr1;
 
-        -- update exception info back to execute1
+        -- update busy signal back to execute1
         e_out.busy <= busy;
-        e_out.exception <= exception;
-        e_out.alignment <= r.align_intr;
-        e_out.instr_fault <= r.instr_fault;
-        e_out.invalid <= m_in.invalid;
-        e_out.badtree <= m_in.badtree;
-        e_out.perm_error <= m_in.perm_error;
-        e_out.rc_error <= m_in.rc_error;
-        e_out.segment_fault <= m_in.segerr;
-        if exception = '1' and r.instr_fault = '0' then
-            v.dar := addr;
-            if m_in.segerr = '0' and r.align_intr = '0' then
-                v.dsisr := dsisr;
-            end if;
-        end if;
 
         -- Update registers
         rin <= v;
@@ -776,7 +801,7 @@ begin
         begin
             if rising_edge(clk) then
                 log_data <= e_out.busy &
-                            e_out.exception &
+                            l_out.interrupt &
                             l_out.valid &
                             m_out.valid &
                             d_out.valid &
index c7632ea41810711edf4d3dd7ca14bfc8cd4a55fa..40cd5b401e2cdf149ba3f4f35cd61db09ea3f83e 100644 (file)
@@ -81,11 +81,13 @@ begin
         variable zero : std_ulogic;
         variable sign : std_ulogic;
        variable scf  : std_ulogic_vector(3 downto 0);
+        variable vec  : integer range 0 to 16#fff#;
     begin
         w_out <= WritebackToRegisterFileInit;
         c_out <= WritebackToCrFileInit;
         f := WritebackToFetch1Init;
         interrupt_out <= '0';
+        vec := 0;
         v := r;
 
         complete_out <= instr_tag_init;
@@ -109,7 +111,19 @@ begin
             w_out.write_data <= e_in.last_nia;
             w_out.write_enable <= '1';
             v.state := WRITE_SRR1;
-            v.srr1 := e_in.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
+            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;
+
         else
             if e_in.write_enable = '1' then
                 w_out.write_reg <= e_in.write_reg;
@@ -178,12 +192,14 @@ begin
         end if;
 
         -- Outputs to fetch1
-        f.redirect := e_in.redirect or e_in.interrupt;
+        f.redirect := e_in.redirect;
         f.br_nia := e_in.last_nia;
-        f.br_last := e_in.br_last and not e_in.interrupt;
+        f.br_last := e_in.br_last;
         f.br_taken := e_in.br_taken;
-        if e_in.interrupt = '1' then
-            f.redirect_nia := std_ulogic_vector(to_unsigned(e_in.intr_vec, 64));
+        if e_in.interrupt = '1' or l_in.interrupt = '1' then
+            f.redirect := '1';
+            f.br_last := '0';
+            f.redirect_nia := std_ulogic_vector(to_unsigned(vec, 64));
             f.virt_mode := '0';
             f.priv_mode := '1';
             -- XXX need an interrupt LE bit here, e.g. from LPCR