Add copyright to files in fu/ that I was the primary author on
[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 # Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
27
28 from nmigen import (Module, Signal, Cat, Mux, Const, Array)
29 from nmutil.pipemodbase import PipeModBase
30 from nmutil.extend import exts
31 from soc.fu.branch.pipe_data import BranchInputData, BranchOutputData
32 from soc.decoder.power_enums import MicrOp
33
34 from soc.decoder.power_fields import DecodeFields
35 from soc.decoder.power_fieldsn import SignalBitRange
36
37
38 def br_ext(bd):
39 """computes sign-extended NIA (assumes word-alignment)
40 """
41 return Cat(Const(0, 2), exts(bd, bd.shape().width, 64 - 2))
42
43
44 """
45 Notes on BO Field:
46
47 BO Description
48 0000z Decrement the CTR, then branch if decremented CTR[M:63]!=0 and CR[BI]=0
49 0001z Decrement the CTR, then branch if decremented CTR[M:63]=0 and CR[BI]=0
50 001at Branch if CR[BI]=0
51 0100z Decrement the CTR, then branch if decremented CTR[M:63]!=0 and CR[BI]=1
52 0101z Decrement the CTR, then branch if decremented CTR[M:63]=0 and CR[BI]=1
53 011at Branch if CR[BI]=1
54 1a00t Decrement the CTR, then branch if decremented CTR[M:63]!=0
55 1a01t Decrement the CTR, then branch if decremented CTR[M:63]=0
56 1z1zz Branch always
57 """
58
59 class BranchMainStage(PipeModBase):
60 def __init__(self, pspec):
61 super().__init__(pspec, "main")
62 self.fields = DecodeFields(SignalBitRange, [self.i.ctx.op.insn])
63 self.fields.create_specs()
64
65 def ispec(self):
66 return BranchInputData(self.pspec)
67
68 def ospec(self):
69 return BranchOutputData(self.pspec) # TODO: ALUIntermediateData
70
71 def elaborate(self, platform):
72 m = Module()
73 comb = m.d.comb
74 op = self.i.ctx.op
75 lk = op.lk # see PowerDecode2 as to why this is done
76 cr, cia, ctr, fast1 = self.i.cr, op.cia, self.i.ctr, self.i.fast1
77 fast2 = self.i.fast2
78 nia_o, lr_o, ctr_o = self.o.nia, self.o.lr, self.o.ctr
79
80 # obtain relevant instruction field AA, "Absolute Address" mode
81 i_fields = self.fields.FormI
82 AA = i_fields.AA[0:-1]
83
84 br_imm_addr = Signal(64, reset_less=True)
85 br_addr = Signal(64, reset_less=True)
86 br_taken = Signal(reset_less=True)
87
88 # Handle absolute or relative branches
89 with m.If(AA | (op.insn_type == MicrOp.OP_BCREG)):
90 comb += br_addr.eq(br_imm_addr)
91 with m.Else():
92 comb += br_addr.eq(br_imm_addr + cia)
93
94 # fields for conditional branches (BO and BI are same for BC and BCREG)
95 b_fields = self.fields.FormB
96 BO = b_fields.BO[0:-1]
97 BI = b_fields.BI[0:-1][0:2] # CR0-7 selected already in PowerDecode2.
98
99 cr_bits = Array([cr[3-i] for i in range(4)]) # invert. Because POWER.
100
101 # The bit of CR selected by BI
102 bi = Signal(2, reset_less=True)
103 cr_bit = Signal(reset_less=True)
104 comb += bi.eq(BI) # reduces gate-count due to pmux
105 comb += cr_bit.eq(cr_bits[bi])
106
107 # Whether ctr is written to on a conditional branch
108 ctr_write = Signal(reset_less=True)
109 comb += ctr_write.eq(0)
110
111 # Whether the conditional branch should be taken
112 bc_taken = Signal(reset_less=True)
113 with m.If(BO[2]):
114 comb += bc_taken.eq((cr_bit == BO[3]) | BO[4])
115 with m.Else():
116 # decrement the counter and place into output
117 ctr_n = Signal(64, reset_less=True)
118 comb += ctr_n.eq(ctr - 1)
119 comb += ctr_o.data.eq(ctr_n)
120 comb += ctr_write.eq(1)
121 # take either all 64 bits or only 32 of post-incremented counter
122 ctr_m = Signal(64, reset_less=True)
123 with m.If(op.is_32bit):
124 comb += ctr_m.eq(ctr[:32])
125 with m.Else():
126 comb += ctr_m.eq(ctr)
127 # check CTR zero/non-zero against BO[1]
128 ctr_zero_bo1 = Signal(reset_less=True) # BO[1] == (ctr==0)
129 comb += ctr_zero_bo1.eq(BO[1] ^ ctr_m.any())
130 with m.If(BO[3:5] == 0b00):
131 comb += bc_taken.eq(ctr_zero_bo1 & ~cr_bit)
132 with m.Elif(BO[3:5] == 0b01):
133 comb += bc_taken.eq(ctr_zero_bo1 & cr_bit)
134 with m.Elif(BO[4] == 1):
135 comb += bc_taken.eq(ctr_zero_bo1)
136
137 ### Main Switch Statement ###
138 with m.Switch(op.insn_type):
139 #### branch ####
140 with m.Case(MicrOp.OP_B):
141 LI = i_fields.LI[0:-1]
142 comb += br_imm_addr.eq(br_ext(LI))
143 comb += br_taken.eq(1)
144 #### branch conditional ####
145 with m.Case(MicrOp.OP_BC):
146 BD = b_fields.BD[0:-1]
147 comb += br_imm_addr.eq(br_ext(BD))
148 comb += br_taken.eq(bc_taken)
149 comb += ctr_o.ok.eq(ctr_write)
150 #### branch conditional reg ####
151 with m.Case(MicrOp.OP_BCREG):
152 xo = self.fields.FormXL.XO[0:-1]
153 with m.If(xo[9] & ~xo[5]):
154 comb += br_imm_addr.eq(Cat(Const(0, 2), fast1[2:]))
155 with m.Else():
156 comb += br_imm_addr.eq(Cat(Const(0, 2), fast2[2:]))
157 comb += br_taken.eq(bc_taken)
158 comb += ctr_o.ok.eq(ctr_write)
159
160 # output next instruction address
161 comb += nia_o.data.eq(br_addr)
162 comb += nia_o.ok.eq(br_taken)
163
164 # link register - only activate on operations marked as "lk"
165 with m.If(lk):
166 # ctx.op.lk is the AND of the insn LK field *and* whether the
167 # op is to "listen" to the link field
168 comb += lr_o.data.eq(cia + 4)
169 comb += lr_o.ok.eq(1)
170
171 # and context
172 comb += self.o.ctx.eq(self.i.ctx)
173
174 return m