core: Crack branches that update both CTR and LR
[microwatt.git] / decode2.vhdl
index 03360575324de4a77e21e22021e243e0c1d5e411..274a24181b2a9e7ce8da08400e151652c343a565 100644 (file)
@@ -249,6 +249,9 @@ architecture behaviour of decode2 is
         OP_MOD      => "011",
         OP_CNTZ     => "100",           -- countzero_result
         OP_MFSPR    => "101",           -- spr_result
+        OP_B        => "110",           -- next_nia
+        OP_BC       => "110",
+        OP_BCREG    => "110",
         OP_ADDG6S   => "111",           -- misc_result
         OP_ISEL     => "111",
         OP_DARN     => "111",
@@ -284,9 +287,6 @@ architecture behaviour of decode2 is
     signal gpr_write : gspr_index_t;
     signal gpr_bypassable  : std_ulogic;
 
-    signal update_gpr_write_valid : std_ulogic;
-    signal update_gpr_write_reg : gspr_index_t;
-
     signal gpr_a_read_valid : std_ulogic;
     signal gpr_a_read :gspr_index_t;
     signal gpr_a_bypass : std_ulogic;
@@ -325,8 +325,8 @@ begin
             gpr_write_in       => gpr_write,
             gpr_bypassable     => gpr_bypassable,
 
-            update_gpr_write_valid => update_gpr_write_valid,
-            update_gpr_write_reg => update_gpr_write_reg,
+            update_gpr_write_valid => '0',
+            update_gpr_write_reg => 7x"00",
 
             gpr_a_read_valid_in  => gpr_a_read_valid,
             gpr_a_read_in        => gpr_a_read,
@@ -376,6 +376,7 @@ begin
         variable decoded_reg_c : decode_input_reg_t;
         variable decoded_reg_o : decode_output_reg_t;
         variable length : std_ulogic_vector(3 downto 0);
+        variable op : insn_type_t;
     begin
         v := r;
 
@@ -391,7 +392,14 @@ begin
                                              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);
         decoded_reg_c := decode_input_reg_c (d_in.decode.input_reg_c, d_in.insn, r_in.read3_data);
-        decoded_reg_o := decode_output_reg (d_in.decode.output_reg_a, d_in.insn, d_in.ispr1);
+        decoded_reg_o := decode_output_reg (d_in.decode.output_reg_a, d_in.insn, d_in.ispro);
+
+        if d_in.decode.lr = '1' then
+            v.e.lr := insn_lk(d_in.insn);
+            -- b and bc have even major opcodes; bcreg is considered absolute
+            v.e.br_abs := insn_aa(d_in.insn) or d_in.insn(26);
+        end if;
+        op := d_in.decode.insn_type;
 
         if d_in.decode.repeat /= NONE then
             v.e.repeat := '1';
@@ -414,6 +422,12 @@ begin
                     end if;
                 when others =>
             end case;
+        elsif v.e.lr = '1' and decoded_reg_a.reg_valid = '1' then
+            -- bcl/bclrl/bctarl that needs to write both CTR and LR has to be doubled
+            v.e.repeat := '1';
+            v.e.second := r.repeat;
+            -- first one does CTR, second does LR
+            decoded_reg_o.reg(0) := not r.repeat;
         end if;
 
         r_out.read1_enable <= decoded_reg_a.reg_valid and d_in.valid;
@@ -440,7 +454,6 @@ begin
         v.e.nia := d_in.nia;
         v.e.unit := d_in.decode.unit;
         v.e.fac := d_in.decode.facility;
-        v.e.insn_type := d_in.decode.insn_type;
         v.e.read_reg1 := decoded_reg_a.reg;
         v.e.read_data1 := decoded_reg_a.data;
         v.e.bypass_data1 := gpr_a_bypass;
@@ -460,23 +473,12 @@ begin
         v.e.xerc := c_in.read_xerc_data;
         v.e.invert_a := d_in.decode.invert_a;
         v.e.addm1 := '0';
-        if d_in.decode.insn_type = OP_BC or d_in.decode.insn_type = OP_BCREG then
-            -- add -1 to CTR
-            v.e.addm1 := '1';
-            if d_in.insn(23) = '1' or
-                (d_in.decode.insn_type = OP_BCREG and d_in.insn(10) = '0') then
-                -- don't write decremented CTR if BO(2) = 1 or bcctr
-                v.e.write_reg_enable := '0';
-            end if;
-        end if;
+        v.e.insn_type := op;
         v.e.invert_out := d_in.decode.invert_out;
         v.e.input_carry := d_in.decode.input_carry;
         v.e.output_carry := d_in.decode.output_carry;
         v.e.is_32bit := d_in.decode.is_32bit;
         v.e.is_signed := d_in.decode.is_signed;
-        if d_in.decode.lr = '1' then
-            v.e.lr := insn_lk(d_in.insn);
-        end if;
         v.e.insn := d_in.insn;
         v.e.data_len := length;
         v.e.byte_reverse := d_in.decode.byte_reverse;
@@ -484,8 +486,16 @@ begin
         v.e.update := d_in.decode.update;
         v.e.reserve := d_in.decode.reserve;
         v.e.br_pred := d_in.br_pred;
-        v.e.result_sel := result_select(d_in.decode.insn_type);
-        v.e.sub_select := subresult_select(d_in.decode.insn_type);
+        v.e.result_sel := result_select(op);
+        v.e.sub_select := subresult_select(op);
+        if op = OP_BC or op = OP_BCREG then
+            if d_in.insn(23) = '0' and r.repeat = '0' and
+                not (d_in.decode.insn_type = OP_BCREG and d_in.insn(10) = '0') then
+                -- decrement CTR if BO(2) = 0 and not bcctr
+                v.e.addm1 := '1';
+                v.e.result_sel := "000";        -- select adder output
+            end if;
+        end if;
 
         -- issue control
         control_valid_in <= d_in.valid;
@@ -498,9 +508,6 @@ begin
             gpr_bypassable <= '1';
         end if;
 
-        update_gpr_write_valid <= v.e.lr;
-        update_gpr_write_reg <= fast_spr_num(SPR_LR);
-
         gpr_a_read_valid <= decoded_reg_a.reg_valid;
         gpr_a_read <= decoded_reg_a.reg;