core: Move redirect and interrupt delivery logic to writeback
authorPaul Mackerras <paulus@ozlabs.org>
Wed, 23 Dec 2020 00:13:21 +0000 (11:13 +1100)
committerPaul Mackerras <paulus@ozlabs.org>
Mon, 18 Jan 2021 22:27:29 +0000 (09:27 +1100)
This moves the logic for redirecting fetching and writing SRR0 and
SRR1 to writeback.  The aim is that ultimately units other than
execute1 can send their interrupts to writeback along with their
instruction completions, so that there can be multiple instructions
in flight without needing execute1 to keep track of the address
of each outstanding instruction.

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

index a3a95f41678a9bce6e7c957f4f84d0574d040942..b2d6b134e98bec7b0f151d07104a2a588ee20050 100644 (file)
@@ -139,8 +139,6 @@ 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;
 
-    type irq_state_t is (WRITE_SRR0, WRITE_SRR1);
-
     -- 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
@@ -157,8 +155,6 @@ package common is
        dec: std_ulogic_vector(63 downto 0);
        msr: std_ulogic_vector(63 downto 0);
         cfar: std_ulogic_vector(63 downto 0);
-       irq_state : irq_state_t;
-       srr1: std_ulogic_vector(63 downto 0);
     end record;
 
     type Fetch1ToIcacheType is record
@@ -329,22 +325,6 @@ package common is
        read_xerc_data : xer_common_t;
     end record;
 
-    type Execute1ToFetch1Type is record
-       redirect: std_ulogic;
-        virt_mode: std_ulogic;
-        priv_mode: std_ulogic;
-        big_endian: std_ulogic;
-        mode_32bit: std_ulogic;
-       redirect_nia: std_ulogic_vector(63 downto 0);
-        br_nia : std_ulogic_vector(63 downto 0);
-        br_last : std_ulogic;
-        br_taken : std_ulogic;
-    end record;
-    constant Execute1ToFetch1Init : Execute1ToFetch1Type := (redirect => '0', virt_mode => '0',
-                                                             priv_mode => '0', big_endian => '0',
-                                                             mode_32bit => '0', br_taken => '0',
-                                                             br_last => '0', others => (others => '0'));
-
     type Execute1ToLoadstore1Type is record
        valid : std_ulogic;
         op : insn_type_t;                               -- what ld/st or m[tf]spr or TLB op to do
@@ -492,17 +472,26 @@ package common is
        write_cr_data : std_ulogic_vector(31 downto 0);
        write_xerc_enable : std_ulogic;
        xerc : xer_common_t;
-        exc_write_enable : std_ulogic;
-        exc_write_reg : gspr_index_t;
-        exc_write_data : std_ulogic_vector(63 downto 0);
+        interrupt : std_ulogic;
+        intr_vec : integer range 0 to 16#fff#;
+       redirect: std_ulogic;
+        redir_mode: std_ulogic_vector(3 downto 0);
+        last_nia: std_ulogic_vector(63 downto 0);
+        br_offset: std_ulogic_vector(63 downto 0);
+        br_last: std_ulogic;
+        br_taken: std_ulogic;
+        abs_br: std_ulogic;
+        srr1: std_ulogic_vector(63 downto 0);
     end record;
     constant Execute1ToWritebackInit : Execute1ToWritebackType :=
         (valid => '0', instr_tag => instr_tag_init, rc => '0', mode_32bit => '0',
-         write_enable => '0', write_cr_enable => '0', exc_write_enable => '0',
+         write_enable => '0', write_cr_enable => '0',
          write_xerc_enable => '0', xerc => xerc_init,
          write_data => (others => '0'), write_cr_mask => (others => '0'),
          write_cr_data => (others => '0'), write_reg => (others => '0'),
-         exc_write_reg => (others => '0'), exc_write_data => (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'));
 
     type Execute1ToFPUType is record
         valid   : std_ulogic;
@@ -556,6 +545,22 @@ package common is
     constant DividerToExecute1Init : DividerToExecute1Type := (valid => '0', overflow => '0',
                                                                others => (others => '0'));
 
+    type WritebackToFetch1Type is record
+       redirect: std_ulogic;
+        virt_mode: std_ulogic;
+        priv_mode: std_ulogic;
+        big_endian: std_ulogic;
+        mode_32bit: std_ulogic;
+       redirect_nia: std_ulogic_vector(63 downto 0);
+        br_nia : std_ulogic_vector(63 downto 0);
+        br_last : std_ulogic;
+        br_taken : std_ulogic;
+    end record;
+    constant WritebackToFetch1Init : WritebackToFetch1Type :=
+        (redirect => '0', virt_mode => '0', priv_mode => '0', big_endian => '0',
+         mode_32bit => '0', redirect_nia => (others => '0'),
+         br_last => '0', br_taken => '0', br_nia => (others => '0'));
+
     type WritebackToRegisterFileType is record
        write_reg : gspr_index_t;
        write_data : std_ulogic_vector(63 downto 0);
index 5c83f7874595d8581248f9b3046ce83a8b3cc90c..f14e350cd8f04e02b431282ecd5587d66c158e33 100644 (file)
@@ -235,8 +235,7 @@ begin
         stall_tmp := '0';
 
         if flush_in = '1' then
-            -- expect to see complete_in next cycle
-            v_int.outstanding := 1;
+            v_int.outstanding := 0;
         elsif complete_in.valid = '1' then
             v_int.outstanding := r_int.outstanding - 1;
         end if;
index 7dafd1c638b694450df800446ded8500ec330e9d..e2a93b9df642f1f4bff946af0ceff162e175b711 100644 (file)
--- a/core.vhdl
+++ b/core.vhdl
@@ -46,6 +46,7 @@ end core;
 architecture behave of core is
     -- icache signals
     signal fetch1_to_icache : Fetch1ToIcacheType;
+    signal writeback_to_fetch1: WritebackToFetch1Type;
     signal icache_to_decode1 : IcacheToDecode1Type;
     signal mmu_to_icache : MmuToIcacheType;
 
@@ -66,7 +67,6 @@ architecture behave of core is
 
     -- execute signals
     signal execute1_to_writeback: Execute1ToWritebackType;
-    signal execute1_to_fetch1: Execute1ToFetch1Type;
     signal execute1_bypass: bypass_data_t;
     signal execute1_cr_bypass: cr_bypass_data_t;
 
@@ -108,6 +108,7 @@ architecture behave of core is
     signal terminate: std_ulogic;
     signal core_rst: std_ulogic;
     signal icache_inv: std_ulogic;
+    signal do_interrupt: std_ulogic;
 
     -- Delayed/Latched resets and alt_reset
     signal rst_fetch1  : std_ulogic := '1';
@@ -119,6 +120,7 @@ architecture behave of core is
     signal rst_ex1     : std_ulogic := '1';
     signal rst_fpu     : std_ulogic := '1';
     signal rst_ls1     : std_ulogic := '1';
+    signal rst_wback   : std_ulogic := '1';
     signal rst_dbg     : std_ulogic := '1';
     signal alt_reset_d : std_ulogic;
 
@@ -182,6 +184,7 @@ begin
             rst_ex1     <= core_rst;
             rst_fpu     <= core_rst;
             rst_ls1     <= core_rst;
+            rst_wback   <= core_rst;
             rst_dbg     <= rst;
             alt_reset_d <= alt_reset;
         end if;
@@ -202,7 +205,7 @@ begin
             inval_btc => ex1_icache_inval or mmu_to_icache.tlbie,
            stop_in => dbg_core_stop,
             d_in => decode1_to_fetch1,
-            e_in => execute1_to_fetch1,
+            w_in => writeback_to_fetch1,
             i_out => fetch1_to_icache,
             log_out => log_data(42 downto 0)
             );
@@ -324,14 +327,14 @@ begin
         port map (
             clk => clk,
             rst => rst_ex1,
-            flush_out => flush,
+            flush_in => flush,
            busy_out => ex1_busy_out,
             e_in => decode2_to_execute1,
             l_in => loadstore1_to_execute1,
             fp_in => fpu_to_execute1,
             ext_irq_in => ext_irq,
+            interrupt_in => do_interrupt,
             l_out => execute1_to_loadstore1,
-            f_out => execute1_to_fetch1,
             fp_out => execute1_to_fpu,
             e_out => execute1_to_writeback,
             bypass_data => execute1_bypass,
@@ -416,11 +419,15 @@ begin
     writeback_0: entity work.writeback
         port map (
             clk => clk,
+            rst => rst_wback,
+            flush_out => flush,
             e_in => execute1_to_writeback,
             l_in => loadstore1_to_writeback,
             fp_in => fpu_to_writeback,
             w_out => writeback_to_register_file,
             c_out => writeback_to_cr_file,
+            f_out => writeback_to_fetch1,
+            interrupt_out => do_interrupt,
             complete_out => complete
             );
 
index 0b9ba0e4058f19ae29092e17d90807bf4553ebcc..875e22c95919ce4e8438bd52c8b597da0447243c 100644 (file)
@@ -22,7 +22,7 @@ entity execute1 is
         rst   : in std_ulogic;
 
        -- asynchronous
-       flush_out : out std_ulogic;
+       flush_in : in std_ulogic;
        busy_out : out std_ulogic;
 
        e_in  : in Decode2ToExecute1Type;
@@ -30,10 +30,10 @@ entity execute1 is
         fp_in : in FPUToExecute1Type;
 
        ext_irq_in : std_ulogic;
+        interrupt_in : std_ulogic;
 
        -- asynchronous
         l_out : out Execute1ToLoadstore1Type;
-       f_out : out Execute1ToFetch1Type;
         fp_out : out Execute1ToFPUType;
 
        e_out : out Execute1ToWritebackType;
@@ -61,21 +61,11 @@ architecture behaviour of execute1 is
         fp_exception_next : std_ulogic;
         trace_next : std_ulogic;
         prev_op : insn_type_t;
-       next_lr : std_ulogic_vector(63 downto 0);
         br_taken : std_ulogic;
        mul_in_progress : std_ulogic;
         mul_finish : std_ulogic;
         div_in_progress : std_ulogic;
         cntz_in_progress : std_ulogic;
-        last_nia : std_ulogic_vector(63 downto 0);
-        redirect : std_ulogic;
-        abs_br : std_ulogic;
-        taken_br : std_ulogic;
-        br_last : std_ulogic;
-        do_intr : std_ulogic;
-        vector : integer range 0 to 16#fff#;
-        br_offset : std_ulogic_vector(63 downto 0);
-        redir_mode : std_ulogic_vector(3 downto 0);
         log_addr_spr : std_ulogic_vector(31 downto 0);
     end record;
     constant reg_type_init : reg_type :=
@@ -84,9 +74,6 @@ architecture behaviour of execute1 is
          busy => '0', terminate => '0',
          fp_exception_next => '0', trace_next => '0', prev_op => OP_ILLEGAL, br_taken => '0',
          mul_in_progress => '0', mul_finish => '0', div_in_progress => '0', cntz_in_progress => '0',
-         next_lr => (others => '0'), last_nia => (others => '0'),
-         redirect => '0', abs_br => '0', taken_br => '0', br_last => '0', do_intr => '0', vector => 0,
-         br_offset => (others => '0'), redir_mode => "0000",
          others => (others => '0'));
 
     signal r, rin : reg_type;
@@ -96,8 +83,8 @@ architecture behaviour of execute1 is
     signal xerc_in : xer_common_t;
 
     signal valid_in : std_ulogic;
-    signal ctrl: ctrl_t := (irq_state => WRITE_SRR0, others => (others => '0'));
-    signal ctrl_tmp: ctrl_t := (irq_state => WRITE_SRR0, others => (others => '0'));
+    signal ctrl: ctrl_t := (others => (others => '0'));
+    signal ctrl_tmp: ctrl_t := (others => (others => '0'));
     signal right_shift, rot_clear_left, rot_clear_right: std_ulogic;
     signal rot_sign_ext: std_ulogic;
     signal rotator_result: std_ulogic_vector(63 downto 0);
@@ -307,7 +294,7 @@ begin
     xerc_in <= r.e.xerc when r.e.write_xerc_enable = '1' or r.busy = '1' else e_in.xerc;
 
     busy_out <= l_in.busy or r.busy or fp_in.busy;
-    valid_in <= e_in.valid and not busy_out;
+    valid_in <= e_in.valid and not busy_out and not flush_in;
 
     terminate_out <= r.terminate;
 
@@ -332,7 +319,6 @@ begin
                 ctrl.tb <= (others => '0');
                 ctrl.dec <= (others => '0');
                 ctrl.msr <= (MSR_SF => '1', MSR_LE => '1', others => '0');
-                ctrl.irq_state <= WRITE_SRR0;
             else
                 r <= rin;
                 ctrl <= ctrl_tmp;
@@ -673,7 +659,6 @@ begin
         variable lv : Execute1ToLoadstore1Type;
        variable irq_valid : std_ulogic;
        variable exception : std_ulogic;
-        variable exception_nextpc : std_ulogic;
         variable illegal : std_ulogic;
         variable is_branch : std_ulogic;
         variable is_direct_branch : std_ulogic;
@@ -682,7 +667,6 @@ begin
         variable spr_val : std_ulogic_vector(63 downto 0);
         variable do_trace : std_ulogic;
         variable hold_wr_data : std_ulogic;
-        variable f : Execute1ToFetch1Type;
         variable fv : Execute1ToFPUType;
     begin
         is_branch := '0';
@@ -693,15 +677,8 @@ begin
 
        v := r;
        v.e := Execute1ToWritebackInit;
-        v.redirect := '0';
-        v.abs_br := '0';
-        v.do_intr := '0';
-        v.vector := 0;
-        v.br_offset := (others => '0');
-        v.redir_mode := ctrl.msr(MSR_IR) & not ctrl.msr(MSR_PR) &
-                        not ctrl.msr(MSR_LE) & not ctrl.msr(MSR_SF);
-        v.taken_br := '0';
-        v.br_last := '0';
+        v.e.redir_mode := ctrl.msr(MSR_IR) & not ctrl.msr(MSR_PR) &
+                          not ctrl.msr(MSR_LE) & not ctrl.msr(MSR_SF);
         v.e.xerc := xerc_in;
 
         lv := Execute1ToLoadstore1Init;
@@ -725,11 +702,11 @@ begin
        irq_valid := '0';
        if ctrl.msr(MSR_EE) = '1' then
            if ctrl.dec(63) = '1' then
-               v.vector := 16#900#;
+               v.e.intr_vec := 16#900#;
                report "IRQ valid: DEC";
                irq_valid := '1';
            elsif ext_irq_in = '1' then
-               v.vector := 16#500#;
+               v.e.intr_vec := 16#500#;
                report "IRQ valid: External";
                irq_valid := '1';
            end if;
@@ -748,18 +725,13 @@ 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';
 
-        ctrl_tmp.srr1 <= msr_copy(ctrl.msr);
-       ctrl_tmp.irq_state <= WRITE_SRR0;
+        v.e.srr1 := msr_copy(ctrl.msr);
        exception := '0';
         illegal := '0';
-        exception_nextpc := '0';
-        v.e.exc_write_enable := '0';
-        v.e.exc_write_reg := fast_spr_num(SPR_SRR0);
         if valid_in = '1' then
-            v.e.exc_write_data := e_in.nia;
-            v.last_nia := e_in.nia;
+            v.e.last_nia := e_in.nia;
         else
-            v.e.exc_write_data := r.last_nia;
+            v.e.last_nia := r.e.last_nia;
         end if;
 
         v.e.mode_32bit := not ctrl.msr(MSR_SF);
@@ -777,20 +749,20 @@ begin
                 -- This is used for FP-type program interrupts that
                 -- become pending due to MSR[FE0,FE1] changing from 00 to non-zero.
                 exception := '1';
-                v.vector := 16#700#;
-                ctrl_tmp.srr1(63 - 43) <= '1';
-                ctrl_tmp.srr1(63 - 47) <= '1';
+                v.e.intr_vec := 16#700#;
+                v.e.srr1(63 - 43) := '1';
+                v.e.srr1(63 - 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.vector := 16#d00#;
-                ctrl_tmp.srr1(63 - 33) <= '1';
+                v.e.intr_vec := 16#d00#;
+                v.e.srr1(63 - 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
-                    ctrl_tmp.srr1(63 - 35) <= '1';
+                    v.e.srr1(63 - 35) := '1';
                 elsif r.prev_op = OP_STORE or r.prev_op = OP_DCBZ or r.prev_op = OP_DCBTST then
-                    ctrl_tmp.srr1(63 - 36) <= '1';
+                    v.e.srr1(63 - 36) := '1';
                 end if;
 
             elsif irq_valid = '1' then
@@ -801,9 +773,9 @@ begin
             elsif ctrl.msr(MSR_PR) = '1' and instr_is_privileged(e_in.insn_type, e_in.insn) then
                 -- generate a program interrupt
                 exception := '1';
-                v.vector := 16#700#;
+                v.e.intr_vec := 16#700#;
                 -- set bit 45 to indicate privileged instruction type interrupt
-                ctrl_tmp.srr1(63 - 45) <= '1';
+                v.e.srr1(63 - 45) := '1';
                 report "privileged instruction";
 
             elsif not HAS_FPU and e_in.fac = FPU then
@@ -813,14 +785,13 @@ begin
             elsif HAS_FPU and ctrl.msr(MSR_FP) = '0' and e_in.fac = FPU then
                 -- generate a floating-point unavailable interrupt
                 exception := '1';
-                v.vector := 16#800#;
+                v.e.intr_vec := 16#800#;
                 report "FP unavailable interrupt";
             end if;
         end if;
 
        if valid_in = '1' and exception = '0' and illegal = '0' and e_in.unit = ALU then
             v.cur_instr := e_in;
-            v.next_lr := next_nia;
            v.e.valid := '1';
 
            case_0: case e_in.insn_type is
@@ -835,8 +806,8 @@ begin
                -- we need two cycles to write srr0 and 1
                 if e_in.insn(1) = '1' then
                     exception := '1';
-                    exception_nextpc := '1';
-                    v.vector := 16#C00#;
+                    v.e.intr_vec := 16#C00#;
+                    v.e.last_nia := next_nia;
                     report "sc";
                 else
                     illegal := '1';
@@ -867,9 +838,9 @@ begin
             when OP_CMP =>
             when OP_TRAP =>
                 -- trap instructions (tw, twi, td, tdi)
-                v.vector := 16#700#;
+                v.e.intr_vec := 16#700#;
                 -- set bit 46 to say trap occurred
-                ctrl_tmp.srr1(63 - 46) <= '1';
+                v.e.srr1(63 - 46) := '1';
                 if or (trapval and insn_to(e_in.insn)) = '1' then
                     -- generate trap-type program interrupt
                     exception := '1';
@@ -916,8 +887,8 @@ begin
                 end if;
 
            when OP_RFID =>
-                v.redir_mode := (a_in(MSR_IR) or a_in(MSR_PR)) & not a_in(MSR_PR) &
-                                not a_in(MSR_LE) & not a_in(MSR_SF);
+                v.e.redir_mode := (a_in(MSR_IR) or a_in(MSR_PR)) & not a_in(MSR_PR) &
+                                  not a_in(MSR_LE) & not a_in(MSR_SF);
                 -- Can't use msr_copy here because the partial function MSR
                 -- bits should be left unchanged, not zeroed.
                 ctrl_tmp.msr(63 downto 31) <= a_in(63 downto 31);
@@ -1051,8 +1022,8 @@ begin
             when OP_SETB =>
 
            when OP_ISYNC =>
-               v.redirect := '1';
-                v.br_offset := std_ulogic_vector(to_unsigned(4, 64));
+               v.e.redirect := '1';
+                v.e.br_offset := std_ulogic_vector(to_unsigned(4, 64));
 
            when OP_ICBI =>
                icache_inval <= '1';
@@ -1080,16 +1051,16 @@ begin
                     ctrl_tmp.cfar <= e_in.nia;
                 end if;
                 if taken_branch = '1' then
-                    v.br_offset := b_in;
-                    v.abs_br := abs_branch;
+                    v.e.br_offset := b_in;
+                    v.e.abs_br := abs_branch;
                 else
-                    v.br_offset := std_ulogic_vector(to_unsigned(4, 64));
+                    v.e.br_offset := std_ulogic_vector(to_unsigned(4, 64));
                 end if;
                 if taken_branch /= e_in.br_pred then
-                    v.redirect := '1';
+                    v.e.redirect := '1';
                 end if;
-                v.br_last := is_direct_branch;
-                v.taken_br := taken_branch;
+                v.e.br_last := is_direct_branch;
+                v.e.br_taken := taken_branch;
             end if;
 
         elsif valid_in = '1' and exception = '0' and illegal = '0' then
@@ -1110,28 +1081,7 @@ begin
         -- The following cases all occur when r.busy = 1 and therefore
         -- valid_in = 0.  Hence they don't happen in the same cycle as any of
         -- the cases above which depend on valid_in = 1.
-
-       if ctrl.irq_state = WRITE_SRR1 then
-           v.e.exc_write_reg := fast_spr_num(SPR_SRR1);
-           v.e.exc_write_data := ctrl.srr1;
-            v.e.exc_write_enable := '1';
-            ctrl_tmp.msr(MSR_SF) <= '1';
-            ctrl_tmp.msr(MSR_EE) <= '0';
-            ctrl_tmp.msr(MSR_PR) <= '0';
-            ctrl_tmp.msr(MSR_SE) <= '0';
-            ctrl_tmp.msr(MSR_BE) <= '0';
-            ctrl_tmp.msr(MSR_FP) <= '0';
-            ctrl_tmp.msr(MSR_FE0) <= '0';
-            ctrl_tmp.msr(MSR_FE1) <= '0';
-            ctrl_tmp.msr(MSR_IR) <= '0';
-            ctrl_tmp.msr(MSR_DR) <= '0';
-            ctrl_tmp.msr(MSR_RI) <= '0';
-            ctrl_tmp.msr(MSR_LE) <= '1';
-            v.trace_next := '0';
-            v.fp_exception_next := '0';
-           report "Writing SRR1: " & to_hstring(ctrl.srr1);
-
-        elsif r.cntz_in_progress = '1' then
+        if r.cntz_in_progress = '1' then
             -- cnt[lt]z always takes two cycles
             v.e.valid := '1';
        elsif r.mul_in_progress = '1' or r.div_in_progress = '1' then
@@ -1179,63 +1129,67 @@ begin
         -- 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.vector := 16#700#;
-            ctrl_tmp.srr1(63 - 43) <= '1';
+            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
             exception := '1';
-            v.vector := 16#700#;
+            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
-            ctrl_tmp.srr1(63 - 44) <= '1';
+            v.e.srr1(63 - 44) := '1';
             report "illegal";
         end if;
-       if exception = '1' then
-            v.e.exc_write_enable := '1';
-            if exception_nextpc = '1' then
-                v.e.exc_write_data := next_nia;
-            end if;
-       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.vector := 16#600#;
+                v.e.intr_vec := 16#600#;
             elsif l_in.instr_fault = '0' then
                 if l_in.segment_fault = '0' then
-                    v.vector := 16#300#;
+                    v.e.intr_vec := 16#300#;
                 else
-                    v.vector := 16#380#;
+                    v.e.intr_vec := 16#380#;
                 end if;
             else
                 if l_in.segment_fault = '0' then
-                    ctrl_tmp.srr1(63 - 33) <= l_in.invalid;
-                    ctrl_tmp.srr1(63 - 35) <= l_in.perm_error; -- noexec fault
-                    ctrl_tmp.srr1(63 - 44) <= l_in.badtree;
-                    ctrl_tmp.srr1(63 - 45) <= l_in.rc_error;
-                    v.vector := 16#400#;
+                    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.vector := 16#480#;
+                    v.e.intr_vec := 16#480#;
                 end if;
             end if;
-            v.e.exc_write_enable := '1';
-            v.e.exc_write_reg := fast_spr_num(SPR_SRR0);
-            report "ldst exception writing srr0=" & to_hstring(r.last_nia);
         end if;
 
-        if exception = '1' or l_in.exception = '1' then
-            ctrl_tmp.irq_state <= WRITE_SRR1;
-            v.redirect := '1';
-            v.do_intr := '1';
-        end if;
+        v.e.interrupt := exception or l_in.exception;
 
         if do_trace = '1' then
             v.trace_next := '1';
         end if;
 
+       if interrupt_in = '1' then
+            ctrl_tmp.msr(MSR_SF) <= '1';
+            ctrl_tmp.msr(MSR_EE) <= '0';
+            ctrl_tmp.msr(MSR_PR) <= '0';
+            ctrl_tmp.msr(MSR_SE) <= '0';
+            ctrl_tmp.msr(MSR_BE) <= '0';
+            ctrl_tmp.msr(MSR_FP) <= '0';
+            ctrl_tmp.msr(MSR_FE0) <= '0';
+            ctrl_tmp.msr(MSR_FE1) <= '0';
+            ctrl_tmp.msr(MSR_IR) <= '0';
+            ctrl_tmp.msr(MSR_DR) <= '0';
+            ctrl_tmp.msr(MSR_RI) <= '0';
+            ctrl_tmp.msr(MSR_LE) <= '1';
+            v.trace_next := '0';
+            v.fp_exception_next := '0';
+        end if;
+
         if hold_wr_data = '0' then
             v.e.write_data := alu_result;
         else
@@ -1263,41 +1217,6 @@ begin
             end if;
         end loop;
 
-        -- Defer completion for one cycle when redirecting.
-        -- This also ensures r.busy = 1 when ctrl.irq_state = WRITE_SRR1
-        if v.redirect = '1' then
-            v.busy := '1';
-            v.e.valid := '0';
-        end if;
-        if r.redirect = '1' then
-            v.e.valid := '1';
-        end if;
-
-        -- Outputs to fetch1
-        f.redirect := r.redirect;
-        f.br_nia := r.last_nia;
-        f.br_last := r.br_last and not r.do_intr;
-        f.br_taken := r.taken_br;
-        if r.do_intr = '1' then
-            f.redirect_nia := std_ulogic_vector(to_unsigned(r.vector, 64));
-            f.virt_mode := '0';
-            f.priv_mode := '1';
-            -- XXX need an interrupt LE bit here, e.g. from LPCR
-            f.big_endian := '0';
-            f.mode_32bit := '0';
-        else
-            if r.abs_br = '1' then
-                f.redirect_nia := r.br_offset;
-            else
-                f.redirect_nia := std_ulogic_vector(unsigned(r.last_nia) + unsigned(r.br_offset));
-            end if;
-            -- send MSR[IR], ~MSR[PR], ~MSR[LE] and ~MSR[SF] up to fetch1
-            f.virt_mode := r.redir_mode(3);
-            f.priv_mode := r.redir_mode(2);
-            f.big_endian := r.redir_mode(1);
-            f.mode_32bit := r.redir_mode(0);
-        end if;
-
         -- Outputs to loadstore1 (async)
         lv.op := e_in.insn_type;
         lv.nia := e_in.nia;
@@ -1344,11 +1263,9 @@ begin
        rin <= v;
 
        -- update outputs
-       f_out <= f;
         l_out <= lv;
        e_out <= r.e;
         fp_out <= fv;
-       flush_out <= f_out.redirect;
 
         exception_log <= exception;
         irq_valid_log <= irq_valid;
@@ -1364,13 +1281,13 @@ begin
                             ctrl.msr(MSR_IR) & ctrl.msr(MSR_DR) &
                             exception_log &
                             irq_valid_log &
-                            std_ulogic_vector(to_unsigned(irq_state_t'pos(ctrl.irq_state), 1)) &
+                            interrupt_in &
                             "000" &
                             r.e.write_enable &
                             r.e.valid &
-                            f_out.redirect &
+                            (r.e.redirect or r.e.interrupt) &
                             r.busy &
-                            flush_out;
+                            flush_in;
             end if;
         end process;
         log_out <= log_data;
index 8ca7e57f244101844f78a4eaf36563d4ca76ef2a..788a76d893c39db9f32b0a70fd073af83f2fd2d5 100644 (file)
@@ -22,8 +22,8 @@ entity fetch1 is
        stop_in       : in std_ulogic;
        alt_reset_in  : in std_ulogic;
 
-       -- redirect from execution unit
-       e_in          : in Execute1ToFetch1Type;
+       -- redirect from writeback unit
+       w_in          : in WritebackToFetch1Type;
 
         -- redirect from decode1
         d_in          : in Decode1ToFetch1Type;
@@ -70,12 +70,12 @@ begin
                     " P:" & std_ulogic'image(r_next.priv_mode) &
                     " E:" & std_ulogic'image(r_next.big_endian) &
                     " 32:" & std_ulogic'image(r_next_int.mode_32bit) &
-                   " R:" & std_ulogic'image(e_in.redirect) & std_ulogic'image(d_in.redirect) &
+                   " R:" & std_ulogic'image(w_in.redirect) & std_ulogic'image(d_in.redirect) &
                    " S:" & std_ulogic'image(stall_in) &
                    " T:" & std_ulogic'image(stop_in) &
                    " nia:" & to_hstring(r_next.nia);
            end if;
-            if rst = '1' or e_in.redirect = '1' or d_in.redirect = '1' or stall_in = '0' then
+            if rst = '1' or w_in.redirect = '1' or d_in.redirect = '1' or stall_in = '0' then
                 r.virt_mode <= r_next.virt_mode;
                 r.priv_mode <= r_next.priv_mode;
                 r.big_endian <= r_next.big_endian;
@@ -109,11 +109,11 @@ begin
         signal btc_wr_addr : std_ulogic_vector(BTC_ADDR_BITS - 1 downto 0);
         signal btc_wr_v : std_ulogic;
     begin
-        btc_wr_data <= e_in.br_nia(63 downto BTC_ADDR_BITS + 2) &
-                       e_in.redirect_nia(63 downto 2);
-        btc_wr_addr <= e_in.br_nia(BTC_ADDR_BITS + 1 downto 2);
-        btc_wr <= e_in.br_last;
-        btc_wr_v <= e_in.br_taken;
+        btc_wr_data <= w_in.br_nia(63 downto BTC_ADDR_BITS + 2) &
+                       w_in.redirect_nia(63 downto 2);
+        btc_wr_addr <= w_in.br_nia(BTC_ADDR_BITS + 1 downto 2);
+        btc_wr <= w_in.br_last;
+        btc_wr_v <= w_in.br_taken;
 
         btc_ram : process(clk)
             variable raddr : unsigned(BTC_ADDR_BITS - 1 downto 0);
@@ -158,15 +158,15 @@ begin
             v.big_endian := '0';
             v_int.mode_32bit := '0';
             v_int.predicted_nia := (others => '0');
-       elsif e_in.redirect = '1' then
-           v.nia := e_in.redirect_nia(63 downto 2) & "00";
-            if e_in.mode_32bit = '1' then
+       elsif w_in.redirect = '1' then
+           v.nia := w_in.redirect_nia(63 downto 2) & "00";
+            if w_in.mode_32bit = '1' then
                 v.nia(63 downto 32) := (others => '0');
             end if;
-            v.virt_mode := e_in.virt_mode;
-            v.priv_mode := e_in.priv_mode;
-            v.big_endian := e_in.big_endian;
-            v_int.mode_32bit := e_in.mode_32bit;
+            v.virt_mode := w_in.virt_mode;
+            v.priv_mode := w_in.priv_mode;
+            v.big_endian := w_in.big_endian;
+            v_int.mode_32bit := w_in.mode_32bit;
         elsif d_in.redirect = '1' then
             v.nia := d_in.redirect_nia(63 downto 2) & "00";
             if r_int.mode_32bit = '1' then
@@ -191,7 +191,7 @@ begin
 
         -- If the last NIA value went down with a stop mark, it didn't get
         -- executed, and hence we shouldn't increment NIA.
-        advance_nia <= rst or e_in.redirect or d_in.redirect or (not r.stop_mark and not stall_in);
+        advance_nia <= rst or w_in.redirect or d_in.redirect or (not r.stop_mark and not stall_in);
 
        r_next <= v;
        r_next_int <= v_int;
index 044b1fb88f03cb286332d0286c04d0bbf65045f0..c7632ea41810711edf4d3dd7ca14bfc8cd4a55fa 100644 (file)
@@ -9,6 +9,7 @@ use work.crhelpers.all;
 entity writeback is
     port (
         clk          : in std_ulogic;
+        rst          : in std_ulogic;
 
         e_in         : in Execute1ToWritebackType;
         l_in         : in Loadstore1ToWritebackType;
@@ -16,12 +17,24 @@ entity writeback is
 
         w_out        : out WritebackToRegisterFileType;
         c_out        : out WritebackToCrFileType;
+        f_out        : out WritebackToFetch1Type;
 
+        flush_out    : out std_ulogic;
+        interrupt_out: out std_ulogic;
         complete_out : out instr_tag_t
         );
 end entity writeback;
 
 architecture behaviour of writeback is
+    type irq_state_t is (WRITE_SRR0, WRITE_SRR1);
+
+    type reg_type is record
+        state : irq_state_t;
+        srr1  : std_ulogic_vector(63 downto 0);
+    end record;
+
+    signal r, rin : reg_type;
+
 begin
     writeback_0: process(clk)
         variable x : std_ulogic_vector(0 downto 0);
@@ -29,6 +42,13 @@ begin
         variable w : std_ulogic_vector(0 downto 0);
     begin
         if rising_edge(clk) then
+            if rst = '1' then
+                r.state <= WRITE_SRR0;
+                r.srr1 <= (others => '0');
+            else
+                r <= rin;
+            end if;
+
             -- Do consistency checks only on the clock edge
             x(0) := e_in.valid;
             y(0) := l_in.valid;
@@ -36,7 +56,7 @@ begin
             assert (to_integer(unsigned(x)) + to_integer(unsigned(y)) +
                     to_integer(unsigned(w))) <= 1 severity failure;
 
-            x(0) := e_in.write_enable or e_in.exc_write_enable;
+            x(0) := e_in.write_enable;
             y(0) := l_in.write_enable;
             w(0) := fp_in.write_enable;
             assert (to_integer(unsigned(x)) + to_integer(unsigned(y)) +
@@ -55,6 +75,8 @@ begin
     end process;
 
     writeback_1: process(all)
+        variable v    : reg_type;
+        variable f    : WritebackToFetch1Type;
        variable cf: std_ulogic_vector(3 downto 0);
         variable zero : std_ulogic;
         variable sign : std_ulogic;
@@ -62,6 +84,9 @@ begin
     begin
         w_out <= WritebackToRegisterFileInit;
         c_out <= WritebackToCrFileInit;
+        f := WritebackToFetch1Init;
+        interrupt_out <= '0';
+        v := r;
 
         complete_out <= instr_tag_init;
         if e_in.valid = '1' then
@@ -72,10 +97,19 @@ begin
             complete_out <= fp_in.instr_tag;
         end if;
 
-        if e_in.exc_write_enable = '1' then
-            w_out.write_reg <= e_in.exc_write_reg;
-            w_out.write_data <= e_in.exc_write_data;
+        if r.state = WRITE_SRR1 then
+            w_out.write_reg <= fast_spr_num(SPR_SRR1);
+            w_out.write_data <= r.srr1;
+            w_out.write_enable <= '1';
+            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 := e_in.srr1;
         else
             if e_in.write_enable = '1' then
                 w_out.write_reg <= e_in.write_reg;
@@ -142,5 +176,35 @@ begin
                 c_out.write_cr_data(31 downto 28) <= cf;
             end if;
         end if;
+
+        -- Outputs to fetch1
+        f.redirect := e_in.redirect or e_in.interrupt;
+        f.br_nia := e_in.last_nia;
+        f.br_last := e_in.br_last and not e_in.interrupt;
+        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));
+            f.virt_mode := '0';
+            f.priv_mode := '1';
+            -- XXX need an interrupt LE bit here, e.g. from LPCR
+            f.big_endian := '0';
+            f.mode_32bit := '0';
+        else
+            if e_in.abs_br = '1' then
+                f.redirect_nia := e_in.br_offset;
+            else
+                f.redirect_nia := std_ulogic_vector(unsigned(e_in.last_nia) + unsigned(e_in.br_offset));
+            end if;
+            -- send MSR[IR], ~MSR[PR], ~MSR[LE] and ~MSR[SF] up to fetch1
+            f.virt_mode := e_in.redir_mode(3);
+            f.priv_mode := e_in.redir_mode(2);
+            f.big_endian := e_in.redir_mode(1);
+            f.mode_32bit := e_in.redir_mode(0);
+        end if;
+
+       f_out <= f;
+        flush_out <= f_out.redirect;
+
+        rin <= v;
     end process;
 end;