bug #672: invert testing in sv.minmax and add Rc=1
[openpower-isa.git] / src / openpower / decoder / power_svp64_rm.py
1 # SPDX-License-Identifier: LGPLv3+
2 # Copyright (C) 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3 # Funded by NLnet http://nlnet.nl
4
5 # sigh this entire module is a laborious mess. it really should be
6 # auto-generated from the insndb/types.py database but a technique
7 # for doing so (similar to python HTML/XML-node-walking) is needed
8
9 """SVP64 RM (Remap) Record.
10
11 https://libre-soc.org/openpower/sv/svp64/
12
13 | Field Name | Field bits | Description |
14 |-------------|------------|----------------------------------------|
15 | MASKMODE | `0` | Execution (predication) Mask Kind |
16 | MASK | `1:3` | Execution Mask |
17 | ELWIDTH | `4:5` | Element Width |
18 | ELWIDTH_SRC | `6:7` | Element Width for Source |
19 | SUBVL | `8:9` | Sub-vector length |
20 | EXTRA | `10:18` | context-dependent extra |
21 | MODE | `19:23` | changes Vector behaviour |
22 """
23
24 from nmigen import Elaboratable, Module, Signal, Const
25 from openpower.decoder.power_enums import (SVP64RMMode, Function, SVPType,
26 SVMode,
27 SVP64PredMode, SVP64Sat, SVP64LDSTmode,
28 SVP64BCPredMode, SVP64BCVLSETMode,
29 SVP64BCGate, SVP64BCCTRMode,
30 SVP64Width
31 )
32 from openpower.consts import EXTRA3, SVP64MODE
33 from openpower.sv.svp64 import SVP64Rec
34 from nmutil.util import sel
35
36 # a list of fields which need to be added to input records in order
37 # pass on vital information needed by each pipeline.
38 # make sure to keep these the same as SVP64RMModeDecode, in fact,
39 # TODO, make SVP64RMModeDecode *use* this as a Record!
40 sv_input_record_layout = [
41 ('sv_pred_sz', 1), # predicate source zeroing
42 ('sv_pred_dz', 1), # predicate dest zeroing
43 ('sv_saturate', SVP64Sat),
44 ('sv_ldstmode', SVP64LDSTmode),
45 ('SV_Ptype', SVPType),
46 ('SV_mode', SVMode),
47 #('sv_RC1', 1),
48 ]
49
50 """RM Mode
51 there are five Mode variants, two for LD/ST, one for Branch-Conditional,
52 and one for everything else
53 https://libre-soc.org/openpower/sv/svp64/
54 https://libre-soc.org/openpower/sv/ldst/
55 https://libre-soc.org/openpower/sv/branches/
56 https://libre-soc.org/openpower/sv/crops/
57
58 LD/ST immed:
59
60 | 0 | 1 | 2 | 3 4 | description |
61 |---|---| --- |---------|--------------------------- |
62 |els| 0 | PI | zz LF | simple mode |
63 |VLi| 1 | inv | CR-bit | ffirst CR sel |
64
65 LD/ST indexed:
66
67 | 0 | 1 | 2 | 3 4 | description |
68 |---|---| --- |---------|--------------------------- |
69 |els| 0 | PI | zz SEA | simple mode |
70 |VLi| 1 | inv | CR-bit | ffirst CR sel |
71
72 Arithmetic:
73
74 | 0-1 | 2 | 3 4 | description |
75 | ------ | --- |---------|----------------------------------|
76 | 0 0 | 0 | dz sz | simple mode |
77 | 0 0 | 1 | RG 0 | scalar reduce mode (mapreduce) |
78 | 0 0 | 1 | / 1 | reserved |
79 | 1 0 | N | dz sz | sat mode: N=0/1 u/s |
80 | VLi 1 | inv | CR-bit | Rc=1: ffirst CR sel |
81 | VLi 1 | inv | zz RC1 | Rc=0: ffirst z/nonz |
82
83 CROps:
84
85 |6 | 7 |19:20|21 | 22:23 | description |
86 |--|---|-----|---|---------|------------------|
87 |/ | / |0 0 |RG | dz sz | simple mode |
88 |/ | / |1 0 |RG | dz sz | scalar reduce mode (mapreduce) |
89 |zz|SNZ|VLI 1|inv| CR-bit | Ffirst 3-bit mode |
90 |/ |SNZ|VLI 1|inv| dz sz | Ffirst 5-bit mode (implies CR-bit from result) |
91
92 Branch Conditional:
93
94 note that additional BC modes are in *other bits*, specifically
95 the element-width fields: SVP64Rec.ewsrc and SVP64Rec.elwidth
96
97 elwidth ewsrc mode
98 4 5 6 7 19 20 21 22 23
99 ALL LRu / / 0 0 / SNZ sz normal mode
100 ALL LRu / VSb 0 1 VLI SNZ sz VLSET mode
101 ALL LRu BRc / 1 0 / SNZ sz svstep mode
102 ALL LRu BRc VSb 1 1 VLI SNZ sz svstep VLSET mode
103 """
104
105
106 class SVP64RMModeDecode(Elaboratable):
107 def __init__(self, name=None):
108 ##### inputs #####
109 self.rm_in = SVP64Rec(name=name)
110 self.fn_in = Signal(Function) # LD/ST and Branch is different
111 self.sv_mode = Signal(SVMode) # BRANCH/LDST_IMM/CROP etc.
112 self.svp64_vf_in = Signal() # Vertical-First Mode
113 self.ptype_in = Signal(SVPType)
114 self.rc_in = Signal()
115 self.cr_5bit_in = Signal() # if CR field was 5-bit
116 self.cr_2bit_in = Signal() # bottom 2 bits of CR field
117 self.ldst_ra_vec = Signal() # set when RA is vec, indicate Index mode
118 self.ldst_imz_in = Signal() # set when LD/ST immediate is zero
119 self.ldst_postinc = Signal() # set when LD/ST immediate post-inc set
120 self.ldst_ffirst = Signal() # set when LD/ST immediate fail-first set
121
122 ##### outputs #####
123
124 # main mode (normal, reduce, saturate, ffirst, pred-result, branch)
125 self.mode = Signal(SVP64RMMode)
126
127 # Branch Conditional Modes
128 self.bc_vlset = Signal(SVP64BCVLSETMode) # Branch-Conditional VLSET
129 self.bc_ctrtest = Signal(SVP64BCCTRMode) # Branch-Conditional CTR-Test
130 self.bc_pred = Signal(SVP64BCPredMode) # BC predicate mode
131 self.bc_vsb = Signal() # BC VLSET-branch (like BO[1])
132 self.bc_gate = Signal(SVP64BCGate) # BC ALL or ANY gate
133 self.bc_lru = Signal() # BC Link Register Update
134
135 # predication
136 self.predmode = Signal(SVP64PredMode)
137 self.srcpred = Signal(3) # source predicate
138 self.dstpred = Signal(3) # destination predicate
139 self.pred_sz = Signal(1) # predicate source zeroing
140 self.pred_dz = Signal(1) # predicate dest zeroing
141
142 # Modes n stuff
143 self.ew_src = Signal(SVP64Width) # source elwidth
144 self.ew_dst = Signal(SVP64Width) # dest elwidth
145 self.subvl= Signal(2) # subvl
146 self.saturate = Signal(SVP64Sat)
147 self.RC1 = Signal()
148 self.vli = Signal()
149 self.cr_sel = Signal(2) # bit of CR to test (index 0-3)
150 self.inv = Signal(1) # and whether it's inverted (like branch BO)
151 self.map_evm = Signal(1)
152 self.map_crm = Signal(1)
153 self.reverse_gear = Signal(1) # elements to go VL-1..0
154 self.ldstmode = Signal(SVP64LDSTmode) # LD/ST Mode (strided type)
155
156 def elaborate(self, platform):
157 m = Module()
158 comb = m.d.comb
159 mode = self.rm_in.mode
160
161 # decode pieces of mode
162 is_ldst = Signal()
163 is_bc = Signal()
164 is_cr = Signal()
165 is_ldstimm = Signal()
166 comb += is_ldst.eq(self.fn_in == Function.LDST)
167 comb += is_bc.eq(self.fn_in == Function.BRANCH) # XXX TODO use SV Mode
168 comb += is_cr.eq(self.sv_mode == SVMode.CROP.value)
169 comb += is_ldstimm.eq(self.sv_mode == SVMode.LDST_IMM.value)
170 mode2 = sel(m, mode, SVP64MODE.MOD2)
171 cr = sel(m, mode, SVP64MODE.CR)
172
173 #####################
174 # Branch-Conditional decoding
175 #####################
176 with m.If(is_bc):
177 # Counter-Test Mode.
178 with m.If(mode[SVP64MODE.BC_CTRTEST]):
179 with m.If(self.rm_in.ewsrc[1]):
180 comb += self.bc_ctrtest.eq(SVP64BCCTRMode.TEST_INV)
181 with m.Else():
182 comb += self.bc_ctrtest.eq(SVP64BCCTRMode.TEST)
183
184 # BC Mode ALL or ANY (Great-Big-AND-gate or Great-Big-OR-gate)
185 comb += self.bc_gate.eq(self.rm_in.elwidth[1])
186 # Link-Register Update
187 comb += self.bc_lru.eq(self.rm_in.elwidth[0])
188 comb += self.bc_vsb.eq(self.rm_in.ewsrc[0])
189
190 #####################
191 # CRops decoding
192 #####################
193 with m.Elif(is_cr):
194 with m.Switch(mode2):
195 with m.Case(0, 2): # needs further decoding (LDST no mapreduce)
196 with m.If(mode[SVP64MODE.REDUCE]):
197 comb += self.mode.eq(SVP64RMMode.MAPREDUCE)
198 with m.Else():
199 comb += self.mode.eq(SVP64RMMode.NORMAL)
200 with m.Case(1,3):
201 comb += self.mode.eq(SVP64RMMode.FFIRST) # fail-first
202
203 # extract failfirst
204 with m.If(self.mode == SVP64RMMode.FFIRST): # fail-first
205 comb += self.inv.eq(mode[SVP64MODE.INV])
206 comb += self.vli.eq(mode[SVP64MODE.VLI])
207 with m.If(self.cr_5bit_in):
208 comb += self.cr_sel.eq(0b10) # EQ bit index is implicit
209 with m.Else():
210 comb += self.cr_sel.eq(cr)
211
212 #####################
213 # LDST decoding (both Idx and Imm - should be separate)
214 #####################
215 with m.Elif(is_ldst):
216 with m.Switch(mode2):
217 with m.Case(0, 2): # needs further decoding (LDST no mapreduce)
218 comb += self.mode.eq(SVP64RMMode.NORMAL)
219 comb += self.ldst_postinc.eq(mode[SVP64MODE.LDI_PI])
220 comb += self.ldst_ffirst.eq(mode[SVP64MODE.LDI_FF])
221 with m.Case(1, 3):
222 comb += self.mode.eq(SVP64RMMode.FFIRST) # ffirst
223
224 # extract zeroing
225 with m.If(is_ldst & ~is_ldstimm): # LDST-Indexed
226 with m.Switch(mode2):
227 with m.Case(0,2):
228 # sz/dz only when mode2[0] = 0
229 comb += self.pred_sz.eq(mode[SVP64MODE.DZ])
230 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
231
232 with m.Elif(is_ldstimm): # LDST-Immediate
233 with m.Switch(mode2):
234 with m.Case(0,2): # simple mode
235 # use zz
236 comb += self.pred_sz.eq(mode[SVP64MODE.ZZ])
237 comb += self.pred_dz.eq(mode[SVP64MODE.ZZ])
238
239 # extract failfirst
240 with m.If(self.mode == SVP64RMMode.FFIRST): # fail-first
241 comb += self.inv.eq(mode[SVP64MODE.INV])
242 with m.If(is_ldst):
243 comb += self.vli.eq(mode[SVP64MODE.LDST_VLI])
244 with m.If(self.rc_in):
245 comb += self.cr_sel.eq(cr)
246 with m.Else():
247 # only when Rc=0
248 comb += self.RC1.eq(mode[SVP64MODE.RC1])
249 with m.If(~is_ldst):
250 comb += self.vli.eq(mode[SVP64MODE.VLI])
251 comb += self.cr_sel.eq(0b10) # EQ bit index is implicit
252
253 # extract saturate
254 with m.Switch(mode2):
255 with m.Case(2):
256 with m.If(mode[SVP64MODE.N]):
257 comb += self.saturate.eq(SVP64Sat.UNSIGNED)
258 with m.Else():
259 comb += self.saturate.eq(SVP64Sat.SIGNED)
260 with m.Default():
261 comb += self.saturate.eq(SVP64Sat.NONE)
262
263 # do elwidth/elwidth_src extract
264 comb += self.ew_src.eq(self.rm_in.ewsrc)
265 comb += self.ew_dst.eq(self.rm_in.elwidth)
266 comb += self.subvl.eq(self.rm_in.subvl)
267
268 # extract els (element strided mode bit)
269 # see https://libre-soc.org/openpower/sv/ldst/
270 els = Signal()
271 with m.Switch(mode2):
272 with m.Case(0, 2):
273 comb += els.eq(mode[SVP64MODE.LDST_ELS])
274 with m.Case(1, 3):
275 with m.If(self.rc_in):
276 comb += els.eq(mode[SVP64MODE.ELS_FFIRST_PRED])
277
278 # RA is vectorised
279 with m.If(self.ldst_ra_vec):
280 comb += self.ldstmode.eq(SVP64LDSTmode.INDEXED)
281 # not element-strided, therefore unit...
282 with m.Elif(~els):
283 comb += self.ldstmode.eq(SVP64LDSTmode.UNITSTRIDE)
284 # but if the LD/ST immediate is zero, allow cache-inhibited
285 # loads from same location, therefore don't do element-striding
286 with m.Elif(~self.ldst_imz_in):
287 comb += self.ldstmode.eq(SVP64LDSTmode.ELSTRIDE)
288
289 ######################
290 # arith decoding
291 ######################
292 with m.Else():
293 with m.Switch(mode2):
294 with m.Case(0): # needs further decoding (LDST no mapreduce)
295 with m.If(mode[SVP64MODE.REDUCE]):
296 comb += self.mode.eq(SVP64RMMode.MAPREDUCE)
297 with m.Else():
298 comb += self.mode.eq(SVP64RMMode.NORMAL)
299 with m.Case(1,3):
300 comb += self.mode.eq(SVP64RMMode.FFIRST) # ffirst
301 with m.Case(2):
302 comb += self.mode.eq(SVP64RMMode.SATURATE) # saturate
303
304 # extract "reverse gear" for mapreduce mode
305 with m.If((~is_ldst) & # not for LD/ST
306 (mode2 == 0) & # first 2 bits == 0
307 mode[SVP64MODE.REDUCE] & # bit 2 == 1
308 (~mode[SVP64MODE.MOD3])): # bit 3 == 0
309 comb += self.reverse_gear.eq(mode[SVP64MODE.RG]) # finally whew
310
311 # extract zeroing
312 with m.Switch(mode2):
313 with m.Case(0):
314 # normal-mode only active in simple mode
315 with m.If(~mode[SVP64MODE.REDUCE]): # bit 2 is zero?
316 comb += self.pred_sz.eq(mode[SVP64MODE.SZ])
317 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
318 with m.Case(2):
319 # sat-mode all good...
320 comb += self.pred_sz.eq(mode[SVP64MODE.SZ])
321 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
322 with m.Case(3):
323 # predicate-result has ZZ
324 with m.If(self.rc_in):
325 comb += self.pred_sz.eq(mode[SVP64MODE.ZZ])
326 comb += self.pred_dz.eq(mode[SVP64MODE.ZZ])
327
328 # extract failfirst
329 with m.If(self.mode == SVP64RMMode.FFIRST): # fail-first
330 comb += self.inv.eq(mode[SVP64MODE.INV])
331 with m.If(self.rc_in):
332 comb += self.cr_sel.eq(cr)
333 with m.Else():
334 # only when Rc=0
335 comb += self.RC1.eq(mode[SVP64MODE.RC1])
336 with m.If(~is_ldst):
337 comb += self.vli.eq(mode[SVP64MODE.VLI])
338 comb += self.cr_sel.eq(0b10) # EQ bit index is implicit
339
340 # extract saturate
341 with m.Switch(mode2):
342 with m.Case(2):
343 with m.If(mode[SVP64MODE.N]):
344 comb += self.saturate.eq(SVP64Sat.UNSIGNED)
345 with m.Else():
346 comb += self.saturate.eq(SVP64Sat.SIGNED)
347 with m.Default():
348 comb += self.saturate.eq(SVP64Sat.NONE)
349
350 # do elwidth/elwidth_src extract
351 comb += self.ew_src.eq(self.rm_in.ewsrc)
352 comb += self.ew_dst.eq(self.rm_in.elwidth)
353 comb += self.subvl.eq(self.rm_in.subvl)
354
355 ######################
356 # Common fields (not many, sigh)
357 ######################
358
359 # extract src/dest predicate. use EXTRA3.MASK because EXTRA2.MASK
360 # is in exactly the same bits
361 srcmask = sel(m, self.rm_in.extra, EXTRA3.MASK)
362 dstmask = self.rm_in.mask
363 with m.If(self.ptype_in == SVPType.P2):
364 comb += self.srcpred.eq(srcmask)
365 with m.Else():
366 comb += self.srcpred.eq(dstmask)
367 comb += self.dstpred.eq(dstmask)
368
369 # identify predicate mode
370 with m.If(self.rm_in.mmode == 1):
371 comb += self.predmode.eq(SVP64PredMode.CR) # CR Predicate
372 with m.Elif((self.srcpred == 0) & (self.dstpred == 0)):
373 comb += self.predmode.eq(SVP64PredMode.ALWAYS) # No predicate
374 with m.Else():
375 comb += self.predmode.eq(SVP64PredMode.INT) # non-zero src: INT
376
377 return m
378