import dataclasses as _dataclasses
import enum as _enum
import functools as _functools
-import itertools as _itertools
import os as _os
import operator as _operator
import pathlib as _pathlib
@_functools.total_ordering
-class Verbosity(_enum.Enum):
+class Style(_enum.Enum):
+ LEGACY = _enum.auto()
SHORT = _enum.auto()
NORMAL = _enum.auto()
VERBOSE = _enum.auto()
return ((self.value & self.mask) == (key & self.mask))
+@_functools.total_ordering
+@_dataclasses.dataclass(eq=True, frozen=True)
class IntegerOpcode(Opcode):
def __init__(self, value):
if value.startswith("0b"):
return super().__init__(value=value, mask=mask)
+@_functools.total_ordering
+@_dataclasses.dataclass(eq=True, frozen=True)
class PatternOpcode(Opcode):
def __init__(self, pattern):
if not isinstance(pattern, str):
"sgl pipe",
)
- class Flags(frozenset, metaclass=FlagsMeta):
+ class Flags(tuple, metaclass=FlagsMeta):
def __new__(cls, flags=frozenset()):
flags = frozenset(flags)
diff = (flags - frozenset(cls))
if diff:
raise ValueError(flags)
- return super().__new__(cls, flags)
+ return super().__new__(cls, sorted(flags))
opcode: Opcode
comment: str
class PPCMultiRecord(tuple):
def __getattr__(self, attr):
if attr == "opcode":
- raise AttributeError(attr)
+ if len(self) != 1:
+ raise AttributeError(attr)
return getattr(self[0], attr)
extra_reg_cr_in2 = property(_functools.partial(extra_reg, key="cr_in2"))
extra_reg_cr_out = property(_functools.partial(extra_reg, key="cr_out"))
- @property
- def cr_3bit(self):
- regtype = None
+ @cached_property
+ def extra_CR(self):
+ extra = None
for idx in range(0, 4):
- for entry in self.svp64.extra[idx]:
+ for entry in self.extra[idx]:
if entry.regtype is _SVExtraRegType.DST:
- if regtype is not None:
+ if extra is not None:
raise ValueError(self.svp64)
- regtype = _RegType(entry.reg)
- if regtype not in (_RegType.CR_5BIT, _RegType.CR_3BIT):
+ extra = entry
+ break
+
+ if _RegType(extra.reg) not in (_RegType.CR_3BIT, _RegType.CR_5BIT):
raise ValueError(self.svp64)
- return (regtype is _RegType.CR_3BIT)
+
+ return extra
+
+ @cached_property
+ def extra_CR_3bit(self):
+ return (_RegType(self.extra_CR.reg) is _RegType.CR_3BIT)
class BitSel:
class Operands:
+ __GPR_PAIRS = (
+ _SVExtraReg.RTp,
+ _SVExtraReg.RSp,
+ )
+ __FPR_PAIRS = (
+ _SVExtraReg.FRAp,
+ _SVExtraReg.FRBp,
+ _SVExtraReg.FRSp,
+ _SVExtraReg.FRTp,
+ )
+
def __init__(self, insn, iterable):
custom_insns = {
"b": {"target_addr": TargetAddrOperandLI},
"SIM": SignedOperand,
"SVD": SignedOperand,
"SVDS": SignedOperand,
+ "RSp": GPRPairOperand,
+ "RTp": GPRPairOperand,
+ "FRAp": FPRPairOperand,
+ "FRBp": FPRPairOperand,
+ "FRSp": FPRPairOperand,
+ "FRTp": FPRPairOperand,
}
custom_immediates = {
"DQ": EXTSOperandDQ,
name = operand
if name.endswith(")"):
name = name.replace("(", " ").replace(")", "")
- (immediate, _, name) = name.partition(" ")
+ (imm_name, _, name) = name.partition(" ")
else:
- immediate = None
+ imm_name = None
- if immediate is not None:
- cls = custom_immediates.get(immediate, ImmediateOperand)
+ if imm_name is not None:
+ imm_cls = custom_immediates.get(imm_name, ImmediateOperand)
if insn in custom_insns and name in custom_insns[insn]:
cls = custom_insns[insn][name]
elif name in custom_fields:
cls = custom_fields[name]
- if name in _RegType.__members__:
- regtype = _RegType[name]
- if regtype is _RegType.GPR:
- cls = GPROperand
- elif regtype is _RegType.FPR:
- cls = FPROperand
- if regtype is _RegType.CR_5BIT:
- cls = CR5Operand
- if regtype is _RegType.CR_3BIT:
- cls = CR3Operand
-
+ if name in _SVExtraReg.__members__:
+ reg = _SVExtraReg[name]
+ if reg in self.__class__.__GPR_PAIRS:
+ cls = GPRPairOperand
+ elif reg in self.__class__.__FPR_PAIRS:
+ cls = FPRPairOperand
+ else:
+ regtype = _RegType[name]
+ if regtype is _RegType.GPR:
+ cls = GPROperand
+ elif regtype is _RegType.FPR:
+ cls = FPROperand
+ elif regtype is _RegType.CR_3BIT:
+ cls = CR3Operand
+ elif regtype is _RegType.CR_5BIT:
+ cls = CR5Operand
+
+ if imm_name is not None:
+ mapping[imm_name] = (imm_cls, {"name": imm_name})
mapping[name] = (cls, {"name": name})
static = []
return self.__dynamic
+class Arguments(tuple):
+ def __new__(cls, arguments, operands):
+ arguments = iter(tuple(arguments))
+ operands = iter(tuple(operands))
+
+ items = []
+ while True:
+ try:
+ operand = next(operands)
+ except StopIteration:
+ break
+
+ try:
+ argument = next(arguments)
+ except StopIteration:
+ raise ValueError("operands count mismatch")
+
+ if isinstance(operand, ImmediateOperand):
+ argument = argument.replace("(", " ").replace(")", "")
+ (imm_argument, _, argument) = argument.partition(" ")
+ try:
+ (imm_operand, operand) = (operand, next(operands))
+ except StopIteration:
+ raise ValueError("operands count mismatch")
+ items.append((imm_argument, imm_operand))
+ items.append((argument, operand))
+
+ try:
+ next(arguments)
+ except StopIteration:
+ pass
+ else:
+ raise ValueError("operands count mismatch")
+
+ return super().__new__(cls, items)
+
+
class PCode:
def __init__(self, iterable):
self.__pcode = tuple(iterable)
return (lhs < rhs)
@cached_property
- def PO(self):
- PO = self.section.opcode
- if PO is None:
- assert len(self.ppc) == 1
- PO = self.ppc[0].opcode
-
- return POStaticOperand(record=self,
- name="PO", value=int(PO.value), mask=int(PO.mask))
-
- @cached_property
- def XO(self):
- def XO(ppc):
- XO = ppc.opcode
- PO = self.section.opcode
- if PO is None:
- PO = XO
- XO = None
-
- if XO is None:
- return XOStaticOperand(record=self,
- name="XO", value=0, mask=0)
- else:
- return XOStaticOperand(record=self,
- name="XO", value=int(XO.value), mask=int(XO.mask))
-
- return tuple(dict.fromkeys(map(XO, self.ppc)))
+ def operands(self):
+ return (self.static_operands + self.dynamic_operands)
@cached_property
def static_operands(self):
operands = []
-
- operands.append(self.PO)
- operands.extend(self.XO)
-
+ operands.append(POStaticOperand(record=self, value=self.PO))
+ for ppc in self.ppc:
+ operands.append(XOStaticOperand(
+ record=self,
+ value=ppc.opcode.value,
+ span=self.section.bitsel,
+ ))
for (cls, kwargs) in self.mdwn.operands.static:
operands.append(cls(record=self, **kwargs))
-
return tuple(operands)
@cached_property
def dynamic_operands(self):
operands = []
-
for (cls, kwargs) in self.mdwn.operands.dynamic:
operands.append(cls(record=self, **kwargs))
-
return tuple(operands)
- @property
+ @cached_property
def opcodes(self):
- bits = 32
- if self.svp64 is not None:
- bits = 64
- origin_value = ([0] * bits)
- origin_mask = ([0] * bits)
-
- for operand in ((self.PO,) + tuple(self.static_operands)):
- for (src, dst) in enumerate(reversed(operand.span)):
- origin_value[dst] = int((operand.value & (1 << src)) != 0)
- origin_mask[dst] = 1
-
- def opcode(XO):
- value = list(origin_value)
- mask = list(origin_mask)
- for (src, dst) in enumerate(reversed(XO.span)):
- value[dst] = int((XO.value & (1 << src)) != 0)
- mask[dst] = 1
+ def binary(mapping):
+ return int("".join(str(int(mapping[bit])) for bit in sorted(mapping)), 2)
+
+ def PO_XO(value, mask, opcode, bits):
+ value = dict(value)
+ mask = dict(mask)
+ for (src, dst) in enumerate(reversed(bits)):
+ value[dst] = ((opcode.value & (1 << src)) != 0)
+ mask[dst] = ((opcode.mask & (1 << src)) != 0)
+ return (value, mask)
+
+ def PO(value, mask, opcode, bits):
+ return PO_XO(value=value, mask=mask, opcode=opcode, bits=bits)
+
+ def XO(value, mask, opcode, bits):
+ (value, mask) = PO_XO(value=value, mask=mask, opcode=opcode, bits=bits)
+ for (op_cls, op_kwargs) in self.mdwn.operands.static:
+ operand = op_cls(record=self, **op_kwargs)
+ for (src, dst) in enumerate(reversed(operand.span)):
+ value[dst] = ((operand.value & (1 << src)) != 0)
+ mask[dst] = True
+ return (value, mask)
+
+ pairs = []
+ value = {bit:False for bit in range(32)}
+ mask = {bit:False for bit in range(32)}
+ if self.section.opcode is not None:
+ (value, mask) = PO(value=value, mask=mask,
+ opcode=self.section.opcode, bits=range(0, 6))
+ for ppc in self.ppc:
+ pairs.append(XO(value=value, mask=mask,
+ opcode=ppc.opcode, bits=self.section.bitsel))
+
+ result = []
+ for (value, mask) in pairs:
+ value = Opcode.Value(binary(value))
+ mask = Opcode.Mask(binary(mask))
+ result.append(Opcode(value=value, mask=mask))
+
+ return tuple(result)
- value = Opcode.Value(int(("".join(map(str, value))), 2))
- mask = Opcode.Mask(int(("".join(map(str, mask))), 2))
+ @cached_property
+ def PO(self):
+ opcode = self.section.opcode
+ if opcode is None:
+ opcode = self.ppc[0].opcode
+ if isinstance(opcode, PatternOpcode):
+ value = int(opcode.value)
+ bits = opcode.value.bit_length()
+ return int(_SelectableInt(value=value, bits=bits)[0:6])
- return Opcode(value=value, mask=mask)
+ return int(opcode.value)
- return tuple(dict.fromkeys(map(opcode, self.XO)))
+ @cached_property
+ def XO(self):
+ return tuple(ppc.opcode for ppc in self.ppc)
def match(self, key):
for opcode in self.opcodes:
return self["Rc"].value
-@_dataclasses.dataclass(eq=True, frozen=True)
class Operand:
- name: str
- record: Record = _dataclasses.field(repr=False)
+ def __init__(self, record, name):
+ self.__record = record
+ self.__name = name
- def __post_init__(self):
- pass
+ def __iter__(self):
+ yield ("record", self.record)
+ yield ("name", self.__name)
+
+ def __repr__(self):
+ return f"{self.__class__.__name__}({self.name})"
+
+ @property
+ def name(self):
+ return self.__name
+
+ @property
+ def record(self):
+ return self.__record
@cached_property
def span(self):
- span = self.record.fields[self.name]
- if self.record.svp64 is not None:
- span = tuple(map(lambda bit: (bit + 32), span))
- return span
+ return self.record.fields[self.name]
+
+ def assemble(self, insn):
+ raise NotImplementedError()
- def assemble(self, value, insn):
+ def disassemble(self, insn,
+ style=Style.NORMAL, indent=""):
+ raise NotImplementedError()
+
+
+class DynamicOperand(Operand):
+ def assemble(self, insn, value):
span = self.span
if isinstance(value, str):
value = int(value, 0)
insn[span] = value
def disassemble(self, insn,
- verbosity=Verbosity.NORMAL, indent=""):
- raise NotImplementedError
-
-
-@_dataclasses.dataclass(eq=True, frozen=True)
-class DynamicOperand(Operand):
- def disassemble(self, insn,
- verbosity=Verbosity.NORMAL, indent=""):
+ style=Style.NORMAL, indent=""):
span = self.span
value = insn[span]
- if verbosity >= Verbosity.VERBOSE:
+ if style >= Style.VERBOSE:
span = map(str, span)
yield f"{indent}{self.name}"
yield f"{indent}{indent}{int(value):0{value.bits}b}"
yield str(int(value))
-@_dataclasses.dataclass(eq=True, frozen=True)
class SignedOperand(DynamicOperand):
- def assemble(self, value, insn):
+ def assemble(self, insn, value):
if isinstance(value, str):
value = int(value, 0)
return super().assemble(value=value, insn=insn)
+ def assemble(self, insn, value):
+ span = self.span
+ if isinstance(value, str):
+ value = int(value, 0)
+ insn[span] = value
+
def disassemble(self, insn,
- verbosity=Verbosity.NORMAL, indent=""):
+ style=Style.NORMAL, indent=""):
span = self.span
- value = insn[span]
+ value = insn[span].to_signed_int()
+ sign = "-" if (value < 0) else ""
+ value = abs(value)
- if verbosity >= Verbosity.VERBOSE:
+ if style >= Style.VERBOSE:
span = map(str, span)
yield f"{indent}{self.name}"
- yield f"{indent}{indent}{int(value):0{value.bits}b}"
+ yield f"{indent}{indent}{sign}{value}"
yield f"{indent}{indent}{', '.join(span)}"
else:
- yield str(value.to_signed_int())
+ yield f"{sign}{value}"
-@_dataclasses.dataclass(eq=True, frozen=True)
class StaticOperand(Operand):
- value: int
+ def __init__(self, record, name, value):
+ self.__value = value
+ return super().__init__(record=record, name=name)
+
+ def __iter__(self):
+ yield ("value", self.__value)
+ yield from super().__iter__()
+
+ def __repr__(self):
+ return f"{self.__class__.__name__}({self.name}, value={self.value})"
+
+ @property
+ def value(self):
+ return self.__value
def assemble(self, insn):
- return super().assemble(value=self.value, insn=insn)
+ insn[self.span] = self.value
def disassemble(self, insn,
- verbosity=Verbosity.NORMAL, indent=""):
+ style=Style.NORMAL, indent=""):
span = self.span
value = insn[span]
- if verbosity >= Verbosity.VERBOSE:
+ if style >= Style.VERBOSE:
span = map(str, span)
yield f"{indent}{self.name}"
yield f"{indent}{indent}{int(value):0{value.bits}b}"
yield str(int(value))
-@_dataclasses.dataclass(eq=True, frozen=True)
-class POStaticOperand(StaticOperand):
- mask: int
+class SpanStaticOperand(StaticOperand):
+ def __init__(self, record, name, value, span):
+ self.__span = tuple(span)
+ return super().__init__(record=record, name=name, value=value)
- @cached_property
+ def __iter__(self):
+ yield ("span", self.__span)
+ yield from super().__iter__()
+
+ @property
def span(self):
- span = tuple(range(0, 6))
- if self.record.svp64 is not None:
- span = tuple(map(lambda bit: (bit + 32), span))
- return span
+ return self.__span
-@_dataclasses.dataclass(eq=True, frozen=True)
-class XOStaticOperand(StaticOperand):
- mask: int
-
- def __post_init__(self):
- if self.record.section.opcode is None:
- assert self.value == 0
- assert self.mask == 0
- object.__setattr__(self, "span", ())
- return
+class POStaticOperand(SpanStaticOperand):
+ def __init__(self, record, value):
+ return super().__init__(record=record, name="PO", value=value, span=range(0, 6))
+
+ def __iter__(self):
+ for (key, value) in super().__iter__():
+ if key not in {"name", "span"}:
+ yield (key, value)
+
- bits = self.record.section.bitsel
- value = _SelectableInt(value=self.value, bits=len(bits))
+class XOStaticOperand(SpanStaticOperand):
+ def __init__(self, record, value, span):
+ bits = record.section.bitsel
+ value = _SelectableInt(value=value, bits=len(bits))
span = dict(zip(bits, range(len(bits))))
span_rev = {value:key for (key, value) in span.items()}
- # This part is tricky: we could have used self.record.static_operands,
- # but this would cause an infinite recursion, since this code is called
- # from the self.record.static_operands method already.
- operands = []
- operands.extend(self.record.mdwn.operands.static)
- operands.extend(self.record.mdwn.operands.dynamic)
- for (cls, kwargs) in operands:
- operand = cls(record=self.record, **kwargs)
+ # This part is tricky: we cannot use record.operands,
+ # as this code is called by record.static_operands method.
+ for (cls, kwargs) in record.mdwn.operands:
+ operand = cls(record=record, **kwargs)
for idx in operand.span:
rev = span.pop(idx, None)
if rev is not None:
span_rev.pop(rev, None)
- # This part is simpler: we drop bits which are not in the mask.
- for bit in tuple(span.values()):
- rev = (len(bits) - bit - 1)
- if ((self.mask & (1 << bit)) == 0):
- idx = span_rev.pop(rev, None)
- if idx is not None:
- span.pop(idx, None)
-
value = int(_selectconcat(*(value[bit] for bit in span.values())))
span = tuple(span.keys())
- if self.record.svp64 is not None:
- span = tuple(map(lambda bit: (bit + 32), span))
- object.__setattr__(self, "value", value)
- object.__setattr__(self, "span", span)
+ return super().__init__(record=record, name="XO", value=value, span=span)
- return super().__post_init__()
+ def __iter__(self):
+ for (key, value) in super().__iter__():
+ if key not in {"name"}:
+ yield (key, value)
-@_dataclasses.dataclass(eq=True, frozen=True)
class ImmediateOperand(DynamicOperand):
pass
-@_dataclasses.dataclass(eq=True, frozen=True)
class SignedImmediateOperand(SignedOperand, ImmediateOperand):
pass
-@_dataclasses.dataclass(eq=True, frozen=True)
class NonZeroOperand(DynamicOperand):
- def assemble(self, value, insn):
+ def assemble(self, insn, value):
if isinstance(value, str):
value = int(value, 0)
if not isinstance(value, int):
return super().assemble(value=value, insn=insn)
def disassemble(self, insn,
- verbosity=Verbosity.NORMAL, indent=""):
+ style=Style.NORMAL, indent=""):
span = self.span
value = insn[span]
- if verbosity >= Verbosity.VERBOSE:
+ if style >= Style.VERBOSE:
span = map(str, span)
yield f"{indent}{self.name}"
yield f"{indent}{indent}{int(value):0{value.bits}b}"
yield str(int(value) + 1)
-@_dataclasses.dataclass(eq=True, frozen=True)
class ExtendableOperand(DynamicOperand):
def sv_spec_enter(self, value, span):
return (value, span)
@property
def extra_idx(self):
+ pairs = {
+ _SVExtraReg.RSp: _SVExtraReg.RS,
+ _SVExtraReg.RTp: _SVExtraReg.RT,
+ _SVExtraReg.FRAp: _SVExtraReg.FRA,
+ _SVExtraReg.FRBp: _SVExtraReg.FRB,
+ _SVExtraReg.FRSp: _SVExtraReg.FRS,
+ _SVExtraReg.FRTp: _SVExtraReg.FRT,
+ }
+
for key in frozenset({
"in1", "in2", "in3", "cr_in", "cr_in2",
"out", "out2", "cr_out",
}):
extra_reg = self.record.svp64.extra_reg(key=key)
- if extra_reg is self.extra_reg:
+ if pairs.get(extra_reg, extra_reg) is pairs.get(self.extra_reg, self.extra_reg):
return self.record.extra_idx(key=key)
return _SVExtra.NONE
def remap(self, value, vector):
- raise NotImplementedError
+ raise NotImplementedError()
def assemble(self, value, insn, prefix):
vector = False
else:
raise ValueError(self.record.etype)
- return super().assemble(value=value, insn=insn)
-
return super().assemble(value=value, insn=insn)
def disassemble(self, insn,
- verbosity=Verbosity.NORMAL, prefix="", indent=""):
+ style=Style.NORMAL, prefix="", indent=""):
(vector, value, span) = self.spec(insn=insn)
- if verbosity >= Verbosity.VERBOSE:
+ if style >= Style.VERBOSE:
mode = "vector" if vector else "scalar"
yield f"{indent}{self.name} ({mode})"
yield f"{indent}{indent}{int(value):0{value.bits}b}"
yield f"{vector}{prefix}{int(value)}"
-@_dataclasses.dataclass(eq=True, frozen=True)
class SimpleRegisterOperand(ExtendableOperand):
def remap(self, value, vector):
if vector:
return (value, extra)
-@_dataclasses.dataclass(eq=True, frozen=True)
class GPROperand(SimpleRegisterOperand):
- def assemble(self, value, insn):
+ def assemble(self, insn, value):
return super().assemble(value=value, insn=insn, prefix="r")
def disassemble(self, insn,
- verbosity=Verbosity.NORMAL, indent=""):
- prefix = "" if (verbosity <= Verbosity.SHORT) else "r"
+ style=Style.NORMAL, indent=""):
+ prefix = "" if (style <= Style.SHORT) else "r"
yield from super().disassemble(prefix=prefix, insn=insn,
- verbosity=verbosity, indent=indent)
+ style=style, indent=indent)
+
+
+class GPRPairOperand(GPROperand):
+ pass
-@_dataclasses.dataclass(eq=True, frozen=True)
class FPROperand(SimpleRegisterOperand):
- def assemble(self, value, insn):
+ def assemble(self, insn, value):
return super().assemble(value=value, insn=insn, prefix="f")
def disassemble(self, insn,
- verbosity=Verbosity.NORMAL, indent=""):
- prefix = "" if (verbosity <= Verbosity.SHORT) else "f"
+ style=Style.NORMAL, indent=""):
+ prefix = "" if (style <= Style.SHORT) else "f"
yield from super().disassemble(prefix=prefix, insn=insn,
- verbosity=verbosity, indent=indent)
+ style=style, indent=indent)
+
+
+class FPRPairOperand(FPROperand):
+ pass
-@_dataclasses.dataclass(eq=True, frozen=True)
class ConditionRegisterFieldOperand(ExtendableOperand):
def pattern(name_pattern):
(name, pattern) = name_pattern
def remap(self, value, vector, regtype):
if regtype is _RegType.CR_5BIT:
- subvalue = (value & 0x3)
+ subvalue = (value & 0b11)
value >>= 2
if vector:
- extra = (value & 0xf)
+ extra = (value & 0b1111)
value >>= 4
else:
extra = (value >> 3)
- value &= 0x7
+ value &= 0b111
if self.record.etype is _SVEType.EXTRA2:
if vector:
- assert (extra & 0x7) == 0, \
+ assert (extra & 0b111) == 0, \
"vector CR cannot fit into EXTRA2"
- extra = (0x2 | (extra >> 3))
+ extra = (0b10 | (extra >> 3))
else:
assert (extra >> 1) == 0, \
"scalar CR cannot fit into EXTRA2"
- extra &= 0x1
+ extra &= 0b01
elif self.record.etype is _SVEType.EXTRA3:
if vector:
- assert (extra & 0x3) == 0, \
+ assert (extra & 0b11) == 0, \
"vector CR cannot fit into EXTRA3"
- extra = (0x4 | (extra >> 2))
+ extra = (0b100 | (extra >> 2))
else:
assert (extra >> 2) == 0, \
"scalar CR cannot fit into EXTRA3"
- extra &= 0x3
+ extra &= 0b11
if regtype is _RegType.CR_5BIT:
value = ((value << 2) | subvalue)
return (value, extra)
- def assemble(self, value, insn):
+ def assemble(self, insn, value):
if isinstance(value, str):
vector = False
value = ((CR * N) + BIT)
break
+ value = str(value)
+ if vector:
+ value = f"*{value}"
+
return super().assemble(value=value, insn=insn, prefix="cr")
def disassemble(self, insn,
- verbosity=Verbosity.NORMAL, prefix="", indent=""):
+ style=Style.NORMAL, prefix="", indent=""):
(vector, value, span) = self.spec(insn=insn)
- if verbosity >= Verbosity.VERBOSE:
+ if style >= Style.VERBOSE:
mode = "vector" if vector else "scalar"
yield f"{indent}{self.name} ({mode})"
yield f"{indent}{indent}{int(value):0{value.bits}b}"
yield f"{indent}{indent}{etype}{extra_idx!r}"
else:
vector = "*" if vector else ""
- cr = int(value >> 2)
- cc = int(value & 3)
- cond = ("lt", "gt", "eq", "so")[cc]
- if verbosity >= Verbosity.NORMAL:
- if cr != 0:
+ CR = int(value >> 2)
+ CC = int(value & 3)
+ cond = ("lt", "gt", "eq", "so")[CC]
+ if style >= Style.NORMAL:
+ if CR != 0:
if isinstance(insn, SVP64Instruction):
- yield f"{vector}cr{cr}.{cond}"
+ yield f"{vector}cr{CR}.{cond}"
else:
- yield f"4*cr{cr}+{cond}"
+ yield f"4*cr{CR}+{cond}"
else:
yield cond
else:
yield f"{vector}{prefix}{int(value)}"
-@_dataclasses.dataclass(eq=True, frozen=True)
class CR3Operand(ConditionRegisterFieldOperand):
def remap(self, value, vector):
return super().remap(value=value, vector=vector,
regtype=_RegType.CR_3BIT)
-@_dataclasses.dataclass(eq=True, frozen=True)
class CR5Operand(ConditionRegisterFieldOperand):
def remap(self, value, vector):
return super().remap(value=value, vector=vector,
return (value, span)
-@_dataclasses.dataclass(eq=True, frozen=True)
-class EXTSOperand(DynamicOperand):
+class EXTSOperand(SignedOperand):
field: str # real name to report
nz: int = 0 # number of zeros
fmt: str = "d" # integer formatter
- def __post_init__(self):
- if not self.field:
- object.__setattr__(self, "field", self.name)
+ def __init__(self, record, name, field, nz=0, fmt="d"):
+ self.__field = field
+ self.__nz = nz
+ self.__fmt = fmt
+ return super().__init__(record=record, name=name)
+
+ @property
+ def field(self):
+ return self.__field
+
+ @property
+ def nz(self):
+ return self.__nz
+
+ @property
+ def fmt(self):
+ return self.__fmt
@cached_property
def span(self):
- span = self.record.fields[self.field]
- if self.record.svp64 is not None:
- span = tuple(map(lambda bit: (bit + 32), span))
- return span
+ return self.record.fields[self.field]
+
+ def assemble(self, insn, value):
+ span = self.span
+ if isinstance(value, str):
+ value = int(value, 0)
+ insn[span] = (value >> self.nz)
def disassemble(self, insn,
- verbosity=Verbosity.NORMAL, indent=""):
+ style=Style.NORMAL, indent=""):
span = self.span
- value = insn[span]
+ value = insn[span].to_signed_int()
+ sign = "-" if (value < 0) else ""
+ value = (abs(value) << self.nz)
- if verbosity >= Verbosity.VERBOSE:
+ if style >= Style.VERBOSE:
span = (tuple(map(str, span)) + (("{0}",) * self.nz))
zeros = ("0" * self.nz)
hint = f"{self.name} = EXTS({self.field} || {zeros})"
yield f"{indent * 1}{hint}"
yield f"{indent * 2}{self.field}"
- yield f"{indent * 3}{int(value):0{value.bits}b}{zeros}"
+ yield f"{indent * 3}{sign}{value:{self.fmt}}"
yield f"{indent * 3}{', '.join(span)}"
else:
- value = _selectconcat(value,
- _SelectableInt(value=0, bits=self.nz)).to_signed_int()
- yield f"{value:{self.fmt}}"
+ yield f"{sign}{value:{self.fmt}}"
-@_dataclasses.dataclass(eq=True, frozen=True)
class TargetAddrOperand(EXTSOperand):
- nz: int = 2
- fmt: str = "#x"
+ def __init__(self, record, name, field):
+ return super().__init__(record=record, name=name, field=field, nz=2, fmt="#x")
-@_dataclasses.dataclass(eq=True, frozen=True)
class TargetAddrOperandLI(TargetAddrOperand):
- field: str = "LI"
+ def __init__(self, record, name):
+ return super().__init__(record=record, name=name, field="LI")
-@_dataclasses.dataclass(eq=True, frozen=True)
class TargetAddrOperandBD(TargetAddrOperand):
- field: str = "BD"
+ def __init__(self, record, name):
+ return super().__init__(record=record, name=name, field="BD")
-@_dataclasses.dataclass(eq=True, frozen=True)
class EXTSOperandDS(EXTSOperand, ImmediateOperand):
- field: str = "DS"
- nz: int = 2
+ def __init__(self, record, name):
+ return super().__init__(record=record, name=name, field="DS", nz=2)
-@_dataclasses.dataclass(eq=True, frozen=True)
class EXTSOperandDQ(EXTSOperand, ImmediateOperand):
- field: str = "DQ"
- nz: int = 4
+ def __init__(self, record, name):
+ return super().__init__(record=record, name=name, field="DQ", nz=4)
-@_dataclasses.dataclass(eq=True, frozen=True)
class DOperandDX(SignedOperand):
@cached_property
def span(self):
cls = lambda name: DynamicOperand(record=self.record, name=name)
operands = map(cls, ("d0", "d1", "d2"))
spans = map(lambda operand: operand.span, operands)
- span = sum(spans, tuple())
- if self.record.svp64 is not None:
- span = tuple(map(lambda bit: (bit + 32), span))
- return span
+ return sum(spans, tuple())
def disassemble(self, insn,
- verbosity=Verbosity.NORMAL, indent=""):
+ style=Style.NORMAL, indent=""):
span = self.span
- value = insn[span]
+ value = insn[span].to_signed_int()
+ sign = "-" if (value < 0) else ""
+ value = abs(value)
- if verbosity >= Verbosity.VERBOSE:
+ if style >= Style.VERBOSE:
yield f"{indent}D"
mapping = {
"d0": "[0:9]",
for (subname, subspan) in mapping.items():
operand = DynamicOperand(name=subname)
span = operand.span
- value = insn[span]
span = map(str, span)
yield f"{indent}{indent}{operand.name} = D{subspan}"
- yield f"{indent}{indent}{indent}{int(value):0{value.bits}b}"
+ yield f"{indent}{indent}{indent}{sign}{value}"
yield f"{indent}{indent}{indent}{', '.join(span)}"
else:
- yield str(value.to_signed_int())
+ yield f"{sign}{value}"
class Instruction(_Mapping):
nr_bytes = (len(self.__class__) // 8)
return int(self).to_bytes(nr_bytes, byteorder=byteorder)
- def record(self, db):
- record = db[self]
+ @classmethod
+ def record(cls, db, entry):
+ record = db[entry]
if record is None:
- raise KeyError(self)
+ raise KeyError(entry)
return record
- def spec(self, db, prefix):
- record = self.record(db=db)
+ @classmethod
+ def operands(cls, record):
+ yield from record.operands
+
+ @classmethod
+ def static_operands(cls, record):
+ return filter(lambda operand: isinstance(operand, StaticOperand),
+ cls.operands(record=record))
+
+ @classmethod
+ def dynamic_operands(cls, record):
+ return filter(lambda operand: isinstance(operand, DynamicOperand),
+ cls.operands(record=record))
+ def spec(self, record, prefix):
dynamic_operands = tuple(map(_operator.itemgetter(0),
- self.dynamic_operands(db=db)))
+ self.spec_dynamic_operands(record=record)))
static_operands = []
- for (name, value) in self.static_operands(db=db):
+ for (name, value) in self.spec_static_operands(record=record):
static_operands.append(f"{name}={value}")
operands = ""
return f"{prefix}{record.name}{operands}"
- def dynamic_operands(self, db, verbosity=Verbosity.NORMAL):
- record = self.record(db=db)
+ def spec_static_operands(self, record):
+ for operand in self.static_operands(record=record):
+ if not isinstance(operand, (POStaticOperand, XOStaticOperand)):
+ yield (operand.name, operand.value)
+ def spec_dynamic_operands(self, record, style=Style.NORMAL):
imm = False
imm_name = ""
imm_value = ""
- for operand in record.dynamic_operands:
+ for operand in self.dynamic_operands(record=record):
name = operand.name
value = " ".join(operand.disassemble(insn=self,
- verbosity=min(verbosity, Verbosity.NORMAL)))
+ style=min(style, Style.NORMAL)))
if imm:
name = f"{imm_name}({name})"
value = f"{imm_value}({value})"
if not imm:
yield (name, value)
- def static_operands(self, db):
- record = self.record(db=db)
- for operand in record.static_operands:
- yield (operand.name, operand.value)
-
@classmethod
- def assemble(cls, db, opcode, arguments=None):
- raise NotImplementedError(f"{cls.__name__}.assemble")
+ def assemble(cls, record, arguments=None):
+ if arguments is None:
+ arguments = ()
+
+ insn = cls.integer(value=0)
+
+ for operand in cls.static_operands(record=record):
+ operand.assemble(insn=insn)
- def disassemble(self, db,
+ dynamic_operands = tuple(cls.dynamic_operands(record=record))
+ for (value, operand) in Arguments(arguments, dynamic_operands):
+ operand.assemble(insn=insn, value=value)
+
+ return insn
+
+ def disassemble(self, record,
byteorder="little",
- verbosity=Verbosity.NORMAL):
- raise NotImplementedError
+ style=Style.NORMAL):
+ raise NotImplementedError()
class WordInstruction(Instruction):
bits.append(bit)
return "".join(map(str, bits))
- @classmethod
- def assemble(cls, db, opcode, arguments=None):
- if arguments is None:
- arguments = ()
-
- record = db[opcode]
- insn = cls.integer(value=0)
- for operand in record.static_operands:
- operand.assemble(insn=insn)
-
- dynamic_operands = tuple(record.dynamic_operands)
- if len(dynamic_operands) != len(arguments):
- raise ValueError("operands count mismatch")
- for (value, operand) in zip(arguments, dynamic_operands):
- operand.assemble(value=value, insn=insn)
-
- return insn
-
- def disassemble(self, db,
+ def disassemble(self, record,
byteorder="little",
- verbosity=Verbosity.NORMAL):
- if verbosity <= Verbosity.SHORT:
+ style=Style.NORMAL):
+ if style <= Style.SHORT:
blob = ""
else:
blob = self.bytes(byteorder=byteorder)
blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
blob += " "
- record = db[self]
if record is None:
yield f"{blob}.long 0x{int(self):08x}"
return
- operands = tuple(map(_operator.itemgetter(1),
- self.dynamic_operands(db=db, verbosity=verbosity)))
- if operands:
- operands = ",".join(operands)
- yield f"{blob}{record.name} {operands}"
+ paired = False
+ if style is Style.LEGACY:
+ paired = False
+ for operand in self.dynamic_operands(record=record):
+ if isinstance(operand, (GPRPairOperand, FPRPairOperand)):
+ paired = True
+
+ if style is Style.LEGACY and (paired or record.ppc.unofficial):
+ yield f"{blob}.long 0x{int(self):08x}"
else:
- yield f"{blob}{record.name}"
+ operands = tuple(map(_operator.itemgetter(1),
+ self.spec_dynamic_operands(record=record, style=style)))
+ if operands:
+ operands = ",".join(operands)
+ yield f"{blob}{record.name} {operands}"
+ else:
+ yield f"{blob}{record.name}"
- if verbosity >= Verbosity.VERBOSE:
+ if style >= Style.VERBOSE:
indent = (" " * 4)
binary = self.binary
- spec = self.spec(db=db, prefix="")
+ spec = self.spec(record=record, prefix="")
yield f"{indent}spec"
yield f"{indent}{indent}{spec}"
yield f"{indent}pcode"
yield f"{indent}opcodes"
for opcode in record.opcodes:
yield f"{indent}{indent}{opcode!r}"
- for (cls, kwargs) in record.mdwn.operands:
- operand = cls(record=record, **kwargs)
+ for operand in self.operands(record=record):
yield from operand.disassemble(insn=self,
- verbosity=verbosity, indent=indent)
+ style=style, indent=indent)
yield ""
3: "vec4",
}[subvl]
- def disassemble(self, verbosity=Verbosity.NORMAL):
- if verbosity >= Verbosity.VERBOSE:
+ def disassemble(self, style=Style.NORMAL):
+ if style >= Style.VERBOSE:
indent = (" " * 4)
for (name, span) in self.traverse(path="RM"):
value = self.storage[span]
class CROpSimpleRM(PredicateBaseRM, ZZCombinedBaseRM, CROpBaseRM):
- """cr_op: simple mode"""
+ """crop: simple mode"""
RG: BaseRM[20]
dz: BaseRM[22]
sz: BaseRM[23]
yield from super().specifiers(record=record)
+
class CROpMRRM(MRBaseRM, ZZCombinedBaseRM, CROpBaseRM):
- """cr_op: scalar reduce mode (mapreduce), SUBVL=1"""
+ """crop: scalar reduce mode (mapreduce), SUBVL=1"""
RG: BaseRM[20]
dz: BaseRM[22]
sz: BaseRM[23]
-class CROpFF3RM(FFPRRc1BaseRM, VLiBaseRM, ZZBaseRM, PredicateBaseRM, CROpBaseRM):
- """cr_op: ffirst 3-bit mode"""
+class CROpFF3RM(FFPRRc0BaseRM, PredicateBaseRM, VLiBaseRM, DZBaseRM, SZBaseRM, CROpBaseRM):
+ """crop: ffirst 3-bit mode"""
+ RC1: BaseRM[19]
VLi: BaseRM[20]
inv: BaseRM[21]
- CR: BaseRM[22, 23]
- zz: BaseRM[6]
- sz: BaseRM[6]
- dz: BaseRM[6]
+ dz: BaseRM[22]
+ sz: BaseRM[23]
def specifiers(self, record):
yield from super().specifiers(record=record, mode="ff")
-class CROpFF5RM(FFPRRc0BaseRM, PredicateBaseRM,
- VLiBaseRM, ZZCombinedBaseRM, CROpBaseRM):
+# FIXME: almost everything in this class contradicts the specs.
+# However, this is the direct translation of the pysvp64asm code.
+# Please revisit this code; there is an inactive sketch below.
+class CROpFF5RM(FFPRRc1BaseRM, PredicateBaseRM, VLiBaseRM, CROpBaseRM):
"""cr_op: ffirst 5-bit mode"""
VLi: BaseRM[20]
inv: BaseRM[21]
- RC1: BaseRM[19] # cheat: set RC=1 based on ffirst mode being set
+ CR: BaseRM[22, 23]
dz: BaseRM[22]
sz: BaseRM[23]
normal: NormalRM
ldst_imm: LDSTImmRM
ldst_idx: LDSTIdxRM
- cr_op: CROpRM
+ crop: CROpRM
branch: BranchRM
- def select(self, record):
- rm = self
- Rc = record.Rc
-
- # the idea behind these tables is that they are now literally
- # in identical format to insndb.csv and minor_xx.csv and can
- # be done precisely as that. the only thing to watch out for
- # is the insertion of Rc=1 as a "mask/value" bit and likewise
- # regtype detection (3-bit BF/BFA, 5-bit BA/BB/BT) also inserted
- # as the LSB.
- table = None
- if record.svp64.mode is _SVMode.NORMAL:
- # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
- # mode Rc mask Rc member
- table = (
- (0b000000, 0b111000, "simple"), # simple (no Rc)
- (0b001000, 0b111000, "mr"), # mapreduce (no Rc)
- (0b010001, 0b110001, "ffrc1"), # ffirst, Rc=1
- (0b010000, 0b110001, "ffrc0"), # ffirst, Rc=0
- (0b100000, 0b110000, "sat"), # saturation (no Rc)
- (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
- (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
- )
- rm = rm.normal
- search = ((int(rm.mode) << 1) | Rc)
-
- elif record.svp64.mode is _SVMode.LDST_IMM:
- # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
- # mode Rc mask Rc member
- # ironically/coincidentally this table is identical to NORMAL
- # mode except reserved in place of mr
- table = (
- (0b000000, 0b111000, "simple"), # simple (no Rc)
- (0b001000, 0b111000, "post"), # post (no Rc)
- (0b010001, 0b110001, "ffrc1"), # ffirst, Rc=1
- (0b010000, 0b110001, "ffrc0"), # ffirst, Rc=0
- (0b100000, 0b110000, "sat"), # saturation (no Rc)
- (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
- (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
- )
- rm = rm.ldst_imm
- search = ((int(rm.mode) << 1) | Rc)
-
- elif record.svp64.mode is _SVMode.LDST_IDX:
- # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
- # mode Rc mask Rc member
- table = (
- (0b000000, 0b110000, "simple"), # simple (no Rc)
- (0b010000, 0b110000, "stride"), # strided, (no Rc)
- (0b100000, 0b110000, "sat"), # saturation (no Rc)
- (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
- (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
- )
- rm = rm.ldst_idx
- search = ((int(rm.mode) << 1) | Rc)
-
- elif record.svp64.mode is _SVMode.CROP:
- # concatenate mode 5-bit with regtype (LSB) then do mask/map search
- # mode 3b mask 3b member
- table = (
- (0b000000, 0b111000, "simple"), # simple
- (0b001000, 0b111000, "mr"), # mapreduce
- (0b100001, 0b100001, "ff3"), # ffirst, 3-bit CR
- (0b100000, 0b100000, "ff5"), # ffirst, 5-bit CR
- )
- rm = rm.cr_op
- search = ((int(rm.mode) << 1) | int(record.svp64.cr_3bit))
-
- elif record.svp64.mode is _SVMode.BRANCH:
- # just mode 2-bit
- # mode mask member
- table = (
- (0b00, 0b11, "simple"), # simple
- (0b01, 0b11, "vls"), # VLset
- (0b10, 0b11, "ctr"), # CTR mode
- (0b11, 0b11, "ctrvls"), # CTR+VLset mode
- )
- # slightly weird: doesn't have a 5-bit "mode" field like others
- rm = rm.branch
- search = int(rm.mode.sel)
-
- # look up in table
- if table is not None:
- for (value, mask, member) in table:
- if ((value & mask) == (search & mask)):
- rm = getattr(rm, member)
- break
-
- if rm.__class__ is self.__class__:
- raise ValueError(self)
-
- return rm
-
@_dataclasses.dataclass(eq=True, frozen=True)
class Specifier:
@classmethod
def match(cls, desc, record):
- raise NotImplementedError
+ raise NotImplementedError()
def validate(self, others):
pass
def assemble(self, insn):
- raise NotImplementedError
+ raise NotImplementedError()
@_dataclasses.dataclass(eq=True, frozen=True)
class SpecifierWidth(Specifier):
- value: _SVP64Width
+ width: _SVP64Width
@classmethod
def match(cls, desc, record, etalon):
value = value.strip()
if mode != etalon:
return None
- value = _SVP64Width(value)
+ width = _SVP64Width(value)
- return cls(record=record, mode=mode, value=value)
+ return cls(record=record, width=width)
@_dataclasses.dataclass(eq=True, frozen=True)
return super().match(desc=desc, record=record, etalon="w")
def assemble(self, insn):
- insn.prefix.rm.ewsrc = int(self.value)
- insn.prefix.rm.elwidth = int(self.value)
+ selector = insn.select(record=self.record)
+ selector.ewsrc = self.width.value
+ selector.elwidth = self.width.value
@_dataclasses.dataclass(eq=True, frozen=True)
return super().match(desc=desc, record=record, etalon="sw")
def assemble(self, insn):
- insn.prefix.rm.ewsrc = int(self.value)
+ selector = insn.select(record=self.record)
+ selector.ewsrc = self.width.value
@_dataclasses.dataclass(eq=True, frozen=True)
return super().match(desc=desc, record=record, etalon="dw")
def assemble(self, insn):
- insn.prefix.rm.elwidth = int(self.value)
+ selector = insn.select(record=self.record)
+ selector.elwidth = self.width.value
@_dataclasses.dataclass(eq=True, frozen=True)
return cls(record=record, value=value)
def assemble(self, insn):
- insn.prefix.rm.subvl = int(self.value.value)
+ selector = insn.select(record=self.record)
+ selector.subvl = int(self.value.value)
@_dataclasses.dataclass(eq=True, frozen=True)
_SVP64PredMode.RC1,
))
- def assemble(self, insn):
- rm = insn.prefix.rm
- if rm.mode.sel != 0:
- raise ValueError("cannot override mode")
-
+ def validate(self, others):
if self.record.svp64.mode is _SVMode.CROP:
if self.mode == "pr":
raise ValueError("crop: 'pr' mode not supported")
- rm.mode.sel = 0b10
- if self.record.svp64.cr_3bit:
- rm = rm.cr_op.ff3
- else:
- rm = rm.cr_op.ff5
+ if (self.record.svp64.extra_CR_3bit and
+ (self.pred.mode is not _SVP64PredMode.RC1)):
+ raise ValueError("3-bit CRs only support RC1/~RC1 BO")
+
+ def assemble(self, insn):
+ selector = insn.select(record=self.record)
+ if selector.mode.sel != 0:
+ raise ValueError("cannot override mode")
+ if self.record.svp64.mode is _SVMode.CROP:
+ selector.mode.sel = 0b10
+ selector.inv = self.pred.inv
+ if not self.record.svp64.extra_CR_3bit:
+ selector.CR = self.pred.state
else:
- if self.record.svp64.mode is _SVMode.NORMAL:
- rm = rm.normal
- elif self.record.svp64.mode is _SVMode.LDST_IMM:
- rm = rm.ldst_imm
- elif self.record.svp64.mode is _SVMode.LDST_IDX:
- rm = rm.ldst_idx
- if self.mode == "ff":
- raise ValueError("ld/st idx: 'ff' mode not supported")
+ selector.mode.sel = 0b01 if self.mode == "ff" else 0b11
+ selector.inv = self.pred.inv
+ if self.record.Rc:
+ selector.CR = self.pred.state
else:
- raise ValueError(f"{self.mode!r} not supported")
-
- # These 2-bit values should have bits swapped
- def bitswap(value):
- return (((value & 0b10) >> 1) | ((value & 0b01) << 1))
-
- rm.mode.sel = {
- "ff": bitswap(_SVP64RMMode.FFIRST.value),
- "pr": bitswap(_SVP64RMMode.PREDRES.value),
- }[self.mode]
-
- Rc = int(self.record.Rc)
- rm = getattr(rm, f"{self.mode}rc{Rc}")
- rm.inv = self.pred.inv
- if Rc:
- rm.CR = self.pred.state
- else:
- rm.RC1 = self.pred.state
+ selector.RC1 = self.pred.state
@_dataclasses.dataclass(eq=True, frozen=True)
))
def assemble(self, insn):
- raise NotImplementedError
+ raise NotImplementedError()
@_dataclasses.dataclass(eq=True, frozen=True)
return super().match(desc=desc, record=record, mode="m")
def validate(self, others):
- items = list(others)
- while items:
- spec = items.pop()
+ for spec in others:
if isinstance(spec, SpecifierSM):
raise ValueError("source-mask and predicate mask conflict")
elif isinstance(spec, SpecifierDM):
raise ValueError("dest-mask and predicate mask conflict")
- spec.validate(others=items)
def assemble(self, insn):
- insn.prefix.rm.mask = int(self.pred)
+ selector = insn.select(record=self.record)
+ selector.mask = int(self.pred)
+ if ((self.record.ptype is _SVPType.P2) and
+ (self.record.svp64.mode is not _SVMode.BRANCH)):
+ selector.smask = int(self.pred)
+ selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
@_dataclasses.dataclass(eq=True, frozen=True)
if self.pred.mode is _SVP64PredMode.CR:
twin = None
- items = list(others)
- while items:
- spec = items.pop()
+ for spec in others:
if isinstance(spec, SpecifierDM):
twin = spec
- spec.validate(others=items)
if twin is None:
raise ValueError("missing dest-mask in CR twin predication")
- if self.pred != twin.pred:
- raise ValueError(f"predicate masks mismatch: {self!r} vs {twin!r}")
+ if self.pred.mode != twin.pred.mode:
+ raise ValueError(f"predicate masks mismatch: {self.pred!r} vs {twin.pred!r}")
def assemble(self, insn):
- insn.prefix.rm.smask = int(self.pred)
+ selector = insn.select(record=self.record)
+ selector.smask = int(self.pred)
+ selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
@_dataclasses.dataclass(eq=True, frozen=True)
if self.pred.mode is _SVP64PredMode.CR:
twin = None
- items = list(others)
- while items:
- spec = items.pop()
+ for spec in others:
if isinstance(spec, SpecifierSM):
twin = spec
- spec.validate(others=items)
if twin is None:
raise ValueError("missing source-mask in CR twin predication")
- if self.pred != twin.pred:
- raise ValueError(f"predicate masks mismatch: {self!r} vs {twin!r}")
+ if self.pred.mode != twin.pred.mode:
+ raise ValueError(f"predicate masks mismatch: {self.pred!r} vs {twin.pred!r}")
def assemble(self, insn):
- insn.prefix.rm.mask = int(self.pred)
-
+ selector = insn.select(record=self.record)
+ selector.mask = int(self.pred)
+ selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
@_dataclasses.dataclass(eq=True, frozen=True)
return cls(record=record)
def validate(self, others):
- items = list(others)
- while items:
- spec = items.pop()
-
- # Since m=xx takes precedence (overrides) sm=xx and dm=xx,
+ for spec in others:
+ # Since zz takes precedence (overrides) sz and dz,
# treat them as mutually exclusive.
if isinstance(spec, (SpecifierSZ, SpecifierDZ)):
raise ValueError("mutually exclusive predicate masks")
- spec.validate(others=items)
-
def assemble(self, insn):
- rm = insn.prefix.rm.select(record=self.record)
- if hasattr(rm, "zz"):
- rm.zz = 1
+ selector = insn.select(record=self.record)
+ if hasattr(selector, "zz"): # this should be done in a different way
+ selector.zz = 1
else:
- rm.sz = 1
- rm.dz = 1
+ selector.sz = 1
+ selector.dz = 1
@_dataclasses.dataclass(eq=True, frozen=True)
@classmethod
def match(cls, desc, record, etalon, hint):
- if not desc != etalon:
+ if desc != etalon:
return None
return cls(desc=desc, record=record, hint=hint)
if self.pred.mode is _SVP64PredMode.CR:
twin = None
- items = list(others)
- while items:
- spec = items.pop()
- if isinstance(spec, SpecifierSM):
+ for spec in others:
+ if isinstance(spec, SpecifierXZ):
twin = spec
- spec.validate(others=items)
if twin is None:
raise ValueError(f"missing {self.hint} in CR twin predication")
if self.pred != twin.pred:
- raise ValueError(f"predicate masks mismatch: {self!r} vs {twin!r}")
+ raise ValueError(f"predicate masks mismatch: {self.pred!r} vs {twin.pred!r}")
def assemble(self, insn):
- rm = insn.prefix.rm.select(record=self.record)
- setattr(rm, self.desc, 1)
+ selector = insn.select(record=self.record)
+ setattr(selector, self.desc, 1)
@_dataclasses.dataclass(eq=True, frozen=True)
etalon="sz", hint="source-mask")
def validate(self, others):
- items = list(others)
- while items:
- spec = items.pop()
- if isinstance(spec, SpecifierFF):
- raise ValueError("source-zero not allowed in ff mode")
- elif isinstance(spec, SpecifierPR):
- raise ValueError("source-zero not allowed in pr mode")
- spec.validate(others=items)
+ for spec in others:
+ if self.record.svp64.mode is not _SVMode.CROP:
+ if isinstance(spec, SpecifierFF):
+ raise ValueError("source-zero not allowed in ff mode")
+ elif isinstance(spec, SpecifierPR):
+ raise ValueError("source-zero not allowed in pr mode")
@_dataclasses.dataclass(eq=True, frozen=True)
etalon="dz", hint="dest-mask")
def validate(self, others):
- items = list(others)
- while items:
- spec = items.pop()
- if (isinstance(spec, (SpecifierFF, SpecifierPR)) and
+ for spec in others:
+ if ((self.record.svp64.mode is not _SVMode.CROP) and
+ isinstance(spec, (SpecifierFF, SpecifierPR)) and
(spec.pred.mode is _SVP64PredMode.RC1)):
mode = "ff" if isinstance(spec, SpecifierFF) else "pr"
raise ValueError(f"dest-zero not allowed in {mode} mode BO")
- spec.validate(others=items)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierEls(Specifier):
+ @classmethod
+ def match(cls, desc, record):
+ if desc != "els":
+ return None
+
+ if record.svp64.mode not in (_SVMode.LDST_IMM, _SVMode.LDST_IDX):
+ raise ValueError("els is only valid in ld/st modes")
+
+ return cls(record=record)
+
+ def assemble(self, insn):
+ if self.record.svp64.mode is _SVMode.LDST_IDX: # stride mode
+ insn.prefix.rm.mode[0] = 0
+ insn.prefix.rm.mode[1] = 1
+
+ selector = insn.select(record=self.record)
+ if self.record.svp64.mode is not _SVMode.LDST_IDX: # stride mode
+ selector.els = 1
+
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierSEA(Specifier):
+ @classmethod
+ def match(cls, desc, record):
+ if desc != "sea":
+ return None
+
+ return cls(record=record)
+
+ def validate(self, others):
+ if self.record.svp64.mode is not _SVMode.LDST_IDX:
+ raise ValueError("sea is only valid in ld/st modes")
+
+ for spec in others:
+ if isinstance(spec, SpecifierFF):
+ raise ValueError(f"sea cannot be used in ff mode")
+
+ def assemble(self, insn):
+ selector = insn.select(record=self.record)
+ if selector.mode.sel not in (0b00, 0b01):
+ raise ValueError("sea is only valid for normal and els modes")
+ selector.SEA = 1
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierSat(Specifier):
+ desc: str
+ sign: bool
+
+ @classmethod
+ def match(cls, desc, record, etalon, sign):
+ if desc != etalon:
+ return None
+
+ if record.svp64.mode not in (_SVMode.NORMAL, _SVMode.LDST_IMM, _SVMode.LDST_IDX):
+ raise ValueError("only normal, ld/st imm and ld/st idx modes supported")
+
+ return cls(record=record, desc=desc, sign=sign)
+
+ def assemble(self, insn):
+ selector = insn.select(record=self.record)
+ selector.mode[0] = 0b1
+ selector.mode[1] = 0b0
+ selector.N = int(self.sign)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierSatS(SpecifierSat):
+ @classmethod
+ def match(cls, desc, record):
+ return super().match(desc=desc, record=record,
+ etalon="sats", sign=True)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierSatU(SpecifierSat):
+ @classmethod
+ def match(cls, desc, record):
+ return super().match(desc=desc, record=record,
+ etalon="satu", sign=False)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierMapReduce(Specifier):
+ RG: bool
+
+ @classmethod
+ def match(cls, record, RG):
+ if record.svp64.mode not in (_SVMode.NORMAL, _SVMode.CROP):
+ raise ValueError("only normal and crop modes supported")
+
+ return cls(record=record, RG=RG)
+
+ def assemble(self, insn):
+ selector = insn.select(record=self.record)
+ if self.record.svp64.mode not in (_SVMode.NORMAL, _SVMode.CROP):
+ raise ValueError("only normal and crop modes supported")
+ selector.mode[0] = 0
+ selector.mode[1] = 0
+ selector.mode[2] = 1
+ selector.RG = self.RG
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierMR(SpecifierMapReduce):
+ @classmethod
+ def match(cls, desc, record):
+ if desc != "mr":
+ return None
+
+ return super().match(record=record, RG=False)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierMRR(SpecifierMapReduce):
+ @classmethod
+ def match(cls, desc, record):
+ if desc != "mrr":
+ return None
+
+ return super().match(record=record, RG=True)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierBranch(Specifier):
+ @classmethod
+ def match(cls, desc, record, etalon):
+ if desc != etalon:
+ return None
+
+ if record.svp64.mode is not _SVMode.BRANCH:
+ raise ValueError("only branch modes supported")
+
+ return cls(record=record)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierAll(SpecifierBranch):
+ @classmethod
+ def match(cls, desc, record):
+ return super().match(desc=desc, record=record, etalon="all")
+
+ def assemble(self, insn):
+ selector = insn.select(record=self.record)
+ selector.ALL = 1
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierSNZ(Specifier):
+ @classmethod
+ def match(cls, desc, record):
+ if desc != "snz":
+ return None
+
+ if record.svp64.mode not in (_SVMode.BRANCH, _SVMode.CROP):
+ raise ValueError("only branch and crop modes supported")
+
+ return cls(record=record)
+
+ def assemble(self, insn):
+ selector = insn.select(record=self.record)
+ if self.record.svp64.mode in (_SVMode.CROP, _SVMode.BRANCH):
+ selector.SNZ = 1
+ if self.record.svp64.mode is _SVMode.BRANCH:
+ selector.sz = 1
+ else:
+ raise ValueError("only branch and crop modes supported")
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierSL(SpecifierBranch):
+ @classmethod
+ def match(cls, desc, record):
+ return super().match(desc=desc, record=record, etalon="sl")
+
+ def assemble(self, insn):
+ selector = insn.select(record=self.record)
+ selector.SL = 1
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierSLu(SpecifierBranch):
+ @classmethod
+ def match(cls, desc, record):
+ return super().match(desc=desc, record=record, etalon="slu")
+
+ def assemble(self, insn):
+ selector = insn.select(record=self.record)
+ selector.SLu = 1
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierLRu(SpecifierBranch):
+ @classmethod
+ def match(cls, desc, record):
+ return super().match(desc=desc, record=record, etalon="lru")
+
+ def assemble(self, insn):
+ selector = insn.select(record=self.record)
+ selector.LRu = 1
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierVSXX(SpecifierBranch):
+ VSb: bool
+ VLi: bool
+
+ @classmethod
+ def match(cls, desc, record, etalon, VSb, VLi):
+ if desc != etalon:
+ return None
+
+ if record.svp64.mode is not _SVMode.BRANCH:
+ raise ValueError("only branch modes supported")
+
+ return cls(record=record, VSb=VSb, VLi=VLi)
+
+ def assemble(self, insn):
+ selector = insn.select(record=self.record)
+ selector.VLS = 1
+ selector.VSb = int(self.VSb)
+ selector.VLi = int(self.VLi)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierVS(SpecifierVSXX):
+ @classmethod
+ def match(cls, desc, record):
+ return super().match(desc=desc, record=record,
+ etalon="vs", VSb=False, VLi=False)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierVSi(SpecifierVSXX):
+ @classmethod
+ def match(cls, desc, record):
+ return super().match(desc=desc, record=record,
+ etalon="vsi", VSb=False, VLi=True)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierVSb(SpecifierVSXX):
+ @classmethod
+ def match(cls, desc, record):
+ return super().match(desc=desc, record=record,
+ etalon="vsb", VSb=True, VLi=False)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierVSbi(SpecifierVSXX):
+ @classmethod
+ def match(cls, desc, record):
+ return super().match(desc=desc, record=record,
+ etalon="vsbi", VSb=True, VLi=True)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierCTX(Specifier):
+ CTi: bool
+
+ @classmethod
+ def match(cls, desc, record, etalon, CTi):
+ if desc != etalon:
+ return None
+
+ if record.svp64.mode is not _SVMode.BRANCH:
+ raise ValueError("only branch modes supported")
+
+ return cls(record=record, CTi=CTi)
+
+ def assemble(self, insn):
+ selector = insn.select(record=self.record)
+ selector.CTR = 1
+ selector.CTi = int(self.CTi)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierCTR(SpecifierCTX):
+ @classmethod
+ def match(cls, desc, record):
+ return super().match(desc=desc, record=record,
+ etalon="ctr", CTi=False)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierCTi(SpecifierCTX):
+ @classmethod
+ def match(cls, desc, record):
+ return super().match(desc=desc, record=record,
+ etalon="cti", CTi=True)
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierPI(Specifier):
+ @classmethod
+ def match(cls, desc, record):
+ if desc != "pi":
+ return None
+
+ if record.svp64.mode is not _SVMode.LDST_IMM:
+ raise ValueError("only ld/st imm mode supported")
+
+ return cls(record=record)
+
+ def assemble(self, insn):
+ selector = insn.select(record=self.record)
+ selector.mode[0] = 0b0
+ selector.mode[1] = 0b0
+ selector.mode[2] = 0b1
+ selector.pi = 0b1
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierLF(Specifier):
+ @classmethod
+ def match(cls, desc, record):
+ if desc != "lf":
+ return None
+
+ if record.svp64.mode is not _SVMode.LDST_IMM:
+ raise ValueError("only ld/st imm mode supported")
+
+ return cls(record=record)
+
+ def assemble(self, insn):
+ selector = insn.select(record=self.record)
+ selector.mode[2] = 1
+ selector.lf = 0b1
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class SpecifierVLi(Specifier):
+ @classmethod
+ def match(cls, desc, record):
+ if desc != "vli":
+ return None
+
+ return cls(record=record)
+
+ def validate(self, others):
+ for spec in others:
+ if isinstance(spec, SpecifierFF):
+ return
+
+ raise ValueError("VLi only allowed in failfirst")
+
+ def assemble(self, insn):
+ selector = insn.select(record=self.record)
+ selector.VLi = 1
class Specifiers(tuple):
SpecifierZZ,
SpecifierSZ,
SpecifierDZ,
+ SpecifierEls,
+ SpecifierSEA,
+ SpecifierSatS,
+ SpecifierSatU,
+ SpecifierMR,
+ SpecifierMRR,
+ SpecifierAll,
+ SpecifierSNZ,
+ SpecifierSL,
+ SpecifierSLu,
+ SpecifierLRu,
+ SpecifierVS,
+ SpecifierVSi,
+ SpecifierVSb,
+ SpecifierVSbi,
+ SpecifierVLi,
+ SpecifierCTR,
+ SpecifierCTi,
+ SpecifierPI,
+ SpecifierLF,
)
def __new__(cls, items, record):
return spec
raise ValueError(item)
+ # TODO: remove this hack
+ items = dict.fromkeys(items)
+ if "vli" in items:
+ del items["vli"]
+ items["vli"] = None
+ items = tuple(items)
+
specs = tuple(map(transform, items))
- items = list(specs)
- while items:
- spec = items.pop()
- spec.validate(others=items)
+ for (index, spec) in enumerate(specs):
+ head = specs[:index]
+ tail = specs[index + 1:]
+ spec.validate(others=(head + tail))
return super().__new__(cls, specs)
+class SVP64OperandMeta(type):
+ class SVP64NonZeroOperand(NonZeroOperand):
+ def assemble(self, insn, value):
+ if isinstance(value, str):
+ value = int(value, 0)
+ if not isinstance(value, int):
+ raise ValueError("non-integer operand")
+
+ # FIXME: this is really weird
+ if self.record.name in ("svstep", "svstep."):
+ value += 1 # compensation
+
+ return super().assemble(value=value, insn=insn)
+
+ class SVP64XOStaticOperand(SpanStaticOperand):
+ def __init__(self, record, value, span):
+ return super().__init__(record=record, name="XO", value=value, span=span)
+
+ __TRANSFORM = {
+ NonZeroOperand: SVP64NonZeroOperand,
+ XOStaticOperand: SVP64XOStaticOperand,
+ }
+
+ def __new__(metacls, name, bases, ns):
+ bases = list(bases)
+ for (index, base_cls) in enumerate(bases):
+ bases[index] = metacls.__TRANSFORM.get(base_cls, base_cls)
+
+ bases = tuple(bases)
+
+ return super().__new__(metacls, name, bases, ns)
+
+
+class SVP64Operand(Operand, metaclass=SVP64OperandMeta):
+ @property
+ def span(self):
+ return tuple(map(lambda bit: (bit + 32), super().span))
+
+
+class RMSelector:
+ def __init__(self, insn, record):
+ self.__insn = insn
+ self.__record = record
+ return super().__init__()
+
+ def __str__(self):
+ return self.rm.__doc__
+
+ def __repr__(self):
+ return repr(self.rm)
+
+ @property
+ def insn(self):
+ return self.__insn
+
+ @property
+ def record(self):
+ return self.__record
+
+ @property
+ def rm(self):
+ rm = getattr(self.insn.prefix.rm, self.record.svp64.mode.name.lower())
+
+ # The idea behind these tables is that they are now literally
+ # in identical format to insndb.csv and minor_xx.csv and can
+ # be done precisely as that. The only thing to watch out for
+ # is the insertion of Rc=1 as a "mask/value" bit and likewise
+ # regtype detection (3-bit BF/BFA, 5-bit BA/BB/BT) also inserted
+ # as the LSB.
+ table = None
+ if self.record.svp64.mode is _SVMode.NORMAL:
+ # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
+ # mode Rc mask Rc member
+ table = (
+ (0b000000, 0b111000, "simple"), # simple (no Rc)
+ (0b001000, 0b111000, "mr"), # mapreduce (no Rc)
+ (0b010001, 0b110001, "ffrc1"), # ffirst, Rc=1
+ (0b010000, 0b110001, "ffrc0"), # ffirst, Rc=0
+ (0b100000, 0b110000, "sat"), # saturation (no Rc)
+ (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
+ (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
+ )
+ search = ((int(self.insn.prefix.rm.normal.mode) << 1) | self.record.Rc)
+
+ elif self.record.svp64.mode is _SVMode.LDST_IMM:
+ # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
+ # mode Rc mask Rc member
+ # ironically/coincidentally this table is identical to NORMAL
+ # mode except reserved in place of mr
+ table = (
+ (0b000000, 0b111000, "simple"), # simple (no Rc)
+ (0b001000, 0b111000, "post"), # post (no Rc)
+ (0b010001, 0b110001, "ffrc1"), # ffirst, Rc=1
+ (0b010000, 0b110001, "ffrc0"), # ffirst, Rc=0
+ (0b100000, 0b110000, "sat"), # saturation (no Rc)
+ (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
+ (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
+ )
+ search = ((int(self.insn.prefix.rm.ldst_imm.mode) << 1) | self.record.Rc)
+
+ elif self.record.svp64.mode is _SVMode.LDST_IDX:
+ # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
+ # mode Rc mask Rc member
+ table = (
+ (0b000000, 0b110000, "simple"), # simple (no Rc)
+ (0b010000, 0b110000, "stride"), # strided, (no Rc)
+ (0b100000, 0b110000, "sat"), # saturation (no Rc)
+ (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
+ (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
+ )
+ search = ((int(self.insn.prefix.rm.ldst_idx.mode) << 1) | self.record.Rc)
+
+ elif self.record.svp64.mode is _SVMode.CROP:
+ # concatenate mode 5-bit with regtype (LSB) then do mask/map search
+ # mode 3b mask 3b member
+ table = (
+ (0b000000, 0b111000, "simple"), # simple
+ (0b001000, 0b111000, "mr"), # mapreduce
+ (0b100001, 0b100001, "ff3"), # ffirst, 3-bit CR
+ (0b100000, 0b100000, "ff5"), # ffirst, 5-bit CR
+ )
+ search = ((int(self.insn.prefix.rm.crop.mode) << 1) | int(self.record.svp64.extra_CR_3bit))
+
+ elif self.record.svp64.mode is _SVMode.BRANCH:
+ # just mode 2-bit
+ # mode mask member
+ table = (
+ (0b00, 0b11, "simple"), # simple
+ (0b01, 0b11, "vls"), # VLset
+ (0b10, 0b11, "ctr"), # CTR mode
+ (0b11, 0b11, "ctrvls"), # CTR+VLset mode
+ )
+ # slightly weird: doesn't have a 5-bit "mode" field like others
+ search = int(self.insn.prefix.rm.branch.mode.sel)
+
+ # look up in table
+ if table is not None:
+ for (value, mask, field) in table:
+ if ((value & mask) == (search & mask)):
+ return getattr(rm, field)
+
+ return rm
+
+ def __getattr__(self, key):
+ if key.startswith(f"_{self.__class__.__name__}__"):
+ return super().__getattribute__(key)
+
+ return getattr(self.rm, key)
+
+ def __setattr__(self, key, value):
+ if key.startswith(f"_{self.__class__.__name__}__"):
+ return super().__setattr__(key, value)
+
+ rm = self.rm
+ if not hasattr(rm, key):
+ raise AttributeError(key)
+
+ return setattr(rm, key, value)
+
+
class SVP64Instruction(PrefixedInstruction):
"""SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
class Prefix(PrefixedInstruction.Prefix):
prefix: Prefix
- def record(self, db):
- record = db[self.suffix]
- if record is None:
- raise KeyError(self)
- return record
+ def select(self, record):
+ return RMSelector(insn=self, record=record)
@property
def binary(self):
return "".join(map(str, bits))
@classmethod
- def assemble(cls, db, opcode, arguments=None, specifiers=None):
- if arguments is None:
- arguments = ()
- if specifiers is None:
- specifiers = ()
-
- record = db[opcode]
- insn = cls.integer(value=0)
+ def assemble(cls, record, arguments=None, specifiers=None):
+ insn = super().assemble(record=record, arguments=arguments)
specifiers = Specifiers(items=specifiers, record=record)
for specifier in specifiers:
specifier.assemble(insn=insn)
- for operand in record.static_operands:
- operand.assemble(insn=insn)
-
- dynamic_operands = tuple(record.dynamic_operands)
- if len(dynamic_operands) != len(arguments):
- raise ValueError("operands count mismatch")
- for (value, operand) in zip(arguments, dynamic_operands):
- operand.assemble(value=value, insn=insn)
-
insn.prefix.PO = 0x1
insn.prefix.id = 0x3
return insn
- def disassemble(self, db,
+ def disassemble(self, record,
byteorder="little",
- verbosity=Verbosity.NORMAL):
+ style=Style.NORMAL):
def blob(insn):
- if verbosity <= Verbosity.SHORT:
+ if style <= Style.SHORT:
return ""
else:
blob = insn.bytes(byteorder=byteorder)
blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
return f"{blob} "
- record = self.record(db=db)
blob_prefix = blob(self.prefix)
blob_suffix = blob(self.suffix)
- if record is None or record.svp64 is None:
+ if record is None:
yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
yield f"{blob_suffix}.long 0x{int(self.suffix):08x}"
return
+ assert record.svp64 is not None
+
name = f"sv.{record.name}"
- rm = self.prefix.rm.select(record=record)
+ rm = self.select(record=record)
# convert specifiers to /x/y/z (sorted lexicographically)
specifiers = sorted(rm.specifiers(record=record))
# convert operands to " ,x,y,z"
operands = tuple(map(_operator.itemgetter(1),
- self.dynamic_operands(db=db, verbosity=verbosity)))
+ self.spec_dynamic_operands(record=record, style=style)))
operands = ",".join(operands)
if len(operands) > 0: # if any separate with a space
operands = (" " + operands)
- yield f"{blob_prefix}{name}{specifiers}{operands}"
- if blob_suffix:
- yield f"{blob_suffix}"
+ if style <= Style.LEGACY:
+ yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
+ suffix = WordInstruction.integer(value=int(self.suffix))
+ yield from suffix.disassemble(record=record,
+ byteorder=byteorder, style=style)
+ else:
+ yield f"{blob_prefix}{name}{specifiers}{operands}"
+ if blob_suffix:
+ yield f"{blob_suffix}"
- if verbosity >= Verbosity.VERBOSE:
+ if style >= Style.VERBOSE:
indent = (" " * 4)
binary = self.binary
- spec = self.spec(db=db, prefix="sv.")
+ spec = self.spec(record=record, prefix="sv.")
yield f"{indent}spec"
yield f"{indent}{indent}{spec}"
yield f"{indent}opcodes"
for opcode in record.opcodes:
yield f"{indent}{indent}{opcode!r}"
- for (cls, kwargs) in record.mdwn.operands:
- operand = cls(record=record, **kwargs)
+ for operand in self.operands(record=record):
yield from operand.disassemble(insn=self,
- verbosity=verbosity, indent=indent)
+ style=style, indent=indent)
yield f"{indent}RM"
- yield f"{indent}{indent}{rm.__doc__}"
- for line in rm.disassemble(verbosity=verbosity):
+ yield f"{indent}{indent}{str(rm)}"
+ for line in rm.disassemble(style=style):
yield f"{indent}{indent}{line}"
yield ""
+ @classmethod
+ def operands(cls, record):
+ for operand in super().operands(record=record):
+ parent = operand.__class__
+ name = f"SVP64{parent.__name__}"
+ bases = (SVP64Operand, parent)
+ child = type(name, bases, {})
+ yield child(**dict(operand))
+
def parse(stream, factory):
def match(entry):
# The code below groups the instructions by name:section.
# There can be multiple names for the same instruction.
# The point is to capture different opcodes for the same instruction.
- dd = _collections.defaultdict
sections = {}
records = _collections.defaultdict(set)
path = (root / "insndb.csv")
mdwn=mdwn, fields=fields)
db.add(record)
names[record.name] = record
- PO = section.opcode
- if PO is None:
- PO = ppc[0].opcode
- opcodes[section][PO.value].add(record)
+ opcodes[section][record.PO].add(record)
self.__db = sorted(db)
self.__names = dict(sorted(names.items()))
@_functools.lru_cache(maxsize=None)
def __getitem__(self, key):
+ if isinstance(key, SVP64Instruction):
+ key = key.suffix
+
if isinstance(key, Instruction):
PO = int(key.PO)
key = int(key)
- for (section, group) in self.__opcodes.items():
+ sections = sorted(self.__opcodes)
+ for section in sections:
+ group = self.__opcodes[section]
for record in group[PO]:
if record.match(key=key):
return record