document branch pipeline relationship with PowerDecode2
[soc.git] / src / soc / fu / branch / main_stage.py
1 """Branch Pipeline
2
3 This stage is intended to do most of the work of executing branch
4 instructions. This is OP_B, OP_B, OP_BCREG
5
6 Note: it is PARTICULARLY important to pay attention to PowerDecode2
7 more specifically DecodeRA etc. as these work closely in conjunction
8 with the Branch pipeline, here.
9
10 The Branch pipeline itself does not and cannot read registers: it can
11 only process data and produce results. Therefore, something else needs
12 to know that BC needs CTR, and that one of the outputs from here is to
13 go into LR, and so on. Encoding of which registers are read and written
14 is the responsibility of PowerDecode2 and because some of those decisions
15 are conditional (based on BO2 for example) PowerDecode2 has to duplicate
16 some of that bitlevel operand field decoding.
17
18 It us therefore quite critical to read this code in conjunction side by
19 side with power_decode2.py
20
21 Links:
22 * https://bugs.libre-soc.org/show_bug.cgi?id=313
23 * https://bugs.libre-soc.org/show_bug.cgi?id=335
24 * https://libre-soc.org/openpower/isa/branch/
25 """
26
27 from nmigen import (Module, Signal, Cat, Mux, Const, Array)
28 from nmutil.pipemodbase import PipeModBase
29 from nmutil.extend import exts
30 from soc.fu.branch.pipe_data import BranchInputData, BranchOutputData
31 from soc.decoder.power_enums import MicrOp
32
33 from soc.decoder.power_fields import DecodeFields
34 from soc.decoder.power_fieldsn import SignalBitRange
35
36
37 def br_ext(bd):
38 """computes sign-extended NIA (assumes word-alignment)
39 """
40 return Cat(Const(0, 2), exts(bd, bd.shape().width, 64 - 2))
41
42
43 """
44 Notes on BO Field:
45
46 BO Description
47 0000z Decrement the CTR, then branch if decremented CTR[M:63]!=0 and CR[BI]=0
48 0001z Decrement the CTR, then branch if decremented CTR[M:63]=0 and CR[BI]=0
49 001at Branch if CR[BI]=0
50 0100z Decrement the CTR, then branch if decremented CTR[M:63]!=0 and CR[BI]=1
51 0101z Decrement the CTR, then branch if decremented CTR[M:63]=0 and CR[BI]=1
52 011at Branch if CR[BI]=1
53 1a00t Decrement the CTR, then branch if decremented CTR[M:63]!=0
54 1a01t Decrement the CTR, then branch if decremented CTR[M:63]=0
55 1z1zz Branch always
56 """
57
58 class BranchMainStage(PipeModBase):
59 def __init__(self, pspec):
60 super().__init__(pspec, "main")
61 self.fields = DecodeFields(SignalBitRange, [self.i.ctx.op.insn])
62 self.fields.create_specs()
63
64 def ispec(self):
65 return BranchInputData(self.pspec)
66
67 def ospec(self):
68 return BranchOutputData(self.pspec) # TODO: ALUIntermediateData
69
70 def elaborate(self, platform):
71 m = Module()
72 comb = m.d.comb
73 op = self.i.ctx.op
74 lk = op.lk # see PowerDecode2 as to why this is done
75 cr, cia, ctr, fast1 = self.i.cr, self.i.cia, self.i.ctr, self.i.fast1
76 fast2 = self.i.fast2
77 nia_o, lr_o, ctr_o = self.o.nia, self.o.lr, self.o.ctr
78
79 # obtain relevant instruction field AA, "Absolute Address" mode
80 i_fields = self.fields.FormI
81 AA = i_fields.AA[0:-1]
82
83 br_imm_addr = Signal(64, reset_less=True)
84 br_addr = Signal(64, reset_less=True)
85 br_taken = Signal(reset_less=True)
86
87 # Handle absolute or relative branches
88 with m.If(AA | (op.insn_type == MicrOp.OP_BCREG)):
89 comb += br_addr.eq(br_imm_addr)
90 with m.Else():
91 comb += br_addr.eq(br_imm_addr + cia)
92
93 # fields for conditional branches (BO and BI are same for BC and BCREG)
94 b_fields = self.fields.FormB
95 BO = b_fields.BO[0:-1]
96 BI = b_fields.BI[0:-1][0:2] # CR0-7 selected already in PowerDecode2.
97
98 cr_bits = Array([cr[3-i] for i in range(4)]) # invert. Because POWER.
99
100 # The bit of CR selected by BI
101 bi = Signal(2, reset_less=True)
102 cr_bit = Signal(reset_less=True)
103 comb += bi.eq(BI) # reduces gate-count due to pmux
104 comb += cr_bit.eq(cr_bits[bi])
105
106 # Whether ctr is written to on a conditional branch
107 ctr_write = Signal(reset_less=True)
108 comb += ctr_write.eq(0)
109
110 # Whether the conditional branch should be taken
111 bc_taken = Signal(reset_less=True)
112 with m.If(BO[2]):
113 comb += bc_taken.eq((cr_bit == BO[3]) | BO[4])
114 with m.Else():
115 # decrement the counter and place into output
116 ctr_n = Signal(64, reset_less=True)
117 comb += ctr_n.eq(ctr - 1)
118 comb += ctr_o.data.eq(ctr_n)
119 comb += ctr_write.eq(1)
120 # take either all 64 bits or only 32 of post-incremented counter
121 ctr_m = Signal(64, reset_less=True)
122 with m.If(op.is_32bit):
123 comb += ctr_m.eq(ctr[:32])
124 with m.Else():
125 comb += ctr_m.eq(ctr)
126 # check CTR zero/non-zero against BO[1]
127 ctr_zero_bo1 = Signal(reset_less=True) # BO[1] == (ctr==0)
128 comb += ctr_zero_bo1.eq(BO[1] ^ ctr_m.any())
129 with m.If(BO[3:5] == 0b00):
130 comb += bc_taken.eq(ctr_zero_bo1 & ~cr_bit)
131 with m.Elif(BO[3:5] == 0b01):
132 comb += bc_taken.eq(ctr_zero_bo1 & cr_bit)
133 with m.Elif(BO[4] == 1):
134 comb += bc_taken.eq(ctr_zero_bo1)
135
136 ### Main Switch Statement ###
137 with m.Switch(op.insn_type):
138 #### branch ####
139 with m.Case(MicrOp.OP_B):
140 LI = i_fields.LI[0:-1]
141 comb += br_imm_addr.eq(br_ext(LI))
142 comb += br_taken.eq(1)
143 #### branch conditional ####
144 with m.Case(MicrOp.OP_BC):
145 BD = b_fields.BD[0:-1]
146 comb += br_imm_addr.eq(br_ext(BD))
147 comb += br_taken.eq(bc_taken)
148 comb += ctr_o.ok.eq(ctr_write)
149 #### branch conditional reg ####
150 with m.Case(MicrOp.OP_BCREG):
151 xo = self.fields.FormXL.XO[0:-1]
152 with m.If(xo[9] & ~xo[5]):
153 comb += br_imm_addr.eq(Cat(Const(0, 2), fast1[2:]))
154 with m.Else():
155 comb += br_imm_addr.eq(Cat(Const(0, 2), fast2[2:]))
156 comb += br_taken.eq(bc_taken)
157 comb += ctr_o.ok.eq(ctr_write)
158
159 # output next instruction address
160 comb += nia_o.data.eq(br_addr)
161 comb += nia_o.ok.eq(br_taken)
162
163 # link register - only activate on operations marked as "lk"
164 with m.If(lk):
165 # ctx.op.lk is the AND of the insn LK field *and* whether the
166 # op is to "listen" to the link field
167 comb += lr_o.data.eq(cia + 4)
168 comb += lr_o.ok.eq(1)
169
170 # and context
171 comb += self.o.ctx.eq(self.i.ctx)
172
173 return m