1 # SPDX-License-Identifier: LGPLv3+
2 # Copyright (C) 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3 # Funded by NLnet http://nlnet.nl
5 """SVP64 OpenPOWER v3.0B assembly translator
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.
10 It is very simple and straightforward, the only weirdness being the
11 extraction of the register information and conversion to v3.0B numbering.
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
24 from collections
import OrderedDict
26 from openpower
.decoder
.pseudo
.pagereader
import ISA
27 from openpower
.decoder
.power_svp64
import SVP64RM
, get_regtype
, decode_extra
28 from openpower
.decoder
.selectable_int
import SelectableInt
29 from openpower
.consts
import SVP64MODE
30 from openpower
.decoder
.power_insn
import SVP64Instruction
31 from openpower
.decoder
.power_insn
import Database
32 from openpower
.decoder
.power_enums
import find_wiki_dir
35 from openpower
.util
import log
38 def instruction(*fields
):
39 def instruction(insn
, desc
):
40 (value
, start
, end
) = desc
41 bits
= ((1,) * ((end
+ 1) - start
))
44 mask
= ((mask
<< 1) | bit
)
45 return (insn |
((value
& mask
) << (31 - end
)))
47 return functools
.reduce(instruction
, fields
, 0)
50 def setvl(fields
, Rc
):
52 setvl is a *32-bit-only* instruction. It controls SVSTATE.
53 It is *not* a 64-bit-prefixed Vector instruction (no sv.setvl, yet),
54 it is a Vector *control* instruction.
56 * setvl RT,RA,SVi,vf,vs,ms
58 1.6.28 SVL-FORM - from fields.txt
59 |0 |6 |11 |16 |23 |24 |25 |26 |31 |
60 | PO | RT | RA | SVi |ms |vs |vf | XO |Rc |
64 # ARRRGH these are in a non-obvious order in openpower/isa/simplev.mdwn
65 # compared to the SVL-Form above. sigh
66 # setvl RT,RA,SVi,vf,vs,ms
67 (RT
, RA
, SVi
, vf
, vs
, ms
) = fields
82 def svstep(fields
, Rc
):
84 svstep is a 32-bit instruction. It updates SVSTATE.
85 It *can* be SVP64-prefixed, to indicate that its registers
90 # 1.6.28 SVL-FORM - from fields.txt
91 # |0 |6 |11 |16 |23 |24 |25 |26 |31 |
92 # | PO | RT | / | SVi |/ |/ |vf | XO |Rc |
97 (RT
, SVi
, vf
) = fields
114 svshape is a *32-bit-only* instruction. It updates SVSHAPE and SVSTATE.
115 It is *not* a 64-bit-prefixed Vector instruction (no sv.svshape, yet),
116 it is a Vector *control* instruction.
118 * svshape SVxd,SVyd,SVzd,SVrm,vf
120 # 1.6.33 SVM-FORM from fields.txt
121 # |0 |6 |11 |16 |21 |25 |26 |31 |
122 # | PO | SVxd | SVyd | SVzd | SVrm |vf | XO |
127 (SVxd
, SVyd
, SVzd
, SVrm
, vf
) = fields
144 svindex is a *32-bit-only* instruction. It is a convenience
145 instruction that reduces instruction count for Indexed REMAP
147 It is *not* a 64-bit-prefixed Vector instruction (no sv.svindex, yet),
148 it is a Vector *control* instruction.
151 |0 |6 |11 |16 |21 |23|24|25|26 31|
152 | PO | SVG|rmm | SVd |ew |yx|mm|sk| XO |
154 # note that the dimension field one subtracted
157 (SVG
, rmm
, SVd
, ew
, yx
, mm
, sk
) = fields
174 this is a *32-bit-only* instruction. It updates the SVSHAPE SPR
175 it is *not* a 64-bit-prefixed Vector instruction (no sv.svremap),
176 it is a Vector *control* instruction.
178 * svremap SVme,mi0,mi1,mi2,mo0,mo1,pst
181 |0 |6 |11 |13 |15 |17 |19 |21 |22 |26 |31 |
182 | PO | SVme |mi0 | mi1 | mi2 | mo0 | mo1 |pst |/// | XO |
187 (SVme
, mi0
, mi1
, mi2
, mo0
, mo1
, pst
) = fields
202 # ok from here-on down these are added as 32-bit instructions
203 # and are here only because binutils (at present) doesn't have
204 # them (that's being fixed!)
205 # they can - if implementations then choose - be Vectorised
206 # because they are general-purpose scalar instructions
210 |0 |6 |11 |16 |21 |26 |27 31|
211 | PO | RT | RA | RB |bm |L | XO |
215 (RT
, RA
, RB
, bm
, L
) = fields
227 def fsins(fields
, Rc
):
228 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
229 # however we are out of space with opcode 22
231 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |20|21 |31 |
232 # | PO | FRT | /// | FRB | XO |Rc |
246 def fcoss(fields
, Rc
):
247 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
248 # however we are out of space with opcode 22
250 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |20|21 |31 |
251 # | PO | FRT | /// | FRB | XO |Rc |
265 def ternlogi(fields
, Rc
):
266 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
267 # however we are out of space with opcode 22
269 # |0 |6 |11 |16 |21 |29 |31 |
270 # | PO | RT | RA | RB | TLI | XO |Rc |
273 (RT
, RA
, RB
, TLI
) = fields
285 def grev(fields
, Rc
, imm
, wide
):
286 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
287 # however we are out of space with opcode 22
289 # _ matches fields in table at:
290 # https://libre-soc.org/openPOwer/sv/bitmanip/
296 (RT
, RA
, XBI
) = fields
297 insn
= (insn
<< 5) | RT
298 insn
= (insn
<< 5) | RA
301 insn
= (insn
<< 6) | XBI
302 insn
= (insn
<< 9) | XO
305 insn
= (insn
<< 5) | XBI
306 insn
= (insn
<< 10) | XO
307 insn
= (insn
<< 1) | Rc
311 def av(fields
, XO
, Rc
):
313 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |20|21 |31 |
314 # | PO | RT | RA | RB | XO |Rc |
316 (RT
, RA
, RB
) = fields
328 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
329 # V3.0B 1.6.6 DX-FORM
330 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |26|27 |31 |
331 # | PO | FRS | d1 | d0 | XO |d2 |
335 # first split imm into d1, d0 and d2. sigh
336 d2
= (imm
& 1) # LSB (0)
337 d1
= (imm
>> 1) & 0b11111 # bits 1-5
338 d0
= (imm
>> 6) # MSBs 6-15
350 # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
351 # V3.0B 1.6.6 DX-FORM
352 # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |26|27 |31 |
353 # | PO | FRS | d1 | d0 | XO |d2 |
357 # first split imm into d1, d0 and d2. sigh
358 d2
= (imm
& 1) # LSB (0)
359 d1
= (imm
>> 1) & 0b11111 # bits 1-5
360 d0
= (imm
>> 6) # MSBs 6-15
372 for (name
, hook
) in (
377 ("ternlogi", ternlogi
),
379 CUSTOM_INSNS
[name
] = functools
.partial(hook
, Rc
=False)
380 CUSTOM_INSNS
[f
"{name}."] = functools
.partial(hook
, Rc
=True)
381 CUSTOM_INSNS
["bmask"] = bmask
382 CUSTOM_INSNS
["svshape"] = svshape
383 CUSTOM_INSNS
["svindex"] = svindex
384 CUSTOM_INSNS
["svremap"] = svremap
385 CUSTOM_INSNS
["fmvis"] = fmvis
386 CUSTOM_INSNS
["fishmv"] = fishmv
388 for (name
, imm
, wide
) in (
389 ("grev", False, False),
390 ("grevi", True, False),
391 ("grevw", False, True),
392 ("grevwi", True, True),
394 CUSTOM_INSNS
[name
] = functools
.partial(grev
,
395 imm
=("i" in name
), wide
=("w" in name
), Rc
=False)
396 CUSTOM_INSNS
[f
"{name}."] = functools
.partial(grev
,
397 imm
=("i" in name
), wide
=("w" in name
), Rc
=True)
400 ("maxs", 0b0111001110),
401 ("maxu", 0b0011001110),
402 ("minu", 0b0001001110),
403 ("mins", 0b0101001110),
404 ("absdu", 0b1011110110),
405 ("absds", 0b1001110110),
406 ("avgadd", 0b1101001110),
407 ("absdacu", 0b1111110110),
408 ("absdacs", 0b0111110110),
409 ("cprop", 0b0110001110),
411 CUSTOM_INSNS
[name
] = functools
.partial(av
, XO
=XO
, Rc
=False)
412 CUSTOM_INSNS
[f
"{name}."] = functools
.partial(av
, XO
=XO
, Rc
=True)
415 # decode GPR into sv extra
416 def get_extra_gpr(etype
, regmode
, field
):
417 if regmode
== 'scalar':
418 # cut into 2-bits 5-bits SS FFFFF
419 sv_extra
= field
>> 5
420 field
= field
& 0b11111
422 # cut into 5-bits 2-bits FFFFF SS
423 sv_extra
= field
& 0b11
425 return sv_extra
, field
428 # decode 3-bit CR into sv extra
429 def get_extra_cr_3bit(etype
, regmode
, field
):
430 if regmode
== 'scalar':
431 # cut into 2-bits 3-bits SS FFF
432 sv_extra
= field
>> 3
433 field
= field
& 0b111
435 # cut into 3-bits 4-bits FFF SSSS but will cut 2 zeros off later
436 sv_extra
= field
& 0b1111
438 return sv_extra
, field
442 def decode_subvl(encoding
):
443 pmap
= {'2': 0b01, '3': 0b10, '4': 0b11}
444 assert encoding
in pmap
, \
445 "encoding %s for SUBVL not recognised" % encoding
446 return pmap
[encoding
]
450 def decode_elwidth(encoding
):
451 pmap
= {'8': 0b11, '16': 0b10, '32': 0b01}
452 assert encoding
in pmap
, \
453 "encoding %s for elwidth not recognised" % encoding
454 return pmap
[encoding
]
457 # decodes predicate register encoding
458 def decode_predicate(encoding
):
469 'nl': (1, 0b001), 'ge': (1, 0b001), # same value
471 'ng': (1, 0b011), 'le': (1, 0b011), # same value
474 'so': (1, 0b110), 'un': (1, 0b110), # same value
475 'ns': (1, 0b111), 'nu': (1, 0b111), # same value
477 assert encoding
in pmap
, \
478 "encoding %s for predicate not recognised" % encoding
479 return pmap
[encoding
]
482 # decodes "Mode" in similar way to BO field (supposed to, anyway)
483 def decode_bo(encoding
):
484 pmap
= { # TODO: double-check that these are the same as Branch BO
486 'nl': 0b001, 'ge': 0b001, # same value
488 'ng': 0b011, 'le': 0b011, # same value
491 'so': 0b110, 'un': 0b110, # same value
492 'ns': 0b111, 'nu': 0b111, # same value
494 assert encoding
in pmap
, \
495 "encoding %s for BO Mode not recognised" % encoding
496 return pmap
[encoding
]
499 # partial-decode fail-first mode
500 def decode_ffirst(encoding
):
501 if encoding
in ['RC1', '~RC1']:
503 return decode_bo(encoding
)
506 def decode_reg(field
, macros
=None):
509 # decode the field number. "5.v" or "3.s" or "9"
510 # and now also "*0", and "*%0". note: *NOT* to add "*%rNNN" etc.
511 # https://bugs.libre-soc.org/show_bug.cgi?id=884#c0
512 if field
.startswith(("*%", "*")):
513 if field
.startswith("*%"):
517 while field
in macros
:
518 field
= macros
[field
]
519 return int(field
), "vector" # actual register number
521 # try old convention (to be retired)
522 field
= field
.split(".")
523 regmode
= 'scalar' # default
527 elif field
[1] == 'v':
529 field
= int(field
[0]) # actual register number
530 return field
, regmode
533 def decode_imm(field
):
534 ldst_imm
= "(" in field
and field
[-1] == ')'
536 return field
[:-1].split("(")
541 def crf_extra(etype
, regmode
, field
, extras
):
542 """takes a CR Field number (CR0-CR127), splits into EXTRA2/3 and v3.0
543 the scalar/vector mode (crNN.v or crNN.s) changes both the format
544 of the EXTRA2/3 encoding as well as what range of registers is possible.
545 this function can be used for both BF/BFA and BA/BB/BT by first removing
546 the bottom 2 bits of BA/BB/BT then re-instating them after encoding.
547 see https://libre-soc.org/openpower/sv/svp64/appendix/#cr_extra
550 sv_extra
, field
= get_extra_cr_3bit(etype
, regmode
, field
)
551 # now sanity-check (and shrink afterwards)
552 if etype
== 'EXTRA2':
553 # 3-bit CR Field (BF, BFA) EXTRA2 encoding
554 if regmode
== 'scalar':
555 # range is CR0-CR15 in increments of 1
556 assert (sv_extra
>> 1) == 0, \
557 "scalar CR %s cannot fit into EXTRA2 %s" % \
558 (rname
, str(extras
[extra_idx
]))
559 # all good: encode as scalar
560 sv_extra
= sv_extra
& 0b01
562 # range is CR0-CR127 in increments of 16
563 assert sv_extra
& 0b111 == 0, \
564 "vector CR %s cannot fit into EXTRA2 %s" % \
565 (rname
, str(extras
[extra_idx
]))
566 # all good: encode as vector (bit 2 set)
567 sv_extra
= 0b10 |
(sv_extra
>> 3)
569 # 3-bit CR Field (BF, BFA) EXTRA3 encoding
570 if regmode
== 'scalar':
571 # range is CR0-CR31 in increments of 1
572 assert (sv_extra
>> 2) == 0, \
573 "scalar CR %s cannot fit into EXTRA3 %s" % \
574 (rname
, str(extras
[extra_idx
]))
575 # all good: encode as scalar
576 sv_extra
= sv_extra
& 0b11
578 # range is CR0-CR127 in increments of 8
579 assert sv_extra
& 0b11 == 0, \
580 "vector CR %s cannot fit into EXTRA3 %s" % \
581 (rname
, str(extras
[extra_idx
]))
582 # all good: encode as vector (bit 3 set)
583 sv_extra
= 0b100 |
(sv_extra
>> 2)
584 return sv_extra
, field
587 def to_number(field
):
588 if field
.startswith("0x"):
590 if field
.startswith("0b"):
595 # decodes svp64 assembly listings and creates EXT001 svp64 prefixes
597 def __init__(self
, lst
, bigendian
=False, macros
=None):
602 self
.trans
= self
.translate(lst
)
603 self
.isa
= ISA() # reads the v3.0B pseudo-code markdown files
604 self
.svp64
= SVP64RM() # reads the svp64 Remap entries for registers
605 assert bigendian
== False, "error, bigendian not supported yet"
608 yield from self
.trans
610 def translate_one(self
, insn
, macros
=None):
613 macros
.update(self
.macros
)
616 insn_no_comments
= insn
.partition('#')[0]
617 # find first space, to get opcode
618 ls
= insn_no_comments
.split(' ')
620 # now find opcode fields
621 fields
= ''.join(ls
[1:]).split(',')
622 mfields
= list(map(str.strip
, fields
))
623 log("opcode, fields", ls
, opcode
, mfields
)
626 for field
in mfields
:
627 fields
.append(macro_subst(macros
, field
))
628 log("opcode, fields substed", ls
, opcode
, fields
)
630 # identify if it is a special instruction
631 custom_insn_hook
= CUSTOM_INSNS
.get(opcode
)
632 if custom_insn_hook
is not None:
633 fields
= tuple(map(to_number
, fields
))
634 insn_num
= custom_insn_hook(fields
)
635 log(opcode
, bin(insn_num
))
636 yield ".long 0x%X # %s" % (insn_num
, insn
)
639 # identify if is a svp64 mnemonic
640 if not opcode
.startswith('sv.'):
641 yield insn
# unaltered
643 opcode
= opcode
[3:] # strip leading "sv"
645 # start working on decoding the svp64 op: sv.basev30Bop/vec2/mode
646 opmodes
= opcode
.split("/") # split at "/"
647 v30b_op_orig
= opmodes
.pop(0) # first is the v3.0B
648 # check instruction ends with dot
649 rc_mode
= v30b_op_orig
.endswith('.')
651 v30b_op
= v30b_op_orig
[:-1]
653 v30b_op
= v30b_op_orig
655 # look up the 32-bit op (original, with "." if it has it)
656 if v30b_op_orig
in isa
.instr
:
657 isa_instr
= isa
.instr
[v30b_op_orig
]
659 raise Exception("opcode %s of '%s' not supported" %
660 (v30b_op_orig
, insn
))
662 # look up the svp64 op, first the original (with "." if it has it)
663 if v30b_op_orig
in svp64
.instrs
:
664 rm
= svp64
.instrs
[v30b_op_orig
] # one row of the svp64 RM CSV
665 # then without the "." (if there was one)
666 elif v30b_op
in svp64
.instrs
:
667 rm
= svp64
.instrs
[v30b_op
] # one row of the svp64 RM CSV
669 raise Exception(f
"opcode {v30b_op_orig!r} of "
670 f
"{insn!r} not an svp64 instruction")
672 # get regs info e.g. "RT,RA,RB"
673 v30b_regs
= isa_instr
.regs
[0]
674 log("v3.0B op", v30b_op
, "Rc=1" if rc_mode
else '')
675 log("v3.0B regs", opcode
, v30b_regs
)
678 # right. the first thing to do is identify the ordering of
679 # the registers, by name. the EXTRA2/3 ordering is in
680 # rm['0']..rm['3'] but those fields contain the names RA, BB
681 # etc. we have to read the pseudocode to understand which
682 # reg is which in our instruction. sigh.
684 # first turn the svp64 rm into a "by name" dict, recording
685 # which position in the RM EXTRA it goes into
686 # also: record if the src or dest was a CR, for sanity-checking
687 # (elwidth overrides on CRs are banned)
688 decode
= decode_extra(rm
)
689 dest_reg_cr
, src_reg_cr
, svp64_src
, svp64_dest
= decode
691 log("EXTRA field index, src", svp64_src
)
692 log("EXTRA field index, dest", svp64_dest
)
694 # okaaay now we identify the field value (opcode N,N,N) with
695 # the pseudo-code info (opcode RT, RA, RB)
696 assert len(fields
) == len(v30b_regs
), \
697 "length of fields %s must match insn `%s` fields %s" % \
698 (str(v30b_regs
), insn
, str(fields
))
699 opregfields
= zip(fields
, v30b_regs
) # err that was easy
701 # now for each of those find its place in the EXTRA encoding
702 # note there is the possibility (for LD/ST-with-update) of
703 # RA occurring **TWICE**. to avoid it getting added to the
704 # v3.0B suffix twice, we spot it as a duplicate, here
705 extras
= OrderedDict()
706 for idx
, (field
, regname
) in enumerate(opregfields
):
707 imm
, regname
= decode_imm(regname
)
708 rtype
= get_regtype(regname
)
709 log(" idx find", rtype
, idx
, field
, regname
, imm
)
711 # probably an immediate field, append it straight
712 extras
[('imm', idx
, False)] = (idx
, field
, None, None, None)
714 extra
= svp64_src
.get(regname
, None)
715 if extra
is not None:
716 extra
= ('s', extra
, False) # not a duplicate
717 extras
[extra
] = (idx
, field
, regname
, rtype
, imm
)
718 log(" idx src", idx
, extra
, extras
[extra
])
719 dextra
= svp64_dest
.get(regname
, None)
720 log("regname in", regname
, dextra
)
721 if dextra
is not None:
722 is_a_duplicate
= extra
is not None # duplicate spotted
723 dextra
= ('d', dextra
, is_a_duplicate
)
724 extras
[dextra
] = (idx
, field
, regname
, rtype
, imm
)
725 log(" idx dst", idx
, extra
, extras
[dextra
])
727 # great! got the extra fields in their associated positions:
728 # also we know the register type. now to create the EXTRA encodings
729 etype
= rm
['Etype'] # Extra type: EXTRA3/EXTRA2
730 ptype
= rm
['Ptype'] # Predication type: Twin / Single
733 for extra_idx
, (idx
, field
, rname
, rtype
, iname
) in extras
.items():
734 # is it a field we don't alter/examine? if so just put it
737 v30b_newfields
.append(field
)
740 # identify if this is a ld/st immediate(reg) thing
741 ldst_imm
= "(" in field
and field
[-1] == ')'
743 immed
, field
= field
[:-1].split("(")
745 field
, regmode
= decode_reg(field
, macros
=macros
)
746 log(" ", extra_idx
, rname
, rtype
,
747 regmode
, iname
, field
, end
=" ")
749 # see Mode field https://libre-soc.org/openpower/sv/svp64/
750 # XXX TODO: the following is a bit of a laborious repeated
751 # mess, which could (and should) easily be parameterised.
752 # XXX also TODO: the LD/ST modes which are different
753 # https://libre-soc.org/openpower/sv/ldst/
755 # rright. SVP64 register numbering is from 0 to 127
756 # for GPRs, FPRs *and* CR Fields, where for v3.0 the GPRs and RPFs
757 # are 0-31 and CR Fields are only 0-7. the SVP64 RM "Extra"
758 # area is used to extend the numbering from the 32-bit
759 # instruction, and also to record whether the register
760 # is scalar or vector. on a per-operand basis. this
761 # results in a slightly finnicky encoding: here we go...
763 # encode SV-GPR and SV-FPR field into extra, v3.0field
764 if rtype
in ['GPR', 'FPR']:
765 sv_extra
, field
= get_extra_gpr(etype
, regmode
, field
)
766 # now sanity-check. EXTRA3 is ok, EXTRA2 has limits
767 # (and shrink to a single bit if ok)
768 if etype
== 'EXTRA2':
769 if regmode
== 'scalar':
770 # range is r0-r63 in increments of 1
771 assert (sv_extra
>> 1) == 0, \
772 "scalar GPR %s cannot fit into EXTRA2 %s" % \
773 (rname
, str(extras
[extra_idx
]))
774 # all good: encode as scalar
775 sv_extra
= sv_extra
& 0b01
777 # range is r0-r127 in increments of 2 (r0 r2 ... r126)
778 assert sv_extra
& 0b01 == 0, \
779 "%s: vector field %s cannot fit " \
781 (insn
, rname
, str(extras
[extra_idx
]))
782 # all good: encode as vector (bit 2 set)
783 sv_extra
= 0b10 |
(sv_extra
>> 1)
784 elif regmode
== 'vector':
785 # EXTRA3 vector bit needs marking
788 # encode SV-CR 3-bit field into extra, v3.0field.
789 # 3-bit is for things like BF and BFA
790 elif rtype
== 'CR_3bit':
791 sv_extra
, field
= crf_extra(etype
, regmode
, field
, extras
)
793 # encode SV-CR 5-bit field into extra, v3.0field
794 # 5-bit is for things like BA BB BC BT etc.
795 # *sigh* this is the same as 3-bit except the 2 LSBs of the
796 # 5-bit field are passed through unaltered.
797 elif rtype
== 'CR_5bit':
798 cr_subfield
= field
& 0b11 # record bottom 2 bits for later
799 field
= field
>> 2 # strip bottom 2 bits
800 # use the exact same 3-bit function for the top 3 bits
801 sv_extra
, field
= crf_extra(etype
, regmode
, field
, extras
)
802 # reconstruct the actual 5-bit CR field (preserving the
803 # bottom 2 bits, unaltered)
804 field
= (field
<< 2) | cr_subfield
807 raise Exception("no type match: %s" % rtype
)
809 # capture the extra field info
810 log("=>", "%5s" % bin(sv_extra
), field
)
811 extras
[extra_idx
] = sv_extra
813 # append altered field value to v3.0b, differs for LDST
814 # note that duplicates are skipped e.g. EXTRA2 contains
815 # *BOTH* s:RA *AND* d:RA which happens on LD/ST-with-update
816 srcdest
, idx
, duplicate
= extra_idx
817 if duplicate
: # skip adding to v3.0b fields, already added
820 v30b_newfields
.append(("%s(%s)" % (immed
, str(field
))))
822 v30b_newfields
.append(str(field
))
824 log("new v3.0B fields", v30b_op
, v30b_newfields
)
825 log("extras", extras
)
827 # rright. now we have all the info. start creating SVP64 instruction.
828 db
= Database(find_wiki_dir())
829 svp64_insn
= SVP64Instruction
.pair(prefix
=0, suffix
=0)
830 svp64_prefix
= svp64_insn
.prefix
831 svp64_rm
= svp64_insn
.prefix
.rm
833 # begin with EXTRA fields
834 for idx
, sv_extra
in extras
.items():
840 srcdest
, idx
, duplicate
= idx
841 if etype
== 'EXTRA2':
842 svp64_rm
.extra2
[idx
] = sv_extra
844 svp64_rm
.extra3
[idx
] = sv_extra
846 # identify if the op is a LD/ST. the "blegh" way. copied
847 # from power_enums. TODO, split the list _insns down.
849 "lbarx", "lbz", "lbzu", "lbzux", "lbzx", # load byte
850 "ld", "ldarx", "ldbrx", "ldu", "ldux", "ldx", # load double
851 "lfs", "lfsx", "lfsu", "lfsux", # FP load single
852 "lfd", "lfdx", "lfdu", "lfdux", "lfiwzx", "lfiwax", # FP load dbl
853 "lha", "lharx", "lhau", "lhaux", "lhax", # load half
854 "lhbrx", "lhz", "lhzu", "lhzux", "lhzx", # more load half
855 "lwa", "lwarx", "lwaux", "lwax", "lwbrx", # load word
856 "lwz", "lwzcix", "lwzu", "lwzux", "lwzx", # more load word
859 "stb", "stbcix", "stbcx", "stbu", "stbux", "stbx",
860 "std", "stdbrx", "stdcx", "stdu", "stdux", "stdx",
861 "stfs", "stfsx", "stfsu", "stfux", # FP store sgl
862 "stfd", "stfdx", "stfdu", "stfdux", "stfiwx", # FP store dbl
863 "sth", "sthbrx", "sthcx", "sthu", "sthux", "sthx",
864 "stw", "stwbrx", "stwcx", "stwu", "stwux", "stwx",
866 # use this to determine if the SVP64 RM format is different.
867 # see https://libre-soc.org/openpower/sv/ldst/
868 is_ldst
= is_ld
or is_st
870 # branch-conditional detection
878 destwid
= 0 # bits 4-5
879 srcwid
= 0 # bits 6-7
881 smask
= 0 # bits 16-18 but only for twin-predication
882 mode
= 0 # bits 19-23
884 mask_m_specified
= False
895 mapreduce_crm
= False
896 mapreduce_svm
= False
902 # branch-conditional bits
912 # ok let's start identifying opcode augmentation fields
913 for encmode
in opmodes
:
914 # predicate mask (src and dest)
915 if encmode
.startswith("m="):
917 pmmode
, pmask
= decode_predicate(encmode
[2:])
918 smmode
, smask
= pmmode
, pmask
920 mask_m_specified
= True
921 # predicate mask (dest)
922 elif encmode
.startswith("dm="):
924 pmmode
, pmask
= decode_predicate(encmode
[3:])
927 # predicate mask (src, twin-pred)
928 elif encmode
.startswith("sm="):
930 smmode
, smask
= decode_predicate(encmode
[3:])
934 elif encmode
.startswith("vec"):
935 subvl
= decode_subvl(encmode
[3:])
937 elif encmode
.startswith("ew="):
938 destwid
= decode_elwidth(encmode
[3:])
939 elif encmode
.startswith("sw="):
940 srcwid
= decode_elwidth(encmode
[3:])
941 # element-strided LD/ST
942 elif encmode
== 'els':
945 elif encmode
== 'sats':
946 assert sv_mode
is None
949 elif encmode
== 'satu':
950 assert sv_mode
is None
954 elif encmode
== 'sz':
956 elif encmode
== 'dz':
959 elif encmode
.startswith("ff="):
960 assert sv_mode
is None
962 failfirst
= decode_ffirst(encmode
[3:])
963 # predicate-result, interestingly same as fail-first
964 elif encmode
.startswith("pr="):
965 assert sv_mode
is None
967 predresult
= decode_ffirst(encmode
[3:])
968 # map-reduce mode, reverse-gear
969 elif encmode
== 'mrr':
970 assert sv_mode
is None
975 elif encmode
== 'mr':
976 assert sv_mode
is None
979 elif encmode
== 'crm': # CR on map-reduce
980 assert sv_mode
is None
983 elif encmode
== 'svm': # sub-vector mode
988 elif encmode
== 'st': # svstep mode
990 elif encmode
== 'sr': # svstep BRc mode
993 elif encmode
== 'vs': # VLSET mode
995 elif encmode
== 'vsi': # VLSET mode with VLI (VL inclusives)
998 elif encmode
== 'vsb': # VLSET mode with VSb
1001 elif encmode
== 'vsbi': # VLSET mode with VLI and VSb
1005 elif encmode
== 'snz': # sz (only) already set above
1008 elif encmode
== 'lu': # LR update mode
1011 raise AssertionError("unknown encmode %s" % encmode
)
1013 raise AssertionError("unknown encmode %s" % encmode
)
1016 # since m=xx takes precedence (overrides) sm=xx and dm=xx,
1017 # treat them as mutually exclusive
1018 if mask_m_specified
:
1019 assert not has_smask
,\
1020 "cannot have both source-mask and predicate mask"
1021 assert not has_pmask
,\
1022 "cannot have both dest-mask and predicate mask"
1023 # since the default is INT predication (ALWAYS), if you
1024 # specify one CR mask, you must specify both, to avoid
1025 # mixing INT and CR reg types
1026 if has_pmask
and pmmode
== 1:
1028 "need explicit source-mask in CR twin predication"
1029 if has_smask
and smmode
== 1:
1031 "need explicit dest-mask in CR twin predication"
1032 # sanity-check that 2Pred mask is same mode
1033 if has_pmask
and has_smask
:
1034 assert smmode
== pmmode
, \
1035 "predicate masks %s and %s must be same reg type" % \
1038 # sanity-check that twin-predication mask only specified in 2P mode
1040 assert not has_smask
, \
1041 "source-mask can only be specified on Twin-predicate ops"
1042 assert not has_pmask
, \
1043 "dest-mask can only be specified on Twin-predicate ops"
1045 # construct the mode field, doing sanity-checking along the way
1047 assert sv_mode
== 0b00, "sub-vector mode in mapreduce only"
1048 assert subvl
!= 0, "sub-vector mode not possible on SUBVL=1"
1051 assert has_smask
or mask_m_specified
, \
1052 "src zeroing requires a source predicate"
1054 assert has_pmask
or mask_m_specified
, \
1055 "dest zeroing requires a dest predicate"
1057 # okaaay, so there are 4 different modes, here, which will be
1058 # partly-merged-in: is_ldst is merged in with "normal", but
1059 # is_bc is so different it's done separately. likewise is_cr
1060 # (when it is done). here are the maps:
1062 # for "normal" arithmetic: https://libre-soc.org/openpower/sv/normal/
1064 | 0-1 | 2 | 3 4 | description |
1065 | --- | --- |---------|-------------------------- |
1066 | 00 | 0 | dz sz | normal mode |
1067 | 00 | 1 | 0 RG | scalar reduce mode (mapreduce), SUBVL=1 |
1068 | 00 | 1 | 1 / | parallel reduce mode (mapreduce), SUBVL=1 |
1069 | 00 | 1 | SVM RG | subvector reduce mode, SUBVL>1 |
1070 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
1071 | 01 | inv | VLi RC1 | Rc=0: ffirst z/nonz |
1072 | 10 | N | dz sz | sat mode: N=0/1 u/s |
1073 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1074 | 11 | inv | dz RC1 | Rc=0: pred-result z/nonz |
1077 # https://libre-soc.org/openpower/sv/ldst/
1078 # for LD/ST-immediate:
1080 | 0-1 | 2 | 3 4 | description |
1081 | --- | --- |---------|--------------------------- |
1082 | 00 | 0 | dz els | normal mode |
1083 | 00 | 1 | dz shf | shift mode |
1084 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
1085 | 01 | inv | els RC1 | Rc=0: ffirst z/nonz |
1086 | 10 | N | dz els | sat mode: N=0/1 u/s |
1087 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1088 | 11 | inv | els RC1 | Rc=0: pred-result z/nonz |
1091 # for LD/ST-indexed (RA+RB):
1093 | 0-1 | 2 | 3 4 | description |
1094 | --- | --- |---------|-------------------------- |
1095 | 00 | SEA | dz sz | normal mode |
1096 | 01 | SEA | dz sz | Strided (scalar only source) |
1097 | 10 | N | dz sz | sat mode: N=0/1 u/s |
1098 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
1099 | 11 | inv | dz RC1 | Rc=0: pred-result z/nonz |
1102 # and leaving out branches and cr_ops for now because they're
1104 """ TODO branches and cr_ops
1107 # now create mode and (overridden) src/dst widths
1108 # XXX TODO: sanity-check bc modes
1110 sv_mode
= ((bc_svstep
<< SVP64MODE
.MOD2_MSB
) |
1111 (bc_vlset
<< SVP64MODE
.MOD2_LSB
) |
1112 (bc_snz
<< SVP64MODE
.BC_SNZ
))
1113 srcwid
= (bc_vsb
<< 1) | bc_lru
1114 destwid
= (bc_lru
<< 1) | bc_all
1118 ######################################
1121 mode |
= src_zero
<< SVP64MODE
.SZ
# predicate zeroing
1122 mode |
= dst_zero
<< SVP64MODE
.DZ
# predicate zeroing
1124 # TODO: for now, LD/ST-indexed is ignored.
1125 mode |
= ldst_elstride
<< SVP64MODE
.ELS_NORMAL
# el-strided
1127 # TODO, reduce and subvector mode
1128 # 00 1 dz CRM reduce mode (mapreduce), SUBVL=1
1129 # 00 1 SVM CRM subvector reduce mode, SUBVL>1
1133 ######################################
1135 elif sv_mode
== 0b00:
1136 mode |
= (0b1 << SVP64MODE
.REDUCE
) # sets mapreduce
1137 assert dst_zero
== 0, "dest-zero not allowed in mapreduce mode"
1139 mode |
= (0b1 << SVP64MODE
.RG
) # sets Reverse-gear mode
1141 mode |
= (0b1 << SVP64MODE
.CRM
) # sets CRM mode
1142 assert rc_mode
, "CRM only allowed when Rc=1"
1143 # bit of weird encoding to jam zero-pred or SVM mode in.
1144 # SVM mode can be enabled only when SUBVL=2/3/4 (vec2/3/4)
1146 mode |
= dst_zero
<< SVP64MODE
.DZ
# predicate zeroing
1148 mode |
= (0b1 << SVP64MODE
.SVM
) # sets SVM mode
1150 ######################################
1152 elif sv_mode
== 0b01:
1153 assert src_zero
== 0, "dest-zero not allowed in failfirst mode"
1154 if failfirst
== 'RC1':
1155 mode |
= (0b1 << SVP64MODE
.RC1
) # sets RC1 mode
1156 mode |
= (dst_zero
<< SVP64MODE
.DZ
) # predicate dst-zeroing
1157 assert rc_mode
== False, "ffirst RC1 only ok when Rc=0"
1158 elif failfirst
== '~RC1':
1159 mode |
= (0b1 << SVP64MODE
.RC1
) # sets RC1 mode
1160 mode |
= (dst_zero
<< SVP64MODE
.DZ
) # predicate dst-zeroing
1161 mode |
= (0b1 << SVP64MODE
.INV
) # ... with inversion
1162 assert rc_mode
== False, "ffirst RC1 only ok when Rc=0"
1164 assert dst_zero
== 0, "dst-zero not allowed in ffirst BO"
1165 assert rc_mode
, "ffirst BO only possible when Rc=1"
1166 mode |
= (failfirst
<< SVP64MODE
.BO_LSB
) # set BO
1168 ######################################
1169 # "saturation" modes
1170 elif sv_mode
== 0b10:
1171 mode |
= src_zero
<< SVP64MODE
.SZ
# predicate zeroing
1172 mode |
= dst_zero
<< SVP64MODE
.DZ
# predicate zeroing
1173 mode |
= (saturation
<< SVP64MODE
.N
) # signed/us saturation
1175 ######################################
1176 # "predicate-result" modes. err... code-duplication from ffirst
1177 elif sv_mode
== 0b11:
1178 assert src_zero
== 0, "dest-zero not allowed in predresult mode"
1179 if predresult
== 'RC1':
1180 mode |
= (0b1 << SVP64MODE
.RC1
) # sets RC1 mode
1181 mode |
= (dst_zero
<< SVP64MODE
.DZ
) # predicate dst-zeroing
1182 assert rc_mode
== False, "pr-mode RC1 only ok when Rc=0"
1183 elif predresult
== '~RC1':
1184 mode |
= (0b1 << SVP64MODE
.RC1
) # sets RC1 mode
1185 mode |
= (dst_zero
<< SVP64MODE
.DZ
) # predicate dst-zeroing
1186 mode |
= (0b1 << SVP64MODE
.INV
) # ... with inversion
1187 assert rc_mode
== False, "pr-mode RC1 only ok when Rc=0"
1189 assert dst_zero
== 0, "dst-zero not allowed in pr-mode BO"
1190 assert rc_mode
, "pr-mode BO only possible when Rc=1"
1191 mode |
= (predresult
<< SVP64MODE
.BO_LSB
) # set BO
1193 # whewww.... modes all done :)
1194 # now put into svp64_rm
1197 svp64_rm
.mode
= mode
1199 # put in predicate masks into svp64_rm
1201 # source pred: bits 16-18
1202 svp64_rm
.smask
= smask
1204 svp64_rm
.mmode
= mmode
1206 svp64_rm
.mask
= pmask
1208 # and subvl: bits 8-9
1209 svp64_rm
.subvl
= subvl
1213 svp64_rm
.ewsrc
= srcwid
1215 svp64_rm
.elwidth
= destwid
1217 # nice debug printout. (and now for something completely different)
1218 # https://youtu.be/u0WOIwlXE9g?t=146
1219 svp64_rm_value
= int(svp64_rm
)
1220 log("svp64_rm", hex(svp64_rm_value
), bin(svp64_rm_value
))
1221 log(" mmode 0 :", bin(mmode
))
1222 log(" pmask 1-3 :", bin(pmask
))
1223 log(" dstwid 4-5 :", bin(destwid
))
1224 log(" srcwid 6-7 :", bin(srcwid
))
1225 log(" subvl 8-9 :", bin(subvl
))
1226 log(" mode 19-23:", bin(mode
))
1227 offs
= 2 if etype
== 'EXTRA2' else 3 # 2 or 3 bits
1228 for idx
, sv_extra
in extras
.items():
1233 srcdest
, idx
, duplicate
= idx
1234 start
= (10+idx
*offs
)
1235 end
= start
+ offs
-1
1236 log(" extra%d %2d-%2d:" % (idx
, start
, end
),
1239 log(" smask 16-17:", bin(smask
))
1242 # update prefix PO and ID (aka PID)
1243 svp64_prefix
.po
= 0x1
1244 svp64_prefix
.id = 0b11
1246 # fiinally yield the svp64 prefix and the thingy. v3.0b opcode
1247 rc
= '.' if rc_mode
else ''
1248 yield ".long 0x%08x" % int(svp64_prefix
)
1249 log(v30b_op
, v30b_newfields
)
1250 # argh, sv.fmadds etc. need to be done manually
1251 if v30b_op
== 'ffmadds':
1252 opcode
= 59 << (32-6) # bits 0..6 (MSB0)
1253 opcode |
= int(v30b_newfields
[0]) << (32-11) # FRT
1254 opcode |
= int(v30b_newfields
[1]) << (32-16) # FRA
1255 opcode |
= int(v30b_newfields
[2]) << (32-21) # FRB
1256 opcode |
= int(v30b_newfields
[3]) << (32-26) # FRC
1257 opcode |
= 0b00101 << (32-31) # bits 26-30
1259 opcode |
= 1 # Rc, bit 31.
1260 yield ".long 0x%x" % opcode
1261 # argh, sv.fdmadds need to be done manually
1262 elif v30b_op
== 'fdmadds':
1263 opcode
= 59 << (32-6) # bits 0..6 (MSB0)
1264 opcode |
= int(v30b_newfields
[0]) << (32-11) # FRT
1265 opcode |
= int(v30b_newfields
[1]) << (32-16) # FRA
1266 opcode |
= int(v30b_newfields
[2]) << (32-21) # FRB
1267 opcode |
= int(v30b_newfields
[3]) << (32-26) # FRC
1268 opcode |
= 0b01111 << (32-31) # bits 26-30
1270 opcode |
= 1 # Rc, bit 31.
1271 yield ".long 0x%x" % opcode
1272 # argh, sv.ffadds etc. need to be done manually
1273 elif v30b_op
== 'ffadds':
1274 opcode
= 59 << (32-6) # bits 0..6 (MSB0)
1275 opcode |
= int(v30b_newfields
[0]) << (32-11) # FRT
1276 opcode |
= int(v30b_newfields
[1]) << (32-16) # FRA
1277 opcode |
= int(v30b_newfields
[2]) << (32-21) # FRB
1278 opcode |
= 0b01101 << (32-31) # bits 26-30
1280 opcode |
= 1 # Rc, bit 31.
1281 yield ".long 0x%x" % opcode
1282 # sigh have to do svstep here manually for now...
1283 elif v30b_op
in ["svstep", "svstep."]:
1284 insn
= 22 << (31-5) # opcode 22, bits 0-5
1285 insn |
= int(v30b_newfields
[0]) << (31-10) # RT , bits 6-10
1286 insn |
= int(v30b_newfields
[1]) << (31-22) # SVi , bits 16-22
1287 insn |
= int(v30b_newfields
[2]) << (31-25) # vf , bit 25
1288 insn |
= 0b10011 << (31-30) # XO , bits 26..30
1289 if opcode
== 'svstep.':
1290 insn |
= 1 << (31-31) # Rc=1 , bit 31
1291 log("svstep", bin(insn
))
1292 yield ".long 0x%x" % insn
1293 # argh, sv.fcoss etc. need to be done manually
1294 elif v30b_op
in ["fcoss", "fcoss."]:
1295 insn
= 59 << (31-5) # opcode 59, bits 0-5
1296 insn |
= int(v30b_newfields
[0]) << (31-10) # RT , bits 6-10
1297 insn |
= int(v30b_newfields
[1]) << (31-20) # RB , bits 16-20
1298 insn |
= 0b1000101110 << (31-30) # XO , bits 21..30
1299 if opcode
== 'fcoss.':
1300 insn |
= 1 << (31-31) # Rc=1 , bit 31
1301 log("fcoss", bin(insn
))
1302 yield ".long 0x%x" % insn
1304 if not v30b_op
.endswith('.'):
1306 yield "%s %s" % (v30b_op
, ", ".join(v30b_newfields
))
1307 log("new v3.0B fields", v30b_op
, v30b_newfields
)
1309 def translate(self
, lst
):
1311 yield from self
.translate_one(insn
)
1314 def macro_subst(macros
, txt
):
1316 log("subst", txt
, macros
)
1319 for macro
, value
in macros
.items():
1322 replaced
= txt
.replace(macro
, value
)
1323 log("macro", txt
, "replaced", replaced
, macro
, value
)
1326 toreplace
= '%s.s' % macro
1327 if toreplace
== txt
:
1329 replaced
= txt
.replace(toreplace
, "%s.s" % value
)
1330 log("macro", txt
, "replaced", replaced
, toreplace
, value
)
1333 toreplace
= '%s.v' % macro
1334 if toreplace
== txt
:
1336 replaced
= txt
.replace(toreplace
, "%s.v" % value
)
1337 log("macro", txt
, "replaced", replaced
, toreplace
, value
)
1340 toreplace
= '(%s)' % macro
1341 if toreplace
in txt
:
1343 replaced
= txt
.replace(toreplace
, '(%s)' % value
)
1344 log("macro", txt
, "replaced", replaced
, toreplace
, value
)
1347 log(" processed", txt
)
1355 if not line
[0].isspace():
1363 # get an input file and an output file
1367 outfile
= sys
.stdout
1368 # read the whole lot in advance in case of in-place
1369 lines
= list(infile
.readlines())
1370 elif len(args
) != 2:
1371 print("pysvp64asm [infile | -] [outfile | -]", file=sys
.stderr
)
1377 infile
= open(args
[0], "r")
1378 # read the whole lot in advance in case of in-place overwrite
1379 lines
= list(infile
.readlines())
1382 outfile
= sys
.stdout
1384 outfile
= open(args
[1], "w")
1386 # read the line, look for custom insn, process it
1387 macros
= {} # macros which start ".set"
1390 op
= line
.split("#")[0].strip()
1392 if op
.startswith(".set"):
1393 macro
= op
[4:].split(",")
1394 (macro
, value
) = map(str.strip
, macro
)
1395 macros
[macro
] = value
1396 if not op
.startswith('sv.') and not op
.startswith(tuple(CUSTOM_INSNS
)):
1400 (ws
, line
) = get_ws(line
)
1401 lst
= isa
.translate_one(op
, macros
)
1402 lst
= '; '.join(lst
)
1403 outfile
.write("%s%s # %s\n" % (ws
, lst
, op
))
1406 if __name__
== '__main__':
1407 lst
= ['slw 3, 1, 4',
1410 'sv.cmpi 5, 1, 3, 2',
1412 'sv.isel 64.v, 3, 2, 65.v',
1413 'sv.setb/dm=r3/sm=1<<r3 5, 31',
1414 'sv.setb/m=r3 5, 31',
1415 'sv.setb/vec2 5, 31',
1416 'sv.setb/sw=8/ew=16 5, 31',
1417 'sv.extsw./ff=eq 5, 31',
1418 'sv.extsw./satu/sz/dz/sm=r3/dm=r3 5, 31',
1419 'sv.extsw./pr=eq 5.v, 31',
1420 'sv.add. 5.v, 2.v, 1.v',
1421 'sv.add./m=r3 5.v, 2.v, 1.v',
1424 'sv.stw 5.v, 4(1.v)',
1425 'sv.ld 5.v, 4(1.v)',
1426 'setvl. 2, 3, 4, 0, 1, 1',
1427 'sv.setvl. 2, 3, 4, 0, 1, 1',
1430 "sv.stfsu 0.v, 16(4.v)",
1433 "sv.stfsu/els 0.v, 16(4)",
1436 'sv.add./mr 5.v, 2.v, 1.v',
1438 macros
= {'win2': '50', 'win': '60'}
1440 'sv.addi win2.v, win.v, -1',
1441 'sv.add./mrr 5.v, 2.v, 1.v',
1442 #'sv.lhzsh 5.v, 11(9.v), 15',
1443 #'sv.lwzsh 5.v, 11(9.v), 15',
1444 'sv.ffmadds 6.v, 2.v, 4.v, 6.v',
1447 #'sv.fmadds 0.v, 8.v, 16.v, 4.v',
1448 #'sv.ffadds 0.v, 8.v, 4.v',
1449 'svremap 11, 0, 1, 2, 3, 2, 1',
1450 'svshape 8, 1, 1, 1, 0',
1451 'svshape 8, 1, 1, 1, 1',
1454 #'sv.lfssh 4.v, 11(8.v), 15',
1455 #'sv.lwzsh 4.v, 11(8.v), 15',
1456 #'sv.svstep. 2.v, 4, 0',
1457 #'sv.fcfids. 48.v, 64.v',
1458 'sv.fcoss. 80.v, 0.v',
1459 'sv.fcoss. 20.v, 0.v',
1462 'sv.bc/all 3,12,192',
1463 'sv.bclr/vsbi 3,81.v,192',
1464 'sv.ld 5.v, 4(1.v)',
1465 'sv.svstep. 2.v, 4, 0',
1476 'svindex 0,0,1,0,0,0,0',
1479 'sv.svstep./m=r3 2.v, 4, 0',
1480 'ternlogi 0,0,0,0x5',
1492 'sv.andi. *80, *80, 1',
1493 'sv.ffmadds. 6.v, 2.v, 4.v, 6.v', # incorrectly inserted 32-bit op
1494 'sv.ffmadds 6.v, 2.v, 4.v, 6.v', # correctly converted to .long
1496 isa
= SVP64Asm(lst
, macros
=macros
)
1497 log("list:\n", "\n\t".join(list(isa
)))
1498 # running svp64.py is designed to test hard-coded lists
1499 # (above) - which strictly speaking should all be unit tests.
1500 # if you need to actually do assembler translation at the
1501 # commandline use "pysvp64asm" - see setup.py
1502 # XXX NO. asm_process()