Bugtracker: https://bugs.libre-soc.org/show_bug.cgi?id=578
"""
+import functools
import os
import sys
from collections import OrderedDict
+import inspect
-from openpower.decoder.isa.caller import (SVP64PrefixFields, SV64P_MAJOR_SIZE,
- SV64P_PID_SIZE, SVP64RMFields,
- SVP64RM_EXTRA2_SPEC_SIZE,
- SVP64RM_EXTRA3_SPEC_SIZE,
- SVP64RM_MODE_SIZE, SVP64RM_SMASK_SIZE,
- SVP64RM_MMODE_SIZE, SVP64RM_MASK_SIZE,
- SVP64RM_SUBVL_SIZE, SVP64RM_EWSRC_SIZE,
- SVP64RM_ELWIDTH_SIZE)
from openpower.decoder.pseudo.pagereader import ISA
from openpower.decoder.power_svp64 import SVP64RM, get_regtype, decode_extra
from openpower.decoder.selectable_int import SelectableInt
from openpower.consts import SVP64MODE
+from openpower.decoder.power_insn import SVP64Instruction
+from openpower.decoder.power_insn import Database
+from openpower.decoder.power_enums import find_wiki_dir
# for debug logging
from openpower.util import log
+def instruction(*fields):
+ def instruction(insn, desc):
+ (value, start, end) = desc
+ bits = ((1,) * ((end + 1) - start))
+ mask = 0
+ for bit in bits:
+ mask = ((mask << 1) | bit)
+ return (insn | ((value & mask) << (31 - end)))
+
+ return functools.reduce(instruction, fields, 0)
+
+
+CUSTOM_INSNS = {}
+
+
+def _insn(name, **kwargs):
+ return name, kwargs
+
+
+def _custom_insns(*insns):
+ """ a decorator that adds the function to `CUSTOM_INSNS` """
+
+ def decorator(fn):
+ FIELDS_ARG = object()
+ if len(insns) == 0:
+ insns_ = (fn.__name__, {}),
+ else:
+ insns_ = insns
+ for name, kwargs in insns_:
+ if not isinstance(name, str):
+ raise TypeError("instruction name must be a str: {name!r}")
+ if name in CUSTOM_INSNS:
+ raise ValueError(f"duplicate instruction mnemonic: {name!r}")
+ # use getcallargs to check that arguments work:
+ inspect.getcallargs(fn, FIELDS_ARG, **kwargs)
+ CUSTOM_INSNS[name] = functools.partial(fn, **kwargs)
+ return fn
+ return decorator
+
+
+@_custom_insns(
+ _insn("setvl", Rc=0),
+ _insn("setvl.", Rc=1),
+)
+def setvl(fields, Rc):
+ """
+ setvl is a *32-bit-only* instruction. It controls SVSTATE.
+ It is *not* a 64-bit-prefixed Vector instruction (no sv.setvl, yet),
+ it is a Vector *control* instruction.
+
+ * setvl RT,RA,SVi,vf,vs,ms
+
+ 1.6.28 SVL-FORM - from fields.txt
+ |0 |6 |11 |16 |23 |24 |25 |26 |31 |
+ | PO | RT | RA | SVi |ms |vs |vf | XO |Rc |
+ """
+ PO = 22
+ XO = 0b11011
+ # ARRRGH these are in a non-obvious order in openpower/isa/simplev.mdwn
+ # compared to the SVL-Form above. sigh
+ # setvl RT,RA,SVi,vf,vs,ms
+ (RT, RA, SVi, vf, vs, ms) = fields
+ SVi -= 1
+ return instruction(
+ (PO, 0, 5),
+ (RT, 6, 10),
+ (RA, 11, 15),
+ (SVi, 16, 22),
+ (ms, 23, 23),
+ (vs, 24, 24),
+ (vf, 25, 25),
+ (XO, 26, 30),
+ (Rc, 31, 31),
+ )
+
+
+@_custom_insns(
+ _insn("svstep", Rc=0),
+ _insn("svstep.", Rc=1),
+)
+def svstep(fields, Rc):
+ """
+ svstep is a 32-bit instruction. It updates SVSTATE.
+ It *can* be SVP64-prefixed, to indicate that its registers
+ are Vectorised.
+
+ * svstep RT,SVi,vf
+
+ # 1.6.28 SVL-FORM - from fields.txt
+ # |0 |6 |11 |16 |23 |24 |25 |26 |31 |
+ # | PO | RT | / | SVi |/ |/ |vf | XO |Rc |
+
+ """
+ PO = 22
+ XO = 0b10011
+ (RT, SVi, vf) = fields
+ SVi -= 1
+ return instruction(
+ (PO, 0, 5),
+ (RT, 6, 10),
+ (0, 11, 15),
+ (SVi, 16, 22),
+ (0, 23, 23),
+ (0, 24, 24),
+ (vf, 25, 25),
+ (XO, 26, 30),
+ (Rc, 31, 31),
+ )
+
+
+@_custom_insns()
+def svshape(fields):
+ """
+ svshape is a *32-bit-only* instruction. It updates SVSHAPE and SVSTATE.
+ It is *not* a 64-bit-prefixed Vector instruction (no sv.svshape, yet),
+ it is a Vector *control* instruction.
+
+ https://libre-soc.org/openpower/sv/remap/#svshape
+
+ * svshape SVxd,SVyd,SVzd,SVrm,vf
+
+ # 1.6.33 SVM-FORM from fields.txt
+ # |0 |6 |11 |16 |21 |25 |26 |31 |
+ # | PO | SVxd | SVyd | SVzd | SVrm |vf | XO |
+
+ note that SVrm is not permitted to be 0b0111, 0b1000 or 0b1001.
+ 0b0111 is reserved and 0b100- is for svshape2
+
+ """
+ PO = 22
+ XO = 0b011001
+ (SVxd, SVyd, SVzd, SVrm, vf) = fields
+ SVxd -= 1
+ SVyd -= 1
+ SVzd -= 1
+
+ # check SVrm for reserved (and svshape2) values
+ assert SVrm not in [0b1000, 0b1001], \
+ "svshape reserved SVrm value %s" % bin(SVrm)
+
+ return instruction(
+ (PO, 0, 5),
+ (SVxd, 6, 10),
+ (SVyd, 11, 15),
+ (SVzd, 16, 20),
+ (SVrm, 21, 24),
+ (vf, 25, 25),
+ (XO, 26, 31),
+ )
+
+
+@_custom_insns()
+def svshape2(fields):
+ """
+ svshape2 is a *32-bit-only* instruction. It updates SVSHAPE and SVSTATE.
+ It is *not* a 64-bit-prefixed Vector instruction (no sv.svshape2, yet),
+ it is a Vector *control* instruction, and is a sort-of hybrid of
+ svshape and svindex, with the key important feature being the "offset".
+
+ https://libre-soc.org/openpower/sv/remap/discussion
+
+ * svshape2 SVo,SVM2yx,rmm,SVd,sk,mm
+
+ # 1.6.35.1 SVM2-FORM from fields.txt
+ # |0 |6 |10 |11 |16 |21 |24|25 |26 |31 |
+ # | PO | SVo |SVMyx| rmm | SVd |XO |mm|sk | XO |
+
+ note that this fits into the space of svshape and that XO is
+ split across 2 areas.
+
+ """
+ PO = 22
+ XO = 0b011001
+ XO2 = 0b100 # not really XO2 but hey
+ (offs, yx, rmm, SVd, sk, mm) = fields
+ SVd -= 1 # offset by one
+
+ return instruction(
+ (PO, 0, 5),
+ (offs, 6, 9), # offset (the whole point of adding svshape2)
+ (yx, 10, 10), # like svindex
+ (rmm, 11, 15), # ditto svindex
+ (SVd, 16, 20), # ditto svindex
+ (XO2, 21, 23), # actually XO split across 2 places...
+ (mm, 24, 24), # ditto svindex
+ (sk, 25, 25), # ditto svindex
+ (XO, 26, 31),
+ )
+
+
+@_custom_insns()
+def svindex(fields):
+ """
+ svindex is a *32-bit-only* instruction. It is a convenience
+ instruction that reduces instruction count for Indexed REMAP
+ Mode.
+ It is *not* a 64-bit-prefixed Vector instruction (no sv.svindex, yet),
+ it is a Vector *control* instruction.
+
+ 1.6.28 SVI-FORM
+ |0 |6 |11 |16 |21 |23|24|25|26 31|
+ | PO | SVG|rmm | SVd |ew |yx|mm|sk| XO |
+ """
+ # note that the dimension field one subtracted
+ PO = 22
+ XO = 0b101001
+ (SVG, rmm, SVd, ew, yx, mm, sk) = fields
+ SVd -= 1
+ return instruction(
+ (PO, 0, 5),
+ (SVG, 6, 10),
+ (rmm, 11, 15),
+ (SVd, 16, 20),
+ (ew, 21, 22),
+ (yx, 23, 23),
+ (mm, 24, 24),
+ (sk, 25, 25),
+ (XO, 26, 31),
+ )
+
+
+@_custom_insns()
+def svremap(fields):
+ """
+ this is a *32-bit-only* instruction. It updates the SVSHAPE SPR
+ it is *not* a 64-bit-prefixed Vector instruction (no sv.svremap),
+ it is a Vector *control* instruction.
+
+ * svremap SVme,mi0,mi1,mi2,mo0,mo1,pst
+
+ # 1.6.34 SVRM-FORM
+ |0 |6 |11 |13 |15 |17 |19 |21 |22 |26 |31 |
+ | PO | SVme |mi0 | mi1 | mi2 | mo0 | mo1 |pst |/// | XO |
+
+ """
+ PO = 22
+ XO = 0b111001
+ (SVme, mi0, mi1, mi2, mo0, mo1, pst) = fields
+ return instruction(
+ (PO, 0, 5),
+ (SVme, 6, 10),
+ (mi0, 11, 12),
+ (mi1, 13, 14),
+ (mi2, 15, 16),
+ (mo0, 17, 18),
+ (mo1, 19, 20),
+ (pst, 21, 21),
+ (0, 22, 25),
+ (XO, 26, 31),
+ )
+
+
+# ok from here-on down these are added as 32-bit instructions
+# and are here only because binutils (at present) doesn't have
+# them (that's being fixed!)
+# they can - if implementations then choose - be Vectorised
+# because they are general-purpose scalar instructions
+@_custom_insns()
+def bmask(fields):
+ """
+ 1.6.2.2 BM2-FORM
+ |0 |6 |11 |16 |21 |26 |27 31|
+ | PO | RT | RA | RB |bm |L | XO |
+ """
+ PO = 22
+ XO = 0b010001
+ (RT, RA, RB, bm, L) = fields
+ return instruction(
+ (PO, 0, 5),
+ (RT, 6, 10),
+ (RA, 11, 15),
+ (RB, 16, 20),
+ (bm, 21, 25),
+ (L, 26, 26),
+ (XO, 27, 31),
+ )
+
+
+@_custom_insns(
+ _insn("fsins", Rc=0),
+ _insn("fsins.", Rc=1),
+)
+def fsins(fields, Rc):
+ # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
+ # however we are out of space with opcode 22
+ # 1.6.7 X-FORM
+ # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |20|21 |31 |
+ # | PO | FRT | /// | FRB | XO |Rc |
+ PO = 59
+ XO = 0b1001001101
+ (FRT, FRB) = fields
+ return instruction(
+ (PO, 0, 5),
+ (FRT, 6, 10),
+ (0, 11, 15),
+ (FRB, 16, 20),
+ (XO, 21, 30),
+ (Rc, 31, 31),
+ )
+
+
+@_custom_insns(
+ _insn("fcoss", Rc=0),
+ _insn("fcoss.", Rc=1),
+)
+def fcoss(fields, Rc):
+ # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
+ # however we are out of space with opcode 22
+ # 1.6.7 X-FORM
+ # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |20|21 |31 |
+ # | PO | FRT | /// | FRB | XO |Rc |
+ PO = 59
+ XO = 0b1001101100
+ (FRT, FRB) = fields
+ return instruction(
+ (PO, 0, 5),
+ (FRT, 6, 10),
+ (0, 11, 15),
+ (FRB, 16, 20),
+ (XO, 21, 30),
+ (Rc, 31, 31),
+ )
+
+
+@_custom_insns(
+ _insn("ternlogi", Rc=0),
+ _insn("ternlogi.", Rc=1),
+)
+def ternlogi(fields, Rc):
+ # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
+ # however we are out of space with opcode 22
+ # 1.6.34 TLI-FORM
+ # |0 |6 |11 |16 |21 |29 |31 |
+ # | PO | RT | RA | RB | TLI | XO |Rc |
+ PO = 5
+ XO = 0
+ (RT, RA, RB, TLI) = fields
+ return instruction(
+ (PO, 0, 5),
+ (RT, 6, 10),
+ (RA, 11, 15),
+ (RB, 16, 20),
+ (TLI, 21, 28),
+ (XO, 29, 30),
+ (Rc, 31, 31),
+ )
+
+
+@_custom_insns(
+ _insn("grev", Rc=0, imm=0, word=0),
+ _insn("grevw", Rc=0, imm=0, word=1),
+ _insn("grevi", Rc=0, imm=1, word=0),
+ _insn("grevwi", Rc=0, imm=1, word=1),
+ _insn("grev.", Rc=1, imm=0, word=0),
+ _insn("grevw.", Rc=1, imm=0, word=1),
+ _insn("grevi.", Rc=1, imm=1, word=0),
+ _insn("grevwi.", Rc=1, imm=1, word=1),
+)
+def grev(fields, Rc, imm, word):
+ # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
+ # however we are out of space with opcode 22
+ insn = PO = 5
+ # _ matches fields in table at:
+ # https://libre-soc.org/openpower/sv/bitmanip/
+ XO = 0b1_0010_110
+ if word:
+ XO |= 0b100_000
+ if imm:
+ XO |= 0b1000_000
+ (RT, RA, XBI) = fields
+ insn = (insn << 5) | RT
+ insn = (insn << 5) | RA
+ if imm and not word:
+ assert 0 <= XBI < 64
+ insn = (insn << 6) | XBI
+ insn = (insn << 9) | XO
+ else:
+ assert 0 <= XBI < 32
+ insn = (insn << 5) | XBI
+ insn = (insn << 10) | XO
+ insn = (insn << 1) | Rc
+ return insn
+
+
+@_custom_insns(
+ _insn("maxs", XO=0b0111001110, Rc=0),
+ _insn("maxs.", XO=0b0111001110, Rc=1),
+ _insn("maxu", XO=0b0011001110, Rc=0),
+ _insn("maxu.", XO=0b0011001110, Rc=1),
+ _insn("minu", XO=0b0001001110, Rc=0),
+ _insn("minu.", XO=0b0001001110, Rc=1),
+ _insn("mins", XO=0b0101001110, Rc=0),
+ _insn("mins.", XO=0b0101001110, Rc=1),
+ _insn("absdu", XO=0b1011110110, Rc=0),
+ _insn("absdu.", XO=0b1011110110, Rc=1),
+ _insn("absds", XO=0b1001110110, Rc=0),
+ _insn("absds.", XO=0b1001110110, Rc=1),
+ _insn("avgadd", XO=0b1101001110, Rc=0),
+ _insn("avgadd.", XO=0b1101001110, Rc=1),
+ _insn("absdacu", XO=0b1111110110, Rc=0),
+ _insn("absdacu.", XO=0b1111110110, Rc=1),
+ _insn("absdacs", XO=0b0111110110, Rc=0),
+ _insn("absdacs.", XO=0b0111110110, Rc=1),
+ _insn("cprop", XO=0b0110001110, Rc=0),
+ _insn("cprop.", XO=0b0110001110, Rc=1),
+)
+def av(fields, XO, Rc):
+ # 1.6.7 X-FORM
+ # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |20|21 |31 |
+ # | PO | RT | RA | RB | XO |Rc |
+ PO = 22
+ (RT, RA, RB) = fields
+ return instruction(
+ (PO, 0, 5),
+ (RT, 6, 10),
+ (RA, 11, 15),
+ (RB, 16, 20),
+ (XO, 21, 30),
+ (Rc, 31, 31),
+ )
+
+
+@_custom_insns()
+def fmvis(fields):
+ # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
+ # V3.0B 1.6.6 DX-FORM
+ # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |26|27 |31 |
+ # | PO | FRS | d1 | d0 | XO |d2 |
+ PO = 22
+ XO = 0b00011
+ (FRS, imm) = fields
+ # first split imm into d1, d0 and d2. sigh
+ d2 = (imm & 1) # LSB (0)
+ d1 = (imm >> 1) & 0b11111 # bits 1-5
+ d0 = (imm >> 6) # MSBs 6-15
+ return instruction(
+ (PO, 0, 5),
+ (FRS, 6, 10),
+ (d1, 11, 15),
+ (d0, 16, 25),
+ (XO, 26, 30),
+ (d2, 31, 31),
+ )
+
+
+@_custom_insns()
+def fishmv(fields):
+ # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
+ # V3.0B 1.6.6 DX-FORM
+ # |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |26|27 |31 |
+ # | PO | FRS | d1 | d0 | XO |d2 |
+ PO = 22
+ XO = 0b01011
+ (FRS, imm) = fields
+ # first split imm into d1, d0 and d2. sigh
+ d2 = (imm & 1) # LSB (0)
+ d1 = (imm >> 1) & 0b11111 # bits 1-5
+ d0 = (imm >> 6) # MSBs 6-15
+ return instruction(
+ (PO, 0, 5),
+ (FRS, 6, 10),
+ (d1, 11, 15),
+ (d0, 16, 25),
+ (XO, 26, 30),
+ (d2, 31, 31),
+ )
+
+
# decode GPR into sv extra
def get_extra_gpr(etype, regmode, field):
if regmode == 'scalar':
"encoding %s for BO Mode not recognised" % encoding
return pmap[encoding]
-# partial-decode fail-first mode
-
+# partial-decode fail-first mode
def decode_ffirst(encoding):
if encoding in ['RC1', '~RC1']:
return encoding
return decode_bo(encoding)
-def decode_reg(field):
+def decode_reg(field, macros=None):
+ if macros is None:
+ macros = {}
# decode the field number. "5.v" or "3.s" or "9"
+ # and now also "*0", and "*%0". note: *NOT* to add "*%rNNN" etc.
+ # https://bugs.libre-soc.org/show_bug.cgi?id=884#c0
+ if field.startswith(("*%", "*")):
+ if field.startswith("*%"):
+ field = field[2:]
+ else:
+ field = field[1:]
+ while field in macros:
+ field = macros[field]
+ return int(field), "vector" # actual register number
+
+ # try old convention (to be retired)
field = field.split(".")
regmode = 'scalar' # default
if len(field) == 2:
return None, field
-def crf_extra(etype, regmode, field, extras):
+def crf_extra(etype, rname, extra_idx, regmode, field, extras):
"""takes a CR Field number (CR0-CR127), splits into EXTRA2/3 and v3.0
the scalar/vector mode (crNN.v or crNN.s) changes both the format
of the EXTRA2/3 encoding as well as what range of registers is possible.
(rname, str(extras[extra_idx]))
# all good: encode as scalar
sv_extra = sv_extra & 0b01
- else: # vector
+ else: # vector
# range is CR0-CR127 in increments of 16
assert sv_extra & 0b111 == 0, \
"vector CR %s cannot fit into EXTRA2 %s" % \
(rname, str(extras[extra_idx]))
# all good: encode as scalar
sv_extra = sv_extra & 0b11
- else: # vector
+ else: # vector
# range is CR0-CR127 in increments of 8
assert sv_extra & 0b11 == 0, \
"vector CR %s cannot fit into EXTRA3 %s" % \
return sv_extra, field
+def to_number(field):
+ if field.startswith("0x"):
+ return eval(field)
+ if field.startswith("0b"):
+ return eval(field)
+ return int(field)
+
+
+db = Database(find_wiki_dir())
+
+
# decodes svp64 assembly listings and creates EXT001 svp64 prefixes
class SVP64Asm:
def __init__(self, lst, bigendian=False, macros=None):
macros.update(self.macros)
isa = self.isa
svp64 = self.svp64
+ insn_no_comments = insn.partition('#')[0]
# find first space, to get opcode
- ls = insn.split(' ')
+ ls = insn_no_comments.split(' ')
opcode = ls[0]
# now find opcode fields
fields = ''.join(ls[1:]).split(',')
fields.append(macro_subst(macros, field))
log("opcode, fields substed", ls, opcode, fields)
- # this is a *32-bit-only* instruction. it controls SVSTATE.
- # it is *not* a 64-bit-prefixed Vector instruction (no sv.setvl),
- # it is a Vector *control* instruction.
- # note: EXT022 is the "sandbox" major opcode so it's fine to add
-
- # sigh have to do setvl here manually for now...
- # note the subtract one from SVi.
- if opcode in ["setvl", "setvl."]:
- # 1.6.28 SVL-FORM - from fields.txt
- # |0 |6 |11 |16 |23 |24 |25 |26 |31 |
- # | PO | RT | RA | SVi |ms |vs |vf | XO |Rc |
- insn = 22 << (31-5) # opcode 22, bits 0-5
- fields = list(map(int, fields))
- insn |= fields[0] << (31-10) # RT , bits 6-10
- insn |= fields[1] << (31-15) # RA , bits 11-15
- insn |= (fields[2]-1) << (31-22) # SVi , bits 16-22
- insn |= fields[3] << (31-25) # vf , bit 25
- insn |= fields[4] << (31-24) # vs , bit 24
- insn |= fields[5] << (31-23) # ms , bit 23
- insn |= 0b11011 << (31-30) # XO , bits 26..30
- if opcode == 'setvl.':
- insn |= 1 << (31-31) # Rc=1 , bit 31
- log("setvl", bin(insn))
- yield ".long 0x%x" % insn
- return
-
- # this is a 32-bit instruction. it updates SVSTATE.
- # it *can* be SVP64-prefixed, to indicate that its registers
- # are Vectorised.
- # note: EXT022 is the "sandbox" major opcode so it's fine to add
-
- # sigh have to do setvl here manually for now...
- # note the subtract one from SVi.
- if opcode in ["svstep", "svstep."]:
- # 1.6.28 SVL-FORM - from fields.txt
- # |0 |6 |11 |16 |23 |24 |25 |26 |31 |
- # | PO | RT | RA | SVi |ms |vs |vf | XO |Rc |
- insn = 22 << (31-5) # opcode 22, bits 0-5
- fields = list(map(int, fields))
- insn |= fields[0] << (31-10) # RT , bits 6-10
- insn |= (fields[1]-1) << (31-22) # SVi , bits 16-22
- insn |= fields[2] << (31-25) # vf , bit 25
- insn |= 0b10011 << (31-30) # XO , bits 26..30
- if opcode == 'svstep.':
- insn |= 1 << (31-31) # Rc=1 , bit 31
- log("svstep", bin(insn))
- yield ".long 0x%x" % insn
- return
-
- # this is a *32-bit-only* instruction. it updates SVSHAPE and SVSTATE.
- # it is *not* a 64-bit-prefixed Vector instruction (no sv.svshape),
- # it is a Vector *control* instruction.
- # note: EXT022 is the "sandbox" major opcode so it's fine to add
-
- # and svshape. note that the dimension fields one subtracted from each
- if opcode == 'svshape':
- # 1.6.33 SVM-FORM from fields.txt
- # |0 |6 |11 |16 |21 |25 |26 |31 |
- # |PO | SVxd | SVyd | SVzd | SVRM |vf | XO | / |
- insn = 22 << (31-5) # opcode 22, bits 0-5
- fields = list(map(int, fields))
- insn |= (fields[0]-1) << (31-10) # SVxd , bits 6-10
- insn |= (fields[1]-1) << (31-15) # SVyd , bits 11-15
- insn |= (fields[2]-1) << (31-20) # SVzd , bits 16-20
- insn |= (fields[3]) << (31-24) # SVRM , bits 21-24
- insn |= (fields[4]) << (31-25) # vf , bits 25
- insn |= 0b011001 << (31-31) # XO , bits 26..31
- #insn &= ((1<<32)-1)
- log("svshape", bin(insn))
- yield ".long 0x%x" % insn
- return
-
- # this is a *32-bit-only* instruction. it updates the SVSHAPE SPR
- # it is *not* a 64-bit-prefixed Vector instruction (no sv.svremap),
- # it is a Vector *control* instruction.
- # note: EXT022 is the "sandbox" major opcode so it's fine to add
-
- # and svremap
- if opcode == 'svremap':
- # 1.6.34 SVRM-FORM from fields.txt
- # |0 |6 |11 |13 |15 |17 |19 |21 |22 |26 |31 |
- # |PO | SVme |mi0 | mi1 | mi2 | mo0 | mo1 |pst |/// | XO | / |
- insn = 22 << (31-5) # opcode 22, bits 0-5
- fields = list(map(int, fields))
- insn |= fields[0] << (31-10) # SVme , bits 6-10
- insn |= fields[1] << (31-12) # mi0 , bits 11-12
- insn |= fields[2] << (31-14) # mi1 , bits 13-14
- insn |= fields[3] << (31-16) # mi2 , bits 15-16
- insn |= fields[4] << (31-18) # m00 , bits 17-18
- insn |= fields[5] << (31-20) # m01 , bits 19-20
- insn |= fields[6] << (31-21) # pst , bit 21
- insn |= 0b111001 << (31-31) # XO , bits 26..31
- log("svremap", bin(insn))
- yield ".long 0x%x" % insn
- return
-
- # ok from here-on down these are added as 32-bit instructions
- # and are here only because binutils (at present) doesn't have
- # them (that's being fixed!)
- # they can - if implementations then choose - be Vectorised
- # (sv.fsins) because they are general-purpose scalar instructions
-
- # and fsins
- # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
- # however we are out of space with opcode 22
- if opcode.startswith('fsins'):
- fields = list(map(int, fields))
- insn = 59 << (31-5) # opcode 59, bits 0-5
- insn |= fields[0] << (31-10) # RT , bits 6-10
- insn |= fields[1] << (31-20) # RB , bits 16-20
- insn |= 0b1000001110 << (31-30) # XO , bits 21..30
- if opcode == 'fsins.':
- insn |= 1 << (31-31) # Rc=1 , bit 31
- log("fsins", bin(insn))
- yield ".long 0x%x" % insn
- return
-
- # and fcoss
- # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
- # however we are out of space with opcode 22
- if opcode.startswith('fcoss'):
- fields = list(map(int, fields))
- insn = 59 << (31-5) # opcode 59, bits 0-5
- insn |= fields[0] << (31-10) # RT , bits 6-10
- insn |= fields[1] << (31-20) # RB , bits 16-20
- insn |= 0b1000101110 << (31-30) # XO , bits 21..30
- if opcode == 'fcoss.':
- insn |= 1 << (31-31) # Rc=1 , bit 31
- log("fcoss", bin(insn))
- yield ".long 0x%x" % insn
- return
-
- # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
- # however we are out of space with opcode 22
- if opcode in ('ternlogi', 'ternlogi.'):
- po = 5
- xo = 0
- rt = int(fields[0])
- ra = int(fields[1])
- rb = int(fields[2])
- imm = int(fields[3])
- rc = '.' in opcode
- instr = po
- instr = (instr << 5) | rt
- instr = (instr << 5) | ra
- instr = (instr << 5) | rb
- instr = (instr << 8) | imm
- instr = (instr << 2) | xo
- instr = (instr << 1) | rc
- asm = f"{opcode} {rt}, {ra}, {rb}, {imm}"
- yield f".4byte {hex(instr)} # {asm}"
- return
-
- # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
- # however we are out of space with opcode 22
- if opcode in ('grev', 'grevi', 'grevw', 'grevwi',
- 'grev.', 'grevi.', 'grevw.', 'grevwi.'):
- po = 5
- # _ matches fields in table at:
- # https://libre-soc.org/openpower/sv/bitmanip/
- xo = 0b1_0010_110
- if 'w' in opcode:
- xo |= 0b100_000
- if 'i' in opcode:
- xo |= 0b1000_000
- Rc = 1 if '.' in opcode else 0
- rt = int(fields[0])
- ra = int(fields[1])
- rb_imm = int(fields[2])
- instr = po
- instr = (instr << 5) | rt
- instr = (instr << 5) | ra
- if opcode == 'grevi' or opcode == 'grevi.':
- assert 0 <= rb_imm < 64
- instr = (instr << 6) | rb_imm
- instr = (instr << 9) | xo
- else:
- assert 0 <= rb_imm < 32
- instr = (instr << 5) | rb_imm
- instr = (instr << 10) | xo
- instr = (instr << 1) | Rc
- asm = f"{opcode} {rt}, {ra}, {rb_imm}"
- yield f".4byte {hex(instr)} # {asm}"
- return
-
- # and min/max
- # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
- if opcode in ['mins', 'maxs', 'minu', 'maxu',
- 'mins.', 'maxs.', 'minu.', 'maxu.']:
- if opcode[:4] == 'maxs':
- XO = 0b0111001110
- if opcode[:4] == 'maxu':
- XO = 0b0011001110
- if opcode[:4] == 'mins':
- XO = 0b0101001110
- if opcode[:4] == 'minu':
- XO = 0b0001001110
- fields = list(map(int, fields))
- insn = 22 << (31-5) # opcode 22, bits 0-5
- insn |= fields[0] << (31-10) # RT , bits 6-10
- insn |= fields[1] << (31-15) # RA , bits 11-15
- insn |= fields[2] << (31-20) # RB , bits 16-20
- insn |= XO << (31-30) # XO , bits 21..30
- if opcode.endswith('.'):
- insn |= 1 << (31-31) # Rc=1 , bit 31
- log("maxs", bin(insn))
- yield ".long 0x%x" % insn
- return
-
- # and avgadd, absdu, absaddu, absadds
- # XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
- if opcode in ['avgadd', 'absdu', 'absaddu', 'absadds']:
- if opcode[:5] == 'absdu':
- XO = 0b1011110110
- elif opcode[:6] == 'avgadd':
- XO = 0b1101001110
- elif opcode[:7] == 'absaddu':
- XO = 0b1111110110
- elif opcode[:7] == 'absadds':
- XO = 0b0111110110
- fields = list(map(int, fields))
- insn = 22 << (31-5) # opcode 22, bits 0-5
- insn |= fields[0] << (31-10) # RT , bits 6-10
- insn |= fields[1] << (31-15) # RA , bits 11-15
- insn |= fields[2] << (31-20) # RB , bits 16-20
- insn |= XO << (31-30) # XO , bits 21..30
- if opcode.endswith('.'):
- insn |= 1 << (31-31) # Rc=1 , bit 31
- log(opcode, bin(insn))
- yield ".long 0x%x" % insn
+ # identify if it is a special instruction
+ custom_insn_hook = CUSTOM_INSNS.get(opcode)
+ if custom_insn_hook is not None:
+ fields = tuple(map(to_number, fields))
+ insn_num = custom_insn_hook(fields)
+ log(opcode, bin(insn_num))
+ yield ".long 0x%X # %s" % (insn_num, insn)
return
# identify if is a svp64 mnemonic
# start working on decoding the svp64 op: sv.basev30Bop/vec2/mode
opmodes = opcode.split("/") # split at "/"
- v30b_op = opmodes.pop(0) # first is the v3.0B
+ v30b_op_orig = opmodes.pop(0) # first is the v3.0B
# check instruction ends with dot
- rc_mode = v30b_op.endswith('.')
+ rc_mode = v30b_op_orig.endswith('.')
if rc_mode:
- v30b_op = v30b_op[:-1]
-
- # sigh again, have to recognised LD/ST bit-reverse instructions
- # this has to be "processed" to fit into a v3.0B without the "sh"
- # e.g. ldsh is actually ld
- ldst_shift = v30b_op.startswith("l") and v30b_op.endswith("sh")
+ v30b_op = v30b_op_orig[:-1]
+ else:
+ v30b_op = v30b_op_orig
- if v30b_op not in isa.instr:
+ # look up the 32-bit op (original, with "." if it has it)
+ if v30b_op_orig in isa.instr:
+ isa_instr = isa.instr[v30b_op_orig]
+ else:
raise Exception("opcode %s of '%s' not supported" %
- (v30b_op, insn))
-
- if ldst_shift:
- # okaay we need to process the fields and make this:
- # ldsh RT, SVD(RA), RC - 11 bits for SVD, 5 for RC
- # into this:
- # ld RT, D(RA) - 16 bits
- # likewise same for SVDS (9 bits for SVDS, 5 for RC, 14 bits for DS)
- form = isa.instr[v30b_op].form # get form (SVD-Form, SVDS-Form)
-
- newfields = []
- for field in fields:
- # identify if this is a ld/st immediate(reg) thing
- ldst_imm = "(" in field and field[-1] == ')'
- if ldst_imm:
- newfields.append(field[:-1].split("("))
- else:
- newfields.append(field)
-
- immed, RA = newfields[1]
- immed = int(immed)
- RC = int(newfields.pop(2)) # better be an integer number!
- if form == 'SVD': # 16 bit: immed 11 bits, RC shift up 11
- immed = (immed & 0b11111111111) | (RC << 11)
- if immed & (1 << 15): # should be negative
- immed -= 1 << 16
- if form == 'SVDS': # 14 bit: immed 9 bits, RC shift up 9
- immed = (immed & 0b111111111) | (RC << 9)
- if immed & (1 << 13): # should be negative
- immed -= 1 << 14
- newfields[1] = "%d(%s)" % (immed, RA)
- fields = newfields
-
- # and strip off "sh" from end, and add "sh" to opmodes, instead
- v30b_op = v30b_op[:-2]
- opmodes.append("sh")
- log("rewritten", v30b_op, opmodes, fields)
-
- if v30b_op not in svp64.instrs:
- raise Exception("opcode %s of '%s' not an svp64 instruction" %
- (v30b_op, insn))
- v30b_regs = isa.instr[v30b_op].regs[0] # get regs info "RT, RA, RB"
- rm = svp64.instrs[v30b_op] # one row of the svp64 RM CSV
+ (v30b_op_orig, insn))
+
+ # look up the svp64 op, first the original (with "." if it has it)
+ if v30b_op_orig in svp64.instrs:
+ rm = svp64.instrs[v30b_op_orig] # one row of the svp64 RM CSV
+ # then without the "." (if there was one)
+ elif v30b_op in svp64.instrs:
+ rm = svp64.instrs[v30b_op] # one row of the svp64 RM CSV
+ else:
+ raise Exception(f"opcode {v30b_op_orig!r} of "
+ f"{insn!r} not an svp64 instruction")
+
+ # get regs info e.g. "RT,RA,RB"
+ v30b_regs = isa_instr.regs[0]
log("v3.0B op", v30b_op, "Rc=1" if rc_mode else '')
log("v3.0B regs", opcode, v30b_regs)
log("RM", rm)
if ldst_imm:
immed, field = field[:-1].split("(")
- field, regmode = decode_reg(field)
+ field, regmode = decode_reg(field, macros=macros)
log(" ", extra_idx, rname, rtype,
regmode, iname, field, end=" ")
# encode SV-CR 3-bit field into extra, v3.0field.
# 3-bit is for things like BF and BFA
elif rtype == 'CR_3bit':
- sv_extra, field = crf_extra(etype, regmode, field, extras)
+ sv_extra, field = crf_extra(etype, rname, extra_idx,
+ regmode, field, extras)
# encode SV-CR 5-bit field into extra, v3.0field
# 5-bit is for things like BA BB BC BT etc.
# *sigh* this is the same as 3-bit except the 2 LSBs of the
# 5-bit field are passed through unaltered.
elif rtype == 'CR_5bit':
- cr_subfield = field & 0b11 # record bottom 2 bits for later
+ cr_subfield = field & 0b11 # record bottom 2 bits for later
field = field >> 2 # strip bottom 2 bits
# use the exact same 3-bit function for the top 3 bits
- sv_extra, field = crf_extra(etype, regmode, field, extras)
+ sv_extra, field = crf_extra(etype, rname, extra_idx,
+ regmode, field, extras)
# reconstruct the actual 5-bit CR field (preserving the
# bottom 2 bits, unaltered)
field = (field << 2) | cr_subfield
log("new v3.0B fields", v30b_op, v30b_newfields)
log("extras", extras)
- # rright. now we have all the info. start creating SVP64 RM
- svp64_rm = SVP64RMFields()
+ # rright. now we have all the info. start creating SVP64 instruction.
+ svp64_insn = SVP64Instruction.pair(prefix=0, suffix=0)
+ svp64_prefix = svp64_insn.prefix
+ svp64_rm = svp64_insn.prefix.rm
# begin with EXTRA fields
for idx, sv_extra in extras.items():
continue
srcdest, idx, duplicate = idx
if etype == 'EXTRA2':
- svp64_rm.extra2[idx].eq(
- SelectableInt(sv_extra, SVP64RM_EXTRA2_SPEC_SIZE))
+ svp64_rm.extra2[idx] = sv_extra
else:
- svp64_rm.extra3[idx].eq(
- SelectableInt(sv_extra, SVP64RM_EXTRA3_SPEC_SIZE))
+ svp64_rm.extra3[idx] = sv_extra
# identify if the op is a LD/ST. the "blegh" way. copied
# from power_enums. TODO, split the list _insns down.
smmode, smask = decode_predicate(encmode[3:])
mmode = smmode
has_smask = True
- # shifted LD/ST
- elif encmode.startswith("sh"):
- ldst_shift = True
# vec2/3/4
elif encmode.startswith("vec"):
subvl = decode_subvl(encmode[3:])
assert has_pmask or mask_m_specified, \
"dest zeroing requires a dest predicate"
- # check LDST shifted, only available in "normal" mode
- if is_ldst and ldst_shift:
- assert sv_mode is None, \
- "LD shift cannot have modes (%s) applied" % sv_mode
-
# okaaay, so there are 4 different modes, here, which will be
# partly-merged-in: is_ldst is merged in with "normal", but
# is_bc is so different it's done separately. likewise is_cr
"""
| 0-1 | 2 | 3 4 | description |
| --- | --- |---------|-------------------------- |
- | 00 | 0 | dz sz | normal mode |
+ | 00 | 0 | dz sz | simple mode |
| 00 | 1 | 0 RG | scalar reduce mode (mapreduce), SUBVL=1 |
- | 00 | 1 | 1 / | parallel reduce mode (mapreduce), SUBVL=1 |
- | 00 | 1 | SVM RG | subvector reduce mode, SUBVL>1 |
+ | 00 | 1 | SVM 0 | subvector reduce mode, SUBVL>1 |
+ | 00 | 1 | SVM 1 | Pack/Unpack mode, SUBVL>1 |
| 01 | inv | CR-bit | Rc=1: ffirst CR sel |
| 01 | inv | VLi RC1 | Rc=0: ffirst z/nonz |
- | 10 | N | dz sz | sat mode: N=0/1 u/s |
+ | 10 | N | dz sz | sat mode: N=0/1 u/s, SUBVL=1 |
+ | 10 | N | zz 0 | sat mode: N=0/1 u/s, SUBVL>1 |
+ | 10 | N | zz 1 | Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1 |
| 11 | inv | CR-bit | Rc=1: pred-result CR sel |
- | 11 | inv | dz RC1 | Rc=0: pred-result z/nonz |
+ | 11 | inv | zz RC1 | Rc=0: pred-result z/nonz |
"""
# https://libre-soc.org/openpower/sv/ldst/
if is_ldst:
# TODO: for now, LD/ST-indexed is ignored.
mode |= ldst_elstride << SVP64MODE.ELS_NORMAL # el-strided
- # shifted mode
- if ldst_shift:
- mode |= 1 << SVP64MODE.LDST_SHIFT
else:
# TODO, reduce and subvector mode
# 00 1 dz CRM reduce mode (mapreduce), SUBVL=1
# now put into svp64_rm
mode |= sv_mode
# mode: bits 19-23
- svp64_rm.mode.eq(SelectableInt(mode, SVP64RM_MODE_SIZE))
+ svp64_rm.mode = mode
# put in predicate masks into svp64_rm
if ptype == '2P':
# source pred: bits 16-18
- svp64_rm.smask.eq(SelectableInt(smask, SVP64RM_SMASK_SIZE))
+ svp64_rm.smask = smask
# mask mode: bit 0
- svp64_rm.mmode.eq(SelectableInt(mmode, SVP64RM_MMODE_SIZE))
+ svp64_rm.mmode = mmode
# 1-pred: bits 1-3
- svp64_rm.mask.eq(SelectableInt(pmask, SVP64RM_MASK_SIZE))
+ svp64_rm.mask = pmask
# and subvl: bits 8-9
- svp64_rm.subvl.eq(SelectableInt(subvl, SVP64RM_SUBVL_SIZE))
+ svp64_rm.subvl = subvl
# put in elwidths
# srcwid: bits 6-7
- svp64_rm.ewsrc.eq(SelectableInt(srcwid, SVP64RM_EWSRC_SIZE))
+ svp64_rm.ewsrc = srcwid
# destwid: bits 4-5
- svp64_rm.elwidth.eq(SelectableInt(destwid, SVP64RM_ELWIDTH_SIZE))
+ svp64_rm.elwidth = destwid
# nice debug printout. (and now for something completely different)
# https://youtu.be/u0WOIwlXE9g?t=146
- svp64_rm_value = svp64_rm.spr.value
+ svp64_rm_value = int(svp64_rm)
log("svp64_rm", hex(svp64_rm_value), bin(svp64_rm_value))
log(" mmode 0 :", bin(mmode))
log(" pmask 1-3 :", bin(pmask))
log(" smask 16-17:", bin(smask))
log()
- # first, construct the prefix from its subfields
- svp64_prefix = SVP64PrefixFields()
- svp64_prefix.major.eq(SelectableInt(0x1, SV64P_MAJOR_SIZE))
- svp64_prefix.pid.eq(SelectableInt(0b11, SV64P_PID_SIZE))
- svp64_prefix.rm.eq(svp64_rm.spr)
+ # update prefix PO and ID (aka PID)
+ svp64_prefix.po = 0x1
+ svp64_prefix.id = 0b11
# fiinally yield the svp64 prefix and the thingy. v3.0b opcode
rc = '.' if rc_mode else ''
- yield ".long 0x%08x" % svp64_prefix.insn.value
- log(v30b_newfields)
+ yield ".long 0x%08x" % int(svp64_prefix)
+ log(v30b_op, v30b_newfields)
+
+ v30b_op_rc = v30b_op
+ if not v30b_op.endswith('.'):
+ v30b_op_rc += rc
+
+ # svstep is weird
+ # FIXME(lkcl): should sv.svstep be like svstep?
+ if v30b_op_rc in ("svstep", "svstep."):
+ # compensate for `SVi -= 1` in svstep()
+ v30b_newfields[1] = str(int(v30b_newfields[1]) + 1)
+
+ custom_insn_hook = CUSTOM_INSNS.get(v30b_op_rc)
+ if custom_insn_hook is not None:
+ fields = tuple(map(to_number, v30b_newfields))
+ insn_num = custom_insn_hook(fields)
+ log(opcode, bin(insn_num))
+ yield ".long 0x%X # %s" % (insn_num, insn)
+ return
# argh, sv.fmadds etc. need to be done manually
- if v30b_op == 'ffmadds':
+ elif v30b_op == 'ffmadds':
opcode = 59 << (32-6) # bits 0..6 (MSB0)
opcode |= int(v30b_newfields[0]) << (32-11) # FRT
opcode |= int(v30b_newfields[1]) << (32-16) # FRA
opcode |= int(v30b_newfields[1]) << (32-16) # FRA
opcode |= int(v30b_newfields[2]) << (32-21) # FRB
opcode |= int(v30b_newfields[3]) << (32-26) # FRC
- opcode |= 0b01111 << (32-31) # bits 26-30
+ opcode |= 0b11011 << (32-31) # bits 26-30
if rc:
opcode |= 1 # Rc, bit 31.
yield ".long 0x%x" % opcode
opcode |= int(v30b_newfields[0]) << (32-11) # FRT
opcode |= int(v30b_newfields[1]) << (32-16) # FRA
opcode |= int(v30b_newfields[2]) << (32-21) # FRB
- opcode |= 0b01101 << (32-31) # bits 26-30
+ opcode |= 0b1000001100 << (32-31) # bits 21-30
if rc:
opcode |= 1 # Rc, bit 31.
yield ".long 0x%x" % opcode
- # sigh have to do svstep here manually for now...
- elif opcode in ["svstep", "svstep."]:
- insn = 22 << (31-5) # opcode 22, bits 0-5
- insn |= int(v30b_newfields[0]) << (31-10) # RT , bits 6-10
- insn |= int(v30b_newfields[1]) << (31-22) # SVi , bits 16-22
- insn |= int(v30b_newfields[2]) << (31-25) # vf , bit 25
- insn |= 0b10011 << (31-30) # XO , bits 26..30
- if opcode == 'svstep.':
- insn |= 1 << (31-31) # Rc=1 , bit 31
- log("svstep", bin(insn))
- yield ".long 0x%x" % insn
- # argh, sv.fcoss etc. need to be done manually
- elif v30b_op in ["fcoss", "fcoss."]:
- insn = 59 << (31-5) # opcode 59, bits 0-5
- insn |= int(v30b_newfields[0]) << (31-10) # RT , bits 6-10
- insn |= int(v30b_newfields[1]) << (31-20) # RB , bits 16-20
- insn |= 0b1000101110 << (31-30) # XO , bits 21..30
- if opcode == 'fcoss.':
- insn |= 1 << (31-31) # Rc=1 , bit 31
- log("fcoss", bin(insn))
- yield ".long 0x%x" % insn
-
else:
- yield "%s %s" % (v30b_op+rc, ", ".join(v30b_newfields))
+ if not v30b_op.endswith('.'):
+ v30b_op += rc
+ yield "%s %s" % (v30b_op, ", ".join(v30b_newfields))
log("new v3.0B fields", v30b_op, v30b_newfields)
def translate(self, lst):
else:
outfile = open(args[1], "w")
- # read the line, look for "sv", process it
+ # read the line, look for custom insn, process it
macros = {} # macros which start ".set"
isa = SVP64Asm([])
for line in lines:
macro = op[4:].split(",")
(macro, value) = map(str.strip, macro)
macros[macro] = value
- if not (op.startswith("sv.") or
- op.startswith("setvl") or
- op.startswith("svshape")):
+ if not op.startswith('sv.') and not op.startswith(tuple(CUSTOM_INSNS)):
outfile.write(line)
continue
'maxs. 3,12,5',
'avgadd 3,12,5',
'absdu 3,12,5',
- 'absaddu 3,12,5',
- 'absadds 3,12,5',
+ 'absds 3,12,5',
+ 'absdacu 3,12,5',
+ 'absdacs 3,12,5',
+ 'cprop 3,12,5',
+ 'svindex 0,0,1,0,0,0,0',
+ ]
+ lst = [
+ 'sv.svstep./m=r3 2.v, 4, 0',
+ 'ternlogi 0,0,0,0x5',
+ 'fmvis 5,65535',
+ 'fmvis 5,1',
+ 'fmvis 5,2',
+ 'fmvis 5,4',
+ 'fmvis 5,8',
+ 'fmvis 5,16',
+ 'fmvis 5,32',
+ 'fmvis 5,64',
+ 'fmvis 5,32768',
+ ]
+ lst = [
+ 'sv.andi. *80, *80, 1',
+ 'sv.ffmadds. 6.v, 2.v, 4.v, 6.v', # incorrectly inserted 32-bit op
+ 'sv.ffmadds 6.v, 2.v, 4.v, 6.v', # correctly converted to .long
+ 'svshape2 8, 1, 31, 7, 1, 1',
]
isa = SVP64Asm(lst, macros=macros)
- log("list", list(isa))
- asm_process()
+ log("list:\n", "\n\t".join(list(isa)))
+ # running svp64.py is designed to test hard-coded lists
+ # (above) - which strictly speaking should all be unit tests.
+ # if you need to actually do assembler translation at the
+ # commandline use "pysvp64asm" - see setup.py
+ # XXX NO. asm_process()