Bugtracker: https://bugs.libre-soc.org/show_bug.cgi?id=578
"""
+import functools
import os
import sys
from collections import OrderedDict
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_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.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)
+
+
+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),
+ )
+
+
+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),
+ )
+
+
+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.
+
+ * 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 |
+
+ """
+ PO = 22
+ XO = 0b011001
+ (SVxd, SVyd, SVzd, SVrm, vf) = fields
+ SVxd -= 1
+ SVyd -= 1
+ SVzd -= 1
+ return instruction(
+ (PO , 0 , 5 ),
+ (SVxd, 6 , 10),
+ (SVyd, 11, 15),
+ (SVzd, 16, 20),
+ (SVrm, 21, 24),
+ (vf , 25, 25),
+ (XO , 26, 31),
+ )
+
+
+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),
+ )
+
+
+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
+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),
+ )
+
+
+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 = 0b1000001110
+ (FRT, FRB) = fields
+ return instruction(
+ (PO , 0 , 5 ),
+ (FRT, 6 , 10),
+ (0 , 11, 15),
+ (FRB, 16, 20),
+ (XO , 21, 30),
+ (Rc , 31, 31),
+ )
+
+
+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 = 0b1000101110
+ (FRT, FRB) = fields
+ return instruction(
+ (PO , 0 , 5 ),
+ (FRT, 6 , 10),
+ (0 , 11, 15),
+ (FRB, 16, 20),
+ (XO , 21, 30),
+ (Rc , 31, 31),
+ )
+
+
+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),
+ )
+
+
+def grev(fields, Rc, imm, wide):
+ # 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 wide:
+ 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:
+ 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
+
+
+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),
+ )
+
+
+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 = 0b000011
+ Rc = 0
+ (FRS, imm) = fields
+ return instruction(
+ (PO , 0 , 5),
+ (FRS, 6 , 10),
+ (imm, 11, 26),
+ (XO , 27, 30),
+ (Rc , 31, 31),
+ )
+
+
+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
+
+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':
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):
+ """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.
+ this function can be used for both BF/BFA and BA/BB/BT by first removing
+ the bottom 2 bits of BA/BB/BT then re-instating them after encoding.
+ see https://libre-soc.org/openpower/sv/svp64/appendix/#cr_extra
+ for specification
+ """
+ sv_extra, field = get_extra_cr_3bit(etype, regmode, field)
+ # now sanity-check (and shrink afterwards)
+ if etype == 'EXTRA2':
+ # 3-bit CR Field (BF, BFA) EXTRA2 encoding
+ if regmode == 'scalar':
+ # range is CR0-CR15 in increments of 1
+ assert (sv_extra >> 1) == 0, \
+ "scalar CR %s cannot fit into EXTRA2 %s" % \
+ (rname, str(extras[extra_idx]))
+ # all good: encode as scalar
+ sv_extra = sv_extra & 0b01
+ 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 vector (bit 2 set)
+ sv_extra = 0b10 | (sv_extra >> 3)
+ else:
+ # 3-bit CR Field (BF, BFA) EXTRA3 encoding
+ if regmode == 'scalar':
+ # range is CR0-CR31 in increments of 1
+ assert (sv_extra >> 2) == 0, \
+ "scalar CR %s cannot fit into EXTRA3 %s" % \
+ (rname, str(extras[extra_idx]))
+ # all good: encode as scalar
+ sv_extra = sv_extra & 0b11
+ else: # vector
+ # range is CR0-CR127 in increments of 8
+ assert sv_extra & 0b11 == 0, \
+ "vector CR %s cannot fit into EXTRA3 %s" % \
+ (rname, str(extras[extra_idx]))
+ # all good: encode as vector (bit 3 set)
+ sv_extra = 0b100 | (sv_extra >> 2)
+ 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)
+
+
# decodes svp64 assembly listings and creates EXT001 svp64 prefixes
class SVP64Asm:
def __init__(self, lst, bigendian=False, macros=None):
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."]:
- 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) # ms , bit 25
- insn |= fields[4] << (31-24) # vs , bit 24
- insn |= fields[5] << (31-23) # vf , bit 23
- insn |= 0b00000 << (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-only* instruction. it updates SVSTATE.
- # it is *not* a 64-bit-prefixed Vector instruction (no sv.svstep),
- # 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 ["svstep", "svstep."]:
- 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 |= 0b00011 << (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':
- 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 |= 0b00001 << (31-30) # XO , bits 26..30
- #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':
- 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) # m01 , bit 21
- insn |= 0b00010 << (31-30) # XO , bits 26..30
- #insn &= ((1<<32)-1)
- 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))
+ # 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 = custom_insn_hook(fields)
+ log(opcode, 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
-
# identify if is a svp64 mnemonic
if not opcode.startswith('sv.'):
yield insn # unaltered
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=" ")
# XXX also TODO: the LD/ST modes which are different
# https://libre-soc.org/openpower/sv/ldst/
+ # rright. SVP64 register numbering is from 0 to 127
+ # for GPRs, FPRs *and* CR Fields, where for v3.0 the GPRs and RPFs
+ # are 0-31 and CR Fields are only 0-7. the SVP64 RM "Extra"
+ # area is used to extend the numbering from the 32-bit
+ # instruction, and also to record whether the register
+ # is scalar or vector. on a per-operand basis. this
+ # results in a slightly finnicky encoding: here we go...
+
# encode SV-GPR and SV-FPR field into extra, v3.0field
if rtype in ['GPR', 'FPR']:
sv_extra, field = get_extra_gpr(etype, regmode, field)
# EXTRA3 vector bit needs marking
sv_extra |= 0b100
- # encode SV-CR 3-bit field into extra, v3.0field
+ # 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 = get_extra_cr_3bit(etype, regmode, field)
- # now sanity-check (and shrink afterwards)
- if etype == 'EXTRA2':
- if regmode == 'scalar':
- # range is CR0-CR15 in increments of 1
- assert (sv_extra >> 1) == 0, \
- "scalar CR %s cannot fit into EXTRA2 %s" % \
- (rname, str(extras[extra_idx]))
- # all good: encode as scalar
- sv_extra = sv_extra & 0b01
- else:
- # 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 vector (bit 2 set)
- sv_extra = 0b10 | (sv_extra >> 3)
- else:
- if regmode == 'scalar':
- # range is CR0-CR31 in increments of 1
- assert (sv_extra >> 2) == 0, \
- "scalar CR %s cannot fit into EXTRA2 %s" % \
- (rname, str(extras[extra_idx]))
- # all good: encode as scalar
- sv_extra = sv_extra & 0b11
- else:
- # range is CR0-CR127 in increments of 8
- assert sv_extra & 0b11 == 0, \
- "vector CR %s cannot fit into EXTRA2 %s" % \
- (rname, str(extras[extra_idx]))
- # all good: encode as vector (bit 3 set)
- sv_extra = 0b100 | (sv_extra >> 2)
+ sv_extra, field = crf_extra(etype, regmode, field, extras)
# encode SV-CR 5-bit field into extra, v3.0field
- # *sigh* this is the same as 3-bit except the 2 LSBs are
- # passed through
+ # 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
- field = field >> 2 # strip bottom 2 bits
- sv_extra, field = get_extra_cr_3bit(etype, regmode, field)
- # now sanity-check (and shrink afterwards)
- if etype == 'EXTRA2':
- if regmode == 'scalar':
- # range is CR0-CR15 in increments of 1
- assert (sv_extra >> 1) == 0, \
- "scalar CR %s cannot fit into EXTRA2 %s" % \
- (rname, str(extras[extra_idx]))
- # all good: encode as scalar
- sv_extra = sv_extra & 0b01
- else:
- # 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 vector (bit 2 set)
- sv_extra = 0b10 | (sv_extra >> 3)
- else:
- if regmode == 'scalar':
- # range is CR0-CR31 in increments of 1
- assert (sv_extra >> 2) == 0, \
- "scalar CR %s cannot fit into EXTRA2 %s" % \
- (rname, str(extras[extra_idx]))
- # all good: encode as scalar
- sv_extra = sv_extra & 0b11
- else:
- # range is CR0-CR127 in increments of 8
- assert sv_extra & 0b11 == 0, \
- "vector CR %s cannot fit into EXTRA3 %s" % \
- (rname, str(extras[extra_idx]))
- # all good: encode as vector (bit 3 set)
- sv_extra = 0b100 | (sv_extra >> 2)
- # reconstruct the actual 5-bit CR field
+ 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)
+ # reconstruct the actual 5-bit CR field (preserving the
+ # bottom 2 bits, unaltered)
field = (field << 2) | cr_subfield
else:
- print("no type match", rtype)
+ raise Exception("no type match: %s" % rtype)
# capture the extra field info
log("=>", "%5s" % bin(sv_extra), field)
# fiinally yield the svp64 prefix and the thingy. v3.0b opcode
rc = '.' if rc_mode else ''
- yield ".long 0x%x" % svp64_prefix.insn.value
- log(v30b_newfields)
+ yield ".long 0x%08x" % svp64_prefix.insn.value
+ log(v30b_op, v30b_newfields)
# argh, sv.fmadds etc. need to be done manually
if v30b_op == 'ffmadds':
opcode = 59 << (32-6) # bits 0..6 (MSB0)
opcode |= 1 # Rc, bit 31.
yield ".long 0x%x" % opcode
# sigh have to do svstep here manually for now...
- elif opcode in ["svstep", "svstep."]:
+ 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 |= 0b00011 << (31-30) # XO , bits 26..30
+ 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
-
- elif v30b_op in ["setvl", "setvl."]:
- 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) # ms , bit 25
- insn |= fields[4] << (31-24) # vs , bit 24
- insn |= fields[5] << (31-23) # vf , bit 23
- insn |= 0b00000 << (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
-
+ # 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 |= 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))
log("new v3.0B fields", v30b_op, v30b_newfields)
def macro_subst(macros, txt):
again = True
- print("subst", txt, macros)
+ log("subst", txt, macros)
while again:
again = False
for macro, value in macros.items():
if macro == txt:
again = True
replaced = txt.replace(macro, value)
- print("macro", txt, "replaced", replaced, macro, value)
+ log("macro", txt, "replaced", replaced, macro, value)
txt = replaced
continue
toreplace = '%s.s' % macro
if toreplace == txt:
again = True
replaced = txt.replace(toreplace, "%s.s" % value)
- print("macro", txt, "replaced", replaced, toreplace, value)
+ log("macro", txt, "replaced", replaced, toreplace, value)
txt = replaced
continue
toreplace = '%s.v' % macro
if toreplace == txt:
again = True
replaced = txt.replace(toreplace, "%s.v" % value)
- print("macro", txt, "replaced", replaced, toreplace, value)
+ log("macro", txt, "replaced", replaced, toreplace, value)
txt = replaced
continue
toreplace = '(%s)' % macro
if toreplace in txt:
again = True
replaced = txt.replace(toreplace, '(%s)' % value)
- print("macro", txt, "replaced", replaced, toreplace, value)
+ log("macro", txt, "replaced", replaced, toreplace, value)
txt = replaced
continue
- print(" processed", txt)
+ log(" processed", txt)
return txt
def asm_process():
-
# get an input file and an output file
args = sys.argv[1:]
if len(args) == 0:
# read the whole lot in advance in case of in-place
lines = list(infile.readlines())
elif len(args) != 2:
- print("pysvp64asm [infile | -] [outfile | -]")
+ print("pysvp64asm [infile | -] [outfile | -]", file=sys.stderr)
exit(0)
else:
if args[0] == '--':
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:
- ls = line.split("#")
+ op = line.split("#")[0].strip()
# identify macros
- op = ls[0].strip()
- if op.startswith("setvl") or op.startswith("svshape"):
- ws, line = get_ws(ls[0])
- lst = list(isa.translate_one(ls[0].strip(), macros))
- lst = '; '.join(lst)
- outfile.write("%s%s # %s\n" % (ws, lst, ls[0]))
- continue
- if ls[0].startswith(".set"):
- macro = ls[0][4:].split(",")
- macro, value = list(map(str.strip, macro))
+ if op.startswith(".set"):
+ macro = op[4:].split(",")
+ (macro, value) = map(str.strip, macro)
macros[macro] = value
- if len(ls) != 2:
- outfile.write(line)
- continue
- potential = ls[1].strip()
- if not potential.startswith("sv."):
+ if not op.startswith('sv.') and not op.startswith(tuple(CUSTOM_INSNS)):
outfile.write(line)
continue
- ws, line = get_ws(line)
- # SV line indentified
- lst = list(isa.translate_one(potential, macros))
+ (ws, line) = get_ws(line)
+ lst = isa.translate_one(op, macros)
lst = '; '.join(lst)
- outfile.write("%s%s # %s\n" % (ws, lst, potential))
+ outfile.write("%s%s # %s\n" % (ws, lst, op))
if __name__ == '__main__':
'sv.bc/all 3,12,192',
'sv.bclr/vsbi 3,81.v,192',
'sv.ld 5.v, 4(1.v)',
+ 'sv.svstep. 2.v, 4, 0',
+ ]
+ lst = [
+ 'maxs 3,12,5',
+ 'maxs. 3,12,5',
+ 'avgadd 3,12,5',
+ 'absdu 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'
]
isa = SVP64Asm(lst, macros=macros)
- print("list", list(isa))
- csvs = SVP64RM()
- # asm_process()
+ log("list", list(isa))
+ asm_process()