convert branch pipeline to use msr/cia as immediates
[soc.git] / src / soc / fu / branch / main_stage.py
index f145a63254cf9918a94955d812b6b5337a2e57fe..39631afdca281c1b280765281cbae5cb000b35b3 100644 (file)
@@ -3,6 +3,21 @@
 This stage is intended to do most of the work of executing branch
 instructions. This is OP_B, OP_B, OP_BCREG
 
+Note: it is PARTICULARLY important to pay attention to PowerDecode2
+more specifically DecodeRA etc. as these work closely in conjunction
+with the Branch pipeline, here.
+
+The Branch pipeline itself does not and cannot read registers: it can
+only process data and produce results.  Therefore, something else needs
+to know that BC needs CTR, and that one of the outputs from here is to
+go into LR, and so on.  Encoding of which registers are read and written
+is the responsibility of PowerDecode2 and because some of those decisions
+are conditional (based on BO2 for example) PowerDecode2 has to duplicate
+some of that bitlevel operand field decoding.
+
+It us therefore quite critical to read this code in conjunction side by
+side with power_decode2.py
+
 Links:
 * https://bugs.libre-soc.org/show_bug.cgi?id=313
 * https://bugs.libre-soc.org/show_bug.cgi?id=335
@@ -13,7 +28,7 @@ from nmigen import (Module, Signal, Cat, Mux, Const, Array)
 from nmutil.pipemodbase import PipeModBase
 from nmutil.extend import exts
 from soc.fu.branch.pipe_data import BranchInputData, BranchOutputData
-from soc.decoder.power_enums import InternalOp
+from soc.decoder.power_enums import MicrOp
 
 from soc.decoder.power_fields import DecodeFields
 from soc.decoder.power_fieldsn import SignalBitRange
@@ -57,8 +72,8 @@ class BranchMainStage(PipeModBase):
         comb = m.d.comb
         op = self.i.ctx.op
         lk = op.lk # see PowerDecode2 as to why this is done
-        cr, cia, ctr, spr1 = self.i.cr, self.i.cia, self.i.ctr, self.i.spr1
-        spr2 = self.i.spr2
+        cr, cia, ctr, fast1 = self.i.cr, op.cia, self.i.ctr, self.i.fast1
+        fast2 = self.i.fast2
         nia_o, lr_o, ctr_o = self.o.nia, self.o.lr, self.o.ctr
 
         # obtain relevant instruction field AA, "Absolute Address" mode
@@ -70,24 +85,23 @@ class BranchMainStage(PipeModBase):
         br_taken = Signal(reset_less=True)
 
         # Handle absolute or relative branches
-        with m.If(AA | (op.insn_type == InternalOp.OP_BCREG)):
+        with m.If(AA | (op.insn_type == MicrOp.OP_BCREG)):
             comb += br_addr.eq(br_imm_addr)
         with m.Else():
             comb += br_addr.eq(br_imm_addr + cia)
 
         # fields for conditional branches (BO and BI are same for BC and BCREG)
-        # NOTE: here, BO and BI we would like be treated as CR regfile
-        # selectors (similar to RA, RB, RS, RT).  see comment here:
-        # https://bugs.libre-soc.org/show_bug.cgi?id=313#c2
         b_fields = self.fields.FormB
         BO = b_fields.BO[0:-1]
-        BI = b_fields.BI[0:-1][0:2]
+        BI = b_fields.BI[0:-1][0:2] # CR0-7 selected already in PowerDecode2.
 
-        cr_bits = Array([cr[3-i] for i in range(4)])
+        cr_bits = Array([cr[3-i] for i in range(4)]) # invert. Because POWER.
 
         # The bit of CR selected by BI
+        bi = Signal(2, reset_less=True)
         cr_bit = Signal(reset_less=True)
-        comb += cr_bit.eq(cr_bits[BI])
+        comb += bi.eq(BI)                 # reduces gate-count due to pmux
+        comb += cr_bit.eq(cr_bits[bi])
 
         # Whether ctr is written to on a conditional branch
         ctr_write = Signal(reset_less=True)
@@ -122,19 +136,23 @@ class BranchMainStage(PipeModBase):
         ### Main Switch Statement ###
         with m.Switch(op.insn_type):
             #### branch ####
-            with m.Case(InternalOp.OP_B):
+            with m.Case(MicrOp.OP_B):
                 LI = i_fields.LI[0:-1]
                 comb += br_imm_addr.eq(br_ext(LI))
                 comb += br_taken.eq(1)
             #### branch conditional ####
-            with m.Case(InternalOp.OP_BC):
+            with m.Case(MicrOp.OP_BC):
                 BD = b_fields.BD[0:-1]
                 comb += br_imm_addr.eq(br_ext(BD))
                 comb += br_taken.eq(bc_taken)
                 comb += ctr_o.ok.eq(ctr_write)
             #### branch conditional reg ####
-            with m.Case(InternalOp.OP_BCREG):
-                comb += br_imm_addr.eq(Cat(Const(0, 2), spr2[2:]))
+            with m.Case(MicrOp.OP_BCREG):
+                xo = self.fields.FormXL.XO[0:-1]
+                with m.If(xo[9] & ~xo[5]):
+                    comb += br_imm_addr.eq(Cat(Const(0, 2), fast1[2:]))
+                with m.Else():
+                    comb += br_imm_addr.eq(Cat(Const(0, 2), fast2[2:]))
                 comb += br_taken.eq(bc_taken)
                 comb += ctr_o.ok.eq(ctr_write)