execute1: Move CR result to data path process
authorPaul Mackerras <paulus@ozlabs.org>
Fri, 27 Nov 2020 06:41:39 +0000 (17:41 +1100)
committerPaul Mackerras <paulus@ozlabs.org>
Mon, 18 Jan 2021 22:27:29 +0000 (09:27 +1100)
Also work out in decode2 whether the instruction sets the XER common
bits.

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

index 0151595e50670b5ecb19431e49b2e06f5b1e4015..a3a95f41678a9bce6e7c957f4f84d0574d040942 100644 (file)
@@ -243,6 +243,7 @@ package common is
        output_carry: std_ulogic;
        input_cr: std_ulogic;
        output_cr: std_ulogic;
+        output_xer: std_ulogic;
        is_32bit: std_ulogic;
        is_signed: std_ulogic;
        insn: std_ulogic_vector(31 downto 0);
@@ -261,7 +262,8 @@ package common is
        (valid => '0', unit => NONE, fac => NONE, insn_type => OP_ILLEGAL, instr_tag => instr_tag_init,
          write_reg_enable => '0',
          lr => '0', br_abs => '0', rc => '0', oe => '0', invert_a => '0', addm1 => '0',
-        invert_out => '0', input_carry => ZERO, output_carry => '0', input_cr => '0', output_cr => '0',
+        invert_out => '0', input_carry => ZERO, output_carry => '0', input_cr => '0',
+         output_cr => '0', output_xer => '0',
         is_32bit => '0', is_signed => '0', xerc => xerc_init, reserve => '0', br_pred => '0',
          byte_reverse => '0', sign_extend => '0', update => '0', nia => (others => '0'),
          read_data1 => (others => '0'), read_data2 => (others => '0'), read_data3 => (others => '0'),
index 748edb987bc5401636867fc0f66aac41774fff4f..732cfe05aa64b640063915fa7c9b3f0fb6ed6043 100644 (file)
@@ -208,22 +208,6 @@ architecture behaviour of decode2 is
         end case;
     end;
 
-    -- For now, use "rc" in the decode table to decide whether oe exists.
-    -- This is not entirely correct architecturally: For mulhd and
-    -- mulhdu, the OE field is reserved. It remains to be seen what an
-    -- actual POWER9 does if we set it on those instructions, for now we
-    -- test that further down when assigning to the multiplier oe input.
-    --
-    function decode_oe (t : rc_t; insn_in : std_ulogic_vector(31 downto 0)) return std_ulogic is
-    begin
-        case t is
-            when RC =>
-                return insn_oe(insn_in);
-            when OTHERS =>
-                return '0';
-        end case;
-    end;
-
     -- control signals that are derived from insn_type
     type mux_select_array_t is array(insn_type_t) of std_ulogic_vector(2 downto 0);
 
@@ -277,6 +261,12 @@ architecture behaviour of decode2 is
         OP_MFMSR   => "100",
         OP_MFCR    => "101",
         OP_SETB    => "110",
+        OP_CMP     => "000",            -- cr_result
+        OP_CMPRB   => "001",
+        OP_CMPEQB  => "010",
+        OP_CROP    => "011",
+        OP_MCRXRX  => "100",
+        OP_MTCRF   => "101",
         others     => "000"
         );
 
@@ -393,6 +383,22 @@ begin
         --v.e.input_cr := d_in.decode.input_cr;
         v.e.output_cr := d_in.decode.output_cr;
 
+        -- Work out whether XER common bits are set
+        v.e.output_xer := d_in.decode.output_carry;
+        case d_in.decode.insn_type is
+            when OP_ADD | OP_MUL_L64 | OP_DIV | OP_DIVE =>
+                -- OE field is valid in OP_ADD/OP_MUL_L64 with major opcode 31 only
+                if d_in.insn(31 downto 26) = "011111" and insn_oe(d_in.insn) = '1' then
+                    v.e.oe := '1';
+                    v.e.output_xer := '1';
+                end if;
+            when OP_MTSPR =>
+                if decode_spr_num(d_in.insn) = SPR_XER then
+                    v.e.output_xer := '1';
+                end if;
+            when others =>
+        end case;
+
         decoded_reg_a := decode_input_reg_a (d_in.decode.input_reg_a, d_in.insn, r_in.read1_data, d_in.ispr1,
                                              d_in.nia);
         decoded_reg_b := decode_input_reg_b (d_in.decode.input_reg_b, d_in.insn, r_in.read2_data, d_in.ispr2);
@@ -465,9 +471,6 @@ begin
         v.e.write_reg := decoded_reg_o.reg;
         v.e.write_reg_enable := decoded_reg_o.reg_valid;
         v.e.rc := decode_rc(d_in.decode.rc, d_in.insn);
-        if not (d_in.decode.insn_type = OP_MUL_H32 or d_in.decode.insn_type = OP_MUL_H64) then
-            v.e.oe := decode_oe(d_in.decode.rc, d_in.insn);
-        end if;
         v.e.xerc := c_in.read_xerc_data;
         v.e.invert_a := d_in.decode.invert_a;
         v.e.addm1 := '0';
index cfbb2788128fae4ea7c334a9a0dbcd752338c956..0b9ba0e4058f19ae29092e17d90807bf4553ebcc 100644 (file)
@@ -119,10 +119,11 @@ architecture behaviour of execute1 is
     signal overflow_32 : std_ulogic;
     signal overflow_64 : std_ulogic;
 
-    signal cmprb_result : std_ulogic_vector(3 downto 0);
-    signal cmpeqb_result : std_ulogic_vector(3 downto 0);
     signal trapval : std_ulogic_vector(4 downto 0);
 
+    signal write_cr_mask : std_ulogic_vector(7 downto 0);
+    signal write_cr_data : std_ulogic_vector(31 downto 0);
+
     -- multiply signals
     signal x_to_multiply: MultiplyInputType;
     signal multiply_to_x: MultiplyOutputType;
@@ -169,7 +170,6 @@ architecture behaviour of execute1 is
     begin
        e.xerc.ca32 := carry32;
        e.xerc.ca := carry;
-       e.write_xerc_enable := '1';
     end;
 
     procedure set_ov(e: inout Execute1ToWritebackType;
@@ -181,7 +181,6 @@ architecture behaviour of execute1 is
        if ov = '1' then
            e.xerc.so := '1';
        end if;
-       e.write_xerc_enable := '1';
     end;
 
     function calc_ov(msb_a : std_ulogic; msb_b: std_ulogic;
@@ -360,7 +359,6 @@ begin
        variable darn : std_ulogic_vector(63 downto 0);
        variable setb_result : std_ulogic_vector(63 downto 0);
        variable mfcr_result : std_ulogic_vector(63 downto 0);
-       variable crnum : crnum_t;
        variable lo, hi : integer;
        variable l : std_ulogic;
         variable zerohi, zerolo : std_ulogic;
@@ -368,7 +366,16 @@ begin
         variable a_lt : std_ulogic;
         variable a_lt_lo : std_ulogic;
         variable a_lt_hi : std_ulogic;
-       variable bfa : std_ulogic_vector(2 downto 0);
+       variable newcrf : std_ulogic_vector(3 downto 0);
+       variable bf, bfa : std_ulogic_vector(2 downto 0);
+       variable crnum : crnum_t;
+       variable scrnum : crnum_t;
+        variable cr_operands : std_ulogic_vector(1 downto 0);
+       variable crresult : std_ulogic;
+       variable bt, ba, bb : std_ulogic_vector(4 downto 0);
+        variable btnum : integer range 0 to 3;
+       variable banum, bbnum : integer range 0 to 31;
+        variable j : integer;
     begin
         -- Main adder
         if e_in.invert_a = '0' then
@@ -591,24 +598,77 @@ begin
             end if;
         end if;
 
-        cmprb_result <= ppc_cmprb(a_in, b_in, insn_l(e_in.insn));
-        cmpeqb_result <= ppc_cmpeqb(a_in, b_in);
+        -- CR result mux
+        bf := insn_bf(e_in.insn);
+        crnum := to_integer(unsigned(bf));
+        newcrf := (others => '0');
+        case current.sub_select is
+            when "000" =>
+                -- CMP and CMPL instructions
+                if e_in.is_signed = '1' then
+                    newcrf := trapval(4 downto 2) & xerc_in.so;
+                else
+                    newcrf := trapval(1 downto 0) & trapval(2) & xerc_in.so;
+                end if;
+            when "001" =>
+                newcrf := ppc_cmprb(a_in, b_in, insn_l(e_in.insn));
+            when "010" =>
+                newcrf := ppc_cmpeqb(a_in, b_in);
+            when "011" =>
+                if current.insn(1) = '1' then
+                    -- CR logical instructions
+                    j := (7 - crnum) * 4;
+                    newcrf := cr_in(j + 3 downto j);
+                    bt := insn_bt(e_in.insn);
+                    ba := insn_ba(e_in.insn);
+                    bb := insn_bb(e_in.insn);
+                    btnum := 3 - to_integer(unsigned(bt(1 downto 0)));
+                    banum := 31 - to_integer(unsigned(ba));
+                    bbnum := 31 - to_integer(unsigned(bb));
+                    -- Bits 6-9 of the instruction word give the truth table
+                    -- of the requested logical operation
+                    cr_operands := cr_in(banum) & cr_in(bbnum);
+                    crresult := e_in.insn(6 + to_integer(unsigned(cr_operands)));
+                    for i in 0 to 3 loop
+                        if i = btnum then
+                            newcrf(i) := crresult;
+                        end if;
+                    end loop;
+                else
+                    -- MCRF
+                    bfa := insn_bfa(e_in.insn);
+                    scrnum := to_integer(unsigned(bfa));
+                    j := (7 - scrnum) * 4;
+                    newcrf := cr_in(j + 3 downto j);
+                end if;
+            when "100" =>
+                -- MCRXRX
+                newcrf := xerc_in.ov & xerc_in.ca & xerc_in.ov32 & xerc_in.ca32;
+            when others =>
+        end case;
+        if current.insn_type = OP_MTCRF then
+            if e_in.insn(20) = '0' then
+                -- mtcrf
+                write_cr_mask <= insn_fxm(e_in.insn);
+            else
+                -- mtocrf: We require one hot priority encoding here
+                crnum := fxm_to_num(insn_fxm(e_in.insn));
+                write_cr_mask <= num_to_fxm(crnum);
+            end if;
+            write_cr_data <= c_in(31 downto 0);
+        else
+            write_cr_mask <= num_to_fxm(crnum);
+            write_cr_data <= newcrf & newcrf & newcrf & newcrf &
+                             newcrf & newcrf & newcrf & newcrf;
+        end if;
+
     end process;
 
     execute1_1: process(all)
        variable v : reg_type;
-       variable newcrf : std_ulogic_vector(3 downto 0);
-       variable crnum : crnum_t;
-       variable scrnum : crnum_t;
        variable lo, hi : integer;
        variable sh, mb, me : std_ulogic_vector(5 downto 0);
        variable bo, bi : std_ulogic_vector(4 downto 0);
-       variable bf, bfa : std_ulogic_vector(2 downto 0);
-       variable cr_op : std_ulogic_vector(9 downto 0);
-        variable cr_operands : std_ulogic_vector(1 downto 0);
-       variable bt, ba, bb : std_ulogic_vector(4 downto 0);
-       variable btnum, banum, bbnum : integer range 0 to 31;
-       variable crresult : std_ulogic;
        variable overflow : std_ulogic;
         variable lv : Execute1ToLoadstore1Type;
        variable irq_valid : std_ulogic;
@@ -625,7 +685,6 @@ begin
         variable f : Execute1ToFetch1Type;
         variable fv : Execute1ToFPUType;
     begin
-       newcrf := (others => '0');
         is_branch := '0';
         is_direct_branch := '0';
         taken_branch := '0';
@@ -800,27 +859,12 @@ begin
                     else
                         v.e.xerc.ov := carry_64;
                         v.e.xerc.ov32 := carry_32;
-                        v.e.write_xerc_enable := '1';
                     end if;
                 end if;
                 if e_in.oe = '1' then
                     set_ov(v.e, overflow_64, overflow_32);
                 end if;
             when OP_CMP =>
-                -- CMP and CMPL instructions
-                if e_in.is_signed = '1' then
-                    newcrf := trapval(4 downto 2) & xerc_in.so;
-                else
-                    newcrf := trapval(1 downto 0) & trapval(2) & xerc_in.so;
-                end if;
-                bf := insn_bf(e_in.insn);
-                crnum := to_integer(unsigned(bf));
-                v.e.write_cr_mask := num_to_fxm(crnum);
-                for i in 0 to 7 loop
-                    lo := i*4;
-                    hi := lo + 3;
-                    v.e.write_cr_data(hi downto lo) := newcrf;
-                end loop;
             when OP_TRAP =>
                 -- trap instructions (tw, twi, td, tdi)
                 v.vector := 16#700#;
@@ -833,19 +877,7 @@ begin
                 end if;
             when OP_ADDG6S =>
             when OP_CMPRB =>
-                newcrf := cmprb_result;
-                bf := insn_bf(e_in.insn);
-                crnum := to_integer(unsigned(bf));
-                v.e.write_cr_mask := num_to_fxm(crnum);
-                v.e.write_cr_data := newcrf & newcrf & newcrf & newcrf &
-                                     newcrf & newcrf & newcrf & newcrf;
             when OP_CMPEQB =>
-                newcrf := cmpeqb_result;
-                bf := insn_bf(e_in.insn);
-                crnum := to_integer(unsigned(bf));
-                v.e.write_cr_mask := num_to_fxm(crnum);
-                v.e.write_cr_data := newcrf & newcrf & newcrf & newcrf &
-                                     newcrf & newcrf & newcrf & newcrf;
             when OP_AND | OP_OR | OP_XOR | OP_POPCNT | OP_PRTY | OP_CMPB | OP_EXTS |
                     OP_BPERM | OP_BCD =>
 
@@ -911,53 +943,8 @@ begin
                 v.cntz_in_progress := '1';
                 v.busy := '1';
            when OP_ISEL =>
-           when OP_CROP =>
-               cr_op := insn_cr(e_in.insn);
-               if cr_op(0) = '0' then -- MCRF
-                   bf := insn_bf(e_in.insn);
-                   bfa := insn_bfa(e_in.insn);
-                   crnum := to_integer(unsigned(bf));
-                   scrnum := to_integer(unsigned(bfa));
-                   v.e.write_cr_mask := num_to_fxm(crnum);
-                   for i in 0 to 7 loop
-                       lo := (7-i)*4;
-                       hi := lo + 3;
-                       if i = scrnum then
-                           newcrf := cr_in(hi downto lo);
-                       end if;
-                   end loop;
-                   for i in 0 to 7 loop
-                       lo := i*4;
-                       hi := lo + 3;
-                       v.e.write_cr_data(hi downto lo) := newcrf;
-                   end loop;
-               else
-                   bt := insn_bt(e_in.insn);
-                   ba := insn_ba(e_in.insn);
-                   bb := insn_bb(e_in.insn);
-                   btnum := 31 - to_integer(unsigned(bt));
-                   banum := 31 - to_integer(unsigned(ba));
-                   bbnum := 31 - to_integer(unsigned(bb));
-                    -- Bits 5-8 of cr_op give the truth table of the requested
-                    -- logical operation
-                    cr_operands := cr_in(banum) & cr_in(bbnum);
-                    crresult := cr_op(5 + to_integer(unsigned(cr_operands)));
-                   v.e.write_cr_mask := num_to_fxm((31-btnum) / 4);
-                   for i in 0 to 31 loop
-                       if i = btnum then
-                           v.e.write_cr_data(i) := crresult;
-                       else
-                           v.e.write_cr_data(i) := cr_in(i);
-                       end if;
-                   end loop;
-               end if;
+            when OP_CROP =>
             when OP_MCRXRX =>
-                newcrf := xerc_in.ov & xerc_in.ca & xerc_in.ov32 & xerc_in.ca32;
-                bf := insn_bf(e_in.insn);
-                crnum := to_integer(unsigned(bf));
-                v.e.write_cr_mask := num_to_fxm(crnum);
-                v.e.write_cr_data := newcrf & newcrf & newcrf & newcrf &
-                                     newcrf & newcrf & newcrf & newcrf;
             when OP_DARN =>
            when OP_MFMSR =>
            when OP_MFSPR =>
@@ -1007,15 +994,6 @@ begin
 
            when OP_MFCR =>
            when OP_MTCRF =>
-               if e_in.insn(20) = '0' then
-                   -- mtcrf
-                   v.e.write_cr_mask := insn_fxm(e_in.insn);
-               else
-                   -- mtocrf: We require one hot priority encoding here
-                   crnum := fxm_to_num(insn_fxm(e_in.insn));
-                   v.e.write_cr_mask := num_to_fxm(crnum);
-               end if;
-               v.e.write_cr_data := c_in(31 downto 0);
             when OP_MTMSRD =>
                 if e_in.insn(16) = '1' then
                     -- just update EE and RI
@@ -1050,7 +1028,6 @@ begin
                        v.e.xerc.ca := c_in(63-34);
                        v.e.xerc.ov32 := c_in(63-44);
                        v.e.xerc.ca32 := c_in(63-45);
-                       v.e.write_xerc_enable := '1';
                    end if;
                else
                    -- slow spr
@@ -1170,7 +1147,6 @@ begin
                     v.mul_finish := '1';
                     v.busy := '1';
                 else
-                    v.e.write_xerc_enable := current.oe;
                     -- We must test oe because the RC update code in writeback
                     -- will use the xerc value to set CR0:SO so we must not clobber
                     -- xerc if OE wasn't set.
@@ -1190,7 +1166,6 @@ begin
            end if;
         elsif r.mul_finish = '1' then
             hold_wr_data := '1';
-            v.e.write_xerc_enable := current.oe;
             v.e.xerc.ov := multiply_to_x.overflow;
             v.e.xerc.ov32 := multiply_to_x.overflow;
             if multiply_to_x.overflow = '1' then
@@ -1268,8 +1243,11 @@ begin
         end if;
         v.e.write_reg := current.write_reg;
        v.e.write_enable := current.write_reg_enable and v.e.valid and not exception;
-        v.e.write_cr_enable := current.output_cr and v.e.valid and not exception;
         v.e.rc := current.rc and v.e.valid and not exception;
+        v.e.write_cr_data := write_cr_data;
+        v.e.write_cr_mask := write_cr_mask;
+        v.e.write_cr_enable := current.output_cr and v.e.valid and not exception;
+        v.e.write_xerc_enable := current.output_xer and v.e.valid and not exception;
 
         bypass_data.tag.valid <= current.instr_tag.valid and current.write_reg_enable and v.e.valid;
         bypass_data.tag.tag <= current.instr_tag.tag;