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