execute1: Move EXTS* instruction back into execute1
authorPaul Mackerras <paulus@ozlabs.org>
Thu, 12 Dec 2019 04:25:45 +0000 (15:25 +1100)
committerPaul Mackerras <paulus@ozlabs.org>
Tue, 14 Jan 2020 06:20:52 +0000 (17:20 +1100)
This moves the sign extension done by the extsb, extsh and extsw
instructions back into execute1.  This means that we no longer need
any data formatting in writeback for results coming from execute1,
so this modifies writeback so the data formatter inputs come
directly from the loadstore unit output.  The condition code
updates for RC=1 form instructions are now done on the value from
execute1 rather than the output of the data formatter, which should
help timing.

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

index 639f0f70237f992bc2b2409fed13d12a4ba5753a..86123896e473b7b919403508cc6f64e47ca3571c 100644 (file)
@@ -240,16 +240,14 @@ package common is
        write_enable : std_ulogic;
        write_reg: gspr_index_t;
        write_data: std_ulogic_vector(63 downto 0);
-       write_len : std_ulogic_vector(3 downto 0);
        write_cr_enable : std_ulogic;
        write_cr_mask : std_ulogic_vector(7 downto 0);
        write_cr_data : std_ulogic_vector(31 downto 0);
        write_xerc_enable : std_ulogic;
        xerc : xer_common_t;
-       sign_extend: std_ulogic;
     end record;
     constant Execute1ToWritebackInit : Execute1ToWritebackType := (valid => '0', rc => '0', write_enable => '0',
-                                                                  write_cr_enable => '0', sign_extend => '0',
+                                                                  write_cr_enable => '0',
                                                                   write_xerc_enable => '0', xerc => xerc_init,
                                                                   others => (others => '0'));
 
index 94845d869f1fa6efcadff9792287613edd5452c6..19910091684f7ee43ee52e93f6910cad45c70be3 100644 (file)
@@ -192,6 +192,7 @@ begin
         variable sign1, sign2 : std_ulogic;
         variable abs1, abs2 : signed(63 downto 0);
        variable overflow : std_ulogic;
+       variable negative : std_ulogic;
     begin
        result := (others => '0');
        result_with_carry := (others => '0');
@@ -335,8 +336,6 @@ begin
 
            v.e.valid := '1';
            v.e.write_reg := e_in.write_reg;
-           v.e.write_len := x"8";
-           v.e.sign_extend := '0';
            v.slow_op_dest := gspr_to_gpr(e_in.write_reg);
            v.slow_op_rc := e_in.rc;
            v.slow_op_oe := e_in.oe;
@@ -438,10 +437,19 @@ begin
            when OP_CNTZ =>
                result := countzero_result;
                result_en := '1';
-           when OP_EXTS =>
-               v.e.write_len := e_in.data_len;
-               v.e.sign_extend := '1';
-               result := e_in.read_data3;
+            when OP_EXTS =>
+                -- note data_len is a 1-hot encoding
+               negative := (e_in.data_len(0) and e_in.read_data3(7)) or
+                           (e_in.data_len(1) and e_in.read_data3(15)) or
+                           (e_in.data_len(2) and e_in.read_data3(31));
+               result := (others => negative);
+               if e_in.data_len(2) = '1' then
+                   result(31 downto 16) := e_in.read_data3(31 downto 16);
+               end if;
+               if e_in.data_len(2) = '1' or e_in.data_len(1) = '1' then
+                   result(15 downto 8) := e_in.read_data3(15 downto 8);
+               end if;
+               result(7 downto 0) := e_in.read_data3(7 downto 0);
                result_en := '1';
            when OP_ISEL =>
                crbit := to_integer(unsigned(insn_bc(e_in.insn)));
@@ -660,8 +668,6 @@ begin
            result_en := '1';
            result := r.next_lr;
            v.e.write_reg := fast_spr_num(SPR_LR);
-           v.e.write_len := x"8";
-           v.e.sign_extend := '0';
            v.e.valid := '1';
        elsif r.mul_in_progress = '1' or r.div_in_progress = '1' then
            if (r.mul_in_progress = '1' and multiply_to_x.valid = '1') or
@@ -687,8 +693,6 @@ begin
                    v.e.xerc.so := v.slow_op_xerc.so or overflow;
                end if;
                v.e.valid := '1';
-               v.e.write_len := x"8";
-               v.e.sign_extend := '0';
            else
                stall_out <= '1';
                v.mul_in_progress := r.mul_in_progress;
index 08efe912a6425e4e093004e6f3bfee0c84c70cb9..e53f46bca6f061d1da9415a4ae6e955b8b5f9293 100644 (file)
@@ -42,7 +42,6 @@ architecture behaviour of writeback is
     signal sign_extend : std_ulogic;
     signal negative : std_ulogic;
     signal second_word : std_ulogic;
-    signal zero : std_ulogic;
 begin
     writeback_0: process(clk)
     begin
@@ -62,6 +61,8 @@ begin
         variable k : unsigned(3 downto 0);
        variable cf: std_ulogic_vector(3 downto 0);
        variable xe: xer_common_t;
+        variable zero : std_ulogic;
+        variable sign : std_ulogic;
     begin
         x := "" & e_in.valid;
         y := "" & l_in.valid;
@@ -85,10 +86,7 @@ begin
 
         rc <= '0';
         brev_lenm1 <= "000";
-        byte_offset <= "000";
-        data_len <= x"8";
         partial_write <= '0';
-        sign_extend <= '0';
         second_word <= '0';
        xe := e_in.xerc;
        data_in <= (others => '0');
@@ -96,9 +94,6 @@ begin
         if e_in.write_enable = '1' then
             w_out.write_reg <= e_in.write_reg;
             w_out.write_enable <= '1';
-           data_in <= e_in.write_data;
-            data_len <= unsigned(e_in.write_len);
-            sign_extend <= e_in.sign_extend;
             rc <= e_in.rc;
         end if;
 
@@ -113,12 +108,11 @@ begin
             c_out.write_xerc_data <= e_in.xerc;
        end if;
 
+        sign_extend <= l_in.sign_extend;
+        data_len <= unsigned(l_in.write_len);
+        byte_offset <= unsigned(l_in.write_shift);
        if l_in.write_enable = '1' then
             w_out.write_reg <= gpr_to_gspr(l_in.write_reg);
-            data_in <= l_in.write_data;
-            data_len <= unsigned(l_in.write_len);
-            byte_offset <= unsigned(l_in.write_shift);
-            sign_extend <= l_in.sign_extend;
             if l_in.byte_reverse = '1' then
                 brev_lenm1 <= unsigned(l_in.write_len(2 downto 0)) - 1;
             end if;
@@ -138,7 +132,7 @@ begin
         end loop;
         for i in 0 to 7 loop
             j := to_integer(perm(i)) * 8;
-            data_permuted(i * 8 + 7 downto i * 8) <= data_in(j + 7 downto j);
+            data_permuted(i * 8 + 7 downto i * 8) <= l_in.write_data(j + 7 downto j);
         end loop;
 
         -- If the data can arrive split over two cycles, this will be correct
@@ -160,16 +154,12 @@ begin
                 trim_ctl(i) <= '0' & (negative and sign_extend);
             end if;
         end loop;
-       zero <= not negative;
         for i in 0 to 7 loop
             case trim_ctl(i) is
                 when "11" =>
                     data_trimmed(i * 8 + 7 downto i * 8) <= data_latched(i * 8 + 7 downto i * 8);
                 when "10" =>
                     data_trimmed(i * 8 + 7 downto i * 8) <= data_permuted(i * 8 + 7 downto i * 8);
-                   if or data_permuted(i * 8 + 7 downto i * 8) /= '0' then
-                       zero <= '0';
-                   end if;
                 when "01" =>
                     data_trimmed(i * 8 + 7 downto i * 8) <= x"FF";
                 when others =>
@@ -178,14 +168,21 @@ begin
         end loop;
 
         -- deliver to regfile
-        w_out.write_data <= data_trimmed;
+        if l_in.write_enable = '1' then
+            w_out.write_data <= data_trimmed;
+        else
+            w_out.write_data <= e_in.write_data;
+        end if;
 
         -- Perform CR0 update for RC forms
+        -- Note that loads never have a form with an RC bit, therefore this can test e_in.write_data
         if rc = '1' then
+            sign := e_in.write_data(63);
+            zero := not (or e_in.write_data);
             c_out.write_cr_enable <= '1';
             c_out.write_cr_mask <= num_to_fxm(0);
-           cf(3) := negative;
-           cf(2) := not negative and not zero;
+           cf(3) := sign;
+           cf(2) := not sign and not zero;
            cf(1) := zero;
            cf(0) := xe.so;
            c_out.write_cr_data(31 downto 28) <= cf;