rename pipe to fu
[soc.git] / src / soc / fu / branch / main_stage.py
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
6 # to the output stage
7
8 from nmigen import (Module, Signal, Cat, Repl, Mux, Const, Array)
9 from nmutil.pipemodbase import PipeModBase
10 from soc.branch.pipe_data import BranchInputData, BranchOutputData
11 from soc.decoder.power_enums import InternalOp
12
13 from soc.decoder.power_fields import DecodeFields
14 from soc.decoder.power_fieldsn import SignalBitRange
15
16 def br_ext(bd):
17 return Cat(Const(0, 2), bd, Repl(bd[-1], 64-(bd.shape().width + 2)))
18
19 """
20 Notes on BO Field:
21
22 BO Description
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
31 1z1zz Branch always
32 """
33
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()
39
40 def ispec(self):
41 return BranchInputData(self.pspec)
42
43 def ospec(self):
44 return BranchOutputData(self.pspec) # TODO: ALUIntermediateData
45
46 def elaborate(self, platform):
47 m = Module()
48 comb = m.d.comb
49 op = self.i.ctx.op
50 lk = op.lk # see PowerDecode2 as to why this is done
51 nia_o, lr_o = self.o.nia, self.o.lr
52
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])
57
58 br_imm_addr = Signal(64, reset_less=True)
59 br_addr = Signal(64, reset_less=True)
60 br_taken = Signal(reset_less=True)
61
62 # Handle absolute or relative branches
63 with m.If(aa):
64 comb += br_addr.eq(br_imm_addr)
65 with m.Else():
66 comb += br_addr.eq(br_imm_addr + self.i.cia)
67
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]
75
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)
79
80 # Whether the conditional branch should be taken
81 bc_taken = Signal(reset_less=True)
82 with m.If(BO[2]):
83 comb += bc_taken.eq((cr_bit == BO[3]) | BO[4])
84 with m.Else():
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])
94 with m.Else():
95 comb += ctr_m.eq(ctr)
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)
105
106 ### Main Switch Statement ###
107 with m.Switch(op.insn_type):
108 #### branch ####
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)
122
123 ###### output next instruction address #####
124
125 comb += nia_o.data.eq(br_addr)
126 comb += nia_o.ok.eq(br_taken)
127
128 ###### link register - only activate on operations marked as "lk" #####
129
130 with m.If(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)
135
136 ###### and context #####
137 comb += self.o.ctx.eq(self.i.ctx)
138
139 return m