# decodes svp64 assembly listings and creates EXT001 svp64 prefixes
class SVP64Asm:
- def __init__(self, lst, bigendian=False):
+ def __init__(self, lst, bigendian=False, macros=None):
+ if macros is None:
+ macros = {}
+ self.macros = macros
self.lst = lst
self.trans = self.translate(lst)
self.isa = ISA() # reads the v3.0B pseudo-code markdown files
def __iter__(self):
yield from self.trans
- def translate_one(self, insn):
+ def translate_one(self, insn, macros=None):
+ if macros is None:
+ macros = {}
+ macros.update(self.macros)
isa = self.isa
svp64 = self.svp64
# find first space, to get opcode
opcode = ls[0]
# now find opcode fields
fields = ''.join(ls[1:]).split(',')
- fields = list(map(str.strip, fields))
- log ("opcode, fields", ls, opcode, fields)
+ mfields = list(map(str.strip, fields))
+ log ("opcode, fields", ls, opcode, mfields)
+ fields = []
+ # macro substitution
+ for field in mfields:
+ fields.append(macro_subst(macros, field))
+ log ("opcode, fields substed", ls, opcode, fields)
# sigh have to do setvl here manually for now...
if opcode in ["setvl", "setvl."]:
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 "br"
+ # e.g. ldbr is actually ld
+ ldst_bitreverse = v30b_op.startswith("l") and v30b_op.endswith("br")
+
if v30b_op not in isa.instr:
raise Exception("opcode %s of '%s' not supported" % \
(v30b_op, insn))
+
+ if ldst_bitreverse:
+ # okaay we need to process the fields and make this:
+ # ldbr 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 "br" from end, and add "br" to opmodes, instead
+ v30b_op = v30b_op[:-2]
+ opmodes.append("br")
+ 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))
for idx, (field, regname) in enumerate(opregfields):
imm, regname = decode_imm(regname)
rtype = get_regtype(regname)
- log (" idx find", idx, field, regname, imm)
+ log (" idx find", rtype, idx, field, regname, imm)
+ if rtype is None:
+ # probably an immediate field, append it straight
+ extras[('imm', idx, False)] = (idx, field, None, None, None)
+ continue
extra = svp64_src.get(regname, None)
if extra is not None:
extra = ('s', extra, False) # not a duplicate
# into newfields
if rtype is None:
v30b_newfields.append(field)
+ continue
# identify if this is a ld/st immediate(reg) thing
ldst_imm = "(" in field and field[-1] == ')'
(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
field = (field << 2) | cr_subfield
+ else:
+ print ("no type match", rtype)
+
# capture the extra field info
log ("=>", "%5s" % bin(sv_extra), field)
extras[extra_idx] = sv_extra
# begin with EXTRA fields
for idx, sv_extra in extras.items():
- if idx is None: continue
log (idx)
+ if idx is None: continue
+ if idx[0] == 'imm': continue
srcdest, idx, duplicate = idx
if etype == 'EXTRA2':
svp64_rm.extra2[idx].eq(
sv_mode = None
mapreduce = False
+ reverse_gear = False
mapreduce_crm = False
mapreduce_svm = False
smmode, smask = decode_predicate(encmode[3:])
mmode = smmode
has_smask = True
+ # bitreverse LD/ST
+ elif encmode.startswith("br"):
+ ldst_bitreverse = True
# vec2/3/4
elif encmode.startswith("vec"):
subvl = decode_subvl(encmode[3:])
assert sv_mode is None
sv_mode = 0b11
predresult = decode_ffirst(encmode[3:])
+ # map-reduce mode, reverse-gear
+ elif encmode == 'mrr':
+ assert sv_mode is None
+ sv_mode = 0b00
+ mapreduce = True
+ reverse_gear = True
# map-reduce mode
elif encmode == 'mr':
assert sv_mode is None
assert has_pmask or mask_m_specified, \
"dest zeroing requires a dest predicate"
+ # check LDST bitreverse, only available in "normal" mode
+ if is_ldst and ldst_bitreverse:
+ assert sv_mode is None, \
+ "LD bit-reverse cannot have modes (%s) applied" % sv_mode
+
######################################
# "normal" mode
if sv_mode is None:
if is_ldst:
# TODO: for now, LD/ST-indexed is ignored.
mode |= ldst_elstride << SVP64MODE.ELS_NORMAL # element-strided
+ # bitreverse mode
+ if ldst_bitreverse:
+ mode |= 1 << SVP64MODE.LDST_BITREV
else:
# TODO, reduce and subvector mode
# 00 1 dz CRM reduce mode (mapreduce), SUBVL=1
elif sv_mode == 0b00:
mode |= (0b1<<SVP64MODE.REDUCE) # sets mapreduce
assert dst_zero == 0, "dest-zero not allowed in mapreduce mode"
+ if reverse_gear:
+ mode |= (0b1<<SVP64MODE.RG) # sets Reverse-gear mode
if mapreduce_crm:
mode |= (0b1<<SVP64MODE.CRM) # sets CRM mode
assert rc_mode, "CRM only allowed when Rc=1"
offs = 2 if etype == 'EXTRA2' else 3 # 2 or 3 bits
for idx, sv_extra in extras.items():
if idx is None: continue
+ if idx[0] == 'imm': continue
srcdest, idx, duplicate = idx
start = (10+idx*offs)
end = start + offs-1
# fiinally yield the svp64 prefix and the thingy. v3.0b opcode
rc = '.' if rc_mode else ''
yield ".long 0x%x" % svp64_prefix.insn.value
- yield "%s %s" % (v30b_op+rc, ", ".join(v30b_newfields))
+ log(v30b_newfields)
+ # argh, sv.fmaddso etc. need to be done manually
+ if 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[2]) << (32-21) # FRB
+ opcode |= int(v30b_newfields[3]) << (32-26) # FRC
+ opcode |= 5 << (32-31) # bits 26-30
+ if rc:
+ opcode |= 1 # Rc, bit 31.
+ yield ".long 0x%x" % opcode
+ else:
+ yield "%s %s" % (v30b_op+rc, ", ".join(v30b_newfields))
log ("new v3.0B fields", v30b_op, v30b_newfields)
def translate(self, lst):
yield from self.translate_one(insn)
+def macro_subst(macros, txt):
+ again = True
+ print ("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)
+ 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)
+ 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)
+ 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)
+ txt = replaced
+ continue
+ print (" processed", txt)
+ return txt
+
+
+def get_ws(line):
+ # find whitespace
+ ws = ''
+ while line:
+ if not line[0].isspace():
+ break
+ ws += line[0]
+ line = line[1:]
+ return ws, line
+
+
def asm_process():
# get an input file and an output file
outfile = open(args[1], "w")
# read the line, look for "sv", process it
+ macros = {} # macros which start ".set"
isa = SVP64Asm([])
for line in lines:
ls = line.split("#")
+ # identify macros
+ if ls[0].strip().startswith("setvl"):
+ 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))
+ macros[macro] = value
if len(ls) != 2:
outfile.write(line)
continue
if not potential.startswith("sv."):
outfile.write(line)
continue
- # find whitespace
- ws = ''
- while line:
- if not line[0].isspace():
- break
- ws += line[0]
- line = line[1:]
+ ws, line = get_ws(line)
# SV line indentified
- lst = list(isa.translate_one(potential))
+ lst = list(isa.translate_one(potential, macros))
lst = '; '.join(lst)
outfile.write("%s%s # %s\n" % (ws, lst, potential))
lst = [
"sv.stfsu/els 0.v, 16(4)",
]
- isa = SVP64Asm(lst)
+ lst = [
+ 'sv.add./mr 5.v, 2.v, 1.v',
+ ]
+ macros = {'win2': '50', 'win': '60'}
+ lst = [
+ 'sv.addi win2.v, win.v, -1',
+ 'sv.add./mrr 5.v, 2.v, 1.v',
+ #'sv.lhzbr 5.v, 11(9.v), 15',
+ #'sv.lwzbr 5.v, 11(9.v), 15',
+ 'sv.ffmadds 6.v, 2.v, 4.v, 6.v',
+ ]
+ isa = SVP64Asm(lst, macros=macros)
print ("list", list(isa))
csvs = SVP64RM()
#asm_process()