pysvp64db: fix traversal
[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("maddedu", XO=50),
569 _insn("maddedus", XO=57),
570 _insn("divmod2du", XO=58),
571 _insn("pcdec.", XO=56),
572 )
573 def va_form(fields, XO):
574 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
575 # 1.6.21.1 VA-FORM
576 # |0 |6 |11 |16 |21 |26 |
577 # | PO | RT | RA | RB | RC | XO |
578 PO = 4
579 (RT, RA, RB, RC) = fields
580 return instruction(
581 (PO, 0, 5),
582 (RT, 6, 10),
583 (RA, 11, 15),
584 (RB, 16, 20),
585 (RC, 21, 25),
586 (XO, 26, 31),
587 )
588
589
590 @_custom_insns(
591 _insn("shadd", PO=22, XO=0b01101110, Rc=0),
592 _insn("shadd.", PO=22, XO=0b01101110, Rc=1),
593 _insn("shadduw", PO=22, XO=0b11101110, Rc=0),
594 _insn("shadduw.", PO=22, XO=0b11101110, Rc=1),
595 )
596 def Z23(fields, PO, XO, Rc):
597 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
598 # 1.6.27 Z23-FORM
599 # |0 |6 |11 |15 |16 |21 |23 |31 |
600 # | PO | RT | RA | RB |sm | XO |Rc |
601 (RT, RA, RB, sm) = fields
602 return instruction(
603 (PO, 0, 5),
604 (RT, 6, 10),
605 (RA, 11, 15),
606 (RB, 16, 20),
607 (sm, 21, 22),
608 (XO, 23, 30),
609 (Rc, 31, 31),
610 )
611
612
613 @_custom_insns(
614 _insn("dsld", XO=26, Rc=0), # minor_4=52 (26<<1 | Rc=0)
615 _insn("dsld.", XO=26, Rc=1), # minor_4=53 (26<<1 | Rc=1)
616 _insn("dsrd", XO=27, Rc=0), # minor_4=54 (27<<1 | Rc=0)
617 _insn("dsrd.", XO=27, Rc=1), # minor_4=55 (27<<1 | Rc=1)
618 )
619 def dsld_dsrd(fields, XO, Rc):
620 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
621 # 1.6.21.1 VA2-FORM
622 # |0 |6 |11 |16 |21 |26 |31|
623 # | PO | RT | RA | RB | RC | XO |Rc|
624 PO = 4
625 (RT, RA, RB, RC) = fields
626 return instruction(
627 (PO, 0, 5),
628 (RT, 6, 10),
629 (RA, 11, 15),
630 (RB, 16, 20),
631 (RC, 21, 25),
632 (XO, 26, 30),
633 (Rc, 31, 31),
634 )
635
636
637 # decode GPR into sv extra
638 def get_extra_gpr(etype, regmode, field):
639 if regmode == 'scalar':
640 # cut into 2-bits 5-bits SS FFFFF
641 sv_extra = field >> 5
642 field = field & 0b11111
643 else:
644 # cut into 5-bits 2-bits FFFFF SS
645 sv_extra = field & 0b11
646 field = field >> 2
647 return sv_extra, field
648
649
650 # decode 3-bit CR into sv extra
651 def get_extra_cr_3bit(etype, regmode, field):
652 if regmode == 'scalar':
653 # cut into 2-bits 3-bits SS FFF
654 sv_extra = field >> 3
655 field = field & 0b111
656 else:
657 # cut into 3-bits 4-bits FFF SSSS but will cut 2 zeros off later
658 sv_extra = field & 0b1111
659 field = field >> 4
660 return sv_extra, field
661
662
663 # decodes SUBVL
664 def decode_subvl(encoding):
665 pmap = {'2': 0b01, '3': 0b10, '4': 0b11}
666 assert encoding in pmap, \
667 "encoding %s for SUBVL not recognised" % encoding
668 return pmap[encoding]
669
670
671 # decodes elwidth
672 def decode_elwidth(encoding):
673 pmap = {'8': 0b11, '16': 0b10, '32': 0b01}
674 assert encoding in pmap, \
675 "encoding %s for elwidth not recognised" % encoding
676 return pmap[encoding]
677
678
679 # decodes predicate register encoding
680 def decode_predicate(encoding):
681 pmap = { # integer
682 '1<<r3': (0, 0b001),
683 'r3': (0, 0b010),
684 '~r3': (0, 0b011),
685 'r10': (0, 0b100),
686 '~r10': (0, 0b101),
687 'r30': (0, 0b110),
688 '~r30': (0, 0b111),
689 # CR
690 'lt': (1, 0b000),
691 'nl': (1, 0b001), 'ge': (1, 0b001), # same value
692 'gt': (1, 0b010),
693 'ng': (1, 0b011), 'le': (1, 0b011), # same value
694 'eq': (1, 0b100),
695 'ne': (1, 0b101),
696 'so': (1, 0b110), 'un': (1, 0b110), # same value
697 'ns': (1, 0b111), 'nu': (1, 0b111), # same value
698 }
699 assert encoding in pmap, \
700 "encoding %s for predicate not recognised" % encoding
701 return pmap[encoding]
702
703
704 # decodes "Mode" in similar way to BO field (supposed to, anyway)
705 def decode_bo(encoding):
706 pmap = { # TODO: double-check that these are the same as Branch BO
707 'lt': 0b000,
708 'nl': 0b001, 'ge': 0b001, # same value
709 'gt': 0b010,
710 'ng': 0b011, 'le': 0b011, # same value
711 'eq': 0b100,
712 'ne': 0b101,
713 'so': 0b110, 'un': 0b110, # same value
714 'ns': 0b111, 'nu': 0b111, # same value
715 }
716 assert encoding in pmap, \
717 "encoding %s for BO Mode not recognised" % encoding
718 # barse-ackwards MSB0/LSB0. sigh. this would be nice to be the
719 # same as the decode_predicate() CRfield table above, but (inv,CRbit)
720 # is how it is in the spec [decode_predicate is (CRbit,inv)]
721 mapped = pmap[encoding]
722 si = SelectableInt(0, 3)
723 si[0] = mapped & 1 # inv
724 si[1:3] = mapped >> 1 # CR
725 return int(si)
726
727
728 # partial-decode fail-first mode
729 def decode_ffirst(encoding):
730 if encoding in ['RC1', '~RC1']:
731 return encoding
732 return decode_bo(encoding)
733
734
735 def decode_reg(field, macros=None):
736 if macros is None:
737 macros = {}
738 # decode the field number. "5.v" or "3.s" or "9"
739 # and now also "*0", and "*%0". note: *NOT* to add "*%rNNN" etc.
740 # https://bugs.libre-soc.org/show_bug.cgi?id=884#c0
741 if field.startswith(("*%", "*")):
742 if field.startswith("*%"):
743 field = field[2:]
744 else:
745 field = field[1:]
746 while field in macros:
747 field = macros[field]
748 return int(field), "vector" # actual register number
749
750 # try old convention (to be retired)
751 field = field.split(".")
752 regmode = 'scalar' # default
753 if len(field) == 2:
754 if field[1] == 's':
755 regmode = 'scalar'
756 elif field[1] == 'v':
757 regmode = 'vector'
758 field = int(field[0]) # actual register number
759 return field, regmode
760
761
762 def decode_imm(field):
763 ldst_imm = "(" in field and field[-1] == ')'
764 if ldst_imm:
765 return field[:-1].split("(")
766 else:
767 return None, field
768
769
770 def crf_extra(etype, rname, extra_idx, regmode, field, extras):
771 """takes a CR Field number (CR0-CR127), splits into EXTRA2/3 and v3.0
772 the scalar/vector mode (crNN.v or crNN.s) changes both the format
773 of the EXTRA2/3 encoding as well as what range of registers is possible.
774 this function can be used for both BF/BFA and BA/BB/BT by first removing
775 the bottom 2 bits of BA/BB/BT then re-instating them after encoding.
776 see https://libre-soc.org/openpower/sv/svp64/appendix/#cr_extra
777 for specification
778 """
779 sv_extra, field = get_extra_cr_3bit(etype, regmode, field)
780 # now sanity-check (and shrink afterwards)
781 if etype == 'EXTRA2':
782 # 3-bit CR Field (BF, BFA) EXTRA2 encoding
783 if regmode == 'scalar':
784 # range is CR0-CR15 in increments of 1
785 assert (sv_extra >> 1) == 0, \
786 "scalar CR %s cannot fit into EXTRA2 %s" % \
787 (rname, str(extras[extra_idx]))
788 # all good: encode as scalar
789 sv_extra = sv_extra & 0b01
790 else: # vector
791 # range is CR0-CR127 in increments of 16
792 assert sv_extra & 0b111 == 0, \
793 "vector CR %s cannot fit into EXTRA2 %s" % \
794 (rname, str(extras[extra_idx]))
795 # all good: encode as vector (bit 2 set)
796 sv_extra = 0b10 | (sv_extra >> 3)
797 else:
798 # 3-bit CR Field (BF, BFA) EXTRA3 encoding
799 if regmode == 'scalar':
800 # range is CR0-CR31 in increments of 1
801 assert (sv_extra >> 2) == 0, \
802 "scalar CR %s cannot fit into EXTRA3 %s" % \
803 (rname, str(extras[extra_idx]))
804 # all good: encode as scalar
805 sv_extra = sv_extra & 0b11
806 else: # vector
807 # range is CR0-CR127 in increments of 8
808 assert sv_extra & 0b11 == 0, \
809 "vector CR %s cannot fit into EXTRA3 %s" % \
810 (rname, str(extras[extra_idx]))
811 # all good: encode as vector (bit 3 set)
812 sv_extra = 0b100 | (sv_extra >> 2)
813 return sv_extra, field
814
815
816 def to_number(field):
817 if field.startswith("0x"):
818 return eval(field)
819 if field.startswith("0b"):
820 return eval(field)
821 return int(field)
822
823
824 db = Database(find_wiki_dir())
825
826
827 # decodes svp64 assembly listings and creates EXT001 svp64 prefixes
828 class SVP64Asm:
829 def __init__(self, lst, bigendian=False, macros=None):
830 if macros is None:
831 macros = {}
832 self.macros = macros
833 self.lst = lst
834 self.trans = self.translate(lst)
835 self.isa = ISA() # reads the v3.0B pseudo-code markdown files
836 self.svp64 = SVP64RM() # reads the svp64 Remap entries for registers
837 assert bigendian == False, "error, bigendian not supported yet"
838
839 def __iter__(self):
840 yield from self.trans
841
842 def translate_one(self, insn, macros=None):
843 if macros is None:
844 macros = {}
845 macros.update(self.macros)
846 isa = self.isa
847 svp64 = self.svp64
848 insn_no_comments = insn.partition('#')[0]
849 # find first space, to get opcode
850 ls = insn_no_comments.split()
851 opcode = ls[0]
852 # now find opcode fields
853 fields = ''.join(ls[1:]).split(',')
854 mfields = list(map(str.strip, fields))
855 log("opcode, fields", ls, opcode, mfields)
856 fields = []
857 # macro substitution
858 for field in mfields:
859 fields.append(macro_subst(macros, field))
860 log("opcode, fields substed", ls, opcode, fields)
861
862 # identify if it is a special instruction
863 custom_insn_hook = CUSTOM_INSNS.get(opcode)
864 if custom_insn_hook is not None:
865 fields = tuple(map(to_number, fields))
866 insn_num = custom_insn_hook(fields)
867 log(opcode, bin(insn_num))
868 yield ".long 0x%X # %s" % (insn_num, insn)
869 return
870
871 # identify if is a svp64 mnemonic
872 if not opcode.startswith('sv.'):
873 yield insn # unaltered
874 return
875 opcode = opcode[3:] # strip leading "sv"
876
877 # start working on decoding the svp64 op: sv.basev30Bop/vec2/mode
878 opmodes = opcode.split("/") # split at "/"
879 v30b_op_orig = opmodes.pop(0) # first is the v3.0B
880 # check instruction ends with dot
881 rc_mode = v30b_op_orig.endswith('.')
882 if rc_mode:
883 v30b_op = v30b_op_orig[:-1]
884 else:
885 v30b_op = v30b_op_orig
886
887 # look up the 32-bit op (original, with "." if it has it)
888 if v30b_op_orig in isa.instr:
889 isa_instr = isa.instr[v30b_op_orig]
890 else:
891 raise Exception("opcode %s of '%s' not supported" %
892 (v30b_op_orig, insn))
893
894 # look up the svp64 op, first the original (with "." if it has it)
895 if v30b_op_orig in svp64.instrs:
896 rm = svp64.instrs[v30b_op_orig] # one row of the svp64 RM CSV
897 # then without the "." (if there was one)
898 elif v30b_op in svp64.instrs:
899 rm = svp64.instrs[v30b_op] # one row of the svp64 RM CSV
900 else:
901 raise Exception(f"opcode {v30b_op_orig!r} of "
902 f"{insn!r} not an svp64 instruction")
903
904 # get regs info e.g. "RT,RA,RB"
905 v30b_regs = isa_instr.regs[0]
906 log("v3.0B op", v30b_op, "Rc=1" if rc_mode else '')
907 log("v3.0B regs", opcode, v30b_regs)
908 log("RM", rm)
909
910 # right. the first thing to do is identify the ordering of
911 # the registers, by name. the EXTRA2/3 ordering is in
912 # rm['0']..rm['3'] but those fields contain the names RA, BB
913 # etc. we have to read the pseudocode to understand which
914 # reg is which in our instruction. sigh.
915
916 # first turn the svp64 rm into a "by name" dict, recording
917 # which position in the RM EXTRA it goes into
918 # also: record if the src or dest was a CR, for sanity-checking
919 # (elwidth overrides on CRs are banned)
920 decode = decode_extra(rm)
921 dest_reg_cr, src_reg_cr, svp64_src, svp64_dest = decode
922
923 log("EXTRA field index, src", svp64_src)
924 log("EXTRA field index, dest", svp64_dest)
925
926 # okaaay now we identify the field value (opcode N,N,N) with
927 # the pseudo-code info (opcode RT, RA, RB)
928 assert len(fields) == len(v30b_regs), \
929 "length of fields %s must match insn `%s` fields %s" % \
930 (str(v30b_regs), insn, str(fields))
931 opregfields = zip(fields, v30b_regs) # err that was easy
932
933 # now for each of those find its place in the EXTRA encoding
934 # note there is the possibility (for LD/ST-with-update) of
935 # RA occurring **TWICE**. to avoid it getting added to the
936 # v3.0B suffix twice, we spot it as a duplicate, here
937 extras = OrderedDict()
938 for idx, (field, regname) in enumerate(opregfields):
939 imm, regname = decode_imm(regname)
940 rtype = get_regtype(regname)
941 log(" idx find", rtype, idx, field, regname, imm)
942 if rtype is None:
943 # probably an immediate field, append it straight
944 extras[('imm', idx, False)] = (idx, field, None, None, None)
945 continue
946 extra = svp64_src.get(regname, None)
947 if extra is not None:
948 extra = ('s', extra, False) # not a duplicate
949 extras[extra] = (idx, field, regname, rtype, imm)
950 log(" idx src", idx, extra, extras[extra])
951 dextra = svp64_dest.get(regname, None)
952 log("regname in", regname, dextra)
953 if dextra is not None:
954 is_a_duplicate = extra is not None # duplicate spotted
955 dextra = ('d', dextra, is_a_duplicate)
956 extras[dextra] = (idx, field, regname, rtype, imm)
957 log(" idx dst", idx, extra, extras[dextra])
958
959 # great! got the extra fields in their associated positions:
960 # also we know the register type. now to create the EXTRA encodings
961 etype = rm['Etype'] # Extra type: EXTRA3/EXTRA2
962 ptype = rm['Ptype'] # Predication type: Twin / Single
963 extra_bits = 0
964 v30b_newfields = []
965 for extra_idx, (idx, field, rname, rtype, iname) in extras.items():
966 # is it a field we don't alter/examine? if so just put it
967 # into newfields
968 if rtype is None:
969 v30b_newfields.append(field)
970 continue
971
972 # identify if this is a ld/st immediate(reg) thing
973 ldst_imm = "(" in field and field[-1] == ')'
974 if ldst_imm:
975 immed, field = field[:-1].split("(")
976
977 field, regmode = decode_reg(field, macros=macros)
978 log(" ", extra_idx, rname, rtype,
979 regmode, iname, field, end=" ")
980
981 # see Mode field https://libre-soc.org/openpower/sv/svp64/
982 # XXX TODO: the following is a bit of a laborious repeated
983 # mess, which could (and should) easily be parameterised.
984 # XXX also TODO: the LD/ST modes which are different
985 # https://libre-soc.org/openpower/sv/ldst/
986
987 # rright. SVP64 register numbering is from 0 to 127
988 # for GPRs, FPRs *and* CR Fields, where for v3.0 the GPRs and RPFs
989 # are 0-31 and CR Fields are only 0-7. the SVP64 RM "Extra"
990 # area is used to extend the numbering from the 32-bit
991 # instruction, and also to record whether the register
992 # is scalar or vector. on a per-operand basis. this
993 # results in a slightly finnicky encoding: here we go...
994
995 # encode SV-GPR and SV-FPR field into extra, v3.0field
996 if rtype in ['GPR', 'FPR']:
997 sv_extra, field = get_extra_gpr(etype, regmode, field)
998 # now sanity-check. EXTRA3 is ok, EXTRA2 has limits
999 # (and shrink to a single bit if ok)
1000 if etype == 'EXTRA2':
1001 if regmode == 'scalar':
1002 # range is r0-r63 in increments of 1
1003 assert (sv_extra >> 1) == 0, \
1004 "scalar GPR %s cannot fit into EXTRA2 %s" % \
1005 (rname, str(extras[extra_idx]))
1006 # all good: encode as scalar
1007 sv_extra = sv_extra & 0b01
1008 else:
1009 # range is r0-r127 in increments of 2 (r0 r2 ... r126)
1010 assert sv_extra & 0b01 == 0, \
1011 "%s: vector field %s cannot fit " \
1012 "into EXTRA2 %s" % \
1013 (insn, rname, str(extras[extra_idx]))
1014 # all good: encode as vector (bit 2 set)
1015 sv_extra = 0b10 | (sv_extra >> 1)
1016 elif regmode == 'vector':
1017 # EXTRA3 vector bit needs marking
1018 sv_extra |= 0b100
1019
1020 # encode SV-CR 3-bit field into extra, v3.0field.
1021 # 3-bit is for things like BF and BFA
1022 elif rtype == 'CR_3bit':
1023 sv_extra, field = crf_extra(etype, rname, extra_idx,
1024 regmode, field, extras)
1025
1026 # encode SV-CR 5-bit field into extra, v3.0field
1027 # 5-bit is for things like BA BB BC BT etc.
1028 # *sigh* this is the same as 3-bit except the 2 LSBs of the
1029 # 5-bit field are passed through unaltered.
1030 elif rtype == 'CR_5bit':
1031 cr_subfield = field & 0b11 # record bottom 2 bits for later
1032 field = field >> 2 # strip bottom 2 bits
1033 # use the exact same 3-bit function for the top 3 bits
1034 sv_extra, field = crf_extra(etype, rname, extra_idx,
1035 regmode, field, extras)
1036 # reconstruct the actual 5-bit CR field (preserving the
1037 # bottom 2 bits, unaltered)
1038 field = (field << 2) | cr_subfield
1039
1040 else:
1041 raise Exception("no type match: %s" % rtype)
1042
1043 # capture the extra field info
1044 log("=>", "%5s" % bin(sv_extra), field)
1045 extras[extra_idx] = sv_extra
1046
1047 # append altered field value to v3.0b, differs for LDST
1048 # note that duplicates are skipped e.g. EXTRA2 contains
1049 # *BOTH* s:RA *AND* d:RA which happens on LD/ST-with-update
1050 srcdest, idx, duplicate = extra_idx
1051 if duplicate: # skip adding to v3.0b fields, already added
1052 continue
1053 if ldst_imm:
1054 v30b_newfields.append(("%s(%s)" % (immed, str(field))))
1055 else:
1056 v30b_newfields.append(str(field))
1057
1058 log("new v3.0B fields", v30b_op, v30b_newfields)
1059 log("extras", extras)
1060
1061 # rright. now we have all the info. start creating SVP64 instruction.
1062 svp64_insn = SVP64Instruction.pair(prefix=0, suffix=0)
1063 svp64_prefix = svp64_insn.prefix
1064 svp64_rm = svp64_insn.prefix.rm
1065
1066 # begin with EXTRA fields
1067 for idx, sv_extra in extras.items():
1068 log(idx)
1069 if idx is None:
1070 continue
1071 if idx[0] == 'imm':
1072 continue
1073 srcdest, idx, duplicate = idx
1074 if etype == 'EXTRA2':
1075 svp64_rm.extra2[idx] = sv_extra
1076 else:
1077 svp64_rm.extra3[idx] = sv_extra
1078
1079 # identify if the op is a LD/ST.
1080 # see https://libre-soc.org/openpower/sv/ldst/
1081 is_ldst = rm['mode'] in ['LDST_IDX', 'LDST_IMM']
1082 is_ldst_idx = rm['mode'] == 'LDST_IDX'
1083 is_ldst_imm = rm['mode'] == 'LDST_IMM'
1084 is_ld = v30b_op.startswith("l") and is_ldst
1085 is_st = v30b_op.startswith("s") and is_ldst
1086
1087 # branch-conditional or CR detection
1088 is_bc = rm['mode'] == 'BRANCH'
1089 is_cr = rm['mode'] == 'CROP'
1090
1091 # parts of svp64_rm
1092 mmode = 0 # bit 0
1093 pmask = 0 # bits 1-3
1094 destwid = 0 # bits 4-5
1095 srcwid = 0 # bits 6-7
1096 subvl = 0 # bits 8-9
1097 smask = 0 # bits 16-18 but only for twin-predication
1098 mode = 0 # bits 19-23
1099
1100 mask_m_specified = False
1101 has_pmask = False
1102 has_smask = False
1103
1104 saturation = None
1105 src_zero = 0
1106 dst_zero = 0
1107 sv_mode = None
1108
1109 mapreduce = False
1110 reverse_gear = False
1111 mapreduce_crm = False
1112
1113 predresult = False
1114 failfirst = False
1115 ldst_elstride = 0
1116 ldst_postinc = 0
1117 sea = False
1118
1119 vli = False
1120 sea = False
1121
1122 # ok let's start identifying opcode augmentation fields
1123 for encmode in opmodes:
1124 # predicate mask (src and dest)
1125 if encmode.startswith("m="):
1126 pme = encmode
1127 pmmode, pmask = decode_predicate(encmode[2:])
1128 smmode, smask = pmmode, pmask
1129 mmode = pmmode
1130 mask_m_specified = True
1131 # predicate mask (dest)
1132 elif encmode.startswith("dm="):
1133 pme = encmode
1134 pmmode, pmask = decode_predicate(encmode[3:])
1135 mmode = pmmode
1136 has_pmask = True
1137 # predicate mask (src, twin-pred)
1138 elif encmode.startswith("sm="):
1139 sme = encmode
1140 smmode, smask = decode_predicate(encmode[3:])
1141 mmode = smmode
1142 has_smask = True
1143 # vec2/3/4
1144 elif encmode.startswith("vec"):
1145 subvl = decode_subvl(encmode[3:])
1146 # elwidth (both src and dest, like mask)
1147 elif encmode.startswith("w="):
1148 destwid = decode_elwidth(encmode[2:])
1149 srcwid = decode_elwidth(encmode[2:])
1150 # just dest width
1151 elif encmode.startswith("dw="):
1152 destwid = decode_elwidth(encmode[3:])
1153 # just src width
1154 elif encmode.startswith("sw="):
1155 srcwid = decode_elwidth(encmode[3:])
1156 # post-increment
1157 elif encmode == 'pi':
1158 ldst_postinc = 1
1159 # in indexed mode, set sv_mode=0b00
1160 assert is_ldst_imm is True
1161 sv_mode = 0b00
1162 # element-strided LD/ST
1163 elif encmode == 'els':
1164 ldst_elstride = 1
1165 # in indexed mode, set sv_mode=0b01
1166 if is_ldst_idx:
1167 sv_mode = 0b01
1168 # saturation
1169 elif encmode == 'sats':
1170 assert sv_mode is None
1171 saturation = 1
1172 sv_mode = 0b10
1173 elif encmode == 'satu':
1174 assert sv_mode is None
1175 sv_mode = 0b10
1176 saturation = 0
1177 # predicate zeroing
1178 elif encmode == 'zz': # TODO, a lot more checking on legality
1179 dst_zero = 1 # NOT on cr_ops, that's RM[6]
1180 src_zero = 1
1181 elif encmode == 'sz':
1182 src_zero = 1
1183 elif encmode == 'dz':
1184 dst_zero = 1
1185 # failfirst
1186 elif encmode.startswith("ff="):
1187 assert sv_mode is None
1188 if is_cr: # sigh, CROPs is different
1189 sv_mode = 0b10
1190 else:
1191 sv_mode = 0b01
1192 failfirst = decode_ffirst(encmode[3:])
1193 assert sea is False, "cannot use failfirst with signed-address"
1194 # predicate-result, interestingly same as fail-first
1195 elif encmode.startswith("pr="):
1196 assert sv_mode is None
1197 sv_mode = 0b11
1198 predresult = decode_ffirst(encmode[3:])
1199 # map-reduce mode, reverse-gear
1200 elif encmode == 'mrr':
1201 assert sv_mode is None
1202 sv_mode = 0b00
1203 mapreduce = True
1204 reverse_gear = True
1205 # map-reduce mode
1206 elif encmode == 'mr':
1207 assert sv_mode is None
1208 sv_mode = 0b00
1209 mapreduce = True
1210 elif encmode == 'crm': # CR on map-reduce
1211 assert sv_mode is None
1212 sv_mode = 0b00
1213 mapreduce_crm = True
1214 elif encmode == 'vli':
1215 assert failfirst is not False, "VLi only allowed in failfirst"
1216 vli = True
1217 elif encmode == 'sea':
1218 assert is_ldst_idx
1219 sea = True
1220 assert failfirst is False, "cannot use ffirst+signed-address"
1221 elif is_bc:
1222 if encmode == 'all':
1223 svp64_rm.branch.ALL = 1
1224 elif encmode == 'snz':
1225 svp64_rm.branch.sz = 1
1226 svp64_rm.branch.SNZ = 1
1227 elif encmode == 'sl':
1228 svp64_rm.branch.SL = 1
1229 elif encmode == 'slu':
1230 svp64_rm.branch.SLu = 1
1231 elif encmode == 'lru':
1232 svp64_rm.branch.LRu = 1
1233 elif encmode == 'vs':
1234 svp64_rm.branch.VLS = 1
1235 elif encmode == 'vsi':
1236 svp64_rm.branch.VLS = 1
1237 svp64_rm.branch.vls.VLi = 1
1238 elif encmode == 'vsb':
1239 svp64_rm.branch.VLS = 1
1240 svp64_rm.branch.vls.VSb = 1
1241 elif encmode == 'vsbi':
1242 svp64_rm.branch.VLS = 1
1243 svp64_rm.branch.vls.VSb = 1
1244 svp64_rm.branch.vls.VLi = 1
1245 elif encmode == 'ctr':
1246 svp64_rm.branch.CTR = 1
1247 elif encmode == 'cti':
1248 svp64_rm.branch.CTR = 1
1249 svp64_rm.branch.ctr.CTi = 1
1250 else:
1251 raise AssertionError("unknown encmode %s" % encmode)
1252 else:
1253 raise AssertionError("unknown encmode %s" % encmode)
1254
1255 # post-inc only available on ld-with-update
1256 if ldst_postinc:
1257 assert "u" in opcode, "/pi only available on ld/st-update"
1258
1259 # sanity check if dz/zz used in branch-mode
1260 if is_bc and dst_zero:
1261 raise AssertionError("dz/zz not supported in branch, use 'sz'")
1262
1263 # check sea *after* all qualifiers are evaluated
1264 if sea:
1265 assert sv_mode in (None, 0b00, 0b01)
1266
1267 if ptype == '2P':
1268 # since m=xx takes precedence (overrides) sm=xx and dm=xx,
1269 # treat them as mutually exclusive
1270 if mask_m_specified:
1271 assert not has_smask,\
1272 "cannot have both source-mask and predicate mask"
1273 assert not has_pmask,\
1274 "cannot have both dest-mask and predicate mask"
1275 # since the default is INT predication (ALWAYS), if you
1276 # specify one CR mask, you must specify both, to avoid
1277 # mixing INT and CR reg types
1278 if has_pmask and pmmode == 1:
1279 assert has_smask, \
1280 "need explicit source-mask in CR twin predication"
1281 if has_smask and smmode == 1:
1282 assert has_pmask, \
1283 "need explicit dest-mask in CR twin predication"
1284 # sanity-check that 2Pred mask is same mode
1285 if has_pmask and has_smask:
1286 assert smmode == pmmode, \
1287 "predicate masks %s and %s must be same reg type" % \
1288 (pme, sme)
1289
1290 # sanity-check that twin-predication mask only specified in 2P mode
1291 if ptype == '1P':
1292 assert not has_smask, \
1293 "source-mask can only be specified on Twin-predicate ops"
1294 assert not has_pmask, \
1295 "dest-mask can only be specified on Twin-predicate ops"
1296
1297 # construct the mode field, doing sanity-checking along the way
1298 if src_zero:
1299 assert has_smask or mask_m_specified, \
1300 "src zeroing requires a source predicate"
1301 if dst_zero:
1302 assert has_pmask or mask_m_specified, \
1303 "dest zeroing requires a dest predicate"
1304
1305 # okaaay, so there are 4 different modes, here, which will be
1306 # partly-merged-in: is_ldst is merged in with "normal", but
1307 # is_bc is so different it's done separately. likewise is_cr
1308 # (when it is done). here are the maps:
1309
1310 # for "normal" arithmetic: https://libre-soc.org/openpower/sv/normal/
1311 """
1312 | 0-1 | 2 | 3 4 | description |
1313 | --- | --- |---------|-------------------------- |
1314 | 00 | 0 | dz sz | simple mode |
1315 | 00 | 1 | 0 RG | scalar reduce mode (mapreduce) |
1316 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
1317 | 01 | inv | VLi RC1 | Rc=0: ffirst z/nonz |
1318 | 10 | N | dz sz | sat mode: N=0/1 u/s |
1319 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1320 | 11 | inv | zz RC1 | Rc=0: pred-result z/nonz |
1321 """
1322
1323 # https://libre-soc.org/openpower/sv/ldst/
1324 # for LD/ST-immediate:
1325 """
1326 | 0-1 | 2 | 3 4 | description |
1327 | --- | --- |---------|--------------------------- |
1328 | 00 | 0 | zz els | normal mode |
1329 | 00 | 1 | pi lf | post-inc, LD-fault-first |
1330 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
1331 | 01 | inv | els RC1 | Rc=0: ffirst z/nonz |
1332 | 10 | N | zz els | sat mode: N=0/1 u/s |
1333 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1334 | 11 | inv | els RC1 | Rc=0: pred-result z/nonz |
1335 """
1336
1337 # for LD/ST-indexed (RA+RB):
1338 """
1339 | 0-1 | 2 | 3 4 | description |
1340 | --- | --- |---------|----------------------------- |
1341 | 00 | SEA | dz sz | normal mode |
1342 | 01 | SEA | dz sz | strided (scalar only source) |
1343 | 10 | N | dz sz | sat mode: N=0/1 u/s |
1344 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1345 | 11 | inv | dz RC1 | Rc=0: pred-result z/nonz |
1346 """
1347
1348 # and leaving out branches and cr_ops for now because they're
1349 # under development
1350 """ TODO branches and cr_ops
1351 """
1352
1353 if is_bc:
1354 sv_mode = int(svp64_rm.mode[0, 1])
1355 if src_zero:
1356 svp64_rm.branch.sz = 1
1357
1358 else:
1359 ######################################
1360 # "element-strided" mode, ldst_idx
1361 if sv_mode == 0b01 and is_ldst_idx:
1362 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1363 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1364 mode |= sea << SVP64MODE.SEA # el-strided
1365
1366 ######################################
1367 # "normal" mode
1368 elif sv_mode is None:
1369 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1370 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1371 if is_ldst:
1372 # TODO: for now, LD/ST-indexed is ignored.
1373 mode |= ldst_elstride << SVP64MODE.ELS_NORMAL # el-strided
1374 else:
1375 # TODO, reduce and subvector mode
1376 # 00 1 dz CRM reduce mode (mapreduce), SUBVL=1
1377 # 00 1 SVM CRM subvector reduce mode, SUBVL>1
1378 pass
1379 sv_mode = 0b00
1380
1381 ######################################
1382 # ldst-immediate "post" (and "load-fault-first" modes)
1383 elif sv_mode == 0b00 and ldst_postinc == 1: # (or ldst_ld_ffirst)
1384 mode |= (0b1 << SVP64MODE.LDI_POST) # sets bit 2
1385 mode |= (ldst_postinc << SVP64MODE.LDI_PI) # sets post-inc
1386
1387 ######################################
1388 # "mapreduce" modes
1389 elif sv_mode == 0b00:
1390 mode |= (0b1 << SVP64MODE.REDUCE) # sets mapreduce
1391 assert dst_zero == 0, "dest-zero not allowed in mapreduce mode"
1392 if reverse_gear:
1393 mode |= (0b1 << SVP64MODE.RG) # sets Reverse-gear mode
1394 if mapreduce_crm:
1395 mode |= (0b1 << SVP64MODE.CRM) # sets CRM mode
1396 assert rc_mode, "CRM only allowed when Rc=1"
1397 # bit of weird encoding to jam zero-pred or SVM mode in.
1398 # SVM mode can be enabled only when SUBVL=2/3/4 (vec2/3/4)
1399 if subvl == 0:
1400 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1401
1402 ######################################
1403 # "failfirst" modes
1404 elif failfirst is not False and not is_cr: # sv_mode == 0b01:
1405 assert src_zero == 0, "dest-zero not allowed in failfirst mode"
1406 if failfirst == 'RC1':
1407 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1408 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1409 assert rc_mode == False, "ffirst RC1 only ok when Rc=0"
1410 elif failfirst == '~RC1':
1411 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1412 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1413 mode |= (0b1 << SVP64MODE.INV) # ... with inversion
1414 assert rc_mode == False, "ffirst RC1 only ok when Rc=0"
1415 else:
1416 assert dst_zero == 0, "dst-zero not allowed in ffirst BO"
1417 assert rc_mode, "ffirst BO only possible when Rc=1"
1418 mode |= (failfirst << SVP64MODE.BO_LSB) # set BO
1419
1420 # (crops is really different)
1421 elif failfirst is not False and is_cr:
1422 if failfirst in ['RC1', '~RC1']:
1423 mode |= (src_zero << SVP64MODE.SZ) # predicate src-zeroing
1424 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1425 if failfirst == '~RC1':
1426 mode |= (0b1 << SVP64MODE.INV) # ... with inversion
1427 else:
1428 assert dst_zero == src_zero, "dz must equal sz in ffirst BO"
1429 mode |= (failfirst << SVP64MODE.BO_LSB) # set BO
1430 svp64_rm.cr_op.zz = dst_zero
1431 if vli:
1432 sv_mode |= 1 # set VLI in LSB of 2-bit mode
1433 #svp64_rm.cr_op.vli = 1
1434
1435 ######################################
1436 # "saturation" modes
1437 elif sv_mode == 0b10:
1438 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1439 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1440 mode |= (saturation << SVP64MODE.N) # signed/us saturation
1441
1442 ######################################
1443 # "predicate-result" modes. err... code-duplication from ffirst
1444 elif sv_mode == 0b11:
1445 assert src_zero == 0, "dest-zero not allowed in predresult mode"
1446 if predresult == 'RC1':
1447 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1448 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1449 assert rc_mode == False, "pr-mode RC1 only ok when Rc=0"
1450 elif predresult == '~RC1':
1451 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1452 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1453 mode |= (0b1 << SVP64MODE.INV) # ... with inversion
1454 assert rc_mode == False, "pr-mode RC1 only ok when Rc=0"
1455 else:
1456 assert dst_zero == 0, "dst-zero not allowed in pr-mode BO"
1457 assert rc_mode, "pr-mode BO only possible when Rc=1"
1458 mode |= (predresult << SVP64MODE.BO_LSB) # set BO
1459
1460 # whewww.... modes all done :)
1461 # now put into svp64_rm, but respect MSB0 order
1462 if sv_mode & 1:
1463 mode |= (0b1 << SVP64MODE.MOD2_LSB)
1464 if sv_mode & 2:
1465 mode |= (0b1 << SVP64MODE.MOD2_MSB)
1466
1467 if sea:
1468 mode |= (0b1 << SVP64MODE.SEA)
1469
1470 # this is a mess. really look forward to replacing it with Insn DB
1471 if not is_bc:
1472 svp64_rm.mode = mode # mode: bits 19-23
1473 if vli and not is_cr:
1474 svp64_rm.normal.ffrc0.VLi = 1
1475
1476 # put in predicate masks into svp64_rm
1477 if ptype == '2P':
1478 svp64_rm.smask = smask # source pred: bits 16-18
1479
1480 # put in elwidths unless cr
1481 if not is_cr:
1482 svp64_rm.ewsrc = srcwid # srcwid: bits 6-7
1483 svp64_rm.elwidth = destwid # destwid: bits 4-5
1484
1485 svp64_rm.mmode = mmode # mask mode: bit 0
1486 svp64_rm.mask = pmask # 1-pred: bits 1-3
1487 svp64_rm.subvl = subvl # and subvl: bits 8-9
1488
1489 # nice debug printout. (and now for something completely different)
1490 # https://youtu.be/u0WOIwlXE9g?t=146
1491 svp64_rm_value = int(svp64_rm)
1492 log("svp64_rm", hex(svp64_rm_value), bin(svp64_rm_value))
1493 log(" mmode 0 :", bin(mmode))
1494 log(" pmask 1-3 :", bin(pmask))
1495 log(" dstwid 4-5 :", bin(destwid))
1496 log(" srcwid 6-7 :", bin(srcwid))
1497 log(" subvl 8-9 :", bin(subvl))
1498 log(" mode 19-23:", bin(svp64_rm.mode))
1499 offs = 2 if etype == 'EXTRA2' else 3 # 2 or 3 bits
1500 for idx, sv_extra in extras.items():
1501 if idx is None:
1502 continue
1503 if idx[0] == 'imm':
1504 continue
1505 srcdest, idx, duplicate = idx
1506 start = (10+idx*offs)
1507 end = start + offs-1
1508 log(" extra%d %2d-%2d:" % (idx, start, end),
1509 bin(sv_extra))
1510 if ptype == '2P':
1511 log(" smask 16-17:", bin(smask))
1512 log()
1513
1514 # update prefix PO and ID (aka PID)
1515 svp64_prefix.po = 0x1
1516 svp64_prefix.id = 0b11
1517
1518 # fiinally yield the svp64 prefix and the thingy. v3.0b opcode
1519 rc = '.' if rc_mode else ''
1520 yield ".long 0x%08x" % int(svp64_prefix)
1521 log(v30b_op, v30b_newfields)
1522
1523 v30b_op_rc = v30b_op
1524 if not v30b_op.endswith('.'):
1525 v30b_op_rc += rc
1526
1527 # svstep is weird
1528 # FIXME(lkcl): should sv.svstep be like svstep?
1529 if v30b_op_rc in ("svstep", "svstep."):
1530 # compensate for `SVi -= 1` in svstep()
1531 v30b_newfields[1] = str(int(v30b_newfields[1]) + 1)
1532
1533 custom_insn_hook = CUSTOM_INSNS.get(v30b_op_rc)
1534 if custom_insn_hook is not None:
1535 fields = tuple(map(to_number, v30b_newfields))
1536 insn_num = custom_insn_hook(fields)
1537 log(opcode, bin(insn_num))
1538 yield ".long 0x%X # %s" % (insn_num, insn)
1539 return
1540 # argh, sv.fmadds etc. need to be done manually
1541 elif v30b_op == 'ffmadds':
1542 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1543 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1544 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1545 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1546 opcode |= int(v30b_newfields[3]) << (32-26) # FRC
1547 opcode |= 0b00101 << (32-31) # bits 26-30
1548 if rc:
1549 opcode |= 1 # Rc, bit 31.
1550 yield ".long 0x%x" % opcode
1551 # argh, sv.fdmadds need to be done manually
1552 elif v30b_op == 'fdmadds':
1553 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1554 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1555 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1556 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1557 opcode |= int(v30b_newfields[3]) << (32-26) # FRC
1558 opcode |= 0b11011 << (32-31) # bits 26-30
1559 if rc:
1560 opcode |= 1 # Rc, bit 31.
1561 yield ".long 0x%x" % opcode
1562 # argh, sv.ffadds etc. need to be done manually
1563 elif v30b_op == 'ffadds':
1564 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1565 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1566 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1567 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1568 opcode |= 0b1111100000 << (32-31) # bits 21-30
1569 if rc:
1570 opcode |= 1 # Rc, bit 31.
1571 yield ".long 0x%x" % opcode
1572 else:
1573 if not v30b_op.endswith('.'):
1574 v30b_op += rc
1575 yield "%s %s" % (v30b_op, ", ".join(v30b_newfields))
1576 for (name, span) in svp64_insn.traverse("SVP64"):
1577 value = svp64_insn.storage[span]
1578 log(name, f"{value.value:0{value.bits}b}", span)
1579 log("new v3.0B fields", v30b_op, v30b_newfields)
1580
1581 def translate(self, lst):
1582 for insn in lst:
1583 yield from self.translate_one(insn)
1584
1585
1586 def macro_subst(macros, txt):
1587 again = True
1588 log("subst", txt, macros)
1589 while again:
1590 again = False
1591 for macro, value in macros.items():
1592 if macro == txt:
1593 again = True
1594 replaced = txt.replace(macro, value)
1595 log("macro", txt, "replaced", replaced, macro, value)
1596 txt = replaced
1597 continue
1598 toreplace = '%s.s' % macro
1599 if toreplace == txt:
1600 again = True
1601 replaced = txt.replace(toreplace, "%s.s" % value)
1602 log("macro", txt, "replaced", replaced, toreplace, value)
1603 txt = replaced
1604 continue
1605 toreplace = '%s.v' % macro
1606 if toreplace == txt:
1607 again = True
1608 replaced = txt.replace(toreplace, "%s.v" % value)
1609 log("macro", txt, "replaced", replaced, toreplace, value)
1610 txt = replaced
1611 continue
1612 toreplace = '*%s' % macro
1613 if toreplace in txt:
1614 again = True
1615 replaced = txt.replace(toreplace, '*%s' % value)
1616 log("macro", txt, "replaced", replaced, toreplace, value)
1617 txt = replaced
1618 continue
1619 toreplace = '(%s)' % macro
1620 if toreplace in txt:
1621 again = True
1622 replaced = txt.replace(toreplace, '(%s)' % value)
1623 log("macro", txt, "replaced", replaced, toreplace, value)
1624 txt = replaced
1625 continue
1626 log(" processed", txt)
1627 return txt
1628
1629
1630 def get_ws(line):
1631 # find whitespace
1632 ws = ''
1633 while line:
1634 if not line[0].isspace():
1635 break
1636 ws += line[0]
1637 line = line[1:]
1638 return ws, line
1639
1640
1641 def asm_process():
1642 # get an input file and an output file
1643 args = sys.argv[1:]
1644 if len(args) == 0:
1645 infile = sys.stdin
1646 outfile = sys.stdout
1647 # read the whole lot in advance in case of in-place
1648 lines = list(infile.readlines())
1649 elif len(args) != 2:
1650 print("pysvp64asm [infile | -] [outfile | -]", file=sys.stderr)
1651 exit(0)
1652 else:
1653 if args[0] == '--':
1654 infile = sys.stdin
1655 else:
1656 infile = open(args[0], "r")
1657 # read the whole lot in advance in case of in-place overwrite
1658 lines = list(infile.readlines())
1659
1660 if args[1] == '--':
1661 outfile = sys.stdout
1662 else:
1663 outfile = open(args[1], "w")
1664
1665 # read the line, look for custom insn, process it
1666 macros = {} # macros which start ".set"
1667 isa = SVP64Asm([])
1668 for line in lines:
1669 op = line.split("#")[0].strip()
1670 # identify macros
1671 if op.startswith(".set"):
1672 macro = op[4:].split(",")
1673 (macro, value) = map(str.strip, macro)
1674 macros[macro] = value
1675 if not op.startswith('sv.') and not op.startswith(tuple(CUSTOM_INSNS)):
1676 outfile.write(line)
1677 continue
1678
1679 (ws, line) = get_ws(line)
1680 lst = isa.translate_one(op, macros)
1681 lst = '; '.join(lst)
1682 outfile.write("%s%s # %s\n" % (ws, lst, op))
1683
1684
1685 if __name__ == '__main__':
1686 lst = ['slw 3, 1, 4',
1687 'extsw 5, 3',
1688 'sv.extsw 5, 3',
1689 'sv.cmpi 5, 1, 3, 2',
1690 'sv.setb 5, 31',
1691 'sv.isel 64.v, 3, 2, 65.v',
1692 'sv.setb/dm=r3/sm=1<<r3 5, 31',
1693 'sv.setb/m=r3 5, 31',
1694 'sv.setb/vec2 5, 31',
1695 'sv.setb/sw=8/ew=16 5, 31',
1696 'sv.extsw./ff=eq 5, 31',
1697 'sv.extsw./satu/sz/dz/sm=r3/dm=r3 5, 31',
1698 'sv.extsw./pr=eq 5.v, 31',
1699 'sv.add. 5.v, 2.v, 1.v',
1700 'sv.add./m=r3 5.v, 2.v, 1.v',
1701 ]
1702 lst += [
1703 'sv.stw 5.v, 4(1.v)',
1704 'sv.ld 5.v, 4(1.v)',
1705 'setvl. 2, 3, 4, 0, 1, 1',
1706 'sv.setvl. 2, 3, 4, 0, 1, 1',
1707 ]
1708 lst = [
1709 "sv.stfsu 0.v, 16(4.v)",
1710 ]
1711 lst = [
1712 "sv.stfsu/els 0.v, 16(4)",
1713 ]
1714 lst = [
1715 'sv.add./mr 5.v, 2.v, 1.v',
1716 ]
1717 macros = {'win2': '50', 'win': '60'}
1718 lst = [
1719 'sv.addi win2.v, win.v, -1',
1720 'sv.add./mrr 5.v, 2.v, 1.v',
1721 #'sv.lhzsh 5.v, 11(9.v), 15',
1722 #'sv.lwzsh 5.v, 11(9.v), 15',
1723 'sv.ffmadds 6.v, 2.v, 4.v, 6.v',
1724 ]
1725 lst = [
1726 #'sv.fmadds 0.v, 8.v, 16.v, 4.v',
1727 #'sv.ffadds 0.v, 8.v, 4.v',
1728 'svremap 11, 0, 1, 2, 3, 2, 1',
1729 'svshape 8, 1, 1, 1, 0',
1730 'svshape 8, 1, 1, 1, 1',
1731 ]
1732 lst = [
1733 #'sv.lfssh 4.v, 11(8.v), 15',
1734 #'sv.lwzsh 4.v, 11(8.v), 15',
1735 #'sv.svstep. 2.v, 4, 0',
1736 #'sv.fcfids. 48.v, 64.v',
1737 'sv.fcoss. 80.v, 0.v',
1738 'sv.fcoss. 20.v, 0.v',
1739 ]
1740 lst = [
1741 'sv.bc/all 3,12,192',
1742 'sv.bclr/vsbi 3,81.v,192',
1743 'sv.ld 5.v, 4(1.v)',
1744 'sv.svstep. 2.v, 4, 0',
1745 ]
1746 lst = [
1747 'maxs 3,12,5',
1748 'maxs. 3,12,5',
1749 'avgadd 3,12,5',
1750 'absdu 3,12,5',
1751 'absds 3,12,5',
1752 'absdacu 3,12,5',
1753 'absdacs 3,12,5',
1754 'cprop 3,12,5',
1755 'svindex 0,0,1,0,0,0,0',
1756 ]
1757 lst = [
1758 'sv.svstep./m=r3 2.v, 4, 0',
1759 'ternlogi 0,0,0,0x5',
1760 'fmvis 5,65535',
1761 'fmvis 5,1',
1762 'fmvis 5,2',
1763 'fmvis 5,4',
1764 'fmvis 5,8',
1765 'fmvis 5,16',
1766 'fmvis 5,32',
1767 'fmvis 5,64',
1768 'fmvis 5,32768',
1769 ]
1770 lst = [
1771 'sv.andi. *80, *80, 1',
1772 'sv.ffmadds. 6.v, 2.v, 4.v, 6.v', # incorrectly inserted 32-bit op
1773 'sv.ffmadds 6.v, 2.v, 4.v, 6.v', # correctly converted to .long
1774 'svshape2 8, 1, 31, 7, 1, 1',
1775 'sv.ld 5.v, 4(1.v)',
1776 'sv.stw 5.v, 4(1.v)',
1777 'sv.bc/all 3,12,192',
1778 'pcdec. 0,0,0,0',
1779 ]
1780 lst = [
1781 #"sv.cmp/ff=gt *0,*1,*2,0",
1782 "dsld 5,4,5,3",
1783
1784 ]
1785 isa = SVP64Asm(lst, macros=macros)
1786 log("list:\n", "\n\t".join(list(isa)))
1787 # running svp64.py is designed to test hard-coded lists
1788 # (above) - which strictly speaking should all be unit tests.
1789 # if you need to actually do assembler translation at the
1790 # commandline use "pysvp64asm" - see setup.py
1791 # XXX NO. asm_process()