pysvp64asm: create database once
[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 offs,yx,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 | offs |yx| 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 @_custom_insns(
318 _insn("fsins", Rc=0),
319 _insn("fsins.", Rc=1),
320 )
321 def fsins(fields, Rc):
322 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
323 # however we are out of space with opcode 22
324 # 1.6.7 X-FORM
325 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |20|21 |31 |
326 # | PO | FRT | /// | FRB | XO |Rc |
327 PO = 59
328 XO = 0b1001001101
329 (FRT, FRB) = fields
330 return instruction(
331 (PO, 0, 5),
332 (FRT, 6, 10),
333 (0, 11, 15),
334 (FRB, 16, 20),
335 (XO, 21, 30),
336 (Rc, 31, 31),
337 )
338
339
340 @_custom_insns(
341 _insn("fcoss", Rc=0),
342 _insn("fcoss.", Rc=1),
343 )
344 def fcoss(fields, Rc):
345 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
346 # however we are out of space with opcode 22
347 # 1.6.7 X-FORM
348 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |20|21 |31 |
349 # | PO | FRT | /// | FRB | XO |Rc |
350 PO = 59
351 XO = 0b1001101100
352 (FRT, FRB) = fields
353 return instruction(
354 (PO, 0, 5),
355 (FRT, 6, 10),
356 (0, 11, 15),
357 (FRB, 16, 20),
358 (XO, 21, 30),
359 (Rc, 31, 31),
360 )
361
362
363 @_custom_insns(
364 _insn("ternlogi", Rc=0),
365 _insn("ternlogi.", Rc=1),
366 )
367 def ternlogi(fields, Rc):
368 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
369 # however we are out of space with opcode 22
370 # 1.6.34 TLI-FORM
371 # |0 |6 |11 |16 |21 |29 |31 |
372 # | PO | RT | RA | RB | TLI | XO |Rc |
373 PO = 5
374 XO = 0
375 (RT, RA, RB, TLI) = fields
376 return instruction(
377 (PO, 0, 5),
378 (RT, 6, 10),
379 (RA, 11, 15),
380 (RB, 16, 20),
381 (TLI, 21, 28),
382 (XO, 29, 30),
383 (Rc, 31, 31),
384 )
385
386
387 @_custom_insns(
388 _insn("grev", Rc=0, imm=0, word=0),
389 _insn("grevw", Rc=0, imm=0, word=1),
390 _insn("grevi", Rc=0, imm=1, word=0),
391 _insn("grevwi", Rc=0, imm=1, word=1),
392 _insn("grev.", Rc=1, imm=0, word=0),
393 _insn("grevw.", Rc=1, imm=0, word=1),
394 _insn("grevi.", Rc=1, imm=1, word=0),
395 _insn("grevwi.", Rc=1, imm=1, word=1),
396 )
397 def grev(fields, Rc, imm, word):
398 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
399 # however we are out of space with opcode 22
400 insn = PO = 5
401 # _ matches fields in table at:
402 # https://libre-soc.org/openpower/sv/bitmanip/
403 XO = 0b1_0010_110
404 if word:
405 XO |= 0b100_000
406 if imm:
407 XO |= 0b1000_000
408 (RT, RA, XBI) = fields
409 insn = (insn << 5) | RT
410 insn = (insn << 5) | RA
411 if imm and not word:
412 assert 0 <= XBI < 64
413 insn = (insn << 6) | XBI
414 insn = (insn << 9) | XO
415 else:
416 assert 0 <= XBI < 32
417 insn = (insn << 5) | XBI
418 insn = (insn << 10) | XO
419 insn = (insn << 1) | Rc
420 return insn
421
422
423 @_custom_insns(
424 _insn("maxs", XO=0b0111001110, Rc=0),
425 _insn("maxs.", XO=0b0111001110, Rc=1),
426 _insn("maxu", XO=0b0011001110, Rc=0),
427 _insn("maxu.", XO=0b0011001110, Rc=1),
428 _insn("minu", XO=0b0001001110, Rc=0),
429 _insn("minu.", XO=0b0001001110, Rc=1),
430 _insn("mins", XO=0b0101001110, Rc=0),
431 _insn("mins.", XO=0b0101001110, Rc=1),
432 _insn("absdu", XO=0b1011110110, Rc=0),
433 _insn("absdu.", XO=0b1011110110, Rc=1),
434 _insn("absds", XO=0b1001110110, Rc=0),
435 _insn("absds.", XO=0b1001110110, Rc=1),
436 _insn("avgadd", XO=0b1101001110, Rc=0),
437 _insn("avgadd.", XO=0b1101001110, Rc=1),
438 _insn("absdacu", XO=0b1111110110, Rc=0),
439 _insn("absdacu.", XO=0b1111110110, Rc=1),
440 _insn("absdacs", XO=0b0111110110, Rc=0),
441 _insn("absdacs.", XO=0b0111110110, Rc=1),
442 _insn("cprop", XO=0b0110001110, Rc=0),
443 _insn("cprop.", XO=0b0110001110, Rc=1),
444 )
445 def av(fields, XO, Rc):
446 # 1.6.7 X-FORM
447 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |20|21 |31 |
448 # | PO | RT | RA | RB | XO |Rc |
449 PO = 22
450 (RT, RA, RB) = fields
451 return instruction(
452 (PO, 0, 5),
453 (RT, 6, 10),
454 (RA, 11, 15),
455 (RB, 16, 20),
456 (XO, 21, 30),
457 (Rc, 31, 31),
458 )
459
460
461 @_custom_insns()
462 def fmvis(fields):
463 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
464 # V3.0B 1.6.6 DX-FORM
465 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |26|27 |31 |
466 # | PO | FRS | d1 | d0 | XO |d2 |
467 PO = 22
468 XO = 0b00011
469 (FRS, imm) = fields
470 # first split imm into d1, d0 and d2. sigh
471 d2 = (imm & 1) # LSB (0)
472 d1 = (imm >> 1) & 0b11111 # bits 1-5
473 d0 = (imm >> 6) # MSBs 6-15
474 return instruction(
475 (PO, 0, 5),
476 (FRS, 6, 10),
477 (d1, 11, 15),
478 (d0, 16, 25),
479 (XO, 26, 30),
480 (d2, 31, 31),
481 )
482
483
484 @_custom_insns()
485 def fishmv(fields):
486 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
487 # V3.0B 1.6.6 DX-FORM
488 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |26|27 |31 |
489 # | PO | FRS | d1 | d0 | XO |d2 |
490 PO = 22
491 XO = 0b01011
492 (FRS, imm) = fields
493 # first split imm into d1, d0 and d2. sigh
494 d2 = (imm & 1) # LSB (0)
495 d1 = (imm >> 1) & 0b11111 # bits 1-5
496 d0 = (imm >> 6) # MSBs 6-15
497 return instruction(
498 (PO, 0, 5),
499 (FRS, 6, 10),
500 (d1, 11, 15),
501 (d0, 16, 25),
502 (XO, 26, 30),
503 (d2, 31, 31),
504 )
505
506
507 # decode GPR into sv extra
508 def get_extra_gpr(etype, regmode, field):
509 if regmode == 'scalar':
510 # cut into 2-bits 5-bits SS FFFFF
511 sv_extra = field >> 5
512 field = field & 0b11111
513 else:
514 # cut into 5-bits 2-bits FFFFF SS
515 sv_extra = field & 0b11
516 field = field >> 2
517 return sv_extra, field
518
519
520 # decode 3-bit CR into sv extra
521 def get_extra_cr_3bit(etype, regmode, field):
522 if regmode == 'scalar':
523 # cut into 2-bits 3-bits SS FFF
524 sv_extra = field >> 3
525 field = field & 0b111
526 else:
527 # cut into 3-bits 4-bits FFF SSSS but will cut 2 zeros off later
528 sv_extra = field & 0b1111
529 field = field >> 4
530 return sv_extra, field
531
532
533 # decodes SUBVL
534 def decode_subvl(encoding):
535 pmap = {'2': 0b01, '3': 0b10, '4': 0b11}
536 assert encoding in pmap, \
537 "encoding %s for SUBVL not recognised" % encoding
538 return pmap[encoding]
539
540
541 # decodes elwidth
542 def decode_elwidth(encoding):
543 pmap = {'8': 0b11, '16': 0b10, '32': 0b01}
544 assert encoding in pmap, \
545 "encoding %s for elwidth not recognised" % encoding
546 return pmap[encoding]
547
548
549 # decodes predicate register encoding
550 def decode_predicate(encoding):
551 pmap = { # integer
552 '1<<r3': (0, 0b001),
553 'r3': (0, 0b010),
554 '~r3': (0, 0b011),
555 'r10': (0, 0b100),
556 '~r10': (0, 0b101),
557 'r30': (0, 0b110),
558 '~r30': (0, 0b111),
559 # CR
560 'lt': (1, 0b000),
561 'nl': (1, 0b001), 'ge': (1, 0b001), # same value
562 'gt': (1, 0b010),
563 'ng': (1, 0b011), 'le': (1, 0b011), # same value
564 'eq': (1, 0b100),
565 'ne': (1, 0b101),
566 'so': (1, 0b110), 'un': (1, 0b110), # same value
567 'ns': (1, 0b111), 'nu': (1, 0b111), # same value
568 }
569 assert encoding in pmap, \
570 "encoding %s for predicate not recognised" % encoding
571 return pmap[encoding]
572
573
574 # decodes "Mode" in similar way to BO field (supposed to, anyway)
575 def decode_bo(encoding):
576 pmap = { # TODO: double-check that these are the same as Branch BO
577 'lt': 0b000,
578 'nl': 0b001, 'ge': 0b001, # same value
579 'gt': 0b010,
580 'ng': 0b011, 'le': 0b011, # same value
581 'eq': 0b100,
582 'ne': 0b101,
583 'so': 0b110, 'un': 0b110, # same value
584 'ns': 0b111, 'nu': 0b111, # same value
585 }
586 assert encoding in pmap, \
587 "encoding %s for BO Mode not recognised" % encoding
588 return pmap[encoding]
589
590
591 # partial-decode fail-first mode
592 def decode_ffirst(encoding):
593 if encoding in ['RC1', '~RC1']:
594 return encoding
595 return decode_bo(encoding)
596
597
598 def decode_reg(field, macros=None):
599 if macros is None:
600 macros = {}
601 # decode the field number. "5.v" or "3.s" or "9"
602 # and now also "*0", and "*%0". note: *NOT* to add "*%rNNN" etc.
603 # https://bugs.libre-soc.org/show_bug.cgi?id=884#c0
604 if field.startswith(("*%", "*")):
605 if field.startswith("*%"):
606 field = field[2:]
607 else:
608 field = field[1:]
609 while field in macros:
610 field = macros[field]
611 return int(field), "vector" # actual register number
612
613 # try old convention (to be retired)
614 field = field.split(".")
615 regmode = 'scalar' # default
616 if len(field) == 2:
617 if field[1] == 's':
618 regmode = 'scalar'
619 elif field[1] == 'v':
620 regmode = 'vector'
621 field = int(field[0]) # actual register number
622 return field, regmode
623
624
625 def decode_imm(field):
626 ldst_imm = "(" in field and field[-1] == ')'
627 if ldst_imm:
628 return field[:-1].split("(")
629 else:
630 return None, field
631
632
633 def crf_extra(etype, regmode, field, extras):
634 """takes a CR Field number (CR0-CR127), splits into EXTRA2/3 and v3.0
635 the scalar/vector mode (crNN.v or crNN.s) changes both the format
636 of the EXTRA2/3 encoding as well as what range of registers is possible.
637 this function can be used for both BF/BFA and BA/BB/BT by first removing
638 the bottom 2 bits of BA/BB/BT then re-instating them after encoding.
639 see https://libre-soc.org/openpower/sv/svp64/appendix/#cr_extra
640 for specification
641 """
642 sv_extra, field = get_extra_cr_3bit(etype, regmode, field)
643 # now sanity-check (and shrink afterwards)
644 if etype == 'EXTRA2':
645 # 3-bit CR Field (BF, BFA) EXTRA2 encoding
646 if regmode == 'scalar':
647 # range is CR0-CR15 in increments of 1
648 assert (sv_extra >> 1) == 0, \
649 "scalar CR %s cannot fit into EXTRA2 %s" % \
650 (rname, str(extras[extra_idx]))
651 # all good: encode as scalar
652 sv_extra = sv_extra & 0b01
653 else: # vector
654 # range is CR0-CR127 in increments of 16
655 assert sv_extra & 0b111 == 0, \
656 "vector CR %s cannot fit into EXTRA2 %s" % \
657 (rname, str(extras[extra_idx]))
658 # all good: encode as vector (bit 2 set)
659 sv_extra = 0b10 | (sv_extra >> 3)
660 else:
661 # 3-bit CR Field (BF, BFA) EXTRA3 encoding
662 if regmode == 'scalar':
663 # range is CR0-CR31 in increments of 1
664 assert (sv_extra >> 2) == 0, \
665 "scalar CR %s cannot fit into EXTRA3 %s" % \
666 (rname, str(extras[extra_idx]))
667 # all good: encode as scalar
668 sv_extra = sv_extra & 0b11
669 else: # vector
670 # range is CR0-CR127 in increments of 8
671 assert sv_extra & 0b11 == 0, \
672 "vector CR %s cannot fit into EXTRA3 %s" % \
673 (rname, str(extras[extra_idx]))
674 # all good: encode as vector (bit 3 set)
675 sv_extra = 0b100 | (sv_extra >> 2)
676 return sv_extra, field
677
678
679 def to_number(field):
680 if field.startswith("0x"):
681 return eval(field)
682 if field.startswith("0b"):
683 return eval(field)
684 return int(field)
685
686
687 db = Database(find_wiki_dir())
688
689
690 # decodes svp64 assembly listings and creates EXT001 svp64 prefixes
691 class SVP64Asm:
692 def __init__(self, lst, bigendian=False, macros=None):
693 if macros is None:
694 macros = {}
695 self.macros = macros
696 self.lst = lst
697 self.trans = self.translate(lst)
698 self.isa = ISA() # reads the v3.0B pseudo-code markdown files
699 self.svp64 = SVP64RM() # reads the svp64 Remap entries for registers
700 assert bigendian == False, "error, bigendian not supported yet"
701
702 def __iter__(self):
703 yield from self.trans
704
705 def translate_one(self, insn, macros=None):
706 if macros is None:
707 macros = {}
708 macros.update(self.macros)
709 isa = self.isa
710 svp64 = self.svp64
711 insn_no_comments = insn.partition('#')[0]
712 # find first space, to get opcode
713 ls = insn_no_comments.split(' ')
714 opcode = ls[0]
715 # now find opcode fields
716 fields = ''.join(ls[1:]).split(',')
717 mfields = list(map(str.strip, fields))
718 log("opcode, fields", ls, opcode, mfields)
719 fields = []
720 # macro substitution
721 for field in mfields:
722 fields.append(macro_subst(macros, field))
723 log("opcode, fields substed", ls, opcode, fields)
724
725 # identify if it is a special instruction
726 custom_insn_hook = CUSTOM_INSNS.get(opcode)
727 if custom_insn_hook is not None:
728 fields = tuple(map(to_number, fields))
729 insn_num = custom_insn_hook(fields)
730 log(opcode, bin(insn_num))
731 yield ".long 0x%X # %s" % (insn_num, insn)
732 return
733
734 # identify if is a svp64 mnemonic
735 if not opcode.startswith('sv.'):
736 yield insn # unaltered
737 return
738 opcode = opcode[3:] # strip leading "sv"
739
740 # start working on decoding the svp64 op: sv.basev30Bop/vec2/mode
741 opmodes = opcode.split("/") # split at "/"
742 v30b_op_orig = opmodes.pop(0) # first is the v3.0B
743 # check instruction ends with dot
744 rc_mode = v30b_op_orig.endswith('.')
745 if rc_mode:
746 v30b_op = v30b_op_orig[:-1]
747 else:
748 v30b_op = v30b_op_orig
749
750 # look up the 32-bit op (original, with "." if it has it)
751 if v30b_op_orig in isa.instr:
752 isa_instr = isa.instr[v30b_op_orig]
753 else:
754 raise Exception("opcode %s of '%s' not supported" %
755 (v30b_op_orig, insn))
756
757 # look up the svp64 op, first the original (with "." if it has it)
758 if v30b_op_orig in svp64.instrs:
759 rm = svp64.instrs[v30b_op_orig] # one row of the svp64 RM CSV
760 # then without the "." (if there was one)
761 elif v30b_op in svp64.instrs:
762 rm = svp64.instrs[v30b_op] # one row of the svp64 RM CSV
763 else:
764 raise Exception(f"opcode {v30b_op_orig!r} of "
765 f"{insn!r} not an svp64 instruction")
766
767 # get regs info e.g. "RT,RA,RB"
768 v30b_regs = isa_instr.regs[0]
769 log("v3.0B op", v30b_op, "Rc=1" if rc_mode else '')
770 log("v3.0B regs", opcode, v30b_regs)
771 log("RM", rm)
772
773 # right. the first thing to do is identify the ordering of
774 # the registers, by name. the EXTRA2/3 ordering is in
775 # rm['0']..rm['3'] but those fields contain the names RA, BB
776 # etc. we have to read the pseudocode to understand which
777 # reg is which in our instruction. sigh.
778
779 # first turn the svp64 rm into a "by name" dict, recording
780 # which position in the RM EXTRA it goes into
781 # also: record if the src or dest was a CR, for sanity-checking
782 # (elwidth overrides on CRs are banned)
783 decode = decode_extra(rm)
784 dest_reg_cr, src_reg_cr, svp64_src, svp64_dest = decode
785
786 log("EXTRA field index, src", svp64_src)
787 log("EXTRA field index, dest", svp64_dest)
788
789 # okaaay now we identify the field value (opcode N,N,N) with
790 # the pseudo-code info (opcode RT, RA, RB)
791 assert len(fields) == len(v30b_regs), \
792 "length of fields %s must match insn `%s` fields %s" % \
793 (str(v30b_regs), insn, str(fields))
794 opregfields = zip(fields, v30b_regs) # err that was easy
795
796 # now for each of those find its place in the EXTRA encoding
797 # note there is the possibility (for LD/ST-with-update) of
798 # RA occurring **TWICE**. to avoid it getting added to the
799 # v3.0B suffix twice, we spot it as a duplicate, here
800 extras = OrderedDict()
801 for idx, (field, regname) in enumerate(opregfields):
802 imm, regname = decode_imm(regname)
803 rtype = get_regtype(regname)
804 log(" idx find", rtype, idx, field, regname, imm)
805 if rtype is None:
806 # probably an immediate field, append it straight
807 extras[('imm', idx, False)] = (idx, field, None, None, None)
808 continue
809 extra = svp64_src.get(regname, None)
810 if extra is not None:
811 extra = ('s', extra, False) # not a duplicate
812 extras[extra] = (idx, field, regname, rtype, imm)
813 log(" idx src", idx, extra, extras[extra])
814 dextra = svp64_dest.get(regname, None)
815 log("regname in", regname, dextra)
816 if dextra is not None:
817 is_a_duplicate = extra is not None # duplicate spotted
818 dextra = ('d', dextra, is_a_duplicate)
819 extras[dextra] = (idx, field, regname, rtype, imm)
820 log(" idx dst", idx, extra, extras[dextra])
821
822 # great! got the extra fields in their associated positions:
823 # also we know the register type. now to create the EXTRA encodings
824 etype = rm['Etype'] # Extra type: EXTRA3/EXTRA2
825 ptype = rm['Ptype'] # Predication type: Twin / Single
826 extra_bits = 0
827 v30b_newfields = []
828 for extra_idx, (idx, field, rname, rtype, iname) in extras.items():
829 # is it a field we don't alter/examine? if so just put it
830 # into newfields
831 if rtype is None:
832 v30b_newfields.append(field)
833 continue
834
835 # identify if this is a ld/st immediate(reg) thing
836 ldst_imm = "(" in field and field[-1] == ')'
837 if ldst_imm:
838 immed, field = field[:-1].split("(")
839
840 field, regmode = decode_reg(field, macros=macros)
841 log(" ", extra_idx, rname, rtype,
842 regmode, iname, field, end=" ")
843
844 # see Mode field https://libre-soc.org/openpower/sv/svp64/
845 # XXX TODO: the following is a bit of a laborious repeated
846 # mess, which could (and should) easily be parameterised.
847 # XXX also TODO: the LD/ST modes which are different
848 # https://libre-soc.org/openpower/sv/ldst/
849
850 # rright. SVP64 register numbering is from 0 to 127
851 # for GPRs, FPRs *and* CR Fields, where for v3.0 the GPRs and RPFs
852 # are 0-31 and CR Fields are only 0-7. the SVP64 RM "Extra"
853 # area is used to extend the numbering from the 32-bit
854 # instruction, and also to record whether the register
855 # is scalar or vector. on a per-operand basis. this
856 # results in a slightly finnicky encoding: here we go...
857
858 # encode SV-GPR and SV-FPR field into extra, v3.0field
859 if rtype in ['GPR', 'FPR']:
860 sv_extra, field = get_extra_gpr(etype, regmode, field)
861 # now sanity-check. EXTRA3 is ok, EXTRA2 has limits
862 # (and shrink to a single bit if ok)
863 if etype == 'EXTRA2':
864 if regmode == 'scalar':
865 # range is r0-r63 in increments of 1
866 assert (sv_extra >> 1) == 0, \
867 "scalar GPR %s cannot fit into EXTRA2 %s" % \
868 (rname, str(extras[extra_idx]))
869 # all good: encode as scalar
870 sv_extra = sv_extra & 0b01
871 else:
872 # range is r0-r127 in increments of 2 (r0 r2 ... r126)
873 assert sv_extra & 0b01 == 0, \
874 "%s: vector field %s cannot fit " \
875 "into EXTRA2 %s" % \
876 (insn, rname, str(extras[extra_idx]))
877 # all good: encode as vector (bit 2 set)
878 sv_extra = 0b10 | (sv_extra >> 1)
879 elif regmode == 'vector':
880 # EXTRA3 vector bit needs marking
881 sv_extra |= 0b100
882
883 # encode SV-CR 3-bit field into extra, v3.0field.
884 # 3-bit is for things like BF and BFA
885 elif rtype == 'CR_3bit':
886 sv_extra, field = crf_extra(etype, regmode, field, extras)
887
888 # encode SV-CR 5-bit field into extra, v3.0field
889 # 5-bit is for things like BA BB BC BT etc.
890 # *sigh* this is the same as 3-bit except the 2 LSBs of the
891 # 5-bit field are passed through unaltered.
892 elif rtype == 'CR_5bit':
893 cr_subfield = field & 0b11 # record bottom 2 bits for later
894 field = field >> 2 # strip bottom 2 bits
895 # use the exact same 3-bit function for the top 3 bits
896 sv_extra, field = crf_extra(etype, regmode, field, extras)
897 # reconstruct the actual 5-bit CR field (preserving the
898 # bottom 2 bits, unaltered)
899 field = (field << 2) | cr_subfield
900
901 else:
902 raise Exception("no type match: %s" % rtype)
903
904 # capture the extra field info
905 log("=>", "%5s" % bin(sv_extra), field)
906 extras[extra_idx] = sv_extra
907
908 # append altered field value to v3.0b, differs for LDST
909 # note that duplicates are skipped e.g. EXTRA2 contains
910 # *BOTH* s:RA *AND* d:RA which happens on LD/ST-with-update
911 srcdest, idx, duplicate = extra_idx
912 if duplicate: # skip adding to v3.0b fields, already added
913 continue
914 if ldst_imm:
915 v30b_newfields.append(("%s(%s)" % (immed, str(field))))
916 else:
917 v30b_newfields.append(str(field))
918
919 log("new v3.0B fields", v30b_op, v30b_newfields)
920 log("extras", extras)
921
922 # rright. now we have all the info. start creating SVP64 instruction.
923 svp64_insn = SVP64Instruction.pair(prefix=0, suffix=0)
924 svp64_prefix = svp64_insn.prefix
925 svp64_rm = svp64_insn.prefix.rm
926
927 # begin with EXTRA fields
928 for idx, sv_extra in extras.items():
929 log(idx)
930 if idx is None:
931 continue
932 if idx[0] == 'imm':
933 continue
934 srcdest, idx, duplicate = idx
935 if etype == 'EXTRA2':
936 svp64_rm.extra2[idx] = sv_extra
937 else:
938 svp64_rm.extra3[idx] = sv_extra
939
940 # identify if the op is a LD/ST. the "blegh" way. copied
941 # from power_enums. TODO, split the list _insns down.
942 is_ld = v30b_op in [
943 "lbarx", "lbz", "lbzu", "lbzux", "lbzx", # load byte
944 "ld", "ldarx", "ldbrx", "ldu", "ldux", "ldx", # load double
945 "lfs", "lfsx", "lfsu", "lfsux", # FP load single
946 "lfd", "lfdx", "lfdu", "lfdux", "lfiwzx", "lfiwax", # FP load dbl
947 "lha", "lharx", "lhau", "lhaux", "lhax", # load half
948 "lhbrx", "lhz", "lhzu", "lhzux", "lhzx", # more load half
949 "lwa", "lwarx", "lwaux", "lwax", "lwbrx", # load word
950 "lwz", "lwzcix", "lwzu", "lwzux", "lwzx", # more load word
951 ]
952 is_st = v30b_op in [
953 "stb", "stbcix", "stbcx", "stbu", "stbux", "stbx",
954 "std", "stdbrx", "stdcx", "stdu", "stdux", "stdx",
955 "stfs", "stfsx", "stfsu", "stfux", # FP store sgl
956 "stfd", "stfdx", "stfdu", "stfdux", "stfiwx", # FP store dbl
957 "sth", "sthbrx", "sthcx", "sthu", "sthux", "sthx",
958 "stw", "stwbrx", "stwcx", "stwu", "stwux", "stwx",
959 ]
960 # use this to determine if the SVP64 RM format is different.
961 # see https://libre-soc.org/openpower/sv/ldst/
962 is_ldst = is_ld or is_st
963
964 # branch-conditional detection
965 is_bc = v30b_op in [
966 "bc", "bclr",
967 ]
968
969 # parts of svp64_rm
970 mmode = 0 # bit 0
971 pmask = 0 # bits 1-3
972 destwid = 0 # bits 4-5
973 srcwid = 0 # bits 6-7
974 subvl = 0 # bits 8-9
975 smask = 0 # bits 16-18 but only for twin-predication
976 mode = 0 # bits 19-23
977
978 mask_m_specified = False
979 has_pmask = False
980 has_smask = False
981
982 saturation = None
983 src_zero = 0
984 dst_zero = 0
985 sv_mode = None
986
987 mapreduce = False
988 reverse_gear = False
989 mapreduce_crm = False
990 mapreduce_svm = False
991
992 predresult = False
993 failfirst = False
994 ldst_elstride = 0
995
996 # branch-conditional bits
997 bc_all = 0
998 bc_lru = 0
999 bc_brc = 0
1000 bc_svstep = 0
1001 bc_vsb = 0
1002 bc_vlset = 0
1003 bc_vli = 0
1004 bc_snz = 0
1005
1006 # ok let's start identifying opcode augmentation fields
1007 for encmode in opmodes:
1008 # predicate mask (src and dest)
1009 if encmode.startswith("m="):
1010 pme = encmode
1011 pmmode, pmask = decode_predicate(encmode[2:])
1012 smmode, smask = pmmode, pmask
1013 mmode = pmmode
1014 mask_m_specified = True
1015 # predicate mask (dest)
1016 elif encmode.startswith("dm="):
1017 pme = encmode
1018 pmmode, pmask = decode_predicate(encmode[3:])
1019 mmode = pmmode
1020 has_pmask = True
1021 # predicate mask (src, twin-pred)
1022 elif encmode.startswith("sm="):
1023 sme = encmode
1024 smmode, smask = decode_predicate(encmode[3:])
1025 mmode = smmode
1026 has_smask = True
1027 # vec2/3/4
1028 elif encmode.startswith("vec"):
1029 subvl = decode_subvl(encmode[3:])
1030 # elwidth
1031 elif encmode.startswith("ew="):
1032 destwid = decode_elwidth(encmode[3:])
1033 elif encmode.startswith("sw="):
1034 srcwid = decode_elwidth(encmode[3:])
1035 # element-strided LD/ST
1036 elif encmode == 'els':
1037 ldst_elstride = 1
1038 # saturation
1039 elif encmode == 'sats':
1040 assert sv_mode is None
1041 saturation = 1
1042 sv_mode = 0b10
1043 elif encmode == 'satu':
1044 assert sv_mode is None
1045 sv_mode = 0b10
1046 saturation = 0
1047 # predicate zeroing
1048 elif encmode == 'sz':
1049 src_zero = 1
1050 elif encmode == 'dz':
1051 dst_zero = 1
1052 # failfirst
1053 elif encmode.startswith("ff="):
1054 assert sv_mode is None
1055 sv_mode = 0b01
1056 failfirst = decode_ffirst(encmode[3:])
1057 # predicate-result, interestingly same as fail-first
1058 elif encmode.startswith("pr="):
1059 assert sv_mode is None
1060 sv_mode = 0b11
1061 predresult = decode_ffirst(encmode[3:])
1062 # map-reduce mode, reverse-gear
1063 elif encmode == 'mrr':
1064 assert sv_mode is None
1065 sv_mode = 0b00
1066 mapreduce = True
1067 reverse_gear = True
1068 # map-reduce mode
1069 elif encmode == 'mr':
1070 assert sv_mode is None
1071 sv_mode = 0b00
1072 mapreduce = True
1073 elif encmode == 'crm': # CR on map-reduce
1074 assert sv_mode is None
1075 sv_mode = 0b00
1076 mapreduce_crm = True
1077 elif encmode == 'svm': # sub-vector mode
1078 mapreduce_svm = True
1079 elif is_bc:
1080 if encmode == 'all':
1081 bc_all = 1
1082 elif encmode == 'st': # svstep mode
1083 bc_step = 1
1084 elif encmode == 'sr': # svstep BRc mode
1085 bc_step = 1
1086 bc_brc = 1
1087 elif encmode == 'vs': # VLSET mode
1088 bc_vlset = 1
1089 elif encmode == 'vsi': # VLSET mode with VLI (VL inclusives)
1090 bc_vlset = 1
1091 bc_vli = 1
1092 elif encmode == 'vsb': # VLSET mode with VSb
1093 bc_vlset = 1
1094 bc_vsb = 1
1095 elif encmode == 'vsbi': # VLSET mode with VLI and VSb
1096 bc_vlset = 1
1097 bc_vli = 1
1098 bc_vsb = 1
1099 elif encmode == 'snz': # sz (only) already set above
1100 src_zero = 1
1101 bc_snz = 1
1102 elif encmode == 'lu': # LR update mode
1103 bc_lru = 1
1104 else:
1105 raise AssertionError("unknown encmode %s" % encmode)
1106 else:
1107 raise AssertionError("unknown encmode %s" % encmode)
1108
1109 if ptype == '2P':
1110 # since m=xx takes precedence (overrides) sm=xx and dm=xx,
1111 # treat them as mutually exclusive
1112 if mask_m_specified:
1113 assert not has_smask,\
1114 "cannot have both source-mask and predicate mask"
1115 assert not has_pmask,\
1116 "cannot have both dest-mask and predicate mask"
1117 # since the default is INT predication (ALWAYS), if you
1118 # specify one CR mask, you must specify both, to avoid
1119 # mixing INT and CR reg types
1120 if has_pmask and pmmode == 1:
1121 assert has_smask, \
1122 "need explicit source-mask in CR twin predication"
1123 if has_smask and smmode == 1:
1124 assert has_pmask, \
1125 "need explicit dest-mask in CR twin predication"
1126 # sanity-check that 2Pred mask is same mode
1127 if has_pmask and has_smask:
1128 assert smmode == pmmode, \
1129 "predicate masks %s and %s must be same reg type" % \
1130 (pme, sme)
1131
1132 # sanity-check that twin-predication mask only specified in 2P mode
1133 if ptype == '1P':
1134 assert not has_smask, \
1135 "source-mask can only be specified on Twin-predicate ops"
1136 assert not has_pmask, \
1137 "dest-mask can only be specified on Twin-predicate ops"
1138
1139 # construct the mode field, doing sanity-checking along the way
1140 if mapreduce_svm:
1141 assert sv_mode == 0b00, "sub-vector mode in mapreduce only"
1142 assert subvl != 0, "sub-vector mode not possible on SUBVL=1"
1143
1144 if src_zero:
1145 assert has_smask or mask_m_specified, \
1146 "src zeroing requires a source predicate"
1147 if dst_zero:
1148 assert has_pmask or mask_m_specified, \
1149 "dest zeroing requires a dest predicate"
1150
1151 # okaaay, so there are 4 different modes, here, which will be
1152 # partly-merged-in: is_ldst is merged in with "normal", but
1153 # is_bc is so different it's done separately. likewise is_cr
1154 # (when it is done). here are the maps:
1155
1156 # for "normal" arithmetic: https://libre-soc.org/openpower/sv/normal/
1157 """
1158 | 0-1 | 2 | 3 4 | description |
1159 | --- | --- |---------|-------------------------- |
1160 | 00 | 0 | dz sz | simple mode |
1161 | 00 | 1 | 0 RG | scalar reduce mode (mapreduce), SUBVL=1 |
1162 | 00 | 1 | SVM 0 | subvector reduce mode, SUBVL>1 |
1163 | 00 | 1 | SVM 1 | Pack/Unpack mode, SUBVL>1 |
1164 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
1165 | 01 | inv | VLi RC1 | Rc=0: ffirst z/nonz |
1166 | 10 | N | dz sz | sat mode: N=0/1 u/s, SUBVL=1 |
1167 | 10 | N | zz 0 | sat mode: N=0/1 u/s, SUBVL>1 |
1168 | 10 | N | zz 1 | Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1 |
1169 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1170 | 11 | inv | zz RC1 | Rc=0: pred-result z/nonz |
1171 """
1172
1173 # https://libre-soc.org/openpower/sv/ldst/
1174 # for LD/ST-immediate:
1175 """
1176 | 0-1 | 2 | 3 4 | description |
1177 | --- | --- |---------|--------------------------- |
1178 | 00 | 0 | dz els | normal mode |
1179 | 00 | 1 | dz shf | shift mode |
1180 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
1181 | 01 | inv | els RC1 | Rc=0: ffirst z/nonz |
1182 | 10 | N | dz els | sat mode: N=0/1 u/s |
1183 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1184 | 11 | inv | els RC1 | Rc=0: pred-result z/nonz |
1185 """
1186
1187 # for LD/ST-indexed (RA+RB):
1188 """
1189 | 0-1 | 2 | 3 4 | description |
1190 | --- | --- |---------|-------------------------- |
1191 | 00 | SEA | dz sz | normal mode |
1192 | 01 | SEA | dz sz | Strided (scalar only source) |
1193 | 10 | N | dz sz | sat mode: N=0/1 u/s |
1194 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1195 | 11 | inv | dz RC1 | Rc=0: pred-result z/nonz |
1196 """
1197
1198 # and leaving out branches and cr_ops for now because they're
1199 # under development
1200 """ TODO branches and cr_ops
1201 """
1202
1203 # now create mode and (overridden) src/dst widths
1204 # XXX TODO: sanity-check bc modes
1205 if is_bc:
1206 sv_mode = ((bc_svstep << SVP64MODE.MOD2_MSB) |
1207 (bc_vlset << SVP64MODE.MOD2_LSB) |
1208 (bc_snz << SVP64MODE.BC_SNZ))
1209 srcwid = (bc_vsb << 1) | bc_lru
1210 destwid = (bc_lru << 1) | bc_all
1211
1212 else:
1213
1214 ######################################
1215 # "normal" mode
1216 if sv_mode is None:
1217 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1218 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1219 if is_ldst:
1220 # TODO: for now, LD/ST-indexed is ignored.
1221 mode |= ldst_elstride << SVP64MODE.ELS_NORMAL # el-strided
1222 else:
1223 # TODO, reduce and subvector mode
1224 # 00 1 dz CRM reduce mode (mapreduce), SUBVL=1
1225 # 00 1 SVM CRM subvector reduce mode, SUBVL>1
1226 pass
1227 sv_mode = 0b00
1228
1229 ######################################
1230 # "mapreduce" modes
1231 elif sv_mode == 0b00:
1232 mode |= (0b1 << SVP64MODE.REDUCE) # sets mapreduce
1233 assert dst_zero == 0, "dest-zero not allowed in mapreduce mode"
1234 if reverse_gear:
1235 mode |= (0b1 << SVP64MODE.RG) # sets Reverse-gear mode
1236 if mapreduce_crm:
1237 mode |= (0b1 << SVP64MODE.CRM) # sets CRM mode
1238 assert rc_mode, "CRM only allowed when Rc=1"
1239 # bit of weird encoding to jam zero-pred or SVM mode in.
1240 # SVM mode can be enabled only when SUBVL=2/3/4 (vec2/3/4)
1241 if subvl == 0:
1242 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1243 elif mapreduce_svm:
1244 mode |= (0b1 << SVP64MODE.SVM) # sets SVM mode
1245
1246 ######################################
1247 # "failfirst" modes
1248 elif sv_mode == 0b01:
1249 assert src_zero == 0, "dest-zero not allowed in failfirst mode"
1250 if failfirst == 'RC1':
1251 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1252 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1253 assert rc_mode == False, "ffirst RC1 only ok when Rc=0"
1254 elif failfirst == '~RC1':
1255 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1256 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1257 mode |= (0b1 << SVP64MODE.INV) # ... with inversion
1258 assert rc_mode == False, "ffirst RC1 only ok when Rc=0"
1259 else:
1260 assert dst_zero == 0, "dst-zero not allowed in ffirst BO"
1261 assert rc_mode, "ffirst BO only possible when Rc=1"
1262 mode |= (failfirst << SVP64MODE.BO_LSB) # set BO
1263
1264 ######################################
1265 # "saturation" modes
1266 elif sv_mode == 0b10:
1267 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1268 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1269 mode |= (saturation << SVP64MODE.N) # signed/us saturation
1270
1271 ######################################
1272 # "predicate-result" modes. err... code-duplication from ffirst
1273 elif sv_mode == 0b11:
1274 assert src_zero == 0, "dest-zero not allowed in predresult mode"
1275 if predresult == 'RC1':
1276 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1277 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1278 assert rc_mode == False, "pr-mode RC1 only ok when Rc=0"
1279 elif predresult == '~RC1':
1280 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1281 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1282 mode |= (0b1 << SVP64MODE.INV) # ... with inversion
1283 assert rc_mode == False, "pr-mode RC1 only ok when Rc=0"
1284 else:
1285 assert dst_zero == 0, "dst-zero not allowed in pr-mode BO"
1286 assert rc_mode, "pr-mode BO only possible when Rc=1"
1287 mode |= (predresult << SVP64MODE.BO_LSB) # set BO
1288
1289 # whewww.... modes all done :)
1290 # now put into svp64_rm
1291 mode |= sv_mode
1292 # mode: bits 19-23
1293 svp64_rm.mode = mode
1294
1295 # put in predicate masks into svp64_rm
1296 if ptype == '2P':
1297 # source pred: bits 16-18
1298 svp64_rm.smask = smask
1299 # mask mode: bit 0
1300 svp64_rm.mmode = mmode
1301 # 1-pred: bits 1-3
1302 svp64_rm.mask = pmask
1303
1304 # and subvl: bits 8-9
1305 svp64_rm.subvl = subvl
1306
1307 # put in elwidths
1308 # srcwid: bits 6-7
1309 svp64_rm.ewsrc = srcwid
1310 # destwid: bits 4-5
1311 svp64_rm.elwidth = destwid
1312
1313 # nice debug printout. (and now for something completely different)
1314 # https://youtu.be/u0WOIwlXE9g?t=146
1315 svp64_rm_value = int(svp64_rm)
1316 log("svp64_rm", hex(svp64_rm_value), bin(svp64_rm_value))
1317 log(" mmode 0 :", bin(mmode))
1318 log(" pmask 1-3 :", bin(pmask))
1319 log(" dstwid 4-5 :", bin(destwid))
1320 log(" srcwid 6-7 :", bin(srcwid))
1321 log(" subvl 8-9 :", bin(subvl))
1322 log(" mode 19-23:", bin(mode))
1323 offs = 2 if etype == 'EXTRA2' else 3 # 2 or 3 bits
1324 for idx, sv_extra in extras.items():
1325 if idx is None:
1326 continue
1327 if idx[0] == 'imm':
1328 continue
1329 srcdest, idx, duplicate = idx
1330 start = (10+idx*offs)
1331 end = start + offs-1
1332 log(" extra%d %2d-%2d:" % (idx, start, end),
1333 bin(sv_extra))
1334 if ptype == '2P':
1335 log(" smask 16-17:", bin(smask))
1336 log()
1337
1338 # update prefix PO and ID (aka PID)
1339 svp64_prefix.po = 0x1
1340 svp64_prefix.id = 0b11
1341
1342 # fiinally yield the svp64 prefix and the thingy. v3.0b opcode
1343 rc = '.' if rc_mode else ''
1344 yield ".long 0x%08x" % int(svp64_prefix)
1345 log(v30b_op, v30b_newfields)
1346
1347 v30b_op_rc = v30b_op
1348 if not v30b_op.endswith('.'):
1349 v30b_op_rc += rc
1350
1351 # svstep is weird
1352 # FIXME(lkcl): should sv.svstep be like svstep?
1353 if v30b_op_rc in ("svstep", "svstep."):
1354 # compensate for `SVi -= 1` in svstep()
1355 v30b_newfields[1] = str(int(v30b_newfields[1]) + 1)
1356
1357 custom_insn_hook = CUSTOM_INSNS.get(v30b_op_rc)
1358 if custom_insn_hook is not None:
1359 fields = tuple(map(to_number, v30b_newfields))
1360 insn_num = custom_insn_hook(fields)
1361 log(opcode, bin(insn_num))
1362 yield ".long 0x%X # %s" % (insn_num, insn)
1363 return
1364 # argh, sv.fmadds etc. need to be done manually
1365 elif v30b_op == 'ffmadds':
1366 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1367 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1368 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1369 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1370 opcode |= int(v30b_newfields[3]) << (32-26) # FRC
1371 opcode |= 0b00101 << (32-31) # bits 26-30
1372 if rc:
1373 opcode |= 1 # Rc, bit 31.
1374 yield ".long 0x%x" % opcode
1375 # argh, sv.fdmadds need to be done manually
1376 elif v30b_op == 'fdmadds':
1377 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1378 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1379 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1380 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1381 opcode |= int(v30b_newfields[3]) << (32-26) # FRC
1382 opcode |= 0b11011 << (32-31) # bits 26-30
1383 if rc:
1384 opcode |= 1 # Rc, bit 31.
1385 yield ".long 0x%x" % opcode
1386 # argh, sv.ffadds etc. need to be done manually
1387 elif v30b_op == 'ffadds':
1388 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1389 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1390 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1391 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1392 opcode |= 0b1000001100 << (32-31) # bits 21-30
1393 if rc:
1394 opcode |= 1 # Rc, bit 31.
1395 yield ".long 0x%x" % opcode
1396 else:
1397 if not v30b_op.endswith('.'):
1398 v30b_op += rc
1399 yield "%s %s" % (v30b_op, ", ".join(v30b_newfields))
1400 log("new v3.0B fields", v30b_op, v30b_newfields)
1401
1402 def translate(self, lst):
1403 for insn in lst:
1404 yield from self.translate_one(insn)
1405
1406
1407 def macro_subst(macros, txt):
1408 again = True
1409 log("subst", txt, macros)
1410 while again:
1411 again = False
1412 for macro, value in macros.items():
1413 if macro == txt:
1414 again = True
1415 replaced = txt.replace(macro, value)
1416 log("macro", txt, "replaced", replaced, macro, value)
1417 txt = replaced
1418 continue
1419 toreplace = '%s.s' % macro
1420 if toreplace == txt:
1421 again = True
1422 replaced = txt.replace(toreplace, "%s.s" % value)
1423 log("macro", txt, "replaced", replaced, toreplace, value)
1424 txt = replaced
1425 continue
1426 toreplace = '%s.v' % macro
1427 if toreplace == txt:
1428 again = True
1429 replaced = txt.replace(toreplace, "%s.v" % value)
1430 log("macro", txt, "replaced", replaced, toreplace, value)
1431 txt = replaced
1432 continue
1433 toreplace = '(%s)' % macro
1434 if toreplace in txt:
1435 again = True
1436 replaced = txt.replace(toreplace, '(%s)' % value)
1437 log("macro", txt, "replaced", replaced, toreplace, value)
1438 txt = replaced
1439 continue
1440 log(" processed", txt)
1441 return txt
1442
1443
1444 def get_ws(line):
1445 # find whitespace
1446 ws = ''
1447 while line:
1448 if not line[0].isspace():
1449 break
1450 ws += line[0]
1451 line = line[1:]
1452 return ws, line
1453
1454
1455 def asm_process():
1456 # get an input file and an output file
1457 args = sys.argv[1:]
1458 if len(args) == 0:
1459 infile = sys.stdin
1460 outfile = sys.stdout
1461 # read the whole lot in advance in case of in-place
1462 lines = list(infile.readlines())
1463 elif len(args) != 2:
1464 print("pysvp64asm [infile | -] [outfile | -]", file=sys.stderr)
1465 exit(0)
1466 else:
1467 if args[0] == '--':
1468 infile = sys.stdin
1469 else:
1470 infile = open(args[0], "r")
1471 # read the whole lot in advance in case of in-place overwrite
1472 lines = list(infile.readlines())
1473
1474 if args[1] == '--':
1475 outfile = sys.stdout
1476 else:
1477 outfile = open(args[1], "w")
1478
1479 # read the line, look for custom insn, process it
1480 macros = {} # macros which start ".set"
1481 isa = SVP64Asm([])
1482 for line in lines:
1483 op = line.split("#")[0].strip()
1484 # identify macros
1485 if op.startswith(".set"):
1486 macro = op[4:].split(",")
1487 (macro, value) = map(str.strip, macro)
1488 macros[macro] = value
1489 if not op.startswith('sv.') and not op.startswith(tuple(CUSTOM_INSNS)):
1490 outfile.write(line)
1491 continue
1492
1493 (ws, line) = get_ws(line)
1494 lst = isa.translate_one(op, macros)
1495 lst = '; '.join(lst)
1496 outfile.write("%s%s # %s\n" % (ws, lst, op))
1497
1498
1499 if __name__ == '__main__':
1500 lst = ['slw 3, 1, 4',
1501 'extsw 5, 3',
1502 'sv.extsw 5, 3',
1503 'sv.cmpi 5, 1, 3, 2',
1504 'sv.setb 5, 31',
1505 'sv.isel 64.v, 3, 2, 65.v',
1506 'sv.setb/dm=r3/sm=1<<r3 5, 31',
1507 'sv.setb/m=r3 5, 31',
1508 'sv.setb/vec2 5, 31',
1509 'sv.setb/sw=8/ew=16 5, 31',
1510 'sv.extsw./ff=eq 5, 31',
1511 'sv.extsw./satu/sz/dz/sm=r3/dm=r3 5, 31',
1512 'sv.extsw./pr=eq 5.v, 31',
1513 'sv.add. 5.v, 2.v, 1.v',
1514 'sv.add./m=r3 5.v, 2.v, 1.v',
1515 ]
1516 lst += [
1517 'sv.stw 5.v, 4(1.v)',
1518 'sv.ld 5.v, 4(1.v)',
1519 'setvl. 2, 3, 4, 0, 1, 1',
1520 'sv.setvl. 2, 3, 4, 0, 1, 1',
1521 ]
1522 lst = [
1523 "sv.stfsu 0.v, 16(4.v)",
1524 ]
1525 lst = [
1526 "sv.stfsu/els 0.v, 16(4)",
1527 ]
1528 lst = [
1529 'sv.add./mr 5.v, 2.v, 1.v',
1530 ]
1531 macros = {'win2': '50', 'win': '60'}
1532 lst = [
1533 'sv.addi win2.v, win.v, -1',
1534 'sv.add./mrr 5.v, 2.v, 1.v',
1535 #'sv.lhzsh 5.v, 11(9.v), 15',
1536 #'sv.lwzsh 5.v, 11(9.v), 15',
1537 'sv.ffmadds 6.v, 2.v, 4.v, 6.v',
1538 ]
1539 lst = [
1540 #'sv.fmadds 0.v, 8.v, 16.v, 4.v',
1541 #'sv.ffadds 0.v, 8.v, 4.v',
1542 'svremap 11, 0, 1, 2, 3, 2, 1',
1543 'svshape 8, 1, 1, 1, 0',
1544 'svshape 8, 1, 1, 1, 1',
1545 ]
1546 lst = [
1547 #'sv.lfssh 4.v, 11(8.v), 15',
1548 #'sv.lwzsh 4.v, 11(8.v), 15',
1549 #'sv.svstep. 2.v, 4, 0',
1550 #'sv.fcfids. 48.v, 64.v',
1551 'sv.fcoss. 80.v, 0.v',
1552 'sv.fcoss. 20.v, 0.v',
1553 ]
1554 lst = [
1555 'sv.bc/all 3,12,192',
1556 'sv.bclr/vsbi 3,81.v,192',
1557 'sv.ld 5.v, 4(1.v)',
1558 'sv.svstep. 2.v, 4, 0',
1559 ]
1560 lst = [
1561 'maxs 3,12,5',
1562 'maxs. 3,12,5',
1563 'avgadd 3,12,5',
1564 'absdu 3,12,5',
1565 'absds 3,12,5',
1566 'absdacu 3,12,5',
1567 'absdacs 3,12,5',
1568 'cprop 3,12,5',
1569 'svindex 0,0,1,0,0,0,0',
1570 ]
1571 lst = [
1572 'sv.svstep./m=r3 2.v, 4, 0',
1573 'ternlogi 0,0,0,0x5',
1574 'fmvis 5,65535',
1575 'fmvis 5,1',
1576 'fmvis 5,2',
1577 'fmvis 5,4',
1578 'fmvis 5,8',
1579 'fmvis 5,16',
1580 'fmvis 5,32',
1581 'fmvis 5,64',
1582 'fmvis 5,32768',
1583 ]
1584 lst = [
1585 'sv.andi. *80, *80, 1',
1586 'sv.ffmadds. 6.v, 2.v, 4.v, 6.v', # incorrectly inserted 32-bit op
1587 'sv.ffmadds 6.v, 2.v, 4.v, 6.v', # correctly converted to .long
1588 'svshape2 8, 1, 31, 7, 1, 1',
1589 ]
1590 isa = SVP64Asm(lst, macros=macros)
1591 log("list:\n", "\n\t".join(list(isa)))
1592 # running svp64.py is designed to test hard-coded lists
1593 # (above) - which strictly speaking should all be unit tests.
1594 # if you need to actually do assembler translation at the
1595 # commandline use "pysvp64asm" - see setup.py
1596 # XXX NO. asm_process()