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
8 from nmigen
import (Module
, Signal
, Cat
, Repl
, Mux
, Const
, Array
)
9 from nmutil
.pipemodbase
import PipeModBase
10 from nmutil
.clz
import CLZ
11 from soc
.fu
.logical
.pipe_data
import LogicalInputData
12 from soc
.fu
.logical
.bpermd
import Bpermd
13 from soc
.fu
.alu
.pipe_data
import ALUOutputData
14 from ieee754
.part
.partsig
import PartitionedSignal
15 from soc
.decoder
.power_enums
import InternalOp
17 from soc
.decoder
.power_fields
import DecodeFields
18 from soc
.decoder
.power_fieldsn
import SignalBitRange
21 def array_of(count
, bitwidth
):
23 for i
in range(count
):
24 res
.append(Signal(bitwidth
, reset_less
=True,
25 name
=f
"pop_{bitwidth}_{i}"))
29 class LogicalMainStage(PipeModBase
):
30 def __init__(self
, pspec
):
31 super().__init
__(pspec
, "main")
32 self
.fields
= DecodeFields(SignalBitRange
, [self
.i
.ctx
.op
.insn
])
33 self
.fields
.create_specs()
36 return LogicalInputData(self
.pspec
)
39 return ALUOutputData(self
.pspec
) # TODO: ALUIntermediateData
41 def elaborate(self
, platform
):
44 op
, a
, b
, o
= self
.i
.ctx
.op
, self
.i
.a
, self
.i
.b
, self
.o
.o
46 ##########################
47 # main switch for logic ops AND, OR and XOR, cmpb, parity, and popcount
49 with m
.Switch(op
.insn_type
):
51 ###### AND, OR, XOR #######
52 with m
.Case(InternalOp
.OP_AND
):
54 with m
.Case(InternalOp
.OP_OR
):
56 with m
.Case(InternalOp
.OP_XOR
):
60 with m
.Case(InternalOp
.OP_CMPB
):
63 slc
= slice(i
*8, (i
+1)*8)
64 l
.append(Repl(a
[slc
] == b
[slc
], 8))
67 ###### popcount #######
68 with m
.Case(InternalOp
.OP_POPCNT
):
69 # starting from a, perform successive addition-reductions
70 # creating arrays big enough to store the sum, each time
72 # QTY32 2-bit (to take 2x 1-bit sums) etc.
73 work
= [(32, 2), (16, 3), (8, 4), (4, 5), (2, 6), (1, 7)]
75 pc
.append(array_of(l
, b
))
76 pc8
= pc
[3] # array of 8 8-bit counts (popcntb)
77 pc32
= pc
[5] # array of 2 32-bit counts (popcntw)
78 popcnt
= pc
[-1] # array of 1 64-bit count (popcntd)
79 # cascade-tree of adds
80 for idx
, (l
, b
) in enumerate(work
):
83 src
, dst
= pc
[idx
], pc
[idx
+1]
84 comb
+= dst
[i
].eq(Cat(src
[stt
], Const(0, 1)) +
85 Cat(src
[end
], Const(0, 1)))
86 # decode operation length
87 with m
.If(op
.data_len
== 1):
88 # popcntb - pack 8x 4-bit answers into output
90 comb
+= o
[i
*8:(i
+1)*8].eq(pc8
[i
])
91 with m
.Elif(op
.data_len
== 4):
92 # popcntw - pack 2x 5-bit answers into output
94 comb
+= o
[i
*32:(i
+1)*32].eq(pc32
[i
])
96 # popcntd - put 1x 6-bit answer into output
97 comb
+= o
.eq(popcnt
[0])
100 with m
.Case(InternalOp
.OP_PRTY
):
101 # strange instruction which XORs together the LSBs of each byte
102 par0
= Signal(reset_less
=True)
103 par1
= Signal(reset_less
=True)
104 comb
+= par0
.eq(Cat(a
[0], a
[8], a
[16], a
[24]).xor())
105 comb
+= par1
.eq(Cat(a
[32], a
[40], a
[48], a
[56]).xor())
106 with m
.If(op
.data_len
[3] == 1):
107 comb
+= o
.eq(par0 ^ par1
)
109 comb
+= o
[0].eq(par0
)
110 comb
+= o
[32].eq(par1
)
113 with m
.Case(InternalOp
.OP_CNTZ
):
114 XO
= self
.fields
.FormX
.XO
[0:-1]
115 count_right
= Signal(reset_less
=True)
116 comb
+= count_right
.eq(XO
[-1])
118 cntz_i
= Signal(64, reset_less
=True)
119 a32
= Signal(32, reset_less
=True)
120 comb
+= a32
.eq(a
[0:32])
122 with m
.If(op
.is_32bit
):
123 comb
+= cntz_i
.eq(Mux(count_right
, a32
[::-1], a32
))
125 comb
+= cntz_i
.eq(Mux(count_right
, a
[::-1], a
))
127 m
.submodules
.clz
= clz
= CLZ(64)
128 comb
+= clz
.sig_in
.eq(cntz_i
)
129 comb
+= o
.eq(Mux(op
.is_32bit
, clz
.lz
-32, clz
.lz
))
131 ###### bpermd #######
132 with m
.Case(InternalOp
.OP_BPERM
):
133 m
.submodules
.bpermd
= bpermd
= Bpermd(64)
134 comb
+= bpermd
.rs
.eq(a
)
135 comb
+= bpermd
.rb
.eq(b
)
136 comb
+= o
.eq(bpermd
.ra
)
138 ###### sticky overflow and context, both pass-through #####
140 comb
+= self
.o
.xer_so
.data
.eq(self
.i
.xer_so
)
141 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)