execute1: Move branch adder after register
authorPaul Mackerras <paulus@ozlabs.org>
Wed, 16 Dec 2020 09:41:08 +0000 (20:41 +1100)
committerPaul Mackerras <paulus@ozlabs.org>
Fri, 15 Jan 2021 01:40:09 +0000 (12:40 +1100)
This does the addition of the instruction NIA and the branch offset
after the register at the output of execute1 rather than before.
The propagation through the adder was showing up as a critical path
on the A7-100.  Performance is unaffected and now it makes timing.

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

index 11d81ed7a302df12d189950ad9b935625e94335b..4ea26803413dfe916fbec4f5f956eef57d9f91e1 100644 (file)
@@ -53,7 +53,6 @@ end entity execute1;
 architecture behaviour of execute1 is
     type reg_type is record
        e : Execute1ToWritebackType;
-        f : Execute1ToFetch1Type;
         busy: std_ulogic;
         terminate: std_ulogic;
         fp_exception_next : std_ulogic;
@@ -71,15 +70,24 @@ architecture behaviour of execute1 is
        slow_op_oe : std_ulogic;
        slow_op_xerc : xer_common_t;
         last_nia : std_ulogic_vector(63 downto 0);
+        redirect : std_ulogic;
+        abs_br : 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 :=
-        (e => Execute1ToWritebackInit, f => Execute1ToFetch1Init,
+        (e => Execute1ToWritebackInit,
          busy => '0', lr_update => '0', terminate => '0',
          fp_exception_next => '0', trace_next => '0', prev_op => OP_ILLEGAL,
          mul_in_progress => '0', mul_finish => '0', div_in_progress => '0', cntz_in_progress => '0',
          slow_op_insn => OP_ILLEGAL, slow_op_rc => '0', slow_op_oe => '0', slow_op_xerc => xerc_init,
-         next_lr => (others => '0'), last_nia => (others => '0'), others => (others => '0'));
+         next_lr => (others => '0'), last_nia => (others => '0'),
+         redirect => '0', abs_br => '0', do_intr => '0', vector => 0,
+         br_offset => (others => '0'), redir_mode => "0000",
+         others => (others => '0'));
 
     signal r, rin : reg_type;
 
@@ -340,6 +348,7 @@ begin
         variable spr_val : std_ulogic_vector(63 downto 0);
         variable addend : std_ulogic_vector(127 downto 0);
         variable do_trace : std_ulogic;
+        variable f : Execute1ToFetch1Type;
         variable fv : Execute1ToFPUType;
     begin
        result := (others => '0');
@@ -352,8 +361,15 @@ 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);
+
         lv := Execute1ToLoadstore1Init;
-        v.f.redirect := '0';
         fv := Execute1ToFPUInit;
 
        -- XER forwarding. To avoid having to track XER hazards, we use
@@ -471,11 +487,11 @@ begin
        irq_valid := '0';
        if ctrl.msr(MSR_EE) = '1' then
            if ctrl.dec(63) = '1' then
-               v.f.redirect_nia := std_logic_vector(to_unsigned(16#900#, 64));
+               v.vector := 16#900#;
                report "IRQ valid: DEC";
                irq_valid := '1';
            elsif ext_irq_in = '1' then
-               v.f.redirect_nia := std_logic_vector(to_unsigned(16#500#, 64));
+               v.vector := 16#500#;
                report "IRQ valid: External";
                irq_valid := '1';
            end if;
@@ -484,11 +500,6 @@ begin
        v.terminate := '0';
        icache_inval <= '0';
        v.busy := '0';
-        -- send MSR[IR], ~MSR[PR], ~MSR[LE] and ~MSR[SF] up to fetch1
-        v.f.virt_mode := ctrl.msr(MSR_IR);
-        v.f.priv_mode := not ctrl.msr(MSR_PR);
-        v.f.big_endian := not ctrl.msr(MSR_LE);
-        v.f.mode_32bit := not ctrl.msr(MSR_SF);
 
        -- Next insn adder used in a couple of places
        next_nia := std_ulogic_vector(unsigned(e_in.nia) + 4);
@@ -546,13 +557,13 @@ begin
             if HAS_FPU and r.fp_exception_next = '1' then
                 -- This is used for FP-type program interrupts that
                 -- become pending due to MSR[FE0,FE1] changing from 00 to non-zero.
-                v.f.redirect_nia := std_logic_vector(to_unsigned(16#700#, 64));
+                v.vector := 16#700#;
                 ctrl_tmp.srr1(63 - 43) <= '1';
                 ctrl_tmp.srr1(63 - 47) <= '1';
             else
                 -- Generate a trace interrupt rather than executing the next instruction
                 -- or taking any asynchronous interrupt
-                v.f.redirect_nia := std_logic_vector(to_unsigned(16#d00#, 64));
+                v.vector := 16#d00#;
                 ctrl_tmp.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
@@ -574,7 +585,7 @@ begin
             instr_is_privileged(e_in.insn_type, e_in.insn) then
             -- generate a program interrupt
             exception := '1';
-            v.f.redirect_nia := std_logic_vector(to_unsigned(16#700#, 64));
+            v.vector := 16#700#;
             -- set bit 45 to indicate privileged instruction type interrupt
             ctrl_tmp.srr1(63 - 45) <= '1';
             report "privileged instruction";
@@ -586,7 +597,7 @@ begin
         elsif HAS_FPU and valid_in = '1' and ctrl.msr(MSR_FP) = '0' and e_in.fac = FPU then
             -- generate a floating-point unavailable interrupt
             exception := '1';
-            v.f.redirect_nia := std_logic_vector(to_unsigned(16#800#, 64));
+            v.vector := 16#800#;
             report "FP unavailable interrupt";
 
        elsif valid_in = '1' and e_in.unit = ALU then
@@ -614,7 +625,7 @@ begin
                 if e_in.insn(1) = '1' then
                     exception := '1';
                     exception_nextpc := '1';
-                    v.f.redirect_nia := std_logic_vector(to_unsigned(16#C00#, 64));
+                    v.vector := 16#C00#;
                     report "sc";
                 else
                     illegal := '1';
@@ -702,7 +713,7 @@ begin
                         end loop;
                     else
                         -- trap instructions (tw, twi, td, tdi)
-                        v.f.redirect_nia := std_logic_vector(to_unsigned(16#700#, 64));
+                        v.vector := 16#700#;
                         -- set bit 46 to say trap occurred
                         ctrl_tmp.srr1(63 - 46) <= '1';
                         if or (trapval and insn_to(e_in.insn)) = '1' then
@@ -785,10 +796,8 @@ begin
                 end if;
 
            when OP_RFID =>
-                v.f.virt_mode := a_in(MSR_IR) or a_in(MSR_PR);
-                v.f.priv_mode := not a_in(MSR_PR);
-                v.f.big_endian := not a_in(MSR_LE);
-                v.f.mode_32bit := not a_in(MSR_SF);
+                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);
                 -- 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);
@@ -1032,8 +1041,8 @@ begin
                 end if;
 
            when OP_ISYNC =>
-               v.f.redirect := '1';
-               v.f.redirect_nia := next_nia;
+               v.redirect := '1';
+                v.br_offset := std_ulogic_vector(to_unsigned(4, 64));
 
            when OP_ICBI =>
                icache_inval <= '1';
@@ -1063,16 +1072,13 @@ begin
                     ctrl_tmp.cfar <= e_in.nia;
                 end if;
                 if e_in.br_pred = '0' then
-                    if abs_branch = '1' then
-                        v.f.redirect_nia := b_in;
-                    else
-                        v.f.redirect_nia := std_ulogic_vector(signed(e_in.nia) + signed(b_in));
-                    end if;
+                    v.br_offset := b_in;
+                    v.abs_br := abs_branch;
                 else
-                    v.f.redirect_nia := next_nia;
+                    v.br_offset := std_ulogic_vector(to_unsigned(4, 64));
                 end if;
                 if taken_branch /= e_in.br_pred then
-                    v.f.redirect := '1';
+                    v.redirect := '1';
                 end if;
             end if;
 
@@ -1114,7 +1120,7 @@ begin
         -- 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 r.f.redirect = '1' then
+        if r.redirect = '1' then
             v.e.valid := '1';
         end if;
        if r.lr_update = '1' then
@@ -1195,14 +1201,14 @@ 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.f.redirect_nia := std_logic_vector(to_unsigned(16#700#, 64));
+            v.vector := 16#700#;
             ctrl_tmp.srr1(63 - 43) <= '1';
             exception := '1';
         end if;
 
         if illegal = '1' or (HAS_FPU and fp_in.illegal = '1') then
             exception := '1';
-            v.f.redirect_nia := std_logic_vector(to_unsigned(16#700#, 64));
+            v.vector := 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';
@@ -1226,12 +1232,12 @@ begin
         -- or ISI or ISegI for instruction fetch exceptions
         if l_in.exception = '1' then
             if l_in.alignment = '1' then
-                v.f.redirect_nia := std_logic_vector(to_unsigned(16#600#, 64));
+                v.vector := 16#600#;
             elsif l_in.instr_fault = '0' then
                 if l_in.segment_fault = '0' then
-                    v.f.redirect_nia := std_logic_vector(to_unsigned(16#300#, 64));
+                    v.vector := 16#300#;
                 else
-                    v.f.redirect_nia := std_logic_vector(to_unsigned(16#380#, 64));
+                    v.vector := 16#380#;
                 end if;
             else
                 if l_in.segment_fault = '0' then
@@ -1239,9 +1245,9 @@ begin
                     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.f.redirect_nia := std_logic_vector(to_unsigned(16#400#, 64));
+                    v.vector := 16#400#;
                 else
-                    v.f.redirect_nia := std_logic_vector(to_unsigned(16#480#, 64));
+                    v.vector := 16#480#;
                 end if;
             end if;
             v.e.exc_write_enable := '1';
@@ -1251,19 +1257,37 @@ begin
 
         if exception = '1' or l_in.exception = '1' then
             ctrl_tmp.irq_state <= WRITE_SRR1;
-            v.f.redirect := '1';
-            v.f.virt_mode := '0';
-            v.f.priv_mode := '1';
-            -- XXX need an interrupt LE bit here, e.g. from LPCR
-            v.f.big_endian := '0';
-            v.f.mode_32bit := '0';
+            v.redirect := '1';
+            v.do_intr := '1';
         end if;
 
-        if v.f.redirect = '1' then
+        if v.redirect = '1' then
             v.busy := '1';
             v.e.valid := '0';
         end if;
 
+        -- Outputs to fetch1
+        f.redirect := r.redirect;
+        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;
@@ -1309,7 +1333,7 @@ begin
        rin <= v;
 
        -- update outputs
-       f_out <= r.f;
+       f_out <= f;
         l_out <= lv;
        e_out <= r.e;
         fp_out <= fv;