7bf93eff6dd564a81ad1ec9ede541e520cfdac0c
[openpower-isa.git] / src / openpower / sv / trans / svp64.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 """SVP64 OpenPOWER v3.0B assembly translator
6
7 This class takes raw svp64 assembly mnemonics (aliases excluded) and creates
8 an EXT001-encoded "svp64 prefix" (as a .long) followed by a v3.0B opcode.
9
10 It is very simple and straightforward, the only weirdness being the
11 extraction of the register information and conversion to v3.0B numbering.
12
13 Encoding format of svp64: https://libre-soc.org/openpower/sv/svp64/
14 Encoding format of arithmetic: https://libre-soc.org/openpower/sv/normal/
15 Encoding format of LDST: https://libre-soc.org/openpower/sv/ldst/
16 **TODO format of branches: https://libre-soc.org/openpower/sv/branches/**
17 **TODO format of CRs: https://libre-soc.org/openpower/sv/cr_ops/**
18 Bugtracker: https://bugs.libre-soc.org/show_bug.cgi?id=578
19 """
20
21 import functools
22 import os
23 import sys
24 from collections import OrderedDict
25 import inspect
26
27 from openpower.decoder.pseudo.pagereader import ISA
28 from openpower.decoder.power_svp64 import SVP64RM, get_regtype, decode_extra
29 from openpower.decoder.selectable_int import SelectableInt
30 from openpower.consts import SVP64MODE
31 from openpower.decoder.power_insn import SVP64Instruction
32 from openpower.decoder.power_insn import Database
33 from openpower.decoder.power_enums import find_wiki_dir
34
35 # for debug logging
36 from openpower.util import log
37
38
39 def instruction(*fields):
40 def instruction(insn, desc):
41 (value, start, end) = desc
42 bits = ((1,) * ((end + 1) - start))
43 mask = 0
44 for bit in bits:
45 mask = ((mask << 1) | bit)
46 return (insn | ((value & mask) << (31 - end)))
47
48 return functools.reduce(instruction, fields, 0)
49
50
51 CUSTOM_INSNS = {}
52
53
54 def _insn(name, **kwargs):
55 return name, kwargs
56
57
58 def _custom_insns(*insns):
59 """ a decorator that adds the function to `CUSTOM_INSNS` """
60
61 def decorator(fn):
62 FIELDS_ARG = object()
63 if len(insns) == 0:
64 insns_ = (fn.__name__, {}),
65 else:
66 insns_ = insns
67 for name, kwargs in insns_:
68 if not isinstance(name, str):
69 raise TypeError("instruction name must be a str: {name!r}")
70 if name in CUSTOM_INSNS:
71 raise ValueError(f"duplicate instruction mnemonic: {name!r}")
72 # use getcallargs to check that arguments work:
73 inspect.getcallargs(fn, FIELDS_ARG, **kwargs)
74 CUSTOM_INSNS[name] = functools.partial(fn, **kwargs)
75 return fn
76 return decorator
77
78
79 @_custom_insns(
80 _insn("setvl", Rc=0),
81 _insn("setvl.", Rc=1),
82 )
83 def setvl(fields, Rc):
84 """
85 setvl is a *32-bit-only* instruction. It controls SVSTATE.
86 It is *not* a 64-bit-prefixed Vector instruction (no sv.setvl, yet),
87 it is a Vector *control* instruction.
88
89 * setvl RT,RA,SVi,vf,vs,ms
90
91 1.6.28 SVL-FORM - from fields.txt
92 |0 |6 |11 |16 |23 |24 |25 |26 |31 |
93 | PO | RT | RA | SVi |ms |vs |vf | XO |Rc |
94 """
95 PO = 22
96 XO = 0b11011
97 # ARRRGH these are in a non-obvious order in openpower/isa/simplev.mdwn
98 # compared to the SVL-Form above. sigh
99 # setvl RT,RA,SVi,vf,vs,ms
100 (RT, RA, SVi, vf, vs, ms) = fields
101 SVi -= 1
102 return instruction(
103 (PO, 0, 5),
104 (RT, 6, 10),
105 (RA, 11, 15),
106 (SVi, 16, 22),
107 (ms, 23, 23),
108 (vs, 24, 24),
109 (vf, 25, 25),
110 (XO, 26, 30),
111 (Rc, 31, 31),
112 )
113
114
115 @_custom_insns(
116 _insn("svstep", Rc=0),
117 _insn("svstep.", Rc=1),
118 )
119 def svstep(fields, Rc):
120 """
121 svstep is a 32-bit instruction. It updates SVSTATE.
122 It *can* be SVP64-prefixed, to indicate that its registers
123 are Vectorised.
124
125 * svstep RT,SVi,vf
126
127 # 1.6.28 SVL-FORM - from fields.txt
128 # |0 |6 |11 |16 |23 |24 |25 |26 |31 |
129 # | PO | RT | / | SVi |/ |/ |vf | XO |Rc |
130
131 """
132 PO = 22
133 XO = 0b10011
134 (RT, SVi, vf) = fields
135 SVi -= 1
136 return instruction(
137 (PO, 0, 5),
138 (RT, 6, 10),
139 (0, 11, 15),
140 (SVi, 16, 22),
141 (0, 23, 23),
142 (0, 24, 24),
143 (vf, 25, 25),
144 (XO, 26, 30),
145 (Rc, 31, 31),
146 )
147
148
149 @_custom_insns()
150 def svshape(fields):
151 """
152 svshape is a *32-bit-only* instruction. It updates SVSHAPE and SVSTATE.
153 It is *not* a 64-bit-prefixed Vector instruction (no sv.svshape, yet),
154 it is a Vector *control* instruction.
155
156 https://libre-soc.org/openpower/sv/remap/#svshape
157
158 * svshape SVxd,SVyd,SVzd,SVrm,vf
159
160 # 1.6.33 SVM-FORM from fields.txt
161 # |0 |6 |11 |16 |21 |25 |26 |31 |
162 # | PO | SVxd | SVyd | SVzd | SVrm |vf | XO |
163
164 note that SVrm is not permitted to be 0b0111, 0b1000 or 0b1001.
165 0b0111 is reserved and 0b100- is for svshape2
166
167 """
168 PO = 22
169 XO = 0b011001
170 (SVxd, SVyd, SVzd, SVrm, vf) = fields
171 SVxd -= 1
172 SVyd -= 1
173 SVzd -= 1
174
175 # check SVrm for reserved (and svshape2) values
176 assert SVrm not in [0b1000, 0b1001], \
177 "svshape reserved SVrm value %s" % bin(SVrm)
178
179 return instruction(
180 (PO, 0, 5),
181 (SVxd, 6, 10),
182 (SVyd, 11, 15),
183 (SVzd, 16, 20),
184 (SVrm, 21, 24),
185 (vf, 25, 25),
186 (XO, 26, 31),
187 )
188
189
190 @_custom_insns()
191 def svshape2(fields):
192 """
193 svshape2 is a *32-bit-only* instruction. It updates SVSHAPE and SVSTATE.
194 It is *not* a 64-bit-prefixed Vector instruction (no sv.svshape2, yet),
195 it is a Vector *control* instruction, and is a sort-of hybrid of
196 svshape and svindex, with the key important feature being the "offset".
197
198 https://libre-soc.org/openpower/sv/remap/discussion
199
200 * svshape2 SVo,SVM2yx,rmm,SVd,sk,mm
201
202 # 1.6.35.1 SVM2-FORM from fields.txt
203 # |0 |6 |10 |11 |16 |21 |24|25 |26 |31 |
204 # | PO | SVo |SVMyx| rmm | SVd |XO |mm|sk | XO |
205
206 note that this fits into the space of svshape and that XO is
207 split across 2 areas.
208
209 """
210 PO = 22
211 XO = 0b011001
212 XO2 = 0b100 # not really XO2 but hey
213 (offs, yx, rmm, SVd, sk, mm) = fields
214 SVd -= 1 # offset by one
215
216 return instruction(
217 (PO, 0, 5),
218 (offs, 6, 9), # offset (the whole point of adding svshape2)
219 (yx, 10, 10), # like svindex
220 (rmm, 11, 15), # ditto svindex
221 (SVd, 16, 20), # ditto svindex
222 (XO2, 21, 23), # actually XO split across 2 places...
223 (mm, 24, 24), # ditto svindex
224 (sk, 25, 25), # ditto svindex
225 (XO, 26, 31),
226 )
227
228
229 @_custom_insns()
230 def svindex(fields):
231 """
232 svindex is a *32-bit-only* instruction. It is a convenience
233 instruction that reduces instruction count for Indexed REMAP
234 Mode.
235 It is *not* a 64-bit-prefixed Vector instruction (no sv.svindex, yet),
236 it is a Vector *control* instruction.
237
238 1.6.28 SVI-FORM
239 |0 |6 |11 |16 |21 |23|24|25|26 31|
240 | PO | SVG|rmm | SVd |ew |yx|mm|sk| XO |
241 """
242 # note that the dimension field one subtracted
243 PO = 22
244 XO = 0b101001
245 (SVG, rmm, SVd, ew, yx, mm, sk) = fields
246 SVd -= 1
247 return instruction(
248 (PO, 0, 5),
249 (SVG, 6, 10),
250 (rmm, 11, 15),
251 (SVd, 16, 20),
252 (ew, 21, 22),
253 (yx, 23, 23),
254 (mm, 24, 24),
255 (sk, 25, 25),
256 (XO, 26, 31),
257 )
258
259
260 @_custom_insns()
261 def svremap(fields):
262 """
263 this is a *32-bit-only* instruction. It updates the SVSHAPE SPR
264 it is *not* a 64-bit-prefixed Vector instruction (no sv.svremap),
265 it is a Vector *control* instruction.
266
267 * svremap SVme,mi0,mi1,mi2,mo0,mo1,pst
268
269 # 1.6.34 SVRM-FORM
270 |0 |6 |11 |13 |15 |17 |19 |21 |22 |26 |31 |
271 | PO | SVme |mi0 | mi1 | mi2 | mo0 | mo1 |pst |/// | XO |
272
273 """
274 PO = 22
275 XO = 0b111001
276 (SVme, mi0, mi1, mi2, mo0, mo1, pst) = fields
277 return instruction(
278 (PO, 0, 5),
279 (SVme, 6, 10),
280 (mi0, 11, 12),
281 (mi1, 13, 14),
282 (mi2, 15, 16),
283 (mo0, 17, 18),
284 (mo1, 19, 20),
285 (pst, 21, 21),
286 (0, 22, 25),
287 (XO, 26, 31),
288 )
289
290
291 # ok from here-on down these are added as 32-bit instructions
292 # and are here only because binutils (at present) doesn't have
293 # them (that's being fixed!)
294 # they can - if implementations then choose - be Vectorised
295 # because they are general-purpose scalar instructions
296 @_custom_insns()
297 def bmask(fields):
298 """
299 1.6.2.2 BM2-FORM
300 |0 |6 |11 |16 |21 |26 |27 31|
301 | PO | RT | RA | RB |bm |L | XO |
302 """
303 PO = 22
304 XO = 0b010001
305 (RT, RA, RB, bm, L) = fields
306 return instruction(
307 (PO, 0, 5),
308 (RT, 6, 10),
309 (RA, 11, 15),
310 (RB, 16, 20),
311 (bm, 21, 25),
312 (L, 26, 26),
313 (XO, 27, 31),
314 )
315
316
317 def _fptrans_insn(name, XO):
318 return [
319 _insn(name, PO=63, Rc=0, XO=XO),
320 _insn(name + ".", PO=63, Rc=1, XO=XO),
321 _insn(name + "s", PO=59, Rc=0, XO=XO),
322 _insn(name + "s.", PO=59, Rc=1, XO=XO),
323 ]
324
325
326 @_custom_insns(
327 *_fptrans_insn("fatan2", XO=0b1001001110),
328 *_fptrans_insn("fatan2pi", XO=0b1000001110),
329 *_fptrans_insn("fpow", XO=0b1111101101),
330 *_fptrans_insn("fpown", XO=0b1101101100),
331 *_fptrans_insn("fpowr", XO=0b1111101100),
332 *_fptrans_insn("frootn", XO=0b1101101101),
333 *_fptrans_insn("fhypot", XO=0b1010001110),
334 *_fptrans_insn("fminnum08", XO=0b1011001100),
335 *_fptrans_insn("fmaxnum08", XO=0b1011101100),
336 *_fptrans_insn("fmin19", XO=0b1011001101),
337 *_fptrans_insn("fmax19", XO=0b1011101101),
338 *_fptrans_insn("fminnum19", XO=0b1011001110),
339 *_fptrans_insn("fmaxnum19", XO=0b1011101110),
340 *_fptrans_insn("fminc", XO=0b1011001111),
341 *_fptrans_insn("fmaxc", XO=0b1011101111),
342 *_fptrans_insn("fminmagnum08", XO=0b1100001110),
343 *_fptrans_insn("fmaxmagnum08", XO=0b1100001111),
344 *_fptrans_insn("fminmag19", XO=0b1101101110),
345 *_fptrans_insn("fmaxmag19", XO=0b1101101111),
346 *_fptrans_insn("fminmagnum19", XO=0b1110001110),
347 *_fptrans_insn("fmaxmagnum19", XO=0b1110001111),
348 *_fptrans_insn("fminmagc", XO=0b1111101110),
349 *_fptrans_insn("fmaxmagc", XO=0b1111101111),
350 *_fptrans_insn("fmod", XO=0b1101001111),
351 *_fptrans_insn("fremainder", XO=0b1111001111),
352 )
353 def fptrans_binary(fields, PO, Rc, XO):
354 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
355 # however we are out of space with opcode 22
356 # 1.6.7 X-FORM
357 # |0 |6 |11 |16 |21 |31 |
358 # | PO | FRT | FRA | FRB | XO |Rc |
359 # | PO | FRT | FRA | RB | XO |Rc |
360 (FRT, FRA, FRB) = fields
361 return instruction(
362 (PO, 0, 5),
363 (FRT, 6, 10),
364 (FRA, 11, 15),
365 (FRB, 16, 20),
366 (XO, 21, 30),
367 (Rc, 31, 31),
368 )
369
370
371 @_custom_insns(
372 *_fptrans_insn("frsqrt", XO=0b1001001100),
373 *_fptrans_insn("fcbrt", XO=0b1000001100),
374 *_fptrans_insn("frecip", XO=0b1010001100),
375 *_fptrans_insn("fexp2m1", XO=0b1100001100),
376 *_fptrans_insn("flog2p1", XO=0b1100001101),
377 *_fptrans_insn("fexp2", XO=0b1110001100),
378 *_fptrans_insn("flog2", XO=0b1110001101),
379 *_fptrans_insn("fexpm1", XO=0b1100101100),
380 *_fptrans_insn("flogp1", XO=0b1100101101),
381 *_fptrans_insn("fexp", XO=0b1110101100),
382 *_fptrans_insn("flog", XO=0b1110101101),
383 *_fptrans_insn("fexp10m1", XO=0b1101001100),
384 *_fptrans_insn("flog10p1", XO=0b1101001101),
385 *_fptrans_insn("fexp10", XO=0b1111001100),
386 *_fptrans_insn("flog10", XO=0b1111001101),
387 *_fptrans_insn("fsin", XO=0b1001001101),
388 *_fptrans_insn("fcos", XO=0b1001101100),
389 *_fptrans_insn("ftan", XO=0b1001101101),
390 *_fptrans_insn("fasin", XO=0b1001001111),
391 *_fptrans_insn("facos", XO=0b1001101110),
392 *_fptrans_insn("fatan", XO=0b1001101111),
393 *_fptrans_insn("fsinpi", XO=0b1000001101),
394 *_fptrans_insn("fcospi", XO=0b1000101100),
395 *_fptrans_insn("ftanpi", XO=0b1000101101),
396 *_fptrans_insn("fasinpi", XO=0b1000001111),
397 *_fptrans_insn("facospi", XO=0b1000101110),
398 *_fptrans_insn("fatanpi", XO=0b1000101111),
399 *_fptrans_insn("fsinh", XO=0b1010001101),
400 *_fptrans_insn("fcosh", XO=0b1010101100),
401 *_fptrans_insn("ftanh", XO=0b1010101101),
402 *_fptrans_insn("fasinh", XO=0b1010001111),
403 *_fptrans_insn("facosh", XO=0b1010101110),
404 *_fptrans_insn("fatanh", XO=0b1010101111),
405 )
406 def fptrans_unary(fields, PO, Rc, XO):
407 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
408 # however we are out of space with opcode 22
409 # 1.6.7 X-FORM
410 # |0 |6 |11 |16 |21 |31 |
411 # | PO | FRT | /// | FRB | XO |Rc |
412 (FRT, FRB) = fields
413 return instruction(
414 (PO, 0, 5),
415 (FRT, 6, 10),
416 (0, 11, 15),
417 (FRB, 16, 20),
418 (XO, 21, 30),
419 (Rc, 31, 31),
420 )
421
422
423 @_custom_insns(
424 _insn("ternlogi", Rc=0),
425 _insn("ternlogi.", Rc=1),
426 )
427 def ternlogi(fields, Rc):
428 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
429 # however we are out of space with opcode 22
430 # 1.6.34 TLI-FORM
431 # |0 |6 |11 |16 |21 |29 |31 |
432 # | PO | RT | RA | RB | TLI | XO |Rc |
433 PO = 5
434 XO = 0
435 (RT, RA, RB, TLI) = fields
436 return instruction(
437 (PO, 0, 5),
438 (RT, 6, 10),
439 (RA, 11, 15),
440 (RB, 16, 20),
441 (TLI, 21, 28),
442 (XO, 29, 30),
443 (Rc, 31, 31),
444 )
445
446
447 @_custom_insns(
448 _insn("grev", Rc=0, imm=0, word=0),
449 _insn("grevw", Rc=0, imm=0, word=1),
450 _insn("grevi", Rc=0, imm=1, word=0),
451 _insn("grevwi", Rc=0, imm=1, word=1),
452 _insn("grev.", Rc=1, imm=0, word=0),
453 _insn("grevw.", Rc=1, imm=0, word=1),
454 _insn("grevi.", Rc=1, imm=1, word=0),
455 _insn("grevwi.", Rc=1, imm=1, word=1),
456 )
457 def grev(fields, Rc, imm, word):
458 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
459 # however we are out of space with opcode 22
460 insn = PO = 5
461 # _ matches fields in table at:
462 # https://libre-soc.org/openpower/sv/bitmanip/
463 XO = 0b1_0010_110
464 if word:
465 XO |= 0b100_000
466 if imm:
467 XO |= 0b1000_000
468 (RT, RA, XBI) = fields
469 insn = (insn << 5) | RT
470 insn = (insn << 5) | RA
471 if imm and not word:
472 assert 0 <= XBI < 64
473 insn = (insn << 6) | XBI
474 insn = (insn << 9) | XO
475 else:
476 assert 0 <= XBI < 32
477 insn = (insn << 5) | XBI
478 insn = (insn << 10) | XO
479 insn = (insn << 1) | Rc
480 return insn
481
482
483 @_custom_insns(
484 _insn("maxs", XO=0b0111001110, Rc=0),
485 _insn("maxs.", XO=0b0111001110, Rc=1),
486 _insn("maxu", XO=0b0011001110, Rc=0),
487 _insn("maxu.", XO=0b0011001110, Rc=1),
488 _insn("minu", XO=0b0001001110, Rc=0),
489 _insn("minu.", XO=0b0001001110, Rc=1),
490 _insn("mins", XO=0b0101001110, Rc=0),
491 _insn("mins.", XO=0b0101001110, Rc=1),
492 _insn("absdu", XO=0b1011110110, Rc=0),
493 _insn("absdu.", XO=0b1011110110, Rc=1),
494 _insn("absds", XO=0b1001110110, Rc=0),
495 _insn("absds.", XO=0b1001110110, Rc=1),
496 _insn("avgadd", XO=0b1101001110, Rc=0),
497 _insn("avgadd.", XO=0b1101001110, Rc=1),
498 _insn("absdacu", XO=0b1111110110, Rc=0),
499 _insn("absdacu.", XO=0b1111110110, Rc=1),
500 _insn("absdacs", XO=0b0111110110, Rc=0),
501 _insn("absdacs.", XO=0b0111110110, Rc=1),
502 _insn("cprop", XO=0b0110001110, Rc=0),
503 _insn("cprop.", XO=0b0110001110, Rc=1),
504 )
505 def av(fields, XO, Rc):
506 # 1.6.7 X-FORM
507 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |20|21 |31 |
508 # | PO | RT | RA | RB | XO |Rc |
509 PO = 22
510 (RT, RA, RB) = fields
511 return instruction(
512 (PO, 0, 5),
513 (RT, 6, 10),
514 (RA, 11, 15),
515 (RB, 16, 20),
516 (XO, 21, 30),
517 (Rc, 31, 31),
518 )
519
520
521 @_custom_insns()
522 def fmvis(fields):
523 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
524 # V3.0B 1.6.6 DX-FORM
525 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |26|27 |31 |
526 # | PO | FRS | d1 | d0 | XO |d2 |
527 PO = 22
528 XO = 0b00011
529 (FRS, imm) = fields
530 # first split imm into d1, d0 and d2. sigh
531 d2 = (imm & 1) # LSB (0)
532 d1 = (imm >> 1) & 0b11111 # bits 1-5
533 d0 = (imm >> 6) # MSBs 6-15
534 return instruction(
535 (PO, 0, 5),
536 (FRS, 6, 10),
537 (d1, 11, 15),
538 (d0, 16, 25),
539 (XO, 26, 30),
540 (d2, 31, 31),
541 )
542
543
544 @_custom_insns()
545 def fishmv(fields):
546 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
547 # V3.0B 1.6.6 DX-FORM
548 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |26|27 |31 |
549 # | PO | FRS | d1 | d0 | XO |d2 |
550 PO = 22
551 XO = 0b01011
552 (FRS, imm) = fields
553 # first split imm into d1, d0 and d2. sigh
554 d2 = (imm & 1) # LSB (0)
555 d1 = (imm >> 1) & 0b11111 # bits 1-5
556 d0 = (imm >> 6) # MSBs 6-15
557 return instruction(
558 (PO, 0, 5),
559 (FRS, 6, 10),
560 (d1, 11, 15),
561 (d0, 16, 25),
562 (XO, 26, 30),
563 (d2, 31, 31),
564 )
565
566
567 @_custom_insns(
568 _insn("pcdec."), # named "pcdec." because it always writes to CR0
569 )
570 def pcdec(fields):
571 # 1.6.21.1 VA2-FORM
572 # |0 |6 |11 |16 |21 |24|26 |31 |
573 # | PO | RT | RA | RB | RC | XO |once|
574 PO = 4
575 XO = 0b11100
576 (RT, RA, RB, RC, once) = fields
577 return instruction(
578 (PO, 0, 5),
579 (RT, 6, 10),
580 (RA, 11, 15),
581 (RB, 16, 20),
582 (RC, 21, 25),
583 (XO, 26, 30),
584 (once, 31, 31),
585 )
586
587
588 # decode GPR into sv extra
589 def get_extra_gpr(etype, regmode, field):
590 if regmode == 'scalar':
591 # cut into 2-bits 5-bits SS FFFFF
592 sv_extra = field >> 5
593 field = field & 0b11111
594 else:
595 # cut into 5-bits 2-bits FFFFF SS
596 sv_extra = field & 0b11
597 field = field >> 2
598 return sv_extra, field
599
600
601 # decode 3-bit CR into sv extra
602 def get_extra_cr_3bit(etype, regmode, field):
603 if regmode == 'scalar':
604 # cut into 2-bits 3-bits SS FFF
605 sv_extra = field >> 3
606 field = field & 0b111
607 else:
608 # cut into 3-bits 4-bits FFF SSSS but will cut 2 zeros off later
609 sv_extra = field & 0b1111
610 field = field >> 4
611 return sv_extra, field
612
613
614 # decodes SUBVL
615 def decode_subvl(encoding):
616 pmap = {'2': 0b01, '3': 0b10, '4': 0b11}
617 assert encoding in pmap, \
618 "encoding %s for SUBVL not recognised" % encoding
619 return pmap[encoding]
620
621
622 # decodes elwidth
623 def decode_elwidth(encoding):
624 pmap = {'8': 0b11, '16': 0b10, '32': 0b01}
625 assert encoding in pmap, \
626 "encoding %s for elwidth not recognised" % encoding
627 return pmap[encoding]
628
629
630 # decodes predicate register encoding
631 def decode_predicate(encoding):
632 pmap = { # integer
633 '1<<r3': (0, 0b001),
634 'r3': (0, 0b010),
635 '~r3': (0, 0b011),
636 'r10': (0, 0b100),
637 '~r10': (0, 0b101),
638 'r30': (0, 0b110),
639 '~r30': (0, 0b111),
640 # CR
641 'lt': (1, 0b000),
642 'nl': (1, 0b001), 'ge': (1, 0b001), # same value
643 'gt': (1, 0b010),
644 'ng': (1, 0b011), 'le': (1, 0b011), # same value
645 'eq': (1, 0b100),
646 'ne': (1, 0b101),
647 'so': (1, 0b110), 'un': (1, 0b110), # same value
648 'ns': (1, 0b111), 'nu': (1, 0b111), # same value
649 }
650 assert encoding in pmap, \
651 "encoding %s for predicate not recognised" % encoding
652 return pmap[encoding]
653
654
655 # decodes "Mode" in similar way to BO field (supposed to, anyway)
656 def decode_bo(encoding):
657 pmap = { # TODO: double-check that these are the same as Branch BO
658 'lt': 0b000,
659 'nl': 0b001, 'ge': 0b001, # same value
660 'gt': 0b010,
661 'ng': 0b011, 'le': 0b011, # same value
662 'eq': 0b100,
663 'ne': 0b101,
664 'so': 0b110, 'un': 0b110, # same value
665 'ns': 0b111, 'nu': 0b111, # same value
666 }
667 assert encoding in pmap, \
668 "encoding %s for BO Mode not recognised" % encoding
669 # barse-ackwards MSB0/LSB0. sigh. this would be nice to be the
670 # same as the decode_predicate() CRfield table above, but (inv,CRbit)
671 # is how it is in the spec [decode_predicate is (CRbit,inv)]
672 mapped = pmap[encoding]
673 si = SelectableInt(0, 3)
674 si[0] = mapped & 1 # inv
675 si[1:3] = mapped >> 1 # CR
676 return int(si)
677
678
679 # partial-decode fail-first mode
680 def decode_ffirst(encoding):
681 if encoding in ['RC1', '~RC1']:
682 return encoding
683 return decode_bo(encoding)
684
685
686 def decode_reg(field, macros=None):
687 if macros is None:
688 macros = {}
689 # decode the field number. "5.v" or "3.s" or "9"
690 # and now also "*0", and "*%0". note: *NOT* to add "*%rNNN" etc.
691 # https://bugs.libre-soc.org/show_bug.cgi?id=884#c0
692 if field.startswith(("*%", "*")):
693 if field.startswith("*%"):
694 field = field[2:]
695 else:
696 field = field[1:]
697 while field in macros:
698 field = macros[field]
699 return int(field), "vector" # actual register number
700
701 # try old convention (to be retired)
702 field = field.split(".")
703 regmode = 'scalar' # default
704 if len(field) == 2:
705 if field[1] == 's':
706 regmode = 'scalar'
707 elif field[1] == 'v':
708 regmode = 'vector'
709 field = int(field[0]) # actual register number
710 return field, regmode
711
712
713 def decode_imm(field):
714 ldst_imm = "(" in field and field[-1] == ')'
715 if ldst_imm:
716 return field[:-1].split("(")
717 else:
718 return None, field
719
720
721 def crf_extra(etype, rname, extra_idx, regmode, field, extras):
722 """takes a CR Field number (CR0-CR127), splits into EXTRA2/3 and v3.0
723 the scalar/vector mode (crNN.v or crNN.s) changes both the format
724 of the EXTRA2/3 encoding as well as what range of registers is possible.
725 this function can be used for both BF/BFA and BA/BB/BT by first removing
726 the bottom 2 bits of BA/BB/BT then re-instating them after encoding.
727 see https://libre-soc.org/openpower/sv/svp64/appendix/#cr_extra
728 for specification
729 """
730 sv_extra, field = get_extra_cr_3bit(etype, regmode, field)
731 # now sanity-check (and shrink afterwards)
732 if etype == 'EXTRA2':
733 # 3-bit CR Field (BF, BFA) EXTRA2 encoding
734 if regmode == 'scalar':
735 # range is CR0-CR15 in increments of 1
736 assert (sv_extra >> 1) == 0, \
737 "scalar CR %s cannot fit into EXTRA2 %s" % \
738 (rname, str(extras[extra_idx]))
739 # all good: encode as scalar
740 sv_extra = sv_extra & 0b01
741 else: # vector
742 # range is CR0-CR127 in increments of 16
743 assert sv_extra & 0b111 == 0, \
744 "vector CR %s cannot fit into EXTRA2 %s" % \
745 (rname, str(extras[extra_idx]))
746 # all good: encode as vector (bit 2 set)
747 sv_extra = 0b10 | (sv_extra >> 3)
748 else:
749 # 3-bit CR Field (BF, BFA) EXTRA3 encoding
750 if regmode == 'scalar':
751 # range is CR0-CR31 in increments of 1
752 assert (sv_extra >> 2) == 0, \
753 "scalar CR %s cannot fit into EXTRA3 %s" % \
754 (rname, str(extras[extra_idx]))
755 # all good: encode as scalar
756 sv_extra = sv_extra & 0b11
757 else: # vector
758 # range is CR0-CR127 in increments of 8
759 assert sv_extra & 0b11 == 0, \
760 "vector CR %s cannot fit into EXTRA3 %s" % \
761 (rname, str(extras[extra_idx]))
762 # all good: encode as vector (bit 3 set)
763 sv_extra = 0b100 | (sv_extra >> 2)
764 return sv_extra, field
765
766
767 def to_number(field):
768 if field.startswith("0x"):
769 return eval(field)
770 if field.startswith("0b"):
771 return eval(field)
772 return int(field)
773
774
775 db = Database(find_wiki_dir())
776
777
778 # decodes svp64 assembly listings and creates EXT001 svp64 prefixes
779 class SVP64Asm:
780 def __init__(self, lst, bigendian=False, macros=None):
781 if macros is None:
782 macros = {}
783 self.macros = macros
784 self.lst = lst
785 self.trans = self.translate(lst)
786 self.isa = ISA() # reads the v3.0B pseudo-code markdown files
787 self.svp64 = SVP64RM() # reads the svp64 Remap entries for registers
788 assert bigendian == False, "error, bigendian not supported yet"
789
790 def __iter__(self):
791 yield from self.trans
792
793 def translate_one(self, insn, macros=None):
794 if macros is None:
795 macros = {}
796 macros.update(self.macros)
797 isa = self.isa
798 svp64 = self.svp64
799 insn_no_comments = insn.partition('#')[0]
800 # find first space, to get opcode
801 ls = insn_no_comments.split()
802 opcode = ls[0]
803 # now find opcode fields
804 fields = ''.join(ls[1:]).split(',')
805 mfields = list(map(str.strip, fields))
806 log("opcode, fields", ls, opcode, mfields)
807 fields = []
808 # macro substitution
809 for field in mfields:
810 fields.append(macro_subst(macros, field))
811 log("opcode, fields substed", ls, opcode, fields)
812
813 # identify if it is a special instruction
814 custom_insn_hook = CUSTOM_INSNS.get(opcode)
815 if custom_insn_hook is not None:
816 fields = tuple(map(to_number, fields))
817 insn_num = custom_insn_hook(fields)
818 log(opcode, bin(insn_num))
819 yield ".long 0x%X # %s" % (insn_num, insn)
820 return
821
822 # identify if is a svp64 mnemonic
823 if not opcode.startswith('sv.'):
824 yield insn # unaltered
825 return
826 opcode = opcode[3:] # strip leading "sv"
827
828 # start working on decoding the svp64 op: sv.basev30Bop/vec2/mode
829 opmodes = opcode.split("/") # split at "/"
830 v30b_op_orig = opmodes.pop(0) # first is the v3.0B
831 # check instruction ends with dot
832 rc_mode = v30b_op_orig.endswith('.')
833 if rc_mode:
834 v30b_op = v30b_op_orig[:-1]
835 else:
836 v30b_op = v30b_op_orig
837
838 # look up the 32-bit op (original, with "." if it has it)
839 if v30b_op_orig in isa.instr:
840 isa_instr = isa.instr[v30b_op_orig]
841 else:
842 raise Exception("opcode %s of '%s' not supported" %
843 (v30b_op_orig, insn))
844
845 # look up the svp64 op, first the original (with "." if it has it)
846 if v30b_op_orig in svp64.instrs:
847 rm = svp64.instrs[v30b_op_orig] # one row of the svp64 RM CSV
848 # then without the "." (if there was one)
849 elif v30b_op in svp64.instrs:
850 rm = svp64.instrs[v30b_op] # one row of the svp64 RM CSV
851 else:
852 raise Exception(f"opcode {v30b_op_orig!r} of "
853 f"{insn!r} not an svp64 instruction")
854
855 # get regs info e.g. "RT,RA,RB"
856 v30b_regs = isa_instr.regs[0]
857 log("v3.0B op", v30b_op, "Rc=1" if rc_mode else '')
858 log("v3.0B regs", opcode, v30b_regs)
859 log("RM", rm)
860
861 # right. the first thing to do is identify the ordering of
862 # the registers, by name. the EXTRA2/3 ordering is in
863 # rm['0']..rm['3'] but those fields contain the names RA, BB
864 # etc. we have to read the pseudocode to understand which
865 # reg is which in our instruction. sigh.
866
867 # first turn the svp64 rm into a "by name" dict, recording
868 # which position in the RM EXTRA it goes into
869 # also: record if the src or dest was a CR, for sanity-checking
870 # (elwidth overrides on CRs are banned)
871 decode = decode_extra(rm)
872 dest_reg_cr, src_reg_cr, svp64_src, svp64_dest = decode
873
874 log("EXTRA field index, src", svp64_src)
875 log("EXTRA field index, dest", svp64_dest)
876
877 # okaaay now we identify the field value (opcode N,N,N) with
878 # the pseudo-code info (opcode RT, RA, RB)
879 assert len(fields) == len(v30b_regs), \
880 "length of fields %s must match insn `%s` fields %s" % \
881 (str(v30b_regs), insn, str(fields))
882 opregfields = zip(fields, v30b_regs) # err that was easy
883
884 # now for each of those find its place in the EXTRA encoding
885 # note there is the possibility (for LD/ST-with-update) of
886 # RA occurring **TWICE**. to avoid it getting added to the
887 # v3.0B suffix twice, we spot it as a duplicate, here
888 extras = OrderedDict()
889 for idx, (field, regname) in enumerate(opregfields):
890 imm, regname = decode_imm(regname)
891 rtype = get_regtype(regname)
892 log(" idx find", rtype, idx, field, regname, imm)
893 if rtype is None:
894 # probably an immediate field, append it straight
895 extras[('imm', idx, False)] = (idx, field, None, None, None)
896 continue
897 extra = svp64_src.get(regname, None)
898 if extra is not None:
899 extra = ('s', extra, False) # not a duplicate
900 extras[extra] = (idx, field, regname, rtype, imm)
901 log(" idx src", idx, extra, extras[extra])
902 dextra = svp64_dest.get(regname, None)
903 log("regname in", regname, dextra)
904 if dextra is not None:
905 is_a_duplicate = extra is not None # duplicate spotted
906 dextra = ('d', dextra, is_a_duplicate)
907 extras[dextra] = (idx, field, regname, rtype, imm)
908 log(" idx dst", idx, extra, extras[dextra])
909
910 # great! got the extra fields in their associated positions:
911 # also we know the register type. now to create the EXTRA encodings
912 etype = rm['Etype'] # Extra type: EXTRA3/EXTRA2
913 ptype = rm['Ptype'] # Predication type: Twin / Single
914 extra_bits = 0
915 v30b_newfields = []
916 for extra_idx, (idx, field, rname, rtype, iname) in extras.items():
917 # is it a field we don't alter/examine? if so just put it
918 # into newfields
919 if rtype is None:
920 v30b_newfields.append(field)
921 continue
922
923 # identify if this is a ld/st immediate(reg) thing
924 ldst_imm = "(" in field and field[-1] == ')'
925 if ldst_imm:
926 immed, field = field[:-1].split("(")
927
928 field, regmode = decode_reg(field, macros=macros)
929 log(" ", extra_idx, rname, rtype,
930 regmode, iname, field, end=" ")
931
932 # see Mode field https://libre-soc.org/openpower/sv/svp64/
933 # XXX TODO: the following is a bit of a laborious repeated
934 # mess, which could (and should) easily be parameterised.
935 # XXX also TODO: the LD/ST modes which are different
936 # https://libre-soc.org/openpower/sv/ldst/
937
938 # rright. SVP64 register numbering is from 0 to 127
939 # for GPRs, FPRs *and* CR Fields, where for v3.0 the GPRs and RPFs
940 # are 0-31 and CR Fields are only 0-7. the SVP64 RM "Extra"
941 # area is used to extend the numbering from the 32-bit
942 # instruction, and also to record whether the register
943 # is scalar or vector. on a per-operand basis. this
944 # results in a slightly finnicky encoding: here we go...
945
946 # encode SV-GPR and SV-FPR field into extra, v3.0field
947 if rtype in ['GPR', 'FPR']:
948 sv_extra, field = get_extra_gpr(etype, regmode, field)
949 # now sanity-check. EXTRA3 is ok, EXTRA2 has limits
950 # (and shrink to a single bit if ok)
951 if etype == 'EXTRA2':
952 if regmode == 'scalar':
953 # range is r0-r63 in increments of 1
954 assert (sv_extra >> 1) == 0, \
955 "scalar GPR %s cannot fit into EXTRA2 %s" % \
956 (rname, str(extras[extra_idx]))
957 # all good: encode as scalar
958 sv_extra = sv_extra & 0b01
959 else:
960 # range is r0-r127 in increments of 2 (r0 r2 ... r126)
961 assert sv_extra & 0b01 == 0, \
962 "%s: vector field %s cannot fit " \
963 "into EXTRA2 %s" % \
964 (insn, rname, str(extras[extra_idx]))
965 # all good: encode as vector (bit 2 set)
966 sv_extra = 0b10 | (sv_extra >> 1)
967 elif regmode == 'vector':
968 # EXTRA3 vector bit needs marking
969 sv_extra |= 0b100
970
971 # encode SV-CR 3-bit field into extra, v3.0field.
972 # 3-bit is for things like BF and BFA
973 elif rtype == 'CR_3bit':
974 sv_extra, field = crf_extra(etype, rname, extra_idx,
975 regmode, field, extras)
976
977 # encode SV-CR 5-bit field into extra, v3.0field
978 # 5-bit is for things like BA BB BC BT etc.
979 # *sigh* this is the same as 3-bit except the 2 LSBs of the
980 # 5-bit field are passed through unaltered.
981 elif rtype == 'CR_5bit':
982 cr_subfield = field & 0b11 # record bottom 2 bits for later
983 field = field >> 2 # strip bottom 2 bits
984 # use the exact same 3-bit function for the top 3 bits
985 sv_extra, field = crf_extra(etype, rname, extra_idx,
986 regmode, field, extras)
987 # reconstruct the actual 5-bit CR field (preserving the
988 # bottom 2 bits, unaltered)
989 field = (field << 2) | cr_subfield
990
991 else:
992 raise Exception("no type match: %s" % rtype)
993
994 # capture the extra field info
995 log("=>", "%5s" % bin(sv_extra), field)
996 extras[extra_idx] = sv_extra
997
998 # append altered field value to v3.0b, differs for LDST
999 # note that duplicates are skipped e.g. EXTRA2 contains
1000 # *BOTH* s:RA *AND* d:RA which happens on LD/ST-with-update
1001 srcdest, idx, duplicate = extra_idx
1002 if duplicate: # skip adding to v3.0b fields, already added
1003 continue
1004 if ldst_imm:
1005 v30b_newfields.append(("%s(%s)" % (immed, str(field))))
1006 else:
1007 v30b_newfields.append(str(field))
1008
1009 log("new v3.0B fields", v30b_op, v30b_newfields)
1010 log("extras", extras)
1011
1012 # rright. now we have all the info. start creating SVP64 instruction.
1013 svp64_insn = SVP64Instruction.pair(prefix=0, suffix=0)
1014 svp64_prefix = svp64_insn.prefix
1015 svp64_rm = svp64_insn.prefix.rm
1016
1017 # begin with EXTRA fields
1018 for idx, sv_extra in extras.items():
1019 log(idx)
1020 if idx is None:
1021 continue
1022 if idx[0] == 'imm':
1023 continue
1024 srcdest, idx, duplicate = idx
1025 if etype == 'EXTRA2':
1026 svp64_rm.extra2[idx] = sv_extra
1027 else:
1028 svp64_rm.extra3[idx] = sv_extra
1029
1030 # identify if the op is a LD/ST.
1031 # see https://libre-soc.org/openpower/sv/ldst/
1032 is_ldst = rm['mode'] in [ 'LDST_IDX', 'LDST_IMM']
1033 is_ldst_idx = rm['mode'] == 'LDST_IDX'
1034 is_ld = v30b_op.startswith("l") and is_ldst
1035 is_st = v30b_op.startswith("s") and is_ldst
1036
1037 # branch-conditional detection
1038 is_bc = rm['mode'] == 'BRANCH'
1039
1040 # parts of svp64_rm
1041 mmode = 0 # bit 0
1042 pmask = 0 # bits 1-3
1043 destwid = 0 # bits 4-5
1044 srcwid = 0 # bits 6-7
1045 subvl = 0 # bits 8-9
1046 smask = 0 # bits 16-18 but only for twin-predication
1047 mode = 0 # bits 19-23
1048
1049 mask_m_specified = False
1050 has_pmask = False
1051 has_smask = False
1052
1053 saturation = None
1054 src_zero = 0
1055 dst_zero = 0
1056 sv_mode = None
1057
1058 mapreduce = False
1059 reverse_gear = False
1060 mapreduce_crm = False
1061
1062 predresult = False
1063 failfirst = False
1064 ldst_elstride = 0
1065 sea = False
1066
1067 vli = False
1068 sea = False
1069
1070 # ok let's start identifying opcode augmentation fields
1071 for encmode in opmodes:
1072 # predicate mask (src and dest)
1073 if encmode.startswith("m="):
1074 pme = encmode
1075 pmmode, pmask = decode_predicate(encmode[2:])
1076 smmode, smask = pmmode, pmask
1077 mmode = pmmode
1078 mask_m_specified = True
1079 # predicate mask (dest)
1080 elif encmode.startswith("dm="):
1081 pme = encmode
1082 pmmode, pmask = decode_predicate(encmode[3:])
1083 mmode = pmmode
1084 has_pmask = True
1085 # predicate mask (src, twin-pred)
1086 elif encmode.startswith("sm="):
1087 sme = encmode
1088 smmode, smask = decode_predicate(encmode[3:])
1089 mmode = smmode
1090 has_smask = True
1091 # vec2/3/4
1092 elif encmode.startswith("vec"):
1093 subvl = decode_subvl(encmode[3:])
1094 # elwidth (both src and dest, like mask)
1095 elif encmode.startswith("w="):
1096 destwid = decode_elwidth(encmode[2:])
1097 srcwid = decode_elwidth(encmode[2:])
1098 # just dest width
1099 elif encmode.startswith("dw="):
1100 destwid = decode_elwidth(encmode[3:])
1101 # just src width
1102 elif encmode.startswith("sw="):
1103 srcwid = decode_elwidth(encmode[3:])
1104 # element-strided LD/ST
1105 elif encmode == 'els':
1106 ldst_elstride = 1
1107 # in indexed mode, set sv_mode=0b01
1108 if is_ldst_idx:
1109 sv_mode = 0b01
1110 # saturation
1111 elif encmode == 'sats':
1112 assert sv_mode is None
1113 saturation = 1
1114 sv_mode = 0b10
1115 elif encmode == 'satu':
1116 assert sv_mode is None
1117 sv_mode = 0b10
1118 saturation = 0
1119 # predicate zeroing
1120 elif encmode == 'zz': # TODO, a lot more checking on legality
1121 dst_zero = 1 # NOT on cr_ops, that's RM[6]
1122 src_zero = 1
1123 elif encmode == 'sz':
1124 src_zero = 1
1125 elif encmode == 'dz':
1126 dst_zero = 1
1127 # failfirst
1128 elif encmode.startswith("ff="):
1129 assert sv_mode is None
1130 sv_mode = 0b01
1131 failfirst = decode_ffirst(encmode[3:])
1132 assert sea is False, "cannot use failfirst with signed-address"
1133 # predicate-result, interestingly same as fail-first
1134 elif encmode.startswith("pr="):
1135 assert sv_mode is None
1136 sv_mode = 0b11
1137 predresult = decode_ffirst(encmode[3:])
1138 # map-reduce mode, reverse-gear
1139 elif encmode == 'mrr':
1140 assert sv_mode is None
1141 sv_mode = 0b00
1142 mapreduce = True
1143 reverse_gear = True
1144 # map-reduce mode
1145 elif encmode == 'mr':
1146 assert sv_mode is None
1147 sv_mode = 0b00
1148 mapreduce = True
1149 elif encmode == 'crm': # CR on map-reduce
1150 assert sv_mode is None
1151 sv_mode = 0b00
1152 mapreduce_crm = True
1153 elif encmode == 'vli':
1154 assert sv_mode == 0b01 # only allow ff mode
1155 vli = True
1156 elif encmode == 'sea':
1157 assert sv_mode in (None, 0b00, 0b01)
1158 assert is_ldst_idx
1159 sea = True
1160 assert failfirst is False, "cannot use ffirst+signed-address"
1161 elif is_bc:
1162 if encmode == 'all':
1163 svp64_rm.branch.ALL = 1
1164 elif encmode == 'snz':
1165 svp64_rm.branch.sz = 1
1166 svp64_rm.branch.SNZ = 1
1167 elif encmode == 'sl':
1168 svp64_rm.branch.SL = 1
1169 elif encmode == 'slu':
1170 svp64_rm.branch.SLu = 1
1171 elif encmode == 'lru':
1172 svp64_rm.branch.LRu = 1
1173 elif encmode == 'vs':
1174 svp64_rm.branch.VLS = 1
1175 elif encmode == 'vsi':
1176 svp64_rm.branch.VLS = 1
1177 svp64_rm.branch.vls.VLI = 1
1178 elif encmode == 'vsb':
1179 svp64_rm.branch.VLS = 1
1180 svp64_rm.branch.vls.VSb = 1
1181 elif encmode == 'vsbi':
1182 svp64_rm.branch.VLS = 1
1183 svp64_rm.branch.vls.VSb = 1
1184 svp64_rm.branch.vls.VLI = 1
1185 elif encmode == 'ctr':
1186 svp64_rm.branch.CTR = 1
1187 elif encmode == 'cti':
1188 svp64_rm.branch.CTR = 1
1189 svp64_rm.branch.ctr.CTi = 1
1190 else:
1191 raise AssertionError("unknown encmode %s" % encmode)
1192 else:
1193 raise AssertionError("unknown encmode %s" % encmode)
1194
1195 if ptype == '2P':
1196 # since m=xx takes precedence (overrides) sm=xx and dm=xx,
1197 # treat them as mutually exclusive
1198 if mask_m_specified:
1199 assert not has_smask,\
1200 "cannot have both source-mask and predicate mask"
1201 assert not has_pmask,\
1202 "cannot have both dest-mask and predicate mask"
1203 # since the default is INT predication (ALWAYS), if you
1204 # specify one CR mask, you must specify both, to avoid
1205 # mixing INT and CR reg types
1206 if has_pmask and pmmode == 1:
1207 assert has_smask, \
1208 "need explicit source-mask in CR twin predication"
1209 if has_smask and smmode == 1:
1210 assert has_pmask, \
1211 "need explicit dest-mask in CR twin predication"
1212 # sanity-check that 2Pred mask is same mode
1213 if has_pmask and has_smask:
1214 assert smmode == pmmode, \
1215 "predicate masks %s and %s must be same reg type" % \
1216 (pme, sme)
1217
1218 # sanity-check that twin-predication mask only specified in 2P mode
1219 if ptype == '1P':
1220 assert not has_smask, \
1221 "source-mask can only be specified on Twin-predicate ops"
1222 assert not has_pmask, \
1223 "dest-mask can only be specified on Twin-predicate ops"
1224
1225 # construct the mode field, doing sanity-checking along the way
1226
1227 if src_zero:
1228 assert has_smask or mask_m_specified, \
1229 "src zeroing requires a source predicate"
1230 if dst_zero:
1231 assert has_pmask or mask_m_specified, \
1232 "dest zeroing requires a dest predicate"
1233
1234 # okaaay, so there are 4 different modes, here, which will be
1235 # partly-merged-in: is_ldst is merged in with "normal", but
1236 # is_bc is so different it's done separately. likewise is_cr
1237 # (when it is done). here are the maps:
1238
1239 # for "normal" arithmetic: https://libre-soc.org/openpower/sv/normal/
1240 """
1241 | 0-1 | 2 | 3 4 | description |
1242 | --- | --- |---------|-------------------------- |
1243 | 00 | 0 | dz sz | simple mode |
1244 | 00 | 1 | 0 RG | scalar reduce mode (mapreduce) |
1245 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
1246 | 01 | inv | VLi RC1 | Rc=0: ffirst z/nonz |
1247 | 10 | N | dz sz | sat mode: N=0/1 u/s |
1248 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1249 | 11 | inv | zz RC1 | Rc=0: pred-result z/nonz |
1250 """
1251
1252 # https://libre-soc.org/openpower/sv/ldst/
1253 # for LD/ST-immediate:
1254 """
1255 | 0-1 | 2 | 3 4 | description |
1256 | --- | --- |---------|--------------------------- |
1257 | 00 | 0 | zz els | normal mode |
1258 | 00 | 1 | / / | reserved |
1259 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
1260 | 01 | inv | els RC1 | Rc=0: ffirst z/nonz |
1261 | 10 | N | zz els | sat mode: N=0/1 u/s |
1262 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1263 | 11 | inv | els RC1 | Rc=0: pred-result z/nonz |
1264 """
1265
1266 # for LD/ST-indexed (RA+RB):
1267 """
1268 | 0-1 | 2 | 3 4 | description |
1269 | --- | --- |---------|----------------------------- |
1270 | 00 | SEA | dz sz | normal mode |
1271 | 01 | SEA | dz sz | strided (scalar only source) |
1272 | 10 | N | dz sz | sat mode: N=0/1 u/s |
1273 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1274 | 11 | inv | dz RC1 | Rc=0: pred-result z/nonz |
1275 """
1276
1277 # and leaving out branches and cr_ops for now because they're
1278 # under development
1279 """ TODO branches and cr_ops
1280 """
1281
1282 if is_bc:
1283 sv_mode = int(svp64_rm.mode[0, 1])
1284 if src_zero:
1285 svp64_rm.branch.sz = 1
1286
1287 else:
1288 ######################################
1289 # "element-strided" mode, ldst_idx
1290 if sv_mode == 0b01 and is_ldst_idx:
1291 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1292 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1293 mode |= sea << SVP64MODE.SEA # el-strided
1294
1295 ######################################
1296 # "normal" mode
1297 elif sv_mode is None:
1298 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1299 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1300 if is_ldst:
1301 # TODO: for now, LD/ST-indexed is ignored.
1302 mode |= ldst_elstride << SVP64MODE.ELS_NORMAL # el-strided
1303 else:
1304 # TODO, reduce and subvector mode
1305 # 00 1 dz CRM reduce mode (mapreduce), SUBVL=1
1306 # 00 1 SVM CRM subvector reduce mode, SUBVL>1
1307 pass
1308 sv_mode = 0b00
1309
1310 ######################################
1311 # "mapreduce" modes
1312 elif sv_mode == 0b00:
1313 mode |= (0b1 << SVP64MODE.REDUCE) # sets mapreduce
1314 assert dst_zero == 0, "dest-zero not allowed in mapreduce mode"
1315 if reverse_gear:
1316 mode |= (0b1 << SVP64MODE.RG) # sets Reverse-gear mode
1317 if mapreduce_crm:
1318 mode |= (0b1 << SVP64MODE.CRM) # sets CRM mode
1319 assert rc_mode, "CRM only allowed when Rc=1"
1320 # bit of weird encoding to jam zero-pred or SVM mode in.
1321 # SVM mode can be enabled only when SUBVL=2/3/4 (vec2/3/4)
1322 if subvl == 0:
1323 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1324
1325 ######################################
1326 # "failfirst" modes
1327 elif sv_mode == 0b01:
1328 assert src_zero == 0, "dest-zero not allowed in failfirst mode"
1329 if failfirst == 'RC1':
1330 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1331 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1332 assert rc_mode == False, "ffirst RC1 only ok when Rc=0"
1333 elif failfirst == '~RC1':
1334 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1335 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1336 mode |= (0b1 << SVP64MODE.INV) # ... with inversion
1337 assert rc_mode == False, "ffirst RC1 only ok when Rc=0"
1338 else:
1339 assert dst_zero == 0, "dst-zero not allowed in ffirst BO"
1340 assert rc_mode, "ffirst BO only possible when Rc=1"
1341 mode |= (failfirst << SVP64MODE.BO_LSB) # set BO
1342
1343 ######################################
1344 # "saturation" modes
1345 elif sv_mode == 0b10:
1346 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1347 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1348 mode |= (saturation << SVP64MODE.N) # signed/us saturation
1349
1350 ######################################
1351 # "predicate-result" modes. err... code-duplication from ffirst
1352 elif sv_mode == 0b11:
1353 assert src_zero == 0, "dest-zero not allowed in predresult mode"
1354 if predresult == 'RC1':
1355 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1356 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1357 assert rc_mode == False, "pr-mode RC1 only ok when Rc=0"
1358 elif predresult == '~RC1':
1359 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1360 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1361 mode |= (0b1 << SVP64MODE.INV) # ... with inversion
1362 assert rc_mode == False, "pr-mode RC1 only ok when Rc=0"
1363 else:
1364 assert dst_zero == 0, "dst-zero not allowed in pr-mode BO"
1365 assert rc_mode, "pr-mode BO only possible when Rc=1"
1366 mode |= (predresult << SVP64MODE.BO_LSB) # set BO
1367
1368 # whewww.... modes all done :)
1369 # now put into svp64_rm, but respect MSB0 order
1370 if sv_mode&1:
1371 mode |= (0b1<<SVP64MODE.MOD2_LSB)
1372 if sv_mode&2:
1373 mode |= (0b1<<SVP64MODE.MOD2_MSB)
1374
1375 if sea:
1376 mode |= (0b1 << SVP64MODE.SEA)
1377
1378 if not is_bc:
1379 svp64_rm.mode = mode # mode: bits 19-23
1380 if vli:
1381 svp64_rm.normal.ffrc0.VLi = 1
1382
1383 # put in predicate masks into svp64_rm
1384 if ptype == '2P':
1385 svp64_rm.smask = smask # source pred: bits 16-18
1386
1387 # put in elwidths unless bc
1388 svp64_rm.ewsrc = srcwid # srcwid: bits 6-7
1389 svp64_rm.elwidth = destwid # destwid: bits 4-5
1390
1391 svp64_rm.mmode = mmode # mask mode: bit 0
1392 svp64_rm.mask = pmask # 1-pred: bits 1-3
1393 svp64_rm.subvl = subvl # and subvl: bits 8-9
1394
1395 # nice debug printout. (and now for something completely different)
1396 # https://youtu.be/u0WOIwlXE9g?t=146
1397 svp64_rm_value = int(svp64_rm)
1398 log("svp64_rm", hex(svp64_rm_value), bin(svp64_rm_value))
1399 log(" mmode 0 :", bin(mmode))
1400 log(" pmask 1-3 :", bin(pmask))
1401 log(" dstwid 4-5 :", bin(destwid))
1402 log(" srcwid 6-7 :", bin(srcwid))
1403 log(" subvl 8-9 :", bin(subvl))
1404 log(" mode 19-23:", bin(svp64_rm.mode))
1405 offs = 2 if etype == 'EXTRA2' else 3 # 2 or 3 bits
1406 for idx, sv_extra in extras.items():
1407 if idx is None:
1408 continue
1409 if idx[0] == 'imm':
1410 continue
1411 srcdest, idx, duplicate = idx
1412 start = (10+idx*offs)
1413 end = start + offs-1
1414 log(" extra%d %2d-%2d:" % (idx, start, end),
1415 bin(sv_extra))
1416 if ptype == '2P':
1417 log(" smask 16-17:", bin(smask))
1418 log()
1419
1420 # update prefix PO and ID (aka PID)
1421 svp64_prefix.po = 0x1
1422 svp64_prefix.id = 0b11
1423
1424 # fiinally yield the svp64 prefix and the thingy. v3.0b opcode
1425 rc = '.' if rc_mode else ''
1426 yield ".long 0x%08x" % int(svp64_prefix)
1427 log(v30b_op, v30b_newfields)
1428
1429 v30b_op_rc = v30b_op
1430 if not v30b_op.endswith('.'):
1431 v30b_op_rc += rc
1432
1433 # svstep is weird
1434 # FIXME(lkcl): should sv.svstep be like svstep?
1435 if v30b_op_rc in ("svstep", "svstep."):
1436 # compensate for `SVi -= 1` in svstep()
1437 v30b_newfields[1] = str(int(v30b_newfields[1]) + 1)
1438
1439 custom_insn_hook = CUSTOM_INSNS.get(v30b_op_rc)
1440 if custom_insn_hook is not None:
1441 fields = tuple(map(to_number, v30b_newfields))
1442 insn_num = custom_insn_hook(fields)
1443 log(opcode, bin(insn_num))
1444 yield ".long 0x%X # %s" % (insn_num, insn)
1445 return
1446 # argh, sv.fmadds etc. need to be done manually
1447 elif v30b_op == 'ffmadds':
1448 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1449 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1450 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1451 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1452 opcode |= int(v30b_newfields[3]) << (32-26) # FRC
1453 opcode |= 0b00101 << (32-31) # bits 26-30
1454 if rc:
1455 opcode |= 1 # Rc, bit 31.
1456 yield ".long 0x%x" % opcode
1457 # argh, sv.fdmadds need to be done manually
1458 elif v30b_op == 'fdmadds':
1459 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1460 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1461 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1462 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1463 opcode |= int(v30b_newfields[3]) << (32-26) # FRC
1464 opcode |= 0b11011 << (32-31) # bits 26-30
1465 if rc:
1466 opcode |= 1 # Rc, bit 31.
1467 yield ".long 0x%x" % opcode
1468 # argh, sv.ffadds etc. need to be done manually
1469 elif v30b_op == 'ffadds':
1470 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1471 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1472 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1473 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1474 opcode |= 0b1111100000 << (32-31) # bits 21-30
1475 if rc:
1476 opcode |= 1 # Rc, bit 31.
1477 yield ".long 0x%x" % opcode
1478 else:
1479 if not v30b_op.endswith('.'):
1480 v30b_op += rc
1481 yield "%s %s" % (v30b_op, ", ".join(v30b_newfields))
1482 for (name, span) in svp64_insn.traverse("SVP64"):
1483 value = svp64_insn.storage[span]
1484 log(name, f"{value.value:0{value.bits}b}", span)
1485 log("new v3.0B fields", v30b_op, v30b_newfields)
1486
1487 def translate(self, lst):
1488 for insn in lst:
1489 yield from self.translate_one(insn)
1490
1491
1492 def macro_subst(macros, txt):
1493 again = True
1494 log("subst", txt, macros)
1495 while again:
1496 again = False
1497 for macro, value in macros.items():
1498 if macro == txt:
1499 again = True
1500 replaced = txt.replace(macro, value)
1501 log("macro", txt, "replaced", replaced, macro, value)
1502 txt = replaced
1503 continue
1504 toreplace = '%s.s' % macro
1505 if toreplace == txt:
1506 again = True
1507 replaced = txt.replace(toreplace, "%s.s" % value)
1508 log("macro", txt, "replaced", replaced, toreplace, value)
1509 txt = replaced
1510 continue
1511 toreplace = '%s.v' % macro
1512 if toreplace == txt:
1513 again = True
1514 replaced = txt.replace(toreplace, "%s.v" % value)
1515 log("macro", txt, "replaced", replaced, toreplace, value)
1516 txt = replaced
1517 continue
1518 toreplace = '*%s' % macro
1519 if toreplace in txt:
1520 again = True
1521 replaced = txt.replace(toreplace, '*%s' % value)
1522 log("macro", txt, "replaced", replaced, toreplace, value)
1523 txt = replaced
1524 continue
1525 toreplace = '(%s)' % macro
1526 if toreplace in txt:
1527 again = True
1528 replaced = txt.replace(toreplace, '(%s)' % value)
1529 log("macro", txt, "replaced", replaced, toreplace, value)
1530 txt = replaced
1531 continue
1532 log(" processed", txt)
1533 return txt
1534
1535
1536 def get_ws(line):
1537 # find whitespace
1538 ws = ''
1539 while line:
1540 if not line[0].isspace():
1541 break
1542 ws += line[0]
1543 line = line[1:]
1544 return ws, line
1545
1546
1547 def asm_process():
1548 # get an input file and an output file
1549 args = sys.argv[1:]
1550 if len(args) == 0:
1551 infile = sys.stdin
1552 outfile = sys.stdout
1553 # read the whole lot in advance in case of in-place
1554 lines = list(infile.readlines())
1555 elif len(args) != 2:
1556 print("pysvp64asm [infile | -] [outfile | -]", file=sys.stderr)
1557 exit(0)
1558 else:
1559 if args[0] == '--':
1560 infile = sys.stdin
1561 else:
1562 infile = open(args[0], "r")
1563 # read the whole lot in advance in case of in-place overwrite
1564 lines = list(infile.readlines())
1565
1566 if args[1] == '--':
1567 outfile = sys.stdout
1568 else:
1569 outfile = open(args[1], "w")
1570
1571 # read the line, look for custom insn, process it
1572 macros = {} # macros which start ".set"
1573 isa = SVP64Asm([])
1574 for line in lines:
1575 op = line.split("#")[0].strip()
1576 # identify macros
1577 if op.startswith(".set"):
1578 macro = op[4:].split(",")
1579 (macro, value) = map(str.strip, macro)
1580 macros[macro] = value
1581 if not op.startswith('sv.') and not op.startswith(tuple(CUSTOM_INSNS)):
1582 outfile.write(line)
1583 continue
1584
1585 (ws, line) = get_ws(line)
1586 lst = isa.translate_one(op, macros)
1587 lst = '; '.join(lst)
1588 outfile.write("%s%s # %s\n" % (ws, lst, op))
1589
1590
1591 if __name__ == '__main__':
1592 lst = ['slw 3, 1, 4',
1593 'extsw 5, 3',
1594 'sv.extsw 5, 3',
1595 'sv.cmpi 5, 1, 3, 2',
1596 'sv.setb 5, 31',
1597 'sv.isel 64.v, 3, 2, 65.v',
1598 'sv.setb/dm=r3/sm=1<<r3 5, 31',
1599 'sv.setb/m=r3 5, 31',
1600 'sv.setb/vec2 5, 31',
1601 'sv.setb/sw=8/ew=16 5, 31',
1602 'sv.extsw./ff=eq 5, 31',
1603 'sv.extsw./satu/sz/dz/sm=r3/dm=r3 5, 31',
1604 'sv.extsw./pr=eq 5.v, 31',
1605 'sv.add. 5.v, 2.v, 1.v',
1606 'sv.add./m=r3 5.v, 2.v, 1.v',
1607 ]
1608 lst += [
1609 'sv.stw 5.v, 4(1.v)',
1610 'sv.ld 5.v, 4(1.v)',
1611 'setvl. 2, 3, 4, 0, 1, 1',
1612 'sv.setvl. 2, 3, 4, 0, 1, 1',
1613 ]
1614 lst = [
1615 "sv.stfsu 0.v, 16(4.v)",
1616 ]
1617 lst = [
1618 "sv.stfsu/els 0.v, 16(4)",
1619 ]
1620 lst = [
1621 'sv.add./mr 5.v, 2.v, 1.v',
1622 ]
1623 macros = {'win2': '50', 'win': '60'}
1624 lst = [
1625 'sv.addi win2.v, win.v, -1',
1626 'sv.add./mrr 5.v, 2.v, 1.v',
1627 #'sv.lhzsh 5.v, 11(9.v), 15',
1628 #'sv.lwzsh 5.v, 11(9.v), 15',
1629 'sv.ffmadds 6.v, 2.v, 4.v, 6.v',
1630 ]
1631 lst = [
1632 #'sv.fmadds 0.v, 8.v, 16.v, 4.v',
1633 #'sv.ffadds 0.v, 8.v, 4.v',
1634 'svremap 11, 0, 1, 2, 3, 2, 1',
1635 'svshape 8, 1, 1, 1, 0',
1636 'svshape 8, 1, 1, 1, 1',
1637 ]
1638 lst = [
1639 #'sv.lfssh 4.v, 11(8.v), 15',
1640 #'sv.lwzsh 4.v, 11(8.v), 15',
1641 #'sv.svstep. 2.v, 4, 0',
1642 #'sv.fcfids. 48.v, 64.v',
1643 'sv.fcoss. 80.v, 0.v',
1644 'sv.fcoss. 20.v, 0.v',
1645 ]
1646 lst = [
1647 'sv.bc/all 3,12,192',
1648 'sv.bclr/vsbi 3,81.v,192',
1649 'sv.ld 5.v, 4(1.v)',
1650 'sv.svstep. 2.v, 4, 0',
1651 ]
1652 lst = [
1653 'maxs 3,12,5',
1654 'maxs. 3,12,5',
1655 'avgadd 3,12,5',
1656 'absdu 3,12,5',
1657 'absds 3,12,5',
1658 'absdacu 3,12,5',
1659 'absdacs 3,12,5',
1660 'cprop 3,12,5',
1661 'svindex 0,0,1,0,0,0,0',
1662 ]
1663 lst = [
1664 'sv.svstep./m=r3 2.v, 4, 0',
1665 'ternlogi 0,0,0,0x5',
1666 'fmvis 5,65535',
1667 'fmvis 5,1',
1668 'fmvis 5,2',
1669 'fmvis 5,4',
1670 'fmvis 5,8',
1671 'fmvis 5,16',
1672 'fmvis 5,32',
1673 'fmvis 5,64',
1674 'fmvis 5,32768',
1675 ]
1676 lst = [
1677 'sv.andi. *80, *80, 1',
1678 'sv.ffmadds. 6.v, 2.v, 4.v, 6.v', # incorrectly inserted 32-bit op
1679 'sv.ffmadds 6.v, 2.v, 4.v, 6.v', # correctly converted to .long
1680 'svshape2 8, 1, 31, 7, 1, 1',
1681 'sv.ld 5.v, 4(1.v)',
1682 'sv.stw 5.v, 4(1.v)',
1683 'sv.bc/all 3,12,192',
1684 'pcdec. 0,0,0,0,0',
1685 ]
1686 isa = SVP64Asm(lst, macros=macros)
1687 log("list:\n", "\n\t".join(list(isa)))
1688 # running svp64.py is designed to test hard-coded lists
1689 # (above) - which strictly speaking should all be unit tests.
1690 # if you need to actually do assembler translation at the
1691 # commandline use "pysvp64asm" - see setup.py
1692 # XXX NO. asm_process()