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