*technically* don't use a full crossbar
[soc.git] / src / soc / fu / cr / main_stage.py
1 # This stage is intended to do Condition Register instructions
2 # and output, as well as carry and overflow generation.
3 # NOTE: with the exception of mtcrf and mfcr, we really should be doing
4 # the field decoding which
5 # selects which bits of CR are to be read / written, back in the
6 # decoder / insn-isue, have both self.i.cr and self.o.cr
7 # be broken down into 4-bit-wide "registers", with their
8 # own "Register File" (indexed by bt, ba and bb),
9 # exactly how INT regs are done (by RA, RB, RS and RT)
10 # however we are pushed for time so do it as *one* register.
11
12 from nmigen import (Module, Signal, Cat, Repl, Mux, Const, Array)
13 from nmutil.pipemodbase import PipeModBase
14 from soc.fu.cr.pipe_data import CRInputData, CROutputData
15 from soc.decoder.power_enums import InternalOp
16
17 from soc.decoder.power_fields import DecodeFields
18 from soc.decoder.power_fieldsn import SignalBitRange
19
20
21 class CRMainStage(PipeModBase):
22 def __init__(self, pspec):
23 super().__init__(pspec, "main")
24 self.fields = DecodeFields(SignalBitRange, [self.i.ctx.op.insn])
25 self.fields.create_specs()
26
27 def ispec(self):
28 return CRInputData(self.pspec)
29
30 def ospec(self):
31 return CROutputData(self.pspec)
32
33 def elaborate(self, platform):
34 m = Module()
35 comb = m.d.comb
36 op = self.i.ctx.op
37 a, cr = self.i.a, self.i.cr
38 xl_fields = self.fields.FormXL
39 xfx_fields = self.fields.FormXFX
40 # default: cr_o remains same as cr input unless modified, below
41 cr_o = Signal.like(cr)
42 comb += cr_o.eq(cr)
43
44 ##### prepare inputs / temp #####
45
46 # Generate array for cr input so bits can be selected
47 cr_arr = Array([Signal(name=f"cr_arr_{i}") for i in range(32)])
48 for i in range(32):
49 comb += cr_arr[i].eq(cr[31-i])
50
51 # Generate array for cr output so the bit to write to can be
52 # selected by a signal
53 cr_out_arr = Array([Signal(name=f"cr_out_{i}") for i in range(32)])
54 for i in range(32):
55 comb += cr_o[31-i].eq(cr_out_arr[i])
56 comb += cr_out_arr[i].eq(cr_arr[i])
57
58 # Generate the mask for mtcrf, mtocrf, and mfocrf
59 # replicate every fxm field in the insn to 4-bit, as a mask
60 FXM = xfx_fields.FXM[0:-1]
61 mask = Signal(32, reset_less=True)
62 comb += mask.eq(Cat(*[Repl(FXM[i], 4) for i in range(8)]))
63
64 #################################
65 ##### main switch statement #####
66
67 with m.Switch(op.insn_type):
68 ##### mcrf #####
69 with m.Case(InternalOp.OP_MCRF):
70 # MCRF copies the 4 bits of crA to crB (for instance
71 # copying cr2 to cr1)
72 BF = xl_fields.BF[0:-1] # destination CR
73 BFA = xl_fields.BFA[0:-1] # source CR
74 bf = Signal(BF.shape(), reset_less=True)
75 bfa = Signal(BFA.shape(), reset_less=True)
76 # use temporary signals because ilang output is insane otherwise
77 comb += bf.eq(BF)
78 comb += bfa.eq(BFA)
79
80 for i in range(4):
81 comb += cr_out_arr[bf*4 + i].eq(cr_arr[bfa*4 + i])
82
83 ##### crand, cror, crnor etc. #####
84 with m.Case(InternalOp.OP_CROP):
85 # crand/cror and friends get decoded to the same opcode, but
86 # one of the fields inside the instruction is a 4 bit lookup
87 # table. This lookup table gets indexed by bits a and b from
88 # the CR to determine what the resulting bit should be.
89
90 # Grab the lookup table for cr_op type instructions
91 lut = Signal(4, reset_less=True)
92 # There's no field, just have to grab it directly from the insn
93 comb += lut.eq(op.insn[6:10])
94
95 # Get the bit selector fields from the instruction
96 BT = xl_fields.BT[0:-1]
97 BA = xl_fields.BA[0:-1]
98 BB = xl_fields.BB[0:-1]
99 bt = Signal(BT.shape(), reset_less=True)
100 ba = Signal(BA.shape(), reset_less=True)
101 bb = Signal(BB.shape(), reset_less=True)
102 # use temporary signals because ilang output is insane otherwise
103 # also when accessing LUT
104 comb += bt.eq(BT)
105 comb += ba.eq(BA)
106 comb += bb.eq(BB)
107
108 # Extract the two input bits from the CR
109 bit_a = Signal(reset_less=True)
110 bit_b = Signal(reset_less=True)
111 comb += bit_a.eq((1<<(31-ba) & cr) != 0)
112 comb += bit_b.eq((1<<(31-bb) & cr) != 0)
113
114 # Use the two input bits to look up the result in the LUT
115 bit_out = Signal(reset_less=True)
116 comb += bit_out.eq(Mux(bit_b,
117 Mux(bit_a, lut[3], lut[1]),
118 Mux(bit_a, lut[2], lut[0])))
119 # Set the output to the result above
120 mask_ = Signal(32, reset_less=True)
121 comb += mask_.eq(1<<(31-bt))
122 comb += cr_o.eq(Mux(bit_out, mask_, 0) | (~mask_ & cr))
123
124 ##### mtcrf #####
125 with m.Case(InternalOp.OP_MTCRF):
126 # mtocrf and mtcrf are essentially identical
127 # put input (RA) - mask-selected - into output CR, leave
128 # rest of CR alone.
129 comb += cr_o.eq((a[0:32] & mask) | (cr & ~mask))
130
131 ##### mfcr #####
132 with m.Case(InternalOp.OP_MFCR):
133 # Ugh. mtocrf and mtcrf have one random bit differentiating
134 # them. This bit is not in any particular field, so this
135 # extracts that bit from the instruction
136 move_one = Signal(reset_less=True)
137 comb += move_one.eq(op.insn[20])
138
139 # mfocrf
140 with m.If(move_one):
141 comb += self.o.o.eq(cr & mask) # output register RT
142 # mfcrf
143 with m.Else():
144 comb += self.o.o.eq(cr) # output register RT
145
146 # output and context
147 comb += self.o.cr.eq(cr_o)
148 comb += self.o.ctx.eq(self.i.ctx)
149
150 return m