import os
import sys
from collections import OrderedDict
+import inspect
from openpower.decoder.pseudo.pagereader import ISA
from openpower.decoder.power_svp64 import SVP64RM, get_regtype, decode_extra
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.
)
+@_custom_insns(
+ _insn("svstep", Rc=0),
+ _insn("svstep.", Rc=1),
+)
def svstep(fields, Rc):
"""
svstep is a 32-bit instruction. It updates SVSTATE.
)
+@_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 -= 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),
)
+@_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
)
+@_custom_insns()
def svremap(fields):
"""
this is a *32-bit-only* instruction. It updates the SVSHAPE SPR
# 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
)
+@_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
# |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |20|21 |31 |
# | PO | FRT | /// | FRB | XO |Rc |
PO = 59
- XO = 0b1000001110
+ XO = 0b1001001101
(FRT, FRB) = fields
return instruction(
(PO, 0, 5),
)
+@_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
# |0 |6 |7|8|9 |10 |11|12|13 |15|16|17 |20|21 |31 |
# | PO | FRT | /// | FRB | XO |Rc |
PO = 59
- XO = 0b1000101110
+ XO = 0b1001101100
(FRT, FRB) = fields
return instruction(
(PO, 0, 5),
)
+@_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
)
-def grev(fields, Rc, imm, wide):
+@_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/
+ # https://libre-soc.org/openpower/sv/bitmanip/
XO = 0b1_0010_110
- if wide:
+ 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 wide:
+ if imm and not word:
assert 0 <= XBI < 64
insn = (insn << 6) | XBI
insn = (insn << 9) | XO
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 |
)
+@_custom_insns()
def fmvis(fields):
# XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
# V3.0B 1.6.6 DX-FORM
)
+@_custom_insns()
def fishmv(fields):
# XXX WARNING THESE ARE NOT APPROVED BY OPF ISA WG
# V3.0B 1.6.6 DX-FORM
)
-CUSTOM_INSNS = {}
-for (name, hook) in (
- ("setvl", setvl),
- ("svstep", svstep),
- ("fsins", fsins),
- ("fcoss", fcoss),
- ("ternlogi", ternlogi),
-):
- CUSTOM_INSNS[name] = functools.partial(hook, Rc=False)
- CUSTOM_INSNS[f"{name}."] = functools.partial(hook, Rc=True)
-CUSTOM_INSNS["bmask"] = bmask
-CUSTOM_INSNS["svshape"] = svshape
-CUSTOM_INSNS["svindex"] = svindex
-CUSTOM_INSNS["svremap"] = svremap
-CUSTOM_INSNS["fmvis"] = fmvis
-CUSTOM_INSNS["fishmv"] = fishmv
-
-for (name, imm, wide) in (
- ("grev", False, False),
- ("grevi", True, False),
- ("grevw", False, True),
- ("grevwi", True, True),
-):
- CUSTOM_INSNS[name] = functools.partial(grev,
- imm=("i" in name), wide=("w" in name), Rc=False)
- CUSTOM_INSNS[f"{name}."] = functools.partial(grev,
- imm=("i" in name), wide=("w" in name), Rc=True)
-
-for (name, XO) in (
- ("maxs", 0b0111001110),
- ("maxu", 0b0011001110),
- ("minu", 0b0001001110),
- ("mins", 0b0101001110),
- ("absdu", 0b1011110110),
- ("absds", 0b1001110110),
- ("avgadd", 0b1101001110),
- ("absdacu", 0b1111110110),
- ("absdacs", 0b0111110110),
- ("cprop", 0b0110001110),
-):
- CUSTOM_INSNS[name] = functools.partial(av, XO=XO, Rc=False)
- CUSTOM_INSNS[f"{name}."] = functools.partial(av, XO=XO, Rc=True)
-
-
# 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 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.
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):
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")
+ f"{insn!r} not an svp64 instruction")
# get regs info e.g. "RT,RA,RB"
v30b_regs = isa_instr.regs[0]
# 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.
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("extras", extras)
# rright. now we have all the info. start creating SVP64 instruction.
- db = Database(find_wiki_dir())
svp64_insn = SVP64Instruction.pair(prefix=0, suffix=0)
svp64_prefix = svp64_insn.prefix
svp64_rm = svp64_insn.prefix.rm
"""
| 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/
rc = '.' if rc_mode else ''
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 v30b_op 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:
if not v30b_op.endswith('.'):
v30b_op += rc
]
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', # 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:\n", "\n\t".join(list(isa)))