CR field on Br input data is specd as 0:3 range
[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, Mux, Const, Array)
9 from nmutil.pipemodbase import PipeModBase
10 from nmutil.extend import exts
11 from soc.fu.branch.pipe_data import BranchInputData, BranchOutputData
12 from soc.decoder.power_enums import InternalOp
13
14 from soc.decoder.power_fields import DecodeFields
15 from soc.decoder.power_fieldsn import SignalBitRange
16
17 def br_ext(bd):
18 """computes sign-extended NIA (assumes word-alignment)
19 """
20 return Cat(Const(0, 2), exts(bd, bd.shape().width, 64 - 2))
21
22
23 """
24 Notes on BO Field:
25
26 BO Description
27 0000z Decrement the CTR, then branch if decremented CTR[M:63]!=0 and CR[BI]=0
28 0001z Decrement the CTR, then branch if decremented CTR[M:63]=0 and CR[BI]=0
29 001at Branch if CR[BI]=0
30 0100z Decrement the CTR, then branch if decremented CTR[M:63]!=0 and CR[BI]=1
31 0101z Decrement the CTR, then branch if decremented CTR[M:63]=0 and CR[BI]=1
32 011at Branch if CR[BI]=1
33 1a00t Decrement the CTR, then branch if decremented CTR[M:63]!=0
34 1a01t Decrement the CTR, then branch if decremented CTR[M:63]=0
35 1z1zz Branch always
36 """
37
38 class BranchMainStage(PipeModBase):
39 def __init__(self, pspec):
40 super().__init__(pspec, "main")
41 self.fields = DecodeFields(SignalBitRange, [self.i.ctx.op.insn])
42 self.fields.create_specs()
43
44 def ispec(self):
45 return BranchInputData(self.pspec)
46
47 def ospec(self):
48 return BranchOutputData(self.pspec) # TODO: ALUIntermediateData
49
50 def elaborate(self, platform):
51 m = Module()
52 comb = m.d.comb
53 op = self.i.ctx.op
54 lk = op.lk # see PowerDecode2 as to why this is done
55 cr, cia, ctr, spr1 = self.i.cr, self.i.cia, self.i.ctr, self.i.spr1
56 nia_o, lr_o, ctr_o = self.o.nia, self.o.lr, self.o.ctr
57
58 # obtain relevant instruction field AA, "Absolute Address" mode
59 i_fields = self.fields.FormI
60 AA = i_fields.AA[0:-1]
61
62 br_imm_addr = Signal(64, reset_less=True)
63 br_addr = Signal(64, reset_less=True)
64 br_taken = Signal(reset_less=True)
65
66 # Handle absolute or relative branches
67 with m.If(AA | (op.insn_type == InternalOp.OP_BCREG)):
68 comb += br_addr.eq(br_imm_addr)
69 with m.Else():
70 comb += br_addr.eq(br_imm_addr + cia)
71
72 # fields for conditional branches (BO and BI are same for BC and BCREG)
73 # NOTE: here, BO and BI we would like be treated as CR regfile
74 # selectors (similar to RA, RB, RS, RT). see comment here:
75 # https://bugs.libre-soc.org/show_bug.cgi?id=313#c2
76 b_fields = self.fields.FormB
77 BO = b_fields.BO[0:-1]
78 BI = b_fields.BI[0:-1][0:2]
79
80 cr_bits = Array([cr[3-i] for i in range(4)])
81
82 # The bit of CR selected by BI
83 cr_bit = Signal(reset_less=True)
84 comb += cr_bit.eq(cr_bits[BI])
85
86 # Whether the conditional branch should be taken
87 bc_taken = Signal(reset_less=True)
88 with m.If(BO[2]):
89 comb += bc_taken.eq((cr_bit == BO[3]) | BO[4])
90 with m.Else():
91 # decrement the counter and place into output
92 ctr_n = Signal(64, reset_less=True)
93 comb += ctr_n.eq(ctr - 1)
94 comb += ctr_o.data.eq(ctr_n)
95 comb += ctr_o.ok.eq(1)
96 # take either all 64 bits or only 32 of post-incremented counter
97 ctr_m = Signal(64, reset_less=True)
98 with m.If(op.is_32bit):
99 comb += ctr_m.eq(ctr[:32])
100 with m.Else():
101 comb += ctr_m.eq(ctr)
102 # check CTR zero/non-zero against BO[1]
103 ctr_zero_bo1 = Signal(reset_less=True) # BO[1] == (ctr==0)
104 comb += ctr_zero_bo1.eq(BO[1] ^ ctr_m.any())
105 with m.If(BO[3:5] == 0b00):
106 comb += bc_taken.eq(ctr_zero_bo1 & ~cr_bit)
107 with m.Elif(BO[3:5] == 0b01):
108 comb += bc_taken.eq(ctr_zero_bo1 & cr_bit)
109 with m.Elif(BO[4] == 1):
110 comb += bc_taken.eq(ctr_zero_bo1)
111
112 ### Main Switch Statement ###
113 with m.Switch(op.insn_type):
114 #### branch ####
115 with m.Case(InternalOp.OP_B):
116 LI = i_fields.LI[0:-1]
117 comb += br_imm_addr.eq(br_ext(LI))
118 comb += br_taken.eq(1)
119 #### branch conditional ####
120 with m.Case(InternalOp.OP_BC):
121 BD = b_fields.BD[0:-1]
122 comb += br_imm_addr.eq(br_ext(BD))
123 comb += br_taken.eq(bc_taken)
124 #### branch conditional reg ####
125 with m.Case(InternalOp.OP_BCREG):
126 comb += br_imm_addr.eq(spr1) # SPR1 is set by decode unit
127 comb += br_taken.eq(bc_taken)
128
129 # output next instruction address
130 comb += nia_o.data.eq(br_addr)
131 comb += nia_o.ok.eq(br_taken)
132
133 # link register - only activate on operations marked as "lk"
134 with m.If(lk):
135 # ctx.op.lk is the AND of the insn LK field *and* whether the
136 # op is to "listen" to the link field
137 comb += lr_o.data.eq(cia + 4)
138 comb += lr_o.ok.eq(1)
139
140 # and context
141 comb += self.o.ctx.eq(self.i.ctx)
142
143 return m