1 # This stage is intended to do most of the work of executing Logical
2 # instructions. This is OR, AND, XOR, POPCNT, PRTY, CMPB, BPERMD, CNTLZ
3 # however input and output stages also perform bit-negation on input(s)
4 # and output, as well as carry and overflow generation.
5 # This module however should not gate the carry or overflow, that's up
8 from nmigen
import (Module
, Signal
, Cat
, Repl
, Mux
, Const
, Array
)
9 from nmutil
.pipemodbase
import PipeModBase
10 from soc
.fu
.branch
.pipe_data
import BranchInputData
, BranchOutputData
11 from soc
.decoder
.power_enums
import InternalOp
13 from soc
.decoder
.power_fields
import DecodeFields
14 from soc
.decoder
.power_fieldsn
import SignalBitRange
17 return Cat(Const(0, 2), bd
, Repl(bd
[-1], 64-(bd
.shape().width
+ 2)))
23 0000z Decrement the CTR, then branch if decremented CTR[M:63]!=0 and CR[BI]=0
24 0001z Decrement the CTR, then branch if decremented CTR[M:63]=0 and CR[BI]=0
25 001at Branch if CR[BI]=0
26 0100z Decrement the CTR, then branch if decremented CTR[M:63]!=0 and CR[BI]=1
27 0101z Decrement the CTR, then branch if decremented CTR[M:63]=0 and CR[BI]=1
28 011at Branch if CR[BI]=1
29 1a00t Decrement the CTR, then branch if decremented CTR[M:63]!=0
30 1a01t Decrement the CTR, then branch if decremented CTR[M:63]=0
34 class BranchMainStage(PipeModBase
):
35 def __init__(self
, pspec
):
36 super().__init
__(pspec
, "main")
37 self
.fields
= DecodeFields(SignalBitRange
, [self
.i
.ctx
.op
.insn
])
38 self
.fields
.create_specs()
41 return BranchInputData(self
.pspec
)
44 return BranchOutputData(self
.pspec
) # TODO: ALUIntermediateData
46 def elaborate(self
, platform
):
50 lk
= op
.lk
# see PowerDecode2 as to why this is done
51 nia_o
, lr_o
= self
.o
.nia
, self
.o
.lr
53 # obtain relevant instruction fields
54 i_fields
= self
.fields
.FormI
55 aa
= Signal(i_fields
.AA
[0:-1].shape())
56 comb
+= aa
.eq(i_fields
.AA
[0:-1])
58 br_imm_addr
= Signal(64, reset_less
=True)
59 br_addr
= Signal(64, reset_less
=True)
60 br_taken
= Signal(reset_less
=True)
62 # Handle absolute or relative branches
64 comb
+= br_addr
.eq(br_imm_addr
)
66 comb
+= br_addr
.eq(br_imm_addr
+ self
.i
.cia
)
68 # fields for conditional branches (BO and BI are same for BC and BCREG)
69 # NOTE: here, BO and BI we would like be treated as CR regfile
70 # selectors (similar to RA, RB, RS, RT). see comment here:
71 # https://bugs.libre-soc.org/show_bug.cgi?id=313#c2
72 b_fields
= self
.fields
.FormB
73 BO
= b_fields
.BO
[0:-1]
74 BI
= b_fields
.BI
[0:-1]
76 # The bit of CR selected by BI
77 cr_bit
= Signal(reset_less
=True)
78 comb
+= cr_bit
.eq((self
.i
.cr
& (1<<(31-BI
))) != 0)
80 # Whether the conditional branch should be taken
81 bc_taken
= Signal(reset_less
=True)
83 comb
+= bc_taken
.eq((cr_bit
== BO
[3]) | BO
[4])
85 # decrement the counter and place into output
86 ctr
= Signal(64, reset_less
=True)
87 comb
+= ctr
.eq(self
.i
.ctr
- 1)
88 comb
+= self
.o
.ctr
.data
.eq(ctr
)
89 comb
+= self
.o
.ctr
.ok
.eq(1)
90 # take either all 64 bits or only 32 of post-incremented counter
91 ctr_m
= Signal(64, reset_less
=True)
92 with m
.If(op
.is_32bit
):
93 comb
+= ctr_m
.eq(ctr
[:32])
96 # check CTR zero/non-zero against BO[1]
97 ctr_zero_bo1
= Signal(reset_less
=True) # BO[1] == (ctr==0)
98 comb
+= ctr_zero_bo1
.eq(BO
[1] ^ ctr_m
.any())
99 with m
.If(BO
[3:5] == 0b00):
100 comb
+= bc_taken
.eq(ctr_zero_bo1
& ~cr_bit
)
101 with m
.Elif(BO
[3:5] == 0b01):
102 comb
+= bc_taken
.eq(ctr_zero_bo1
& cr_bit
)
103 with m
.Elif(BO
[4] == 1):
104 comb
+= bc_taken
.eq(ctr_zero_bo1
)
106 ### Main Switch Statement ###
107 with m
.Switch(op
.insn_type
):
109 with m
.Case(InternalOp
.OP_B
):
110 LI
= i_fields
.LI
[0:-1]
111 comb
+= br_imm_addr
.eq(br_ext(LI
))
112 comb
+= br_taken
.eq(1)
113 #### branch conditional ####
114 with m
.Case(InternalOp
.OP_BC
):
115 BD
= b_fields
.BD
[0:-1]
116 comb
+= br_imm_addr
.eq(br_ext(BD
))
117 comb
+= br_taken
.eq(bc_taken
)
118 #### branch conditional reg ####
119 with m
.Case(InternalOp
.OP_BCREG
):
120 comb
+= br_imm_addr
.eq(self
.i
.spr1
) # SPR1 is set by decode unit
121 comb
+= br_taken
.eq(bc_taken
)
123 ###### output next instruction address #####
125 comb
+= nia_o
.data
.eq(br_addr
)
126 comb
+= nia_o
.ok
.eq(br_taken
)
128 ###### link register - only activate on operations marked as "lk" #####
131 # ctx.op.lk is the AND of the insn LK field *and* whether the
132 # op is to "listen" to the link field
133 comb
+= lr_o
.data
.eq(self
.i
.cia
+ 4)
134 comb
+= lr_o
.ok
.eq(1)
136 ###### and context #####
137 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)