import enum as _enum
import functools as _functools
import os as _os
+import operator as _operator
import pathlib as _pathlib
import re as _re
)
from openpower.decoder.power_fields import (
Field as _Field,
- Array as _Array,
Mapping as _Mapping,
DecodeFields as _DecodeFields,
)
from openpower.decoder.pseudo.pagereader import ISA as _ISA
+@_functools.total_ordering
+class Verbosity(_enum.Enum):
+ SHORT = _enum.auto()
+ NORMAL = _enum.auto()
+ VERBOSE = _enum.auto()
+
+ def __lt__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return (self.value < other.value)
+
+
def dataclass(cls, record, keymap=None, typemap=None):
if keymap is None:
keymap = {}
flags.add(flag)
record["flags"] = PPCRecord.Flags(flags)
- return dataclass(cls, record, keymap=PPCRecord.__KEYMAP, typemap=typemap)
+ return dataclass(cls, record,
+ keymap=PPCRecord.__KEYMAP,
+ typemap=typemap)
@cached_property
def names(self):
return frozenset(self.comment.split("=")[-1].split("/"))
-class PPCMultiRecord(tuple):
+class PPCMultiRecord(frozenset):
@cached_property
def unified(self):
def merge(lhs, rhs):
value |= (vstate << bit)
mask |= (mstate << bit)
- return _dataclasses.replace(lhs, opcode=Opcode(value=value, mask=mask))
+ opcode = opcode=Opcode(value=value, mask=mask)
+
+ return _dataclasses.replace(lhs, opcode=opcode)
return _functools.reduce(merge, self)
if value == "0":
record[key] = "NONE"
- record["extra"] = cls.ExtraMap(record.pop(f"{index}") for index in range(0, 4))
+ extra = []
+ for idx in range(0, 4):
+ extra.append(record.pop(f"{idx}"))
+
+ record["extra"] = cls.ExtraMap(extra)
return dataclass(cls, record, keymap=cls.__KEYMAP)
+ @_functools.lru_cache(maxsize=None)
+ def extra_idx(self, key):
+ extra_idx = (
+ _SVExtra.Idx0,
+ _SVExtra.Idx1,
+ _SVExtra.Idx2,
+ _SVExtra.Idx3,
+ )
+
+ if key not in frozenset({
+ "in1", "in2", "in3", "cr_in",
+ "out", "out2", "cr_out",
+ }):
+ raise KeyError(key)
+
+ sel = getattr(self, key)
+ if sel is _CRInSel.BA_BB:
+ return _SVExtra.Idx_1_2
+ reg = _SVExtraReg(sel)
+ if reg is _SVExtraReg.NONE:
+ return _SVExtra.NONE
+
+ extra_map = {
+ _SVExtraRegType.SRC: {},
+ _SVExtraRegType.DST: {},
+ }
+ for index in range(0, 4):
+ for entry in self.extra[index]:
+ extra_map[entry.regtype][entry.reg] = extra_idx[index]
+
+ for regtype in (_SVExtraRegType.SRC, _SVExtraRegType.DST):
+ extra = extra_map[regtype].get(reg, _SVExtra.NONE)
+ if extra is not _SVExtra.NONE:
+ return extra
+
+ return _SVExtra.NONE
+
+ extra_idx_in1 = property(_functools.partial(extra_idx, key="in1"))
+ extra_idx_in2 = property(_functools.partial(extra_idx, key="in2"))
+ extra_idx_in3 = property(_functools.partial(extra_idx, key="in3"))
+ extra_idx_out = property(_functools.partial(extra_idx, key="out"))
+ extra_idx_out2 = property(_functools.partial(extra_idx, key="out2"))
+ extra_idx_cr_in = property(_functools.partial(extra_idx, key="cr_in"))
+ extra_idx_cr_out = property(_functools.partial(extra_idx, key="cr_out"))
+
+ @_functools.lru_cache(maxsize=None)
+ def extra_reg(self, key):
+ return _SVExtraReg(getattr(self, key))
+
+ extra_reg_in1 = property(_functools.partial(extra_reg, key="in1"))
+ extra_reg_in2 = property(_functools.partial(extra_reg, key="in2"))
+ extra_reg_in3 = property(_functools.partial(extra_reg, key="in3"))
+ extra_reg_out = property(_functools.partial(extra_reg, key="out"))
+ extra_reg_out2 = property(_functools.partial(extra_reg, key="out2"))
+ extra_reg_cr_in = property(_functools.partial(extra_reg, key="cr_in"))
+ extra_reg_cr_out = property(_functools.partial(extra_reg, key="cr_out"))
+
class BitSel:
def __init__(self, value=(0, 32)):
def transform(item):
(name, bitrange) = item
- return (name, list(bitrange.values()))
+ return (name, tuple(bitrange.values()))
self.__mapping = dict(map(transform, items))
return self.__mapping.get(key, None)
-class Operands:
- @_dataclasses.dataclass(eq=True, frozen=True)
- class Operand:
- name: str
+@_dataclasses.dataclass(eq=True, frozen=True)
+class Operand:
+ name: str
+
+ def disassemble(self, insn, record,
+ verbosity=Verbosity.NORMAL, indent=""):
+ raise NotImplementedError
- def disassemble(self, value, record, verbose=False):
- raise NotImplementedError
- @_dataclasses.dataclass(eq=True, frozen=True)
- class DynamicOperand(Operand):
- 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 DynamicOperand(Operand):
+ def disassemble(self, insn, record,
+ verbosity=Verbosity.NORMAL, indent=""):
+ span = record.fields[self.name]
+ if isinstance(insn, SVP64Instruction):
+ span = tuple(map(lambda bit: (bit + 32), span))
+ value = insn[span]
+
+ if verbosity >= Verbosity.VERBOSE:
+ span = map(str, span)
+ yield f"{indent}{self.name}"
+ yield f"{indent}{indent}{int(value):0{value.bits}b}"
+ yield f"{indent}{indent}{', '.join(span)}"
+ else:
+ yield str(int(value))
- @_dataclasses.dataclass(eq=True, frozen=True)
- class StaticOperand(Operand):
- 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):
- @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):
- @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}"
+@_dataclasses.dataclass(eq=True, frozen=True)
+class DynamicOperandReg(DynamicOperand):
+ def spec(self, insn, record):
+ vector = False
+ span = record.fields[self.name]
+ if isinstance(insn, SVP64Instruction):
+ span = tuple(map(lambda bit: (bit + 32), span))
+ value = insn[span]
+
+ if isinstance(insn, SVP64Instruction):
+ extra_idx = self.extra_idx(record=record)
+
+ if record.etype is _SVEtype.EXTRA3:
+ extra = insn.prefix.rm.extra3[extra_idx]
+ elif record.etype is _SVEtype.EXTRA2:
+ extra = insn.prefix.rm.extra2[extra_idx]
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, 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, 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):
+ raise ValueError(record.etype)
+
+ if extra != 0:
+ vector = bool(extra[0])
+ span = tuple(map(str, span))
+ extra_span = extra.__class__
+ if record.etype is _SVEtype.EXTRA3:
+ extra_span = tuple(map(str, extra_span[1, 2]))
+ extra = extra[1, 2]
+ elif record.etype is _SVEtype.EXTRA2:
+ extra_span = tuple(map(str, extra_span[1,]))
+ extra = _SelectableInt(value=extra[1].value, bits=2)
+ if vector:
+ extra <<= 1
+ extra_span = (extra_span + ("{0}",))
+ else:
+ extra_span = (("{0}",) + extra_span)
+ else:
+ raise ValueError(record.etype)
+
+ bits = (len(span) + len(extra_span))
+ value = _SelectableInt(value=value.value, bits=bits)
+ extra = _SelectableInt(value=extra.value, bits=bits)
+ if vector:
+ value = ((value << 2) | extra)
+ span = (span + extra_span)
+ else:
+ value = ((extra << 5) | value)
+ span = (extra_span + span)
+
+ value = _SelectableInt(value=value, bits=bits)
+
+ else:
+ value = insn[span]
+
+ span = tuple(map(str, span))
+
+ return (vector, value, span)
+
+ @property
+ def extra_reg(self):
+ return _SVExtraReg(self.name)
+
+ def extra_idx(self, record):
+ for key in frozenset({
+ "in1", "in2", "in3", "cr_in",
+ "out", "out2", "cr_out",
+ }):
+ extra_reg = record.svp64.extra_reg(key=key)
+ if extra_reg is self.extra_reg:
+ return record.extra_idx(key=key)
+
+ return _SVExtra.NONE
+
+ def disassemble(self, insn, record,
+ verbosity=Verbosity.NORMAL, prefix="", indent=""):
+ (vector, value, span) = self.spec(insn=insn, record=record)
+
+ if verbosity >= Verbosity.VERBOSE:
+ yield f"{indent}{self.name}"
+ yield f"{indent}{indent}{int(value):0{value.bits}b}"
+ yield f"{indent}{indent}{', '.join(span)}"
+ if isinstance(insn, SVP64Instruction):
+ extra_idx = self.extra_idx(record)
+ if record.etype is _SVEtype.NONE:
+ yield f"{indent}{indent}extra[none]"
+ else:
+ etype = repr(record.etype).lower()
+ yield f"{indent}{indent}{etype}{extra_idx!r}"
+ yield f"{indent}type"
+ yield f"{indent}{indent}{'vector' if vector else 'scalar'}"
+ else:
+ vector = "*" if vector else ""
+ yield f"{vector}{prefix}{int(value)}"
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class ImmediateOperand(DynamicOperand):
+ pass
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class StaticOperand(Operand):
+ value: int
+
+ def disassemble(self, insn, record,
+ verbosity=Verbosity.NORMAL, indent=""):
+ span = record.fields[self.name]
+ if isinstance(insn, SVP64Instruction):
+ span = tuple(map(lambda bit: (bit + 32), span))
+ value = insn[span]
+
+ if verbosity >= Verbosity.VERBOSE:
+ span = map(str, span)
+ yield f"{indent}{self.name}"
+ yield f"{indent}{indent}{int(value):0{value.bits}b}"
+ yield f"{indent}{indent}{', '.join(span)}"
+ else:
+ yield str(int(value))
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class DynamicOperandTargetAddr(DynamicOperandReg):
+ def disassemble(self, insn, record, field,
+ verbosity=Verbosity.NORMAL, indent=""):
+ span = record.fields[field]
+ if isinstance(insn, SVP64Instruction):
+ span = tuple(map(lambda bit: (bit + 32), span))
+ value = insn[span]
+
+ if verbosity >= Verbosity.VERBOSE:
+ span = tuple(map(str, span))
+ yield f"{indent}{self.name}"
+ yield f"{indent}{indent}{int(value):0{value.bits}b}00"
+ yield f"{indent}{indent}{', '.join(span + ('{0}', '{0}'))}"
+ yield f"{indent}{indent}target_addr = EXTS({field} || 0b00))"
+ else:
+ yield hex(int(_selectconcat(value,
+ _SelectableInt(value=0b00, bits=2))))
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class DynamicOperandTargetAddrLI(DynamicOperandTargetAddr):
+ def disassemble(self, insn, record,
+ verbosity=Verbosity.NORMAL, indent=""):
+ return super().disassemble(field="LI",
+ insn=insn, record=record,
+ verbosity=verbosity, indent=indent)
+
+
+class DynamicOperandTargetAddrBD(DynamicOperandTargetAddr):
+ def disassemble(self, insn, record,
+ verbosity=Verbosity.NORMAL, indent=""):
+ return super().disassemble(field="BD",
+ insn=insn, record=record,
+ verbosity=verbosity, indent=indent)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class DynamicOperandGPR(DynamicOperandReg):
+ def disassemble(self, insn, record,
+ verbosity=Verbosity.NORMAL, indent=""):
+ prefix = "" if (verbosity <= Verbosity.SHORT) else "r"
+ yield from super().disassemble(prefix=prefix,
+ insn=insn, record=record,
+ verbosity=verbosity, indent=indent)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class DynamicOperandFPR(DynamicOperandReg):
+ def disassemble(self, insn, record,
+ verbosity=Verbosity.NORMAL, indent=""):
+ prefix = "" if (verbosity <= Verbosity.SHORT) else "f"
+ yield from super().disassemble(prefix=prefix,
+ insn=insn, record=record,
+ verbosity=verbosity, indent=indent)
+
+
+class Operands(tuple):
+ def __new__(cls, insn, iterable):
branches = {
- "b": {"LI": self.__class__.DynamicOperandIFormLI},
- "ba": {"LI": self.__class__.DynamicOperandIFormLI},
- "bl": {"LI": self.__class__.DynamicOperandIFormLI},
- "bla": {"LI": self.__class__.DynamicOperandIFormLI},
- "bc": {"BD": self.__class__.DynamicOperandBFormBD},
- "bca": {"BD": self.__class__.DynamicOperandBFormBD},
- "bcl": {"BD": self.__class__.DynamicOperandBFormBD},
- "bcla": {"BD": self.__class__.DynamicOperandBFormBD},
+ "b": {"target_addr": DynamicOperandTargetAddrLI},
+ "ba": {"target_addr": DynamicOperandTargetAddrLI},
+ "bl": {"target_addr": DynamicOperandTargetAddrLI},
+ "bla": {"target_addr": DynamicOperandTargetAddrLI},
+ "bc": {"target_addr": DynamicOperandTargetAddrBD},
+ "bca": {"target_addr": DynamicOperandTargetAddrBD},
+ "bcl": {"target_addr": DynamicOperandTargetAddrBD},
+ "bcla": {"target_addr": DynamicOperandTargetAddrBD},
}
operands = []
for operand in iterable:
- dynamic_cls = self.__class__.DynamicOperand
- static_cls = self.__class__.StaticOperand
+ dynamic_cls = DynamicOperand
+ static_cls = StaticOperand
if "=" in operand:
(name, value) = operand.split("=")
operand = static_cls(name=name, value=int(value))
+ operands.append(operand)
else:
+ if operand.endswith(")"):
+ operand = operand.replace("(", " ").replace(")", "")
+ (immediate, _, operand) = operand.partition(" ")
+ else:
+ immediate = None
+
+ if immediate is not None:
+ operands.append(ImmediateOperand(name=immediate))
+
if insn in branches and operand in branches[insn]:
dynamic_cls = branches[insn][operand]
if operand in _RegType.__members__:
regtype = _RegType[operand]
if regtype is _RegType.GPR:
- dynamic_cls = self.__class__.DynamicOperandGPR
+ dynamic_cls = DynamicOperandGPR
elif regtype is _RegType.FPR:
- dynamic_cls = self.__class__.DynamicOperandFPR
+ dynamic_cls = DynamicOperandFPR
operand = dynamic_cls(name=operand)
+ operands.append(operand)
- operands.append(operand)
-
- self.__operands = operands
-
- return super().__init__()
-
- def __repr__(self):
- return self.__operands.__repr__()
-
- def __iter__(self):
- yield from self.__operands
+ return super().__new__(cls, operands)
def __contains__(self, key):
return self.__getitem__(key) is not None
def __getitem__(self, key):
- for operand in self.__operands:
+ for operand in self:
if operand.name == key:
return operand
@property
def dynamic(self):
for operand in self:
- if isinstance(operand, self.__class__.DynamicOperand):
+ if isinstance(operand, DynamicOperand):
yield operand
@property
def static(self):
for operand in self:
- if isinstance(operand, self.__class__.StaticOperand):
+ if isinstance(operand, StaticOperand):
yield operand
operands: Operands
svp64: SVP64Record = None
- __EXTRA = (
- _SVExtra.Idx0,
- _SVExtra.Idx1,
- _SVExtra.Idx2,
- _SVExtra.Idx3,
- )
-
def __lt__(self, other):
if not isinstance(other, Record):
return NotImplemented
def cr_out(self):
return self.ppc.cr_out
- def sv_extra(self, key):
- if key not in frozenset({
- "in1", "in2", "in3", "cr_in",
- "out", "out2", "cr_out",
- }):
- raise KeyError(key)
-
- sel = getattr(self.svp64, key)
- if sel is _CRInSel.BA_BB:
- return _SVExtra.Idx_1_2
- reg = _SVExtraReg(sel)
- if reg is _SVExtraReg.NONE:
- return _SVExtra.NONE
-
- extra_map = {
- _SVExtraRegType.SRC: {},
- _SVExtraRegType.DST: {},
- }
- for index in range(0, 4):
- for entry in self.svp64.extra[index]:
- extra_map[entry.regtype][entry.reg] = Record.__EXTRA[index]
+ ptype = property(lambda self: self.svp64.ptype)
+ etype = property(lambda self: self.svp64.etype)
- for regtype in (_SVExtraRegType.SRC, _SVExtraRegType.DST):
- extra = extra_map[regtype].get(reg, _SVExtra.NONE)
- if extra is not _SVExtra.NONE:
- return extra
+ def extra_idx(self, key):
+ return self.svp64.extra_idx(key)
- return _SVExtra.NONE
-
- sv_in1 = property(_functools.partial(sv_extra, key="in1"))
- sv_in2 = property(_functools.partial(sv_extra, key="in2"))
- sv_in3 = property(_functools.partial(sv_extra, key="in3"))
- sv_out = property(_functools.partial(sv_extra, key="out"))
- sv_out2 = property(_functools.partial(sv_extra, key="out2"))
- sv_cr_in = property(_functools.partial(sv_extra, key="cr_in"))
- sv_cr_out = property(_functools.partial(sv_extra, key="cr_out"))
-
- @property
- def sv_ptype(self):
- if self.svp64 is None:
- return _SVPtype.NONE
- return self.svp64.ptype
-
- @property
- def sv_etype(self):
- if self.svp64 is None:
- return _SVEtype.NONE
- return self.svp64.etype
+ extra_idx_in1 = property(lambda self: self.svp64.extra_idx_in1)
+ extra_idx_in2 = property(lambda self: self.svp64.extra_idx_in2)
+ extra_idx_in3 = property(lambda self: self.svp64.extra_idx_in3)
+ extra_idx_out = property(lambda self: self.svp64.extra_idx_out)
+ extra_idx_out2 = property(lambda self: self.svp64.extra_idx_out2)
+ extra_idx_cr_in = property(lambda self: self.svp64.extra_idx_cr_in)
+ extra_idx_cr_out = property(lambda self: self.svp64.extra_idx_cr_out)
class Instruction(_Mapping):
def __hash__(self):
return hash(int(self))
- def disassemble(self, db, byteorder="little", verbose=False):
+ def record(self, db):
+ record = db[self]
+ if record is None:
+ raise KeyError(self)
+ return record
+
+ def spec(self, db, prefix):
+ record = self.record(db=db)
+
+ dynamic_operands = tuple(map(_operator.itemgetter(0),
+ self.dynamic_operands(db=db)))
+
+ static_operands = []
+ for (name, value) in self.static_operands(db=db):
+ static_operands.append(f"{name}={value}")
+
+ operands = ""
+ if dynamic_operands:
+ operands += f" {','.join(dynamic_operands)}"
+ if static_operands:
+ operands += f" ({' '.join(static_operands)})"
+
+ return f"{prefix}{record.name}{operands}"
+
+ def dynamic_operands(self, db, verbosity=Verbosity.NORMAL):
+ record = self.record(db=db)
+
+ imm = False
+ imm_name = ""
+ imm_value = ""
+ for operand in record.operands.dynamic:
+ name = operand.name
+ dis = operand.disassemble(insn=self, record=record,
+ verbosity=min(verbosity, Verbosity.NORMAL))
+ value = " ".join(dis)
+ if imm:
+ name = f"{imm_name}({name})"
+ value = f"{imm_value}({value})"
+ imm = False
+ if isinstance(operand, ImmediateOperand):
+ imm_name = name
+ imm_value = value
+ imm = True
+ if not imm:
+ yield (name, value)
+
+ def static_operands(self, db):
+ record = self.record(db=db)
+ for operand in record.operands.static:
+ yield (operand.name, operand.value)
+
+ def disassemble(self, db,
+ byteorder="little",
+ verbosity=Verbosity.NORMAL):
raise NotImplementedError
bits.append(bit)
return "".join(map(str, bits))
- 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):
+ def opcode(self, db):
+ record = self.record(db=db)
return f"0x{record.opcode.value:08x}"
- def mask(self, record):
+ def mask(self, db):
+ record = self.record(db=db)
return f"0x{record.opcode.mask:08x}"
- def disassemble(self, db, byteorder="little", verbose=False):
+ def disassemble(self, db,
+ byteorder="little",
+ verbosity=Verbosity.NORMAL):
integer = int(self)
- blob = integer.to_bytes(length=4, byteorder=byteorder)
- blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
+ if verbosity <= Verbosity.SHORT:
+ blob = ""
+ else:
+ blob = integer.to_bytes(length=4, byteorder=byteorder)
+ blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
+ blob += " "
- record = db[self]
+ record = self.record(db=db)
if record is None:
- yield f"{blob} .long 0x{integer:08x}"
+ 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)
+ operands = tuple(map(_operator.itemgetter(1),
+ self.dynamic_operands(db=db, verbosity=verbosity)))
if operands:
- operands = ",".join(operands)
- operands = f" {operands}"
+ yield f"{blob}{record.name} {','.join(operands)}"
else:
- operands = ""
-
- yield f"{blob} {record.name}{operands}"
+ yield f"{blob}{record.name}"
- if verbose:
- lindent = (" " * 4)
- rindent = (len(blob) - len(lindent))
+ if verbosity >= Verbosity.VERBOSE:
+ indent = (" " * 4)
binary = self.binary
- spec = self.spec(record=record)
- opcode = self.opcode(record=record)
- mask = self.mask(record=record)
- yield f"{lindent}{'spec':{rindent}}{spec}"
- yield f"{lindent}{'binary':{rindent}}{binary[0:8]} [0:8]"
- yield f"{lindent}{' ':{rindent}}{binary[8:16]} [8:16]"
- yield f"{lindent}{' ':{rindent}}{binary[16:24]} [16:24]"
- yield f"{lindent}{' ':{rindent}}{binary[24:32]} [24:32]"
- yield f"{lindent}{'opcode':{rindent}}{opcode}"
- yield f"{lindent}{'mask':{rindent}}{mask}"
+ spec = self.spec(db=db, prefix="")
+ opcode = self.opcode(db=db)
+ mask = self.mask(db=db)
+ yield f"{indent}spec"
+ yield f"{indent}{indent}{spec}"
+ yield f"{indent}binary"
+ yield f"{indent}{indent}[0:8] {binary[0:8]}"
+ yield f"{indent}{indent}[8:16] {binary[8:16]}"
+ yield f"{indent}{indent}[16:24] {binary[16:24]}"
+ yield f"{indent}{indent}[24:32] {binary[24:32]}"
+ yield f"{indent}opcode"
+ yield f"{indent}{indent}{opcode}"
+ yield f"{indent}mask"
+ yield f"{indent}{indent}{mask}"
for operand in record.operands:
- name = operand.name
- value = operand.disassemble(value=self,
- record=record, verbose=True)
- yield f"{lindent}{name:{rindent}}{value}"
+ yield from operand.disassemble(insn=self, record=record,
+ verbosity=verbosity, indent=indent)
+ yield ""
class PrefixedInstruction(Instruction):
prrc0: prrc0
+class ExtraSpec(_Mapping):
+ _: _Field = range(0, 9)
+
+
+class Extra2Spec(ExtraSpec):
+ idx0: _Field = range(0, 2)
+ idx1: _Field = range(2, 4)
+ idx2: _Field = range(4, 6)
+ idx3: _Field = range(6, 8)
+
+ def __getitem__(self, key):
+ return {
+ 0: self.idx0,
+ 1: self.idx1,
+ 2: self.idx2,
+ 3: self.idx3,
+ _SVExtra.Idx0: self.idx0,
+ _SVExtra.Idx1: self.idx1,
+ _SVExtra.Idx2: self.idx2,
+ _SVExtra.Idx3: self.idx3,
+ }[key]
+
+ def __setitem__(self, key, value):
+ self[key].assign(value)
+
+
+class Extra3Spec(ExtraSpec):
+ idx0: _Field = range(0, 3)
+ idx1: _Field = range(3, 6)
+ idx2: _Field = range(6, 9)
+
+ def __getitem__(self, key):
+ return {
+ 0: self.idx0,
+ 1: self.idx1,
+ 2: self.idx2,
+ _SVExtra.Idx0: self.idx0,
+ _SVExtra.Idx1: self.idx1,
+ _SVExtra.Idx2: self.idx2,
+ }[key]
+
+ def __setitem__(self, key, value):
+ self[key].assign(value)
+
+
class RM(_Mapping):
class Mode(Mode):
normal: NormalMode
elwidth: _Field = range(4, 6)
ewsrc: _Field = range(6, 8)
subvl: _Field = range(8, 10)
- extra: _Field = range(10, 19)
mode: Mode.remap(range(19, 24))
- extra2: _Array[4] = (
- range(10, 12),
- range(12, 14),
- range(14, 16),
- range(16, 18),
- )
smask: _Field = range(16, 19)
- extra3: _Array[3] = (
- range(10, 13),
- range(13, 16),
- range(16, 19),
- )
+
+ extra: ExtraSpec.remap(range(10, 19))
+ extra2: Extra2Spec.remap(range(10, 19))
+ extra3: Extra3Spec.remap(range(10, 19))
class SVP64Instruction(PrefixedInstruction):
prefix: Prefix
- 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))
+ @property
+ def binary(self):
+ bits = []
+ for idx in range(64):
+ bit = int(self[idx])
+ bits.append(bit)
+ return "".join(map(str, bits))
+
+ def opcode(self, db):
+ return self.suffix.opcode(db=db)
- integer_suffix = int(self.suffix)
- blob_suffix = integer_suffix.to_bytes(length=4, byteorder=byteorder)
- blob_suffix = " ".join(map(lambda byte: f"{byte:02x}", blob_suffix))
+ def mask(self, db):
+ return self.suffix.mask(db=db)
- record = db[self.suffix]
- 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}"
- return
+ def mode(self, db):
+ record = self.record(db=db)
Rc = False
if record.operands["Rc"] is not None:
Rc = bool(self[record.fields["Rc"]])
+ record = self.record(db=db)
subvl = self.prefix.rm.subvl
mode = self.prefix.rm.mode
sel = mode.sel
else:
mode = mode.prrc0
- if type(mode) is Mode:
- raise NotImplementedError
+ modes = {
+ NormalMode.simple: "normal: simple",
+ NormalMode.smr: "normal: smr",
+ NormalMode.pmr: "normal: pmr",
+ NormalMode.svmr: "normal: svmr",
+ NormalMode.pu: "normal: pu",
+ NormalMode.ffrc1: "normal: ffrc1",
+ NormalMode.ffrc0: "normal: ffrc0",
+ NormalMode.sat: "normal: sat",
+ NormalMode.satx: "normal: satx",
+ NormalMode.satpu: "normal: satpu",
+ NormalMode.prrc1: "normal: prrc1",
+ NormalMode.prrc0: "normal: prrc0",
+ LDSTImmMode.simple: "ld/st imm: simple",
+ LDSTImmMode.spu: "ld/st imm: spu",
+ LDSTImmMode.ffrc1: "ld/st imm: ffrc1",
+ LDSTImmMode.ffrc0: "ld/st imm: ffrc0",
+ LDSTImmMode.sat: "ld/st imm: sat",
+ LDSTImmMode.prrc1: "ld/st imm: prrc1",
+ LDSTImmMode.prrc0: "ld/st imm: prrc0",
+ LDSTIdxMode.simple: "ld/st idx simple",
+ LDSTIdxMode.stride: "ld/st idx stride",
+ LDSTIdxMode.sat: "ld/st idx sat",
+ LDSTIdxMode.prrc1: "ld/st idx prrc1",
+ LDSTIdxMode.prrc0: "ld/st idx prrc0",
+ }
+ for (cls, desc) in modes.items():
+ if isinstance(mode, cls):
+ return (mode, desc)
- yield f"{blob_prefix} sv.{record.name}"
+ if record.svp64.mode is _SVMode.BRANCH:
+ return (self.prefix.rm.mode, "branch")
+
+ raise ValueError(self)
+
+ def disassemble(self, db,
+ byteorder="little",
+ verbosity=Verbosity.NORMAL):
+ def blob(integer):
+ if verbosity <= Verbosity.SHORT:
+ return ""
+ else:
+ blob = integer.to_bytes(length=4, byteorder=byteorder)
+ blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
+ return f"{blob} "
+
+ blob_prefix = blob(int(self.prefix))
+ blob_suffix = blob(int(self.suffix))
+ record = self.record(db=db)
+ 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}"
+ return
+
+ operands = tuple(map(_operator.itemgetter(1),
+ self.dynamic_operands(db=db, verbosity=verbosity)))
+ if operands:
+ yield f"{blob_prefix}sv.{record.name} {','.join(operands)}"
+ else:
+ yield f"{blob_prefix}{record.name}"
yield f"{blob_suffix}"
+ (mode, mode_desc) = self.mode(db=db)
+
+ if verbosity >= Verbosity.VERBOSE:
+ indent = (" " * 4)
+ binary = self.binary
+ spec = self.spec(db=db, prefix="sv.")
+ opcode = self.opcode(db=db)
+ mask = self.mask(db=db)
+ yield f"{indent}spec"
+ yield f"{indent}{indent}{spec}"
+ yield f"{indent}binary"
+ yield f"{indent}{indent}[0:8] {binary[0:8]}"
+ yield f"{indent}{indent}[8:16] {binary[8:16]}"
+ yield f"{indent}{indent}[16:24] {binary[16:24]}"
+ yield f"{indent}{indent}[24:32] {binary[24:32]}"
+ yield f"{indent}{indent}[32:40] {binary[32:40]}"
+ yield f"{indent}{indent}[40:48] {binary[40:48]}"
+ yield f"{indent}{indent}[48:56] {binary[48:56]}"
+ yield f"{indent}{indent}[56:64] {binary[56:64]}"
+ yield f"{indent}opcode"
+ yield f"{indent}{indent}{opcode}"
+ yield f"{indent}mask"
+ yield f"{indent}{indent}{mask}"
+ for operand in record.operands:
+ yield from operand.disassemble(insn=self, record=record,
+ verbosity=verbosity, indent=indent)
+
+ yield f"{indent}mode"
+ yield f"{indent}{indent}{mode_desc}"
+ yield ""
+
def parse(stream, factory):
+ def match(entry):
+ return ("TODO" not in frozenset(entry.values()))
+
lines = filter(lambda line: not line.strip().startswith("#"), stream)
entries = _csv.DictReader(lines)
- entries = filter(lambda entry: "TODO" not in frozenset(entry.values()), entries)
+ entries = filter(match, entries)
return tuple(map(factory, entries))
class PPCDatabase:
- def __init__(self, root, mdwndb, fieldsdb):
+ def __init__(self, root, mdwndb):
# The code below groups the instructions by section:identifier.
# We use the comment as an identifier, there's nothing better.
# The point is to capture different opcodes for the same instruction.
section.Mode.INTEGER: IntegerOpcode,
section.Mode.PATTERN: PatternOpcode,
}[section.mode]
- factory = _functools.partial(PPCRecord.CSV, opcode_cls=opcode_cls)
+ factory = _functools.partial(
+ PPCRecord.CSV, opcode_cls=opcode_cls)
with open(path, "r", encoding="UTF-8") as stream:
for insn in parse(stream, factory):
records[section][insn.comment].add(insn)
self.__db = db
self.__mdwndb = mdwndb
- self.__fieldsdb = fieldsdb
return super().__init__()
for (section, records) in self.__db.items():
for record in records:
- if (exact_match(key, record) or
- Rc_match(key, record) or
+ if exact_match(key, record):
+ return (section, record)
+
+ for record in records:
+ if (Rc_match(key, record) or
LK_match(key, record) or
AA_match(key, record)):
return (section, record)
mdwndb = MarkdownDatabase()
fieldsdb = FieldsDatabase()
- ppcdb = PPCDatabase(root=root, mdwndb=mdwndb, fieldsdb=fieldsdb)
+ ppcdb = PPCDatabase(root=root, mdwndb=mdwndb)
svp64db = SVP64Database(root=root, ppcdb=ppcdb)
db = set()