Add comments on what CROP (crand, cror) do and how they work
[soc.git] / src / soc / cr / 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.cr.pipe_data import CRInputData, CROutputData
11 from ieee754.part.partsig import PartitionedSignal
12 from soc.decoder.power_enums import InternalOp
13 from soc.countzero.countzero import ZeroCounter
14
15 from soc.decoder.power_fields import DecodeFields
16 from soc.decoder.power_fieldsn import SignalBitRange
17
18
19 def array_of(count, bitwidth):
20 res = []
21 for i in range(count):
22 res.append(Signal(bitwidth, reset_less=True))
23 return res
24
25
26 class CRMainStage(PipeModBase):
27 def __init__(self, pspec):
28 super().__init__(pspec, "main")
29 self.fields = DecodeFields(SignalBitRange, [self.i.ctx.op.insn])
30 self.fields.create_specs()
31
32 def ispec(self):
33 return CRInputData(self.pspec)
34
35 def ospec(self):
36 return CROutputData(self.pspec)
37
38 def elaborate(self, platform):
39 m = Module()
40 comb = m.d.comb
41 op = self.i.ctx.op
42 xl_fields = self.fields.instrs['XL']
43
44 cr_output = Signal.like(self.i.cr)
45 comb += cr_output.eq(self.i.cr)
46
47 # Generate array for cr input so bits can be selected
48 cr_arr = Array([Signal(name=f"cr_arr_{i}") for i in range(32)])
49 for i in range(32):
50 comb += cr_arr[i].eq(self.i.cr[31-i])
51
52 # Generate array for cr output so the bit to write to can be
53 # selected by a signal
54 cr_out_arr = Array([Signal(name=f"cr_out_{i}") for i in range(32)])
55 for i in range(32):
56 comb += cr_output[31-i].eq(cr_out_arr[i])
57 comb += cr_out_arr[i].eq(cr_arr[i])
58
59
60 # crand/cror and friends get decoded to the same opcode, but
61 # one of the fields inside the instruction is a 4 bit lookup
62 # table. This lookup table gets indexed by bits a and b from
63 # the CR to determine what the resulting bit should be.
64
65 # Grab the lookup table for cr_op type instructions
66 lut = Signal(4, reset_less=True)
67 # There's no field, just have to grab it directly from the insn
68 comb += lut.eq(self.i.ctx.op.insn[6:10])
69
70
71 with m.Switch(op.insn_type):
72 with m.Case(InternalOp.OP_MCRF):
73 # MCRF copies the 4 bits of crA to crB (for instance
74 # copying cr2 to cr1)
75
76 # The destination CR
77 bf = Signal(xl_fields['BF'][0:-1].shape())
78 comb += bf.eq(xl_fields['BF'][0:-1])
79 # the source CR
80 bfa = Signal(xl_fields['BFA'][0:-1].shape())
81 comb += bfa.eq(xl_fields['BFA'][0:-1])
82
83 for i in range(4):
84 comb += cr_out_arr[bf*4 + i].eq(cr_arr[bfa*4 + i])
85 with m.Case(InternalOp.OP_CROP):
86 # Get the bit selector fields from the instruction
87 bt = Signal(xl_fields['BT'][0:-1].shape())
88 comb += bt.eq(xl_fields['BT'][0:-1])
89 ba = Signal(xl_fields['BA'][0:-1].shape())
90 comb += ba.eq(xl_fields['BA'][0:-1])
91 bb = Signal(xl_fields['BB'][0:-1].shape())
92 comb += bb.eq(xl_fields['BB'][0:-1])
93
94 # Extract the two input bits from the CR
95 bit_a = Signal(reset_less=True)
96 bit_b = Signal(reset_less=True)
97 comb += bit_a.eq(cr_arr[ba])
98 comb += bit_b.eq(cr_arr[bb])
99
100 bit_out = Signal(reset_less=True)
101
102 # Use the two input bits to look up the result in the
103 # lookup table
104 comb += bit_out.eq(Mux(bit_b,
105 Mux(bit_a, lut[3], lut[1]),
106 Mux(bit_a, lut[2], lut[0])))
107 # Set the output to the result above
108 comb += cr_out_arr[bt].eq(bit_out)
109
110
111
112 comb += self.o.cr.eq(cr_output)
113 comb += self.o.ctx.eq(self.i.ctx)
114
115 return m