3 This stage is intended to do most of the work of executing branch
4 instructions. This is OP_B, OP_B, OP_BCREG
7 * https://bugs.libre-soc.org/show_bug.cgi?id=313
8 * https://bugs.libre-soc.org/show_bug.cgi?id=335
9 * https://libre-soc.org/openpower/isa/branch/
12 from nmigen
import (Module
, Signal
, Cat
, Mux
, Const
, Array
)
13 from nmutil
.pipemodbase
import PipeModBase
14 from nmutil
.extend
import exts
15 from soc
.fu
.branch
.pipe_data
import BranchInputData
, BranchOutputData
16 from soc
.decoder
.power_enums
import InternalOp
18 from soc
.decoder
.power_fields
import DecodeFields
19 from soc
.decoder
.power_fieldsn
import SignalBitRange
23 """computes sign-extended NIA (assumes word-alignment)
25 return Cat(Const(0, 2), exts(bd
, bd
.shape().width
, 64 - 2))
32 0000z Decrement the CTR, then branch if decremented CTR[M:63]!=0 and CR[BI]=0
33 0001z Decrement the CTR, then branch if decremented CTR[M:63]=0 and CR[BI]=0
34 001at Branch if CR[BI]=0
35 0100z Decrement the CTR, then branch if decremented CTR[M:63]!=0 and CR[BI]=1
36 0101z Decrement the CTR, then branch if decremented CTR[M:63]=0 and CR[BI]=1
37 011at Branch if CR[BI]=1
38 1a00t Decrement the CTR, then branch if decremented CTR[M:63]!=0
39 1a01t Decrement the CTR, then branch if decremented CTR[M:63]=0
43 class BranchMainStage(PipeModBase
):
44 def __init__(self
, pspec
):
45 super().__init
__(pspec
, "main")
46 self
.fields
= DecodeFields(SignalBitRange
, [self
.i
.ctx
.op
.insn
])
47 self
.fields
.create_specs()
50 return BranchInputData(self
.pspec
)
53 return BranchOutputData(self
.pspec
) # TODO: ALUIntermediateData
55 def elaborate(self
, platform
):
59 lk
= op
.lk
# see PowerDecode2 as to why this is done
60 cr
, cia
, ctr
, spr1
= self
.i
.cr
, self
.i
.cia
, self
.i
.ctr
, self
.i
.spr1
62 nia_o
, lr_o
, ctr_o
= self
.o
.nia
, self
.o
.lr
, self
.o
.ctr
64 # obtain relevant instruction field AA, "Absolute Address" mode
65 i_fields
= self
.fields
.FormI
66 AA
= i_fields
.AA
[0:-1]
68 br_imm_addr
= Signal(64, reset_less
=True)
69 br_addr
= Signal(64, reset_less
=True)
70 br_taken
= Signal(reset_less
=True)
72 # Handle absolute or relative branches
73 with m
.If(AA |
(op
.insn_type
== InternalOp
.OP_BCREG
)):
74 comb
+= br_addr
.eq(br_imm_addr
)
76 comb
+= br_addr
.eq(br_imm_addr
+ cia
)
78 # fields for conditional branches (BO and BI are same for BC and BCREG)
79 b_fields
= self
.fields
.FormB
80 BO
= b_fields
.BO
[0:-1]
81 BI
= b_fields
.BI
[0:-1][0:2] # CR0-7 selected already in PowerDecode2.
83 cr_bits
= Array([cr
[3-i
] for i
in range(4)]) # invert. Because POWER.
85 # The bit of CR selected by BI
86 bi
= Signal(2, reset_less
=True)
87 cr_bit
= Signal(reset_less
=True)
88 comb
+= bi
.eq(BI
) # reduces gate-count due to pmux
89 comb
+= cr_bit
.eq(cr_bits
[bi
])
91 # Whether ctr is written to on a conditional branch
92 ctr_write
= Signal(reset_less
=True)
93 comb
+= ctr_write
.eq(0)
95 # Whether the conditional branch should be taken
96 bc_taken
= Signal(reset_less
=True)
98 comb
+= bc_taken
.eq((cr_bit
== BO
[3]) | BO
[4])
100 # decrement the counter and place into output
101 ctr_n
= Signal(64, reset_less
=True)
102 comb
+= ctr_n
.eq(ctr
- 1)
103 comb
+= ctr_o
.data
.eq(ctr_n
)
104 comb
+= ctr_write
.eq(1)
105 # take either all 64 bits or only 32 of post-incremented counter
106 ctr_m
= Signal(64, reset_less
=True)
107 with m
.If(op
.is_32bit
):
108 comb
+= ctr_m
.eq(ctr
[:32])
110 comb
+= ctr_m
.eq(ctr
)
111 # check CTR zero/non-zero against BO[1]
112 ctr_zero_bo1
= Signal(reset_less
=True) # BO[1] == (ctr==0)
113 comb
+= ctr_zero_bo1
.eq(BO
[1] ^ ctr_m
.any())
114 with m
.If(BO
[3:5] == 0b00):
115 comb
+= bc_taken
.eq(ctr_zero_bo1
& ~cr_bit
)
116 with m
.Elif(BO
[3:5] == 0b01):
117 comb
+= bc_taken
.eq(ctr_zero_bo1
& cr_bit
)
118 with m
.Elif(BO
[4] == 1):
119 comb
+= bc_taken
.eq(ctr_zero_bo1
)
121 ### Main Switch Statement ###
122 with m
.Switch(op
.insn_type
):
124 with m
.Case(InternalOp
.OP_B
):
125 LI
= i_fields
.LI
[0:-1]
126 comb
+= br_imm_addr
.eq(br_ext(LI
))
127 comb
+= br_taken
.eq(1)
128 #### branch conditional ####
129 with m
.Case(InternalOp
.OP_BC
):
130 BD
= b_fields
.BD
[0:-1]
131 comb
+= br_imm_addr
.eq(br_ext(BD
))
132 comb
+= br_taken
.eq(bc_taken
)
133 comb
+= ctr_o
.ok
.eq(ctr_write
)
134 #### branch conditional reg ####
135 with m
.Case(InternalOp
.OP_BCREG
):
136 xo
= self
.fields
.FormXL
.XO
[0:-1]
137 with m
.If(xo
[9] & ~xo
[5]):
138 comb
+= br_imm_addr
.eq(Cat(Const(0, 2), spr1
[2:]))
140 comb
+= br_imm_addr
.eq(Cat(Const(0, 2), spr2
[2:]))
141 comb
+= br_taken
.eq(bc_taken
)
142 comb
+= ctr_o
.ok
.eq(ctr_write
)
144 # output next instruction address
145 comb
+= nia_o
.data
.eq(br_addr
)
146 comb
+= nia_o
.ok
.eq(br_taken
)
148 # link register - only activate on operations marked as "lk"
150 # ctx.op.lk is the AND of the insn LK field *and* whether the
151 # op is to "listen" to the link field
152 comb
+= lr_o
.data
.eq(cia
+ 4)
153 comb
+= lr_o
.ok
.eq(1)
156 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)