fix assembling `sv.add.`
[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 if v30b_op_orig not in isa.instr:
664 raise Exception("opcode %s of '%s' not supported" %
665 (v30b_op_orig, insn))
666 else:
667 isa_instr = isa.instr[v30b_op_orig]
668
669 if v30b_op_orig not in svp64.instrs:
670 if v30b_op in svp64.instrs:
671 rm = svp64.instrs[v30b_op] # one row of the svp64 RM CSV
672 else:
673 raise Exception(f"opcode {v30b_op_orig!r} of "
674 f"{insn!r} not an svp64 instruction")
675 else:
676 rm = svp64.instrs[v30b_op_orig] # one row of the svp64 RM CSV
677 v30b_regs = isa_instr.regs[0] # get regs info "RT, RA, RB"
678 log("v3.0B op", v30b_op, "Rc=1" if rc_mode else '')
679 log("v3.0B regs", opcode, v30b_regs)
680 log("RM", rm)
681
682 # right. the first thing to do is identify the ordering of
683 # the registers, by name. the EXTRA2/3 ordering is in
684 # rm['0']..rm['3'] but those fields contain the names RA, BB
685 # etc. we have to read the pseudocode to understand which
686 # reg is which in our instruction. sigh.
687
688 # first turn the svp64 rm into a "by name" dict, recording
689 # which position in the RM EXTRA it goes into
690 # also: record if the src or dest was a CR, for sanity-checking
691 # (elwidth overrides on CRs are banned)
692 decode = decode_extra(rm)
693 dest_reg_cr, src_reg_cr, svp64_src, svp64_dest = decode
694
695 log("EXTRA field index, src", svp64_src)
696 log("EXTRA field index, dest", svp64_dest)
697
698 # okaaay now we identify the field value (opcode N,N,N) with
699 # the pseudo-code info (opcode RT, RA, RB)
700 assert len(fields) == len(v30b_regs), \
701 "length of fields %s must match insn `%s` fields %s" % \
702 (str(v30b_regs), insn, str(fields))
703 opregfields = zip(fields, v30b_regs) # err that was easy
704
705 # now for each of those find its place in the EXTRA encoding
706 # note there is the possibility (for LD/ST-with-update) of
707 # RA occurring **TWICE**. to avoid it getting added to the
708 # v3.0B suffix twice, we spot it as a duplicate, here
709 extras = OrderedDict()
710 for idx, (field, regname) in enumerate(opregfields):
711 imm, regname = decode_imm(regname)
712 rtype = get_regtype(regname)
713 log(" idx find", rtype, idx, field, regname, imm)
714 if rtype is None:
715 # probably an immediate field, append it straight
716 extras[('imm', idx, False)] = (idx, field, None, None, None)
717 continue
718 extra = svp64_src.get(regname, None)
719 if extra is not None:
720 extra = ('s', extra, False) # not a duplicate
721 extras[extra] = (idx, field, regname, rtype, imm)
722 log(" idx src", idx, extra, extras[extra])
723 dextra = svp64_dest.get(regname, None)
724 log("regname in", regname, dextra)
725 if dextra is not None:
726 is_a_duplicate = extra is not None # duplicate spotted
727 dextra = ('d', dextra, is_a_duplicate)
728 extras[dextra] = (idx, field, regname, rtype, imm)
729 log(" idx dst", idx, extra, extras[dextra])
730
731 # great! got the extra fields in their associated positions:
732 # also we know the register type. now to create the EXTRA encodings
733 etype = rm['Etype'] # Extra type: EXTRA3/EXTRA2
734 ptype = rm['Ptype'] # Predication type: Twin / Single
735 extra_bits = 0
736 v30b_newfields = []
737 for extra_idx, (idx, field, rname, rtype, iname) in extras.items():
738 # is it a field we don't alter/examine? if so just put it
739 # into newfields
740 if rtype is None:
741 v30b_newfields.append(field)
742 continue
743
744 # identify if this is a ld/st immediate(reg) thing
745 ldst_imm = "(" in field and field[-1] == ')'
746 if ldst_imm:
747 immed, field = field[:-1].split("(")
748
749 field, regmode = decode_reg(field, macros=macros)
750 log(" ", extra_idx, rname, rtype,
751 regmode, iname, field, end=" ")
752
753 # see Mode field https://libre-soc.org/openpower/sv/svp64/
754 # XXX TODO: the following is a bit of a laborious repeated
755 # mess, which could (and should) easily be parameterised.
756 # XXX also TODO: the LD/ST modes which are different
757 # https://libre-soc.org/openpower/sv/ldst/
758
759 # rright. SVP64 register numbering is from 0 to 127
760 # for GPRs, FPRs *and* CR Fields, where for v3.0 the GPRs and RPFs
761 # are 0-31 and CR Fields are only 0-7. the SVP64 RM "Extra"
762 # area is used to extend the numbering from the 32-bit
763 # instruction, and also to record whether the register
764 # is scalar or vector. on a per-operand basis. this
765 # results in a slightly finnicky encoding: here we go...
766
767 # encode SV-GPR and SV-FPR field into extra, v3.0field
768 if rtype in ['GPR', 'FPR']:
769 sv_extra, field = get_extra_gpr(etype, regmode, field)
770 # now sanity-check. EXTRA3 is ok, EXTRA2 has limits
771 # (and shrink to a single bit if ok)
772 if etype == 'EXTRA2':
773 if regmode == 'scalar':
774 # range is r0-r63 in increments of 1
775 assert (sv_extra >> 1) == 0, \
776 "scalar GPR %s cannot fit into EXTRA2 %s" % \
777 (rname, str(extras[extra_idx]))
778 # all good: encode as scalar
779 sv_extra = sv_extra & 0b01
780 else:
781 # range is r0-r127 in increments of 2 (r0 r2 ... r126)
782 assert sv_extra & 0b01 == 0, \
783 "%s: vector field %s cannot fit " \
784 "into EXTRA2 %s" % \
785 (insn, rname, str(extras[extra_idx]))
786 # all good: encode as vector (bit 2 set)
787 sv_extra = 0b10 | (sv_extra >> 1)
788 elif regmode == 'vector':
789 # EXTRA3 vector bit needs marking
790 sv_extra |= 0b100
791
792 # encode SV-CR 3-bit field into extra, v3.0field.
793 # 3-bit is for things like BF and BFA
794 elif rtype == 'CR_3bit':
795 sv_extra, field = crf_extra(etype, regmode, field, extras)
796
797 # encode SV-CR 5-bit field into extra, v3.0field
798 # 5-bit is for things like BA BB BC BT etc.
799 # *sigh* this is the same as 3-bit except the 2 LSBs of the
800 # 5-bit field are passed through unaltered.
801 elif rtype == 'CR_5bit':
802 cr_subfield = field & 0b11 # record bottom 2 bits for later
803 field = field >> 2 # strip bottom 2 bits
804 # use the exact same 3-bit function for the top 3 bits
805 sv_extra, field = crf_extra(etype, regmode, field, extras)
806 # reconstruct the actual 5-bit CR field (preserving the
807 # bottom 2 bits, unaltered)
808 field = (field << 2) | cr_subfield
809
810 else:
811 raise Exception("no type match: %s" % rtype)
812
813 # capture the extra field info
814 log("=>", "%5s" % bin(sv_extra), field)
815 extras[extra_idx] = sv_extra
816
817 # append altered field value to v3.0b, differs for LDST
818 # note that duplicates are skipped e.g. EXTRA2 contains
819 # *BOTH* s:RA *AND* d:RA which happens on LD/ST-with-update
820 srcdest, idx, duplicate = extra_idx
821 if duplicate: # skip adding to v3.0b fields, already added
822 continue
823 if ldst_imm:
824 v30b_newfields.append(("%s(%s)" % (immed, str(field))))
825 else:
826 v30b_newfields.append(str(field))
827
828 log("new v3.0B fields", v30b_op, v30b_newfields)
829 log("extras", extras)
830
831 # rright. now we have all the info. start creating SVP64 RM
832 svp64_rm = SVP64RMFields()
833
834 # begin with EXTRA fields
835 for idx, sv_extra in extras.items():
836 log(idx)
837 if idx is None:
838 continue
839 if idx[0] == 'imm':
840 continue
841 srcdest, idx, duplicate = idx
842 if etype == 'EXTRA2':
843 svp64_rm.extra2[idx].eq(
844 SelectableInt(sv_extra, SVP64RM_EXTRA2_SPEC_SIZE))
845 else:
846 svp64_rm.extra3[idx].eq(
847 SelectableInt(sv_extra, SVP64RM_EXTRA3_SPEC_SIZE))
848
849 # identify if the op is a LD/ST. the "blegh" way. copied
850 # from power_enums. TODO, split the list _insns down.
851 is_ld = v30b_op in [
852 "lbarx", "lbz", "lbzu", "lbzux", "lbzx", # load byte
853 "ld", "ldarx", "ldbrx", "ldu", "ldux", "ldx", # load double
854 "lfs", "lfsx", "lfsu", "lfsux", # FP load single
855 "lfd", "lfdx", "lfdu", "lfdux", "lfiwzx", "lfiwax", # FP load dbl
856 "lha", "lharx", "lhau", "lhaux", "lhax", # load half
857 "lhbrx", "lhz", "lhzu", "lhzux", "lhzx", # more load half
858 "lwa", "lwarx", "lwaux", "lwax", "lwbrx", # load word
859 "lwz", "lwzcix", "lwzu", "lwzux", "lwzx", # more load word
860 ]
861 is_st = v30b_op in [
862 "stb", "stbcix", "stbcx", "stbu", "stbux", "stbx",
863 "std", "stdbrx", "stdcx", "stdu", "stdux", "stdx",
864 "stfs", "stfsx", "stfsu", "stfux", # FP store sgl
865 "stfd", "stfdx", "stfdu", "stfdux", "stfiwx", # FP store dbl
866 "sth", "sthbrx", "sthcx", "sthu", "sthux", "sthx",
867 "stw", "stwbrx", "stwcx", "stwu", "stwux", "stwx",
868 ]
869 # use this to determine if the SVP64 RM format is different.
870 # see https://libre-soc.org/openpower/sv/ldst/
871 is_ldst = is_ld or is_st
872
873 # branch-conditional detection
874 is_bc = v30b_op in [
875 "bc", "bclr",
876 ]
877
878 # parts of svp64_rm
879 mmode = 0 # bit 0
880 pmask = 0 # bits 1-3
881 destwid = 0 # bits 4-5
882 srcwid = 0 # bits 6-7
883 subvl = 0 # bits 8-9
884 smask = 0 # bits 16-18 but only for twin-predication
885 mode = 0 # bits 19-23
886
887 mask_m_specified = False
888 has_pmask = False
889 has_smask = False
890
891 saturation = None
892 src_zero = 0
893 dst_zero = 0
894 sv_mode = None
895
896 mapreduce = False
897 reverse_gear = False
898 mapreduce_crm = False
899 mapreduce_svm = False
900
901 predresult = False
902 failfirst = False
903 ldst_elstride = 0
904
905 # branch-conditional bits
906 bc_all = 0
907 bc_lru = 0
908 bc_brc = 0
909 bc_svstep = 0
910 bc_vsb = 0
911 bc_vlset = 0
912 bc_vli = 0
913 bc_snz = 0
914
915 # ok let's start identifying opcode augmentation fields
916 for encmode in opmodes:
917 # predicate mask (src and dest)
918 if encmode.startswith("m="):
919 pme = encmode
920 pmmode, pmask = decode_predicate(encmode[2:])
921 smmode, smask = pmmode, pmask
922 mmode = pmmode
923 mask_m_specified = True
924 # predicate mask (dest)
925 elif encmode.startswith("dm="):
926 pme = encmode
927 pmmode, pmask = decode_predicate(encmode[3:])
928 mmode = pmmode
929 has_pmask = True
930 # predicate mask (src, twin-pred)
931 elif encmode.startswith("sm="):
932 sme = encmode
933 smmode, smask = decode_predicate(encmode[3:])
934 mmode = smmode
935 has_smask = True
936 # vec2/3/4
937 elif encmode.startswith("vec"):
938 subvl = decode_subvl(encmode[3:])
939 # elwidth
940 elif encmode.startswith("ew="):
941 destwid = decode_elwidth(encmode[3:])
942 elif encmode.startswith("sw="):
943 srcwid = decode_elwidth(encmode[3:])
944 # element-strided LD/ST
945 elif encmode == 'els':
946 ldst_elstride = 1
947 # saturation
948 elif encmode == 'sats':
949 assert sv_mode is None
950 saturation = 1
951 sv_mode = 0b10
952 elif encmode == 'satu':
953 assert sv_mode is None
954 sv_mode = 0b10
955 saturation = 0
956 # predicate zeroing
957 elif encmode == 'sz':
958 src_zero = 1
959 elif encmode == 'dz':
960 dst_zero = 1
961 # failfirst
962 elif encmode.startswith("ff="):
963 assert sv_mode is None
964 sv_mode = 0b01
965 failfirst = decode_ffirst(encmode[3:])
966 # predicate-result, interestingly same as fail-first
967 elif encmode.startswith("pr="):
968 assert sv_mode is None
969 sv_mode = 0b11
970 predresult = decode_ffirst(encmode[3:])
971 # map-reduce mode, reverse-gear
972 elif encmode == 'mrr':
973 assert sv_mode is None
974 sv_mode = 0b00
975 mapreduce = True
976 reverse_gear = True
977 # map-reduce mode
978 elif encmode == 'mr':
979 assert sv_mode is None
980 sv_mode = 0b00
981 mapreduce = True
982 elif encmode == 'crm': # CR on map-reduce
983 assert sv_mode is None
984 sv_mode = 0b00
985 mapreduce_crm = True
986 elif encmode == 'svm': # sub-vector mode
987 mapreduce_svm = True
988 elif is_bc:
989 if encmode == 'all':
990 bc_all = 1
991 elif encmode == 'st': # svstep mode
992 bc_step = 1
993 elif encmode == 'sr': # svstep BRc mode
994 bc_step = 1
995 bc_brc = 1
996 elif encmode == 'vs': # VLSET mode
997 bc_vlset = 1
998 elif encmode == 'vsi': # VLSET mode with VLI (VL inclusives)
999 bc_vlset = 1
1000 bc_vli = 1
1001 elif encmode == 'vsb': # VLSET mode with VSb
1002 bc_vlset = 1
1003 bc_vsb = 1
1004 elif encmode == 'vsbi': # VLSET mode with VLI and VSb
1005 bc_vlset = 1
1006 bc_vli = 1
1007 bc_vsb = 1
1008 elif encmode == 'snz': # sz (only) already set above
1009 src_zero = 1
1010 bc_snz = 1
1011 elif encmode == 'lu': # LR update mode
1012 bc_lru = 1
1013 else:
1014 raise AssertionError("unknown encmode %s" % encmode)
1015 else:
1016 raise AssertionError("unknown encmode %s" % encmode)
1017
1018 if ptype == '2P':
1019 # since m=xx takes precedence (overrides) sm=xx and dm=xx,
1020 # treat them as mutually exclusive
1021 if mask_m_specified:
1022 assert not has_smask,\
1023 "cannot have both source-mask and predicate mask"
1024 assert not has_pmask,\
1025 "cannot have both dest-mask and predicate mask"
1026 # since the default is INT predication (ALWAYS), if you
1027 # specify one CR mask, you must specify both, to avoid
1028 # mixing INT and CR reg types
1029 if has_pmask and pmmode == 1:
1030 assert has_smask, \
1031 "need explicit source-mask in CR twin predication"
1032 if has_smask and smmode == 1:
1033 assert has_pmask, \
1034 "need explicit dest-mask in CR twin predication"
1035 # sanity-check that 2Pred mask is same mode
1036 if has_pmask and has_smask:
1037 assert smmode == pmmode, \
1038 "predicate masks %s and %s must be same reg type" % \
1039 (pme, sme)
1040
1041 # sanity-check that twin-predication mask only specified in 2P mode
1042 if ptype == '1P':
1043 assert not has_smask, \
1044 "source-mask can only be specified on Twin-predicate ops"
1045 assert not has_pmask, \
1046 "dest-mask can only be specified on Twin-predicate ops"
1047
1048 # construct the mode field, doing sanity-checking along the way
1049 if mapreduce_svm:
1050 assert sv_mode == 0b00, "sub-vector mode in mapreduce only"
1051 assert subvl != 0, "sub-vector mode not possible on SUBVL=1"
1052
1053 if src_zero:
1054 assert has_smask or mask_m_specified, \
1055 "src zeroing requires a source predicate"
1056 if dst_zero:
1057 assert has_pmask or mask_m_specified, \
1058 "dest zeroing requires a dest predicate"
1059
1060 # okaaay, so there are 4 different modes, here, which will be
1061 # partly-merged-in: is_ldst is merged in with "normal", but
1062 # is_bc is so different it's done separately. likewise is_cr
1063 # (when it is done). here are the maps:
1064
1065 # for "normal" arithmetic: https://libre-soc.org/openpower/sv/normal/
1066 """
1067 | 0-1 | 2 | 3 4 | description |
1068 | --- | --- |---------|-------------------------- |
1069 | 00 | 0 | dz sz | normal mode |
1070 | 00 | 1 | 0 RG | scalar reduce mode (mapreduce), SUBVL=1 |
1071 | 00 | 1 | 1 / | parallel reduce mode (mapreduce), SUBVL=1 |
1072 | 00 | 1 | SVM RG | subvector reduce mode, SUBVL>1 |
1073 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
1074 | 01 | inv | VLi RC1 | Rc=0: ffirst z/nonz |
1075 | 10 | N | dz sz | sat mode: N=0/1 u/s |
1076 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1077 | 11 | inv | dz RC1 | Rc=0: pred-result z/nonz |
1078 """
1079
1080 # https://libre-soc.org/openpower/sv/ldst/
1081 # for LD/ST-immediate:
1082 """
1083 | 0-1 | 2 | 3 4 | description |
1084 | --- | --- |---------|--------------------------- |
1085 | 00 | 0 | dz els | normal mode |
1086 | 00 | 1 | dz shf | shift mode |
1087 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
1088 | 01 | inv | els RC1 | Rc=0: ffirst z/nonz |
1089 | 10 | N | dz els | sat mode: N=0/1 u/s |
1090 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1091 | 11 | inv | els RC1 | Rc=0: pred-result z/nonz |
1092 """
1093
1094 # for LD/ST-indexed (RA+RB):
1095 """
1096 | 0-1 | 2 | 3 4 | description |
1097 | --- | --- |---------|-------------------------- |
1098 | 00 | SEA | dz sz | normal mode |
1099 | 01 | SEA | dz sz | Strided (scalar only source) |
1100 | 10 | N | dz sz | sat mode: N=0/1 u/s |
1101 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1102 | 11 | inv | dz RC1 | Rc=0: pred-result z/nonz |
1103 """
1104
1105 # and leaving out branches and cr_ops for now because they're
1106 # under development
1107 """ TODO branches and cr_ops
1108 """
1109
1110 # now create mode and (overridden) src/dst widths
1111 # XXX TODO: sanity-check bc modes
1112 if is_bc:
1113 sv_mode = ((bc_svstep << SVP64MODE.MOD2_MSB) |
1114 (bc_vlset << SVP64MODE.MOD2_LSB) |
1115 (bc_snz << SVP64MODE.BC_SNZ))
1116 srcwid = (bc_vsb << 1) | bc_lru
1117 destwid = (bc_lru << 1) | bc_all
1118
1119 else:
1120
1121 ######################################
1122 # "normal" mode
1123 if sv_mode is None:
1124 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1125 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1126 if is_ldst:
1127 # TODO: for now, LD/ST-indexed is ignored.
1128 mode |= ldst_elstride << SVP64MODE.ELS_NORMAL # el-strided
1129 else:
1130 # TODO, reduce and subvector mode
1131 # 00 1 dz CRM reduce mode (mapreduce), SUBVL=1
1132 # 00 1 SVM CRM subvector reduce mode, SUBVL>1
1133 pass
1134 sv_mode = 0b00
1135
1136 ######################################
1137 # "mapreduce" modes
1138 elif sv_mode == 0b00:
1139 mode |= (0b1 << SVP64MODE.REDUCE) # sets mapreduce
1140 assert dst_zero == 0, "dest-zero not allowed in mapreduce mode"
1141 if reverse_gear:
1142 mode |= (0b1 << SVP64MODE.RG) # sets Reverse-gear mode
1143 if mapreduce_crm:
1144 mode |= (0b1 << SVP64MODE.CRM) # sets CRM mode
1145 assert rc_mode, "CRM only allowed when Rc=1"
1146 # bit of weird encoding to jam zero-pred or SVM mode in.
1147 # SVM mode can be enabled only when SUBVL=2/3/4 (vec2/3/4)
1148 if subvl == 0:
1149 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1150 elif mapreduce_svm:
1151 mode |= (0b1 << SVP64MODE.SVM) # sets SVM mode
1152
1153 ######################################
1154 # "failfirst" modes
1155 elif sv_mode == 0b01:
1156 assert src_zero == 0, "dest-zero not allowed in failfirst mode"
1157 if failfirst == 'RC1':
1158 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1159 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1160 assert rc_mode == False, "ffirst RC1 only ok when Rc=0"
1161 elif failfirst == '~RC1':
1162 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1163 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1164 mode |= (0b1 << SVP64MODE.INV) # ... with inversion
1165 assert rc_mode == False, "ffirst RC1 only ok when Rc=0"
1166 else:
1167 assert dst_zero == 0, "dst-zero not allowed in ffirst BO"
1168 assert rc_mode, "ffirst BO only possible when Rc=1"
1169 mode |= (failfirst << SVP64MODE.BO_LSB) # set BO
1170
1171 ######################################
1172 # "saturation" modes
1173 elif sv_mode == 0b10:
1174 mode |= src_zero << SVP64MODE.SZ # predicate zeroing
1175 mode |= dst_zero << SVP64MODE.DZ # predicate zeroing
1176 mode |= (saturation << SVP64MODE.N) # signed/us saturation
1177
1178 ######################################
1179 # "predicate-result" modes. err... code-duplication from ffirst
1180 elif sv_mode == 0b11:
1181 assert src_zero == 0, "dest-zero not allowed in predresult mode"
1182 if predresult == 'RC1':
1183 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1184 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1185 assert rc_mode == False, "pr-mode RC1 only ok when Rc=0"
1186 elif predresult == '~RC1':
1187 mode |= (0b1 << SVP64MODE.RC1) # sets RC1 mode
1188 mode |= (dst_zero << SVP64MODE.DZ) # predicate dst-zeroing
1189 mode |= (0b1 << SVP64MODE.INV) # ... with inversion
1190 assert rc_mode == False, "pr-mode RC1 only ok when Rc=0"
1191 else:
1192 assert dst_zero == 0, "dst-zero not allowed in pr-mode BO"
1193 assert rc_mode, "pr-mode BO only possible when Rc=1"
1194 mode |= (predresult << SVP64MODE.BO_LSB) # set BO
1195
1196 # whewww.... modes all done :)
1197 # now put into svp64_rm
1198 mode |= sv_mode
1199 # mode: bits 19-23
1200 svp64_rm.mode.eq(SelectableInt(mode, SVP64RM_MODE_SIZE))
1201
1202 # put in predicate masks into svp64_rm
1203 if ptype == '2P':
1204 # source pred: bits 16-18
1205 svp64_rm.smask.eq(SelectableInt(smask, SVP64RM_SMASK_SIZE))
1206 # mask mode: bit 0
1207 svp64_rm.mmode.eq(SelectableInt(mmode, SVP64RM_MMODE_SIZE))
1208 # 1-pred: bits 1-3
1209 svp64_rm.mask.eq(SelectableInt(pmask, SVP64RM_MASK_SIZE))
1210
1211 # and subvl: bits 8-9
1212 svp64_rm.subvl.eq(SelectableInt(subvl, SVP64RM_SUBVL_SIZE))
1213
1214 # put in elwidths
1215 # srcwid: bits 6-7
1216 svp64_rm.ewsrc.eq(SelectableInt(srcwid, SVP64RM_EWSRC_SIZE))
1217 # destwid: bits 4-5
1218 svp64_rm.elwidth.eq(SelectableInt(destwid, SVP64RM_ELWIDTH_SIZE))
1219
1220 # nice debug printout. (and now for something completely different)
1221 # https://youtu.be/u0WOIwlXE9g?t=146
1222 svp64_rm_value = svp64_rm.spr.value
1223 log("svp64_rm", hex(svp64_rm_value), bin(svp64_rm_value))
1224 log(" mmode 0 :", bin(mmode))
1225 log(" pmask 1-3 :", bin(pmask))
1226 log(" dstwid 4-5 :", bin(destwid))
1227 log(" srcwid 6-7 :", bin(srcwid))
1228 log(" subvl 8-9 :", bin(subvl))
1229 log(" mode 19-23:", bin(mode))
1230 offs = 2 if etype == 'EXTRA2' else 3 # 2 or 3 bits
1231 for idx, sv_extra in extras.items():
1232 if idx is None:
1233 continue
1234 if idx[0] == 'imm':
1235 continue
1236 srcdest, idx, duplicate = idx
1237 start = (10+idx*offs)
1238 end = start + offs-1
1239 log(" extra%d %2d-%2d:" % (idx, start, end),
1240 bin(sv_extra))
1241 if ptype == '2P':
1242 log(" smask 16-17:", bin(smask))
1243 log()
1244
1245 # first, construct the prefix from its subfields
1246 svp64_prefix = SVP64PrefixFields()
1247 svp64_prefix.major.eq(SelectableInt(0x1, SV64P_MAJOR_SIZE))
1248 svp64_prefix.pid.eq(SelectableInt(0b11, SV64P_PID_SIZE))
1249 svp64_prefix.rm.eq(svp64_rm.spr)
1250
1251 # fiinally yield the svp64 prefix and the thingy. v3.0b opcode
1252 rc = '.' if rc_mode else ''
1253 yield ".long 0x%08x" % svp64_prefix.insn.value
1254 log(v30b_op, v30b_newfields)
1255 # argh, sv.fmadds etc. need to be done manually
1256 if v30b_op == 'ffmadds':
1257 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1258 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1259 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1260 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1261 opcode |= int(v30b_newfields[3]) << (32-26) # FRC
1262 opcode |= 0b00101 << (32-31) # bits 26-30
1263 if rc:
1264 opcode |= 1 # Rc, bit 31.
1265 yield ".long 0x%x" % opcode
1266 # argh, sv.fdmadds need to be done manually
1267 elif v30b_op == 'fdmadds':
1268 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1269 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1270 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1271 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1272 opcode |= int(v30b_newfields[3]) << (32-26) # FRC
1273 opcode |= 0b01111 << (32-31) # bits 26-30
1274 if rc:
1275 opcode |= 1 # Rc, bit 31.
1276 yield ".long 0x%x" % opcode
1277 # argh, sv.ffadds etc. need to be done manually
1278 elif v30b_op == 'ffadds':
1279 opcode = 59 << (32-6) # bits 0..6 (MSB0)
1280 opcode |= int(v30b_newfields[0]) << (32-11) # FRT
1281 opcode |= int(v30b_newfields[1]) << (32-16) # FRA
1282 opcode |= int(v30b_newfields[2]) << (32-21) # FRB
1283 opcode |= 0b01101 << (32-31) # bits 26-30
1284 if rc:
1285 opcode |= 1 # Rc, bit 31.
1286 yield ".long 0x%x" % opcode
1287 # sigh have to do svstep here manually for now...
1288 elif v30b_op in ["svstep", "svstep."]:
1289 insn = 22 << (31-5) # opcode 22, bits 0-5
1290 insn |= int(v30b_newfields[0]) << (31-10) # RT , bits 6-10
1291 insn |= int(v30b_newfields[1]) << (31-22) # SVi , bits 16-22
1292 insn |= int(v30b_newfields[2]) << (31-25) # vf , bit 25
1293 insn |= 0b10011 << (31-30) # XO , bits 26..30
1294 if opcode == 'svstep.':
1295 insn |= 1 << (31-31) # Rc=1 , bit 31
1296 log("svstep", bin(insn))
1297 yield ".long 0x%x" % insn
1298 # argh, sv.fcoss etc. need to be done manually
1299 elif v30b_op in ["fcoss", "fcoss."]:
1300 insn = 59 << (31-5) # opcode 59, bits 0-5
1301 insn |= int(v30b_newfields[0]) << (31-10) # RT , bits 6-10
1302 insn |= int(v30b_newfields[1]) << (31-20) # RB , bits 16-20
1303 insn |= 0b1000101110 << (31-30) # XO , bits 21..30
1304 if opcode == 'fcoss.':
1305 insn |= 1 << (31-31) # Rc=1 , bit 31
1306 log("fcoss", bin(insn))
1307 yield ".long 0x%x" % insn
1308 else:
1309 if not v30b_op.endswith('.'):
1310 v30b_op += rc
1311 yield "%s %s" % (v30b_op, ", ".join(v30b_newfields))
1312 log("new v3.0B fields", v30b_op, v30b_newfields)
1313
1314 def translate(self, lst):
1315 for insn in lst:
1316 yield from self.translate_one(insn)
1317
1318
1319 def macro_subst(macros, txt):
1320 again = True
1321 log("subst", txt, macros)
1322 while again:
1323 again = False
1324 for macro, value in macros.items():
1325 if macro == txt:
1326 again = True
1327 replaced = txt.replace(macro, value)
1328 log("macro", txt, "replaced", replaced, macro, value)
1329 txt = replaced
1330 continue
1331 toreplace = '%s.s' % macro
1332 if toreplace == txt:
1333 again = True
1334 replaced = txt.replace(toreplace, "%s.s" % value)
1335 log("macro", txt, "replaced", replaced, toreplace, value)
1336 txt = replaced
1337 continue
1338 toreplace = '%s.v' % macro
1339 if toreplace == txt:
1340 again = True
1341 replaced = txt.replace(toreplace, "%s.v" % value)
1342 log("macro", txt, "replaced", replaced, toreplace, value)
1343 txt = replaced
1344 continue
1345 toreplace = '(%s)' % macro
1346 if toreplace in txt:
1347 again = True
1348 replaced = txt.replace(toreplace, '(%s)' % value)
1349 log("macro", txt, "replaced", replaced, toreplace, value)
1350 txt = replaced
1351 continue
1352 log(" processed", txt)
1353 return txt
1354
1355
1356 def get_ws(line):
1357 # find whitespace
1358 ws = ''
1359 while line:
1360 if not line[0].isspace():
1361 break
1362 ws += line[0]
1363 line = line[1:]
1364 return ws, line
1365
1366
1367 def asm_process():
1368 # get an input file and an output file
1369 args = sys.argv[1:]
1370 if len(args) == 0:
1371 infile = sys.stdin
1372 outfile = sys.stdout
1373 # read the whole lot in advance in case of in-place
1374 lines = list(infile.readlines())
1375 elif len(args) != 2:
1376 print("pysvp64asm [infile | -] [outfile | -]", file=sys.stderr)
1377 exit(0)
1378 else:
1379 if args[0] == '--':
1380 infile = sys.stdin
1381 else:
1382 infile = open(args[0], "r")
1383 # read the whole lot in advance in case of in-place overwrite
1384 lines = list(infile.readlines())
1385
1386 if args[1] == '--':
1387 outfile = sys.stdout
1388 else:
1389 outfile = open(args[1], "w")
1390
1391 # read the line, look for custom insn, process it
1392 macros = {} # macros which start ".set"
1393 isa = SVP64Asm([])
1394 for line in lines:
1395 op = line.split("#")[0].strip()
1396 # identify macros
1397 if op.startswith(".set"):
1398 macro = op[4:].split(",")
1399 (macro, value) = map(str.strip, macro)
1400 macros[macro] = value
1401 if not op.startswith('sv.') and not op.startswith(tuple(CUSTOM_INSNS)):
1402 outfile.write(line)
1403 continue
1404
1405 (ws, line) = get_ws(line)
1406 lst = isa.translate_one(op, macros)
1407 lst = '; '.join(lst)
1408 outfile.write("%s%s # %s\n" % (ws, lst, op))
1409
1410
1411 if __name__ == '__main__':
1412 lst = ['slw 3, 1, 4',
1413 'extsw 5, 3',
1414 'sv.extsw 5, 3',
1415 'sv.cmpi 5, 1, 3, 2',
1416 'sv.setb 5, 31',
1417 'sv.isel 64.v, 3, 2, 65.v',
1418 'sv.setb/dm=r3/sm=1<<r3 5, 31',
1419 'sv.setb/m=r3 5, 31',
1420 'sv.setb/vec2 5, 31',
1421 'sv.setb/sw=8/ew=16 5, 31',
1422 'sv.extsw./ff=eq 5, 31',
1423 'sv.extsw./satu/sz/dz/sm=r3/dm=r3 5, 31',
1424 'sv.extsw./pr=eq 5.v, 31',
1425 'sv.add. 5.v, 2.v, 1.v',
1426 'sv.add./m=r3 5.v, 2.v, 1.v',
1427 ]
1428 lst += [
1429 'sv.stw 5.v, 4(1.v)',
1430 'sv.ld 5.v, 4(1.v)',
1431 'setvl. 2, 3, 4, 0, 1, 1',
1432 'sv.setvl. 2, 3, 4, 0, 1, 1',
1433 ]
1434 lst = [
1435 "sv.stfsu 0.v, 16(4.v)",
1436 ]
1437 lst = [
1438 "sv.stfsu/els 0.v, 16(4)",
1439 ]
1440 lst = [
1441 'sv.add./mr 5.v, 2.v, 1.v',
1442 ]
1443 macros = {'win2': '50', 'win': '60'}
1444 lst = [
1445 'sv.addi win2.v, win.v, -1',
1446 'sv.add./mrr 5.v, 2.v, 1.v',
1447 #'sv.lhzsh 5.v, 11(9.v), 15',
1448 #'sv.lwzsh 5.v, 11(9.v), 15',
1449 'sv.ffmadds 6.v, 2.v, 4.v, 6.v',
1450 ]
1451 lst = [
1452 #'sv.fmadds 0.v, 8.v, 16.v, 4.v',
1453 #'sv.ffadds 0.v, 8.v, 4.v',
1454 'svremap 11, 0, 1, 2, 3, 2, 1',
1455 'svshape 8, 1, 1, 1, 0',
1456 'svshape 8, 1, 1, 1, 1',
1457 ]
1458 lst = [
1459 #'sv.lfssh 4.v, 11(8.v), 15',
1460 #'sv.lwzsh 4.v, 11(8.v), 15',
1461 #'sv.svstep. 2.v, 4, 0',
1462 #'sv.fcfids. 48.v, 64.v',
1463 'sv.fcoss. 80.v, 0.v',
1464 'sv.fcoss. 20.v, 0.v',
1465 ]
1466 lst = [
1467 'sv.bc/all 3,12,192',
1468 'sv.bclr/vsbi 3,81.v,192',
1469 'sv.ld 5.v, 4(1.v)',
1470 'sv.svstep. 2.v, 4, 0',
1471 ]
1472 lst = [
1473 'maxs 3,12,5',
1474 'maxs. 3,12,5',
1475 'avgadd 3,12,5',
1476 'absdu 3,12,5',
1477 'absds 3,12,5',
1478 'absdacu 3,12,5',
1479 'absdacs 3,12,5',
1480 'cprop 3,12,5',
1481 'svindex 0,0,1,0,0,0,0',
1482 ]
1483 lst = [
1484 'sv.svstep./m=r3 2.v, 4, 0',
1485 'ternlogi 0,0,0,0x5',
1486 'fmvis 5,65535',
1487 'fmvis 5,1',
1488 'fmvis 5,2',
1489 'fmvis 5,4',
1490 'fmvis 5,8',
1491 'fmvis 5,16',
1492 'fmvis 5,32',
1493 'fmvis 5,64',
1494 'fmvis 5,32768',
1495 ]
1496 lst = [
1497 'sv.andi. *80, *80, 1',
1498 ]
1499 isa = SVP64Asm(lst, macros=macros)
1500 log("list", list(isa))
1501 # running svp64.py is designed to test hard-coded lists
1502 # (above) - which strictly speaking should all be unit tests.
1503 # if you need to actually do assembler translation at the
1504 # commandline use "pysvp64asm" - see setup.py
1505 # XXX NO. asm_process()