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
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
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
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)
### 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)