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