random commenting and code-morph of Logical
[soc.git] / src / soc / logical / 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.logical.pipe_data import ALUInputData
11 from soc.alu.pipe_data import ALUOutputData
12 from ieee754.part.partsig import PartitionedSignal
13 from soc.decoder.power_enums import InternalOp
14
15 def array_of(count, bitwidth):
16 res = []
17 for i in range(count):
18 res.append(Signal(bitwidth, reset_less=True))
19 return res
20
21
22 class LogicalMainStage(PipeModBase):
23 def __init__(self, pspec):
24 super().__init__(pspec, "main")
25
26 def ispec(self):
27 return ALUInputData(self.pspec)
28
29 def ospec(self):
30 return ALUOutputData(self.pspec) # TODO: ALUIntermediateData
31
32 def elaborate(self, platform):
33 m = Module()
34 comb = m.d.comb
35 op, a, b, o = self.i.ctx.op, self.i.a, self.i.b, self.o.o
36
37 ##########################
38 # main switch for logic ops AND, OR and XOR, cmpb, parity, and popcount
39
40 with m.Switch(op.insn_type):
41
42 ###### AND, OR, XOR #######
43 with m.Case(InternalOp.OP_AND):
44 comb += o.eq(a & b)
45 with m.Case(InternalOp.OP_OR):
46 comb += o.eq(a | b)
47 with m.Case(InternalOp.OP_XOR):
48 comb += o.eq(a ^ b)
49
50 ###### cmpb #######
51 with m.Case(InternalOp.OP_CMPB):
52 for i in range(8):
53 slc = slice(i*8, (i+1)*8)
54 comb += o[slc].eq(Repl(a[slc] == b[slc], 8))
55
56 ###### popcount #######
57 with m.Case(InternalOp.OP_POPCNT):
58 # starting from a, perform successive addition-reductions
59 # creating arrays big enough to store the sum, each time
60 pc = [a]
61 # QTY32 2-bit (to take 2x 1-bit sums) etc.
62 work = [(32, 2), (16, 3), (8, 4), (4, 5), (2, 6), (1, 6)]
63 for l, b in work:
64 pc.append(array_of(l, b))
65 pc8 = pc[3] # array of 8 8-bit counts (popcntb)
66 pc32 = pc[5] # array of 2 32-bit counts (popcntw)
67 popcnt = pc[-1] # array of 1 64-bit count (popcntd)
68 # cascade-tree of adds
69 for idx, (l, b) in enumerate(work):
70 for i in range(l):
71 stt, end = i*2, i*2+1
72 src, dst = pc[idx], pc[idx+1]
73 comb += dst[i].eq(Cat(src[stt], Const(0, 1)) +
74 Cat(src[end], Const(0, 1)))
75 # decode operation length
76 with m.If(op.data_len[2:4] == 0b00):
77 # popcntb - pack 8x 4-bit answers into output
78 for i in range(8):
79 comb += o[i*8:i*8+4].eq(pc8[i])
80 with m.Elif(op.data_len[3] == 0):
81 # popcntw - pack 2x 5-bit answers into output
82 for i in range(2):
83 comb += o[i*32:i*32+5].eq(pc32[i])
84 with m.Else():
85 # popcntd - put 1x 6-bit answer into output
86 comb += o.eq(popcnt[0])
87
88 ###### parity #######
89 with m.Case(InternalOp.OP_PRTY):
90 # strange instruction which XORs together the LSBs of each byte
91 par0 = Signal(8, reset_less=True)
92 par1 = Signal(8, reset_less=True)
93 comb += par0.eq(Cat(a[0] , a[8] , a[16], a[24]).xor())
94 comb += par1.eq(Cat(a[32], a[40], a[48], a[32]).xor())
95 with m.If(op.data_len[3] == 1):
96 comb += o.eq(par0 ^ par1)
97 with m.Else():
98 comb += o[0].eq(par0)
99 comb += o[32].eq(par1)
100
101 ###### cntlz #######
102 # TODO with m.Case(InternalOp.OP_CNTZ):
103 ###### bpermd #######
104 # TODO with m.Case(InternalOp.OP_BPERM): - not in microwatt
105
106 ###### sticky overflow and context, both pass-through #####
107
108 comb += self.o.so.eq(self.i.so)
109 comb += self.o.ctx.eq(self.i.ctx)
110
111 return m