cry_in: _CryIn = _CryIn.ZERO
ldst_len: _LDSTLen = _LDSTLen.NONE
upd: _LDSTMode = _LDSTMode.NONE
- rc: _RCOE = _RCOE.NONE
+ Rc: _RCOE = _RCOE.NONE
form: _Form = _Form.NONE
conditions: str = ""
unofficial: bool = False
"CR out": "cr_out",
"cry in": "cry_in",
"ldst len": "ldst_len",
+ "rc": "Rc",
"CONDITIONS": "conditions",
}
return frozenset(self.comment.split("=")[-1].split("/"))
+class PPCMultiRecord(tuple):
+ @cached_property
+ def unified(self):
+ def merge(lhs, rhs):
+ value = 0
+ mask = 0
+ lvalue = lhs.opcode.value
+ rvalue = rhs.opcode.value
+ lmask = lhs.opcode.mask
+ rmask = rhs.opcode.mask
+ bits = max(lmask.bit_length(), rmask.bit_length())
+ for bit in range(bits):
+ lvstate = ((lvalue & (1 << bit)) != 0)
+ rvstate = ((rvalue & (1 << bit)) != 0)
+ lmstate = ((lmask & (1 << bit)) != 0)
+ rmstate = ((rmask & (1 << bit)) != 0)
+ vstate = lvstate
+ mstate = True
+ if (not lmstate or not rmstate) or (lvstate != rvstate):
+ vstate = 0
+ mstate = 0
+ value |= (vstate << bit)
+ mask |= (mstate << bit)
+
+ return _dataclasses.replace(lhs, opcode=Opcode(value=value, mask=mask))
+
+ return _functools.reduce(merge, self)
+
+ def __getattr__(self, attr):
+ return getattr(self.unified, attr)
+
+
@_dataclasses.dataclass(eq=True, frozen=True)
class SVP64Record:
class ExtraMap(tuple):
cr_in: _CRInSel = _CRInSel.NONE
cr_out: _CROutSel = _CROutSel.NONE
extra: ExtraMap = ExtraMap()
- pu: bool = False
conditions: str = ""
mode: _SVMode = _SVMode.NORMAL
"Etype": "etype",
"CR in": "cr_in",
"CR out": "cr_out",
- "PU": "pu",
}
@classmethod
def transform(item):
(name, bitrange) = item
- return (name, tuple(bitrange.values()))
+ return (name, list(bitrange.values()))
self.__mapping = dict(map(transform, items))
class Operand:
name: str
- def disassemble(self, value, record):
+ def disassemble(self, value, record, verbose=False):
raise NotImplementedError
@_dataclasses.dataclass(eq=True, frozen=True)
class DynamicOperand(Operand):
- def disassemble(self, value, record):
- return str(int(value[record.fields[self.name]]))
+ def disassemble(self, value, record, verbose=False):
+ span = record.fields[self.name]
+ value = value[span]
+ if verbose:
+ return f"{int(value):0{value.bits}b} {span}"
+ else:
+ return str(int(value))
@_dataclasses.dataclass(eq=True, frozen=True)
class StaticOperand(Operand):
- value: int = None
+ value: int
+
+ def disassemble(self, value, record, verbose=False):
+ span = record.fields[self.name]
+ value = value[span]
+ if verbose:
+ return f"{int(value):0{value.bits}b} {span}"
+ else:
+ return str(int(value))
@_dataclasses.dataclass(eq=True, frozen=True)
class DynamicOperandIFormLI(DynamicOperand):
- def disassemble(self, value, record):
- return hex(int(_selectconcat(
- value[record.fields["LI"]],
- _SelectableInt(value=0b00, bits=2))))
+ @property
+ def name(self):
+ return "LI"
+
+ @name.setter
+ def name(self, _):
+ pass
+
+ def disassemble(self, value, record, verbose=False):
+ span = record.fields["LI"]
+ value = value[span]
+ if verbose:
+ hints = "(target_addr=EXTS(LI || 0b00)))"
+ return f"{int(value):0{value.bits}b} {span} {hints}"
+ else:
+ return hex(int(_selectconcat(value,
+ _SelectableInt(value=0b00, bits=2))))
class DynamicOperandBFormBD(DynamicOperand):
- def disassemble(self, value, record):
- return hex(int(_selectconcat(
- value[record.fields["BD"]],
- _SelectableInt(value=0b00, bits=2))))
+ @property
+ def name(self):
+ return "BD"
+
+ @name.setter
+ def name(self, _):
+ pass
+
+ def disassemble(self, value, record, verbose=False):
+ span = record.fields["BD"]
+ value = value[span]
+ if verbose:
+ hints = "(target_addr=EXTS(BD || 0b00))"
+ return f"{int(value):0{value.bits}b} {span} {hints}"
+ else:
+ return hex(int(_selectconcat(value,
+ _SelectableInt(value=0b00, bits=2))))
@_dataclasses.dataclass(eq=True, frozen=True)
class DynamicOperandGPR(DynamicOperand):
- def disassemble(self, value, record):
- return f"r{super().disassemble(value=value, record=record)}"
+ def disassemble(self, value, record, verbose=False):
+ result = super().disassemble(value=value,
+ record=record, verbose=verbose)
+ if not verbose:
+ result = f"r{result}"
+ return result
@_dataclasses.dataclass(eq=True, frozen=True)
class DynamicOperandFPR(DynamicOperand):
- def disassemble(self, value, record):
- return f"f{super().disassemble(value=value, record=record)}"
+ def disassemble(self, value, record, verbose=False):
+ result = super().disassemble(value=value,
+ record=record, verbose=verbose)
+ if not verbose:
+ result = f"f{result}"
+ return result
def __init__(self, insn, iterable):
branches = {
def __iter__(self):
yield from self.__operands
+ def __contains__(self, key):
+ return self.__getitem__(key) is not None
+
def __getitem__(self, key):
for operand in self.__operands:
if operand.name == key:
def __hash__(self):
return hash(int(self))
- def disassemble(self, db, byteorder="little"):
+ def disassemble(self, db, byteorder="little", verbose=False):
raise NotImplementedError
def integer(cls, value, byteorder="little"):
return super().integer(bits=32, value=value, byteorder=byteorder)
- def disassemble(self, db, byteorder="little"):
+ def spec(self, record):
+ dynamic_operands = []
+ for operand in record.operands.dynamic:
+ dynamic_operands.append(operand.name)
+ static_operands = []
+ for operand in record.operands.static:
+ static_operands.append(f"{operand.name}={operand.value}")
+ operands = ""
+ if dynamic_operands:
+ operands += f" {','.join(dynamic_operands)}"
+ if static_operands:
+ operands += f" ({' '.join(static_operands)})"
+ return f"{record.name}{operands}"
+
+ def opcode(self, record):
+ return f"0x{record.opcode.value:08x}"
+
+ def mask(self, record):
+ return f"0x{record.opcode.mask:08x}"
+
+ def disassemble(self, db, byteorder="little", verbose=False):
integer = int(self)
blob = integer.to_bytes(length=4, byteorder=byteorder)
blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
record = db[self]
if record is None:
yield f"{blob} .long 0x{integer:08x}"
+ return
+
+ operands = []
+ for operand in record.operands.dynamic:
+ operand = operand.disassemble(value=self,
+ record=record, verbose=False)
+ operands.append(operand)
+ if operands:
+ operands = ",".join(operands)
+ operands = f" {operands}"
else:
- operands = []
- for operand in record.operands.dynamic:
- operand = operand.disassemble(self, record)
- operands.append(operand)
- if operands:
- operands = ",".join(operands)
- operands = f" {operands}"
- else:
- operands = ""
- yield f"{blob} {record.name}{operands}"
+ operands = ""
+
+ yield f"{blob} {record.name}{operands}"
+
+ if verbose:
+ lindent = (" " * 4)
+ rindent = (len(blob) - len(lindent))
+ spec = self.spec(record=record)
+ opcode = self.opcode(record=record)
+ mask = self.mask(record=record)
+ yield f"{lindent}{'spec':{rindent}}{spec}"
+ yield f"{lindent}{'opcode':{rindent}}{opcode}"
+ yield f"{lindent}{'mask':{rindent}}{mask}"
+ for operand in record.operands:
+ name = operand.name
+ value = operand.disassemble(value=self,
+ record=record, verbose=True)
+ yield f"{lindent}{name:{rindent}}{value}"
+
class PrefixedInstruction(Instruction):
class Prefix(WordInstruction.remap(range(0, 32))):
class Mode(_Mapping):
_: _Field = range(0, 5)
+ sel: _Field = range(0, 2)
+
+class NormalMode(Mode):
+ class simple(Mode):
+ """simple mode"""
+ dz: Mode[3]
+ sz: Mode[4]
-class LDSTMode(Mode):
- class imm(Mode):
- class normal(Mode):
- """normal mode"""
- zz: _Field = (3,)
- els: _Field = (4,)
- dz: _Field = (3,)
- sz: _Field = (3,)
-
- class spu(Mode):
- """Structured Pack/Unpack"""
- zz: _Field = (3,)
- els: _Field = (4,)
- dz: _Field = (3,)
- sz: _Field = (3,)
-
- class ffrc1(Mode):
- """Rc=1: ffirst CR sel"""
- inv: _Field = (2,)
- CRbit: _Field = (3, 4)
-
- class ffrc0(Mode):
- """Rc=0: ffirst z/nonz"""
- inv: _Field = (2,)
- els: _Field = (3,)
- RC1: _Field = (4,)
-
- class sat(Mode):
- """sat mode: N=0/1 u/s"""
- N: _Field = (2,)
- zz: _Field = (3,)
- els: _Field = (4,)
- dz: _Field = (3,)
- sz: _Field = (3,)
-
-
- class prrc1(Mode):
- """Rc=1: pred-result CR sel"""
- inv: _Field = (2,)
- CRbit: _Field = (3, 4)
-
- class prrc0(Mode):
- """Rc=0: pred-result z/nonz"""
- inv: _Field = (2,)
- els: _Field = (3,)
- RC1: _Field = (4,)
-
- normal: normal
- spu: spu
- ffrc1: ffrc1
- ffrc0: ffrc0
- sat: sat
- prrc1: prrc1
- prrc0: prrc0
-
- imm: imm
+ class smr(Mode):
+ """scalar reduce mode (mapreduce), SUBVL=1"""
+ RG: Mode[4]
+
+ class pmr(Mode):
+ """parallel reduce mode (mapreduce), SUBVL=1"""
+ pass
+
+ class svmr(Mode):
+ """subvector reduce mode, SUBVL>1"""
+ SVM: Mode[3]
+
+ class pu(Mode):
+ """Pack/Unpack mode, SUBVL>1"""
+ SVM: Mode[3]
+
+ class ffrc1(Mode):
+ """Rc=1: ffirst CR sel"""
+ inv: Mode[2]
+ CRbit: Mode[3, 4]
+
+ class ffrc0(Mode):
+ """Rc=0: ffirst z/nonz"""
+ inv: Mode[2]
+ VLi: Mode[3]
+ RC1: Mode[4]
+
+ class sat(Mode):
+ """sat mode: N=0/1 u/s, SUBVL=1"""
+ N: Mode[2]
+ dz: Mode[3]
+ sz: Mode[4]
+
+ class satx(Mode):
+ """sat mode: N=0/1 u/s, SUBVL>1"""
+ N: Mode[2]
+ zz: Mode[3]
+ dz: Mode[3]
+ sz: Mode[3]
+
+ class satpu(Mode):
+ """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
+ N: Mode[2]
+ zz: Mode[3]
+ dz: Mode[3]
+ sz: Mode[3]
+
+ class prrc1(Mode):
+ """Rc=1: pred-result CR sel"""
+ inv: Mode[2]
+ CRbit: Mode[3, 4]
+
+ class prrc0(Mode):
+ """Rc=0: pred-result z/nonz"""
+ inv: Mode[2]
+ zz: Mode[3]
+ RC1: Mode[4]
+ dz: Mode[3]
+ sz: Mode[3]
+
+ simple: simple
+ smr: smr
+ pmr: pmr
+ svmr: svmr
+ pu: pu
+ ffrc1: ffrc1
+ ffrc0: ffrc0
+ sat: sat
+ satx: satx
+ satpu: satpu
+ prrc1: prrc1
+ prrc0: prrc0
+
+
+class LDSTImmMode(Mode):
+ class simple(Mode):
+ """simple mode"""
+ zz: Mode[3]
+ els: Mode[4]
+ dz: Mode[3]
+ sz: Mode[3]
+
+ class spu(Mode):
+ """Structured Pack/Unpack"""
+ zz: Mode[3]
+ els: Mode[4]
+ dz: Mode[3]
+ sz: Mode[3]
+
+ class ffrc1(Mode):
+ """Rc=1: ffirst CR sel"""
+ inv: Mode[2]
+ CRbit: Mode[3, 4]
+
+ class ffrc0(Mode):
+ """Rc=0: ffirst z/nonz"""
+ inv: Mode[2]
+ els: Mode[3]
+ RC1: Mode[4]
+
+ class sat(Mode):
+ """sat mode: N=0/1 u/s"""
+ N: Mode[2]
+ zz: Mode[3]
+ els: Mode[4]
+ dz: Mode[3]
+ sz: Mode[3]
+
+ class prrc1(Mode):
+ """Rc=1: pred-result CR sel"""
+ inv: Mode[2]
+ CRbit: Mode[3, 4]
+
+ class prrc0(Mode):
+ """Rc=0: pred-result z/nonz"""
+ inv: Mode[2]
+ els: Mode[3]
+ RC1: Mode[4]
+
+ simple: simple
+ spu: spu
+ ffrc1: ffrc1
+ ffrc0: ffrc0
+ sat: sat
+ prrc1: prrc1
+ prrc0: prrc0
+
+
+class LDSTIdxMode(Mode):
+ class simple(Mode):
+ """simple mode"""
+ SEA: Mode[2]
+ sz: Mode[3]
+ dz: Mode[3]
+
+ class stride(Mode):
+ """strided (scalar only source)"""
+ SEA: Mode[2]
+ dz: Mode[3]
+ sz: Mode[4]
+
+ class sat(Mode):
+ """sat mode: N=0/1 u/s"""
+ N: Mode[2]
+ dz: Mode[3]
+ sz: Mode[4]
+
+ class prrc1(Mode):
+ """Rc=1: pred-result CR sel"""
+ inv: Mode[2]
+ CRbit: Mode[3, 4]
+
+ class prrc0(Mode):
+ """Rc=0: pred-result z/nonz"""
+ inv: Mode[2]
+ zz: Mode[3]
+ RC1: Mode[4]
+ dz: Mode[3]
+ sz: Mode[3]
+
+ simple: simple
+ stride: stride
+ sat: sat
+ prrc1: prrc1
+ prrc0: prrc0
class RM(_Mapping):
class Mode(Mode):
- ldst: LDSTMode
+ normal: NormalMode
+ ldst_imm: LDSTImmMode
+ ldst_idx: LDSTIdxMode
_: _Field = range(24)
mmode: _Field = (0,)
prefix: Prefix
- def disassemble(self, db, byteorder="little"):
+ def disassemble(self, db, byteorder="little", verbose=False):
integer_prefix = int(self.prefix)
blob_prefix = integer_prefix.to_bytes(length=4, byteorder=byteorder)
blob_prefix = " ".join(map(lambda byte: f"{byte:02x}", blob_prefix))
if record is None or record.svp64 is None:
yield f"{blob_prefix} .long 0x{int(self.prefix):08x}"
yield f"{blob_suffix} .long 0x{int(self.suffix):08x}"
- else:
- yield f"{blob_prefix} sv.{record.name}"
- yield f"{blob_suffix}"
+ return
+
+ Rc = False
+ if record.operands["Rc"] is not None:
+ Rc = bool(self[record.fields["Rc"]])
+
+ subvl = self.prefix.rm.subvl
+ mode = self.prefix.rm.mode
+ sel = mode.sel
+
+ if record.svp64.mode is _SVMode.NORMAL:
+ mode = mode.normal
+ if sel == 0b00:
+ if mode[2] == 0b0:
+ mode = mode.simple
+ else:
+ if subvl == 0b00:
+ if mode[3] == 0b0:
+ mode = mode.smr
+ else:
+ mode = mode.pmr
+ else:
+ if mode[4] == 0b0:
+ mode = mode.svmr
+ else:
+ mode = mode.pu
+ elif sel == 0b01:
+ if Rc:
+ mode = mode.ffrc1
+ else:
+ mode = mode.ffrc0
+ elif sel == 0b10:
+ if subvl == 0b00:
+ mode = mode.sat
+ else:
+ if mode[4]:
+ mode = mode.satx
+ else:
+ mode = mode.satpu
+ elif sel == 0b11:
+ if Rc:
+ mode = mode.prrc1
+ else:
+ mode = mode.prrc0
+ elif record.svp64.mode is _SVMode.LDST_IMM:
+ mode = mode.ldst_imm
+ if sel == 0b00:
+ if mode[2] == 0b0:
+ mode = mode.simple
+ else:
+ mode = mode.spu
+ elif sel == 0b01:
+ if Rc:
+ mode = mode.ffrc1
+ else:
+ mode = mode.ffrc0
+ elif sel == 0b10:
+ mode = mode.sat
+ elif sel == 0b11:
+ if Rc:
+ mode = mode.prrc1
+ else:
+ mode = mode.prrc0
+ elif record.svp64.mode is _SVMode.LDST_IMM:
+ mode = mode.ldst_idx
+ if mode.sel == 0b00:
+ mode = mode.simple
+ elif mode.sel == 0b01:
+ mode = mode.stride
+ elif mode.sel == 0b10:
+ mode = mode.sat
+ elif mode.sel == 0b11:
+ if Rc:
+ mode = mode.prrc1
+ else:
+ mode = mode.prrc0
+
+ if type(mode) is Mode:
+ raise NotImplementedError
+
+ yield f"{blob_prefix} sv.{record.name}"
+ yield f"{blob_suffix}"
def parse(stream, factory):
for insn in parse(stream, factory):
records[section][insn.comment].add(insn)
- # Once we collected all instructions with the same identifier,
- # it's time to merge the different opcodes into the single pattern.
- # At this point, we only consider masks; the algorithm as follows:
- # 1. If any of two masks ignores the bit, it's ignored entirely.
- # 2. If the bit is not equal between masks, it's ignored.
- # 3. Otherwise the bits are equal and considered.
- def merge(lhs, rhs):
- value = 0
- mask = 0
- lvalue = lhs.opcode.value
- rvalue = rhs.opcode.value
- lmask = lhs.opcode.mask
- rmask = rhs.opcode.mask
- bits = max(lmask.bit_length(), rmask.bit_length())
- for bit in range(bits):
- lvstate = ((lvalue & (1 << bit)) != 0)
- rvstate = ((rvalue & (1 << bit)) != 0)
- lmstate = ((lmask & (1 << bit)) != 0)
- rmstate = ((rmask & (1 << bit)) != 0)
- vstate = lvstate
- mstate = True
- if (not lmstate or not rmstate) or (lvstate != rvstate):
- vstate = 0
- mstate = 0
- value |= (vstate << bit)
- mask |= (mstate << bit)
- return _dataclasses.replace(lhs, opcode=Opcode(value=value, mask=mask))
-
db = dd(set)
for (section, group) in records.items():
for records in group.values():
- db[section].add(_functools.reduce(merge, records))
+ db[section].add(PPCMultiRecord(records))
self.__db = db
self.__mdwndb = mdwndb
if not key.endswith("."):
return False
- if not record.rc is _RCOE.RC:
+ if not record.Rc is _RCOE.RC:
return False
return exact_match(key[:-1], record)