import enum as _enum
import functools as _functools
import os as _os
-import operator as _operator
import pathlib as _pathlib
import re as _re
SVMode as _SVMode,
SVPtype as _SVPtype,
SVExtra as _SVExtra,
+ RegType as _RegType,
SVExtraRegType as _SVExtraRegType,
SVExtraReg as _SVExtraReg,
)
)
from openpower.decoder.power_fields import (
Field as _Field,
+ Array as _Array,
Mapping as _Mapping,
DecodeFields as _DecodeFields,
)
cry_in: _CryIn = _CryIn.ZERO
ldst_len: _LDSTLen = _LDSTLen.NONE
upd: _LDSTMode = _LDSTMode.NONE
- rc: _RCOE = _RCOE.NONE
+ Rc: _RCOE = _RCOE.NONE
form: _Form = _Form.NONE
conditions: str = ""
unofficial: bool = False
"CR out": "cr_out",
"cry in": "cry_in",
"ldst len": "ldst_len",
+ "rc": "Rc",
"CONDITIONS": "conditions",
}
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):
+ @cached_property
+ def unified(self):
+ def merge(lhs, rhs):
+ value = 0
+ mask = 0
+ lvalue = lhs.opcode.value
+ rvalue = rhs.opcode.value
+ lmask = lhs.opcode.mask
+ rmask = rhs.opcode.mask
+ bits = max(lmask.bit_length(), rmask.bit_length())
+ for bit in range(bits):
+ lvstate = ((lvalue & (1 << bit)) != 0)
+ rvstate = ((rvalue & (1 << bit)) != 0)
+ lmstate = ((lmask & (1 << bit)) != 0)
+ rmstate = ((rmask & (1 << bit)) != 0)
+ vstate = lvstate
+ mstate = True
+ if (not lmstate or not rmstate) or (lvstate != rvstate):
+ vstate = 0
+ mstate = 0
+ value |= (vstate << bit)
+ mask |= (mstate << bit)
+
+ opcode = opcode=Opcode(value=value, mask=mask)
+
+ return _dataclasses.replace(lhs, opcode=opcode)
+
+ return _functools.reduce(merge, self)
+
+ def __getattr__(self, attr):
+ return getattr(self.unified, attr)
+
+
@_dataclasses.dataclass(eq=True, frozen=True)
class SVP64Record:
class ExtraMap(tuple):
cr_in: _CRInSel = _CRInSel.NONE
cr_out: _CROutSel = _CROutSel.NONE
extra: ExtraMap = ExtraMap()
- pu: bool = False
conditions: str = ""
mode: _SVMode = _SVMode.NORMAL
"Etype": "etype",
"CR in": "cr_in",
"CR out": "cr_out",
- "PU": "pu",
}
@classmethod
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)
def transform(item):
(name, bitrange) = item
- return (name, tuple(bitrange.values()))
+ return (name, list(bitrange.values()))
self.__mapping = dict(map(transform, items))
@_dataclasses.dataclass(eq=True, frozen=True)
class Operand:
- pass
+ name: str
+
+ def disassemble(self, value, record, verbose=False):
+ raise NotImplementedError
@_dataclasses.dataclass(eq=True, frozen=True)
class DynamicOperand(Operand):
- name: str
+ def disassemble(self, value, record, verbose=False):
+ span = record.fields[self.name]
+ value = value[span]
+ if verbose:
+ yield f"{int(value):0{value.bits}b}"
+ yield repr(span)
+ else:
+ yield str(int(value))
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class ImmediateOperand(DynamicOperand):
+ pass
@_dataclasses.dataclass(eq=True, frozen=True)
class StaticOperand(Operand):
- name: str
- value: int = None
+ value: int
+
+ def disassemble(self, value, record, verbose=False):
+ span = record.fields[self.name]
+ value = value[span]
+ if verbose:
+ yield f"{int(value):0{value.bits}b}"
+ yield repr(span)
+ else:
+ yield str(int(value))
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class DynamicOperandTargetAddrLI(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:
+ yield f"{int(value):0{value.bits}b}"
+ yield repr(span)
+ yield "target_addr = EXTS(LI || 0b00))"
+ else:
+ yield hex(int(_selectconcat(value,
+ _SelectableInt(value=0b00, bits=2))))
+
+
+class DynamicOperandTargetAddrBD(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:
+ yield f"{int(value):0{value.bits}b}"
+ yield repr(span)
+ yield "target_addr = EXTS(BD || 0b00))"
+ else:
+ yield 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):
+ span = record.fields[self.name]
+ value = value[span]
+ if verbose:
+ yield f"{int(value):0{value.bits}b}"
+ yield repr(span)
+ else:
+ yield f"r{str(int(value))}"
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class DynamicOperandFPR(DynamicOperand):
+ def disassemble(self, value, record, verbose=False):
+ span = record.fields[self.name]
+ value = value[span]
+ if verbose:
+ yield f"{int(value):0{value.bits}b}"
+ yield repr(span)
+ else:
+ yield f"f{str(int(value))}"
class Operands(tuple):
- def __new__(cls, iterable):
+ def __new__(cls, insn, iterable):
+ branches = {
+ "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 = DynamicOperand
+ static_cls = StaticOperand
+
if "=" in operand:
(name, value) = operand.split("=")
- value = int(value)
- operand = StaticOperand(name=name, value=value)
+ operand = static_cls(name=name, value=int(value))
+ operands.append(operand)
else:
- operand = DynamicOperand(name=operand)
- operands.append(operand)
+ 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 = DynamicOperandGPR
+ elif regtype is _RegType.FPR:
+ dynamic_cls = DynamicOperandFPR
+
+ operand = dynamic_cls(name=operand)
+ operands.append(operand)
+
return super().__new__(cls, operands)
+ def __contains__(self, key):
+ return self.__getitem__(key) is not None
+
+ def __getitem__(self, key):
+ for operand in self:
+ if operand.name == key:
+ return operand
+
+ return None
+
+ @property
+ def dynamic(self):
+ for operand in self:
+ if isinstance(operand, DynamicOperand):
+ yield operand
+
+ @property
+ def static(self):
+ for operand in self:
+ if isinstance(operand, StaticOperand):
+ yield operand
+
@_functools.total_ordering
@_dataclasses.dataclass(eq=True, frozen=True)
return NotImplemented
return (self.opcode < other.opcode)
- def __repr__(self):
- return f"{self.__class__.__name__}(name={self.name!r}, opcode={self.opcode})"
-
@cached_property
def opcode(self):
fields = []
else:
fields += [(self.ppc.opcode.value, self.section.bitsel)]
- for operand in self.static_operands:
+ for operand in self.operands.static:
fields += [(operand.value, self.fields[operand.name])]
return FieldsOpcode(fields)
return _SVEtype.NONE
return self.svp64.etype
- @property
- def dynamic_operands(self):
- for operand in self.operands:
- if isinstance(operand, DynamicOperand):
- yield operand
-
- @property
- def static_operands(self):
- for operand in self.operands:
- if isinstance(operand, StaticOperand):
- yield operand
-
class Instruction(_Mapping):
@classmethod
def __hash__(self):
return hash(int(self))
- def disassemble(self, db):
+ def disassemble(self, db, byteorder="little", verbose=False):
raise NotImplementedError
def integer(cls, value, byteorder="little"):
return super().integer(bits=32, value=value, byteorder=byteorder)
- def disassemble(self, db):
+ @property
+ def binary(self):
+ bits = []
+ for idx in range(32):
+ bit = int(self[idx])
+ bits.append(bit)
+ return "".join(map(str, bits))
+
+ def spec(self, record):
+ immediate = ""
+ dynamic_operands = []
+ for operand in record.operands.dynamic:
+ name = operand.name
+ if immediate:
+ name = f"{immediate}({name})"
+ immediate = ""
+ if isinstance(operand, ImmediateOperand):
+ immediate = operand.name
+ if not immediate:
+ dynamic_operands.append(name)
+
+ static_operands = []
+ for operand in record.operands.static:
+ static_operands.append(f"{operand.name}={operand.value}")
+
+ operands = ""
+ if dynamic_operands:
+ operands += f" {','.join(dynamic_operands)}"
+ if static_operands:
+ operands += f" ({' '.join(static_operands)})"
+
+ return f"{record.name}{operands}"
+
+ def opcode(self, record):
+ return f"0x{record.opcode.value:08x}"
+
+ def mask(self, record):
+ return f"0x{record.opcode.mask:08x}"
+
+ def disassemble(self, db, byteorder="little", verbose=False):
+ integer = int(self)
+ blob = integer.to_bytes(length=4, byteorder=byteorder)
+ blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
+
record = db[self]
if record is None:
- yield f".long 0x{int(self):08x}"
+ yield f"{blob} .long 0x{integer:08x}"
+ return
+
+ operands = []
+ for operand in record.operands.dynamic:
+ operand = " ".join(operand.disassemble(value=self,
+ record=record, verbose=False))
+ operands.append(operand)
+ if operands:
+ operands = ",".join(operands)
+ operands = f" {operands}"
else:
- yield f".long 0x{int(self):08x} # {record.name}"
+ operands = ""
+
+ yield f"{blob} {record.name}{operands}"
+
+ if verbose:
+ indent = (" " * 4)
+ binary = self.binary
+ spec = self.spec(record=record)
+ opcode = self.opcode(record=record)
+ mask = self.mask(record=record)
+ 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
+ yield f"{indent}{name}"
+ parts = operand.disassemble(value=self,
+ record=record, verbose=True)
+ for part in parts:
+ yield f"{indent}{indent}{part}"
+ yield ""
class PrefixedInstruction(Instruction):
return super().integer(value=value)
- def disassemble(self, db):
- record = db[self.suffix]
- if record is None:
- yield f".llong 0x{int(self):016x}"
- else:
- yield f".llong 0x{int(self):016x} # {record.name}"
+
+class Mode(_Mapping):
+ _: _Field = range(0, 5)
+ sel: _Field = range(0, 2)
+
+
+class NormalMode(Mode):
+ class simple(Mode):
+ """simple mode"""
+ dz: Mode[3]
+ sz: Mode[4]
+
+ class smr(Mode):
+ """scalar reduce mode (mapreduce), SUBVL=1"""
+ RG: Mode[4]
+
+ class pmr(Mode):
+ """parallel reduce mode (mapreduce), SUBVL=1"""
+ pass
+
+ class svmr(Mode):
+ """subvector reduce mode, SUBVL>1"""
+ SVM: Mode[3]
+
+ class pu(Mode):
+ """Pack/Unpack mode, SUBVL>1"""
+ SVM: Mode[3]
+
+ class ffrc1(Mode):
+ """Rc=1: ffirst CR sel"""
+ inv: Mode[2]
+ CRbit: Mode[3, 4]
+
+ class ffrc0(Mode):
+ """Rc=0: ffirst z/nonz"""
+ inv: Mode[2]
+ VLi: Mode[3]
+ RC1: Mode[4]
+
+ class sat(Mode):
+ """sat mode: N=0/1 u/s, SUBVL=1"""
+ N: Mode[2]
+ dz: Mode[3]
+ sz: Mode[4]
+
+ class satx(Mode):
+ """sat mode: N=0/1 u/s, SUBVL>1"""
+ N: Mode[2]
+ zz: Mode[3]
+ dz: Mode[3]
+ sz: Mode[3]
+
+ class satpu(Mode):
+ """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
+ N: Mode[2]
+ zz: Mode[3]
+ dz: Mode[3]
+ sz: Mode[3]
+
+ class prrc1(Mode):
+ """Rc=1: pred-result CR sel"""
+ inv: Mode[2]
+ CRbit: Mode[3, 4]
+
+ class prrc0(Mode):
+ """Rc=0: pred-result z/nonz"""
+ inv: Mode[2]
+ zz: Mode[3]
+ RC1: Mode[4]
+ dz: Mode[3]
+ sz: Mode[3]
+
+ simple: simple
+ smr: smr
+ pmr: pmr
+ svmr: svmr
+ pu: pu
+ ffrc1: ffrc1
+ ffrc0: ffrc0
+ sat: sat
+ satx: satx
+ satpu: satpu
+ prrc1: prrc1
+ prrc0: prrc0
+
+
+class LDSTImmMode(Mode):
+ class simple(Mode):
+ """simple mode"""
+ zz: Mode[3]
+ els: Mode[4]
+ dz: Mode[3]
+ sz: Mode[3]
+
+ class spu(Mode):
+ """Structured Pack/Unpack"""
+ zz: Mode[3]
+ els: Mode[4]
+ dz: Mode[3]
+ sz: Mode[3]
+
+ class ffrc1(Mode):
+ """Rc=1: ffirst CR sel"""
+ inv: Mode[2]
+ CRbit: Mode[3, 4]
+
+ class ffrc0(Mode):
+ """Rc=0: ffirst z/nonz"""
+ inv: Mode[2]
+ els: Mode[3]
+ RC1: Mode[4]
+
+ class sat(Mode):
+ """sat mode: N=0/1 u/s"""
+ N: Mode[2]
+ zz: Mode[3]
+ els: Mode[4]
+ dz: Mode[3]
+ sz: Mode[3]
+
+ class prrc1(Mode):
+ """Rc=1: pred-result CR sel"""
+ inv: Mode[2]
+ CRbit: Mode[3, 4]
+
+ class prrc0(Mode):
+ """Rc=0: pred-result z/nonz"""
+ inv: Mode[2]
+ els: Mode[3]
+ RC1: Mode[4]
+
+ simple: simple
+ spu: spu
+ ffrc1: ffrc1
+ ffrc0: ffrc0
+ sat: sat
+ prrc1: prrc1
+ prrc0: prrc0
+
+
+class LDSTIdxMode(Mode):
+ class simple(Mode):
+ """simple mode"""
+ SEA: Mode[2]
+ sz: Mode[3]
+ dz: Mode[3]
+
+ class stride(Mode):
+ """strided (scalar only source)"""
+ SEA: Mode[2]
+ dz: Mode[3]
+ sz: Mode[4]
+
+ class sat(Mode):
+ """sat mode: N=0/1 u/s"""
+ N: Mode[2]
+ dz: Mode[3]
+ sz: Mode[4]
+
+ class prrc1(Mode):
+ """Rc=1: pred-result CR sel"""
+ inv: Mode[2]
+ CRbit: Mode[3, 4]
+
+ class prrc0(Mode):
+ """Rc=0: pred-result z/nonz"""
+ inv: Mode[2]
+ zz: Mode[3]
+ RC1: Mode[4]
+ dz: Mode[3]
+ sz: Mode[3]
+
+ simple: simple
+ stride: stride
+ sat: sat
+ prrc1: prrc1
+ prrc0: prrc0
+
+
+class RM(_Mapping):
+ class Mode(Mode):
+ normal: NormalMode
+ ldst_imm: LDSTImmMode
+ ldst_idx: LDSTIdxMode
+
+ _: _Field = range(24)
+ mmode: _Field = (0,)
+ mask: _Field = range(1, 4)
+ 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),
+ )
class SVP64Instruction(PrefixedInstruction):
"""SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
class Prefix(PrefixedInstruction.Prefix):
- class RM(_Mapping):
- _: _Field = range(24)
- mmode: _Field = (0,)
- mask: _Field = range(1, 4)
- elwidth: _Field = range(4, 6)
- ewsrc: _Field = range(6, 8)
- subvl: _Field = range(8, 10)
- extra: _Field = range(10, 19)
- mode: _Field = range(19, 24)
- extra2: _Field[4] = (
- range(10, 12),
- range(12, 14),
- range(14, 16),
- range(16, 18),
- )
- smask: _Field = range(16, 19)
- extra3: _Field[3] = (
- range(10, 13),
- range(13, 16),
- range(16, 19),
- )
-
id: _Field = (7, 9)
- rm: RM = ((6, 8) + tuple(range(10, 32)))
+ rm: RM.remap((6, 8) + tuple(range(10, 32)))
prefix: Prefix
- def disassemble(self, db):
+ @property
+ def binary(self):
+ bits = []
+ for idx in range(64):
+ bit = int(self[idx])
+ bits.append(bit)
+ return "".join(map(str, bits))
+
+ def spec(self, record):
+ return f"sv.{self.suffix.spec(record=record)}"
+
+ def opcode(self, record):
+ return self.suffix.opcode(record=record)
+
+ def mask(self, record):
+ return self.suffix.mask(record=record)
+
+ 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))
+
+ 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))
+
record = db[self.suffix]
- if record is None:
- yield f".llong 0x{int(self):016x}"
- else:
- yield f".llong 0x{int(self):016x} # sv.{record.name}"
+ 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
+
+ Rc = False
+ if record.operands["Rc"] is not None:
+ Rc = bool(self[record.fields["Rc"]])
+
+ subvl = self.prefix.rm.subvl
+ mode = self.prefix.rm.mode
+ sel = mode.sel
+
+ if record.svp64.mode is _SVMode.NORMAL:
+ mode = mode.normal
+ if sel == 0b00:
+ if mode[2] == 0b0:
+ mode = mode.simple
+ else:
+ if subvl == 0b00:
+ if mode[3] == 0b0:
+ mode = mode.smr
+ else:
+ mode = mode.pmr
+ else:
+ if mode[4] == 0b0:
+ mode = mode.svmr
+ else:
+ mode = mode.pu
+ elif sel == 0b01:
+ if Rc:
+ mode = mode.ffrc1
+ else:
+ mode = mode.ffrc0
+ elif sel == 0b10:
+ if subvl == 0b00:
+ mode = mode.sat
+ else:
+ if mode[4]:
+ mode = mode.satx
+ else:
+ mode = mode.satpu
+ elif sel == 0b11:
+ if Rc:
+ mode = mode.prrc1
+ else:
+ mode = mode.prrc0
+ elif record.svp64.mode is _SVMode.LDST_IMM:
+ mode = mode.ldst_imm
+ if sel == 0b00:
+ if mode[2] == 0b0:
+ mode = mode.simple
+ else:
+ mode = mode.spu
+ elif sel == 0b01:
+ if Rc:
+ mode = mode.ffrc1
+ else:
+ mode = mode.ffrc0
+ elif sel == 0b10:
+ mode = mode.sat
+ elif sel == 0b11:
+ if Rc:
+ mode = mode.prrc1
+ else:
+ mode = mode.prrc0
+ elif record.svp64.mode is _SVMode.LDST_IMM:
+ mode = mode.ldst_idx
+ if mode.sel == 0b00:
+ mode = mode.simple
+ elif mode.sel == 0b01:
+ mode = mode.stride
+ elif mode.sel == 0b10:
+ mode = mode.sat
+ elif mode.sel == 0b11:
+ if Rc:
+ mode = mode.prrc1
+ else:
+ mode = mode.prrc0
+
+ if type(mode) is Mode:
+ raise NotImplementedError
+
+ yield f"{blob_prefix} sv.{record.name}"
+ yield f"{blob_suffix}"
+
+ if verbose:
+ indent = (" " * 4)
+ binary = self.binary
+ spec = self.spec(record=record)
+ opcode = self.opcode(record=record)
+ mask = self.mask(record=record)
+ 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:
+ name = operand.name
+ yield f"{indent}{name}"
+ parts = operand.disassemble(value=self,
+ record=record, verbose=True)
+ for part in parts:
+ yield f"{indent}{indent}{part}"
+ 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:
- class KeyError(KeyError):
- pass
+class MarkdownDatabase:
+ def __init__(self):
+ db = {}
+ for (name, desc) in _ISA():
+ operands = []
+ if desc.regs:
+ (dynamic, *static) = desc.regs
+ operands.extend(dynamic)
+ operands.extend(static)
+ db[name] = Operands(insn=name, iterable=operands)
+ self.__db = db
+ return super().__init__()
- def __init__(self, root):
- db = _collections.defaultdict(set)
+ def __iter__(self):
+ yield from self.__db.items()
+
+ def __getitem__(self, key):
+ return self.__db.__getitem__(key)
+
+
+class FieldsDatabase:
+ def __init__(self):
+ db = {}
+ df = _DecodeFields()
+ df.create_specs()
+ for (form, fields) in df.instrs.items():
+ if form in {"DQE", "TX"}:
+ continue
+ if form == "all":
+ form = "NONE"
+ db[_Form[form]] = Fields(fields)
+
+ self.__db = db
+
+ return super().__init__()
+
+ def __getitem__(self, key):
+ return self.__db.__getitem__(key)
+
+
+class PPCDatabase:
+ def __init__(self, root, mdwndb, fieldsdb):
+ # 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.
+ dd = _collections.defaultdict
+ records = dd(lambda: dd(set))
path = (root / "insndb.csv")
with open(path, "r", encoding="UTF-8") as stream:
for section in parse(stream, Section.CSV):
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:
- db[section].update(parse(stream, factory))
+ for insn in parse(stream, factory):
+ records[section][insn.comment].add(insn)
+
+ db = dd(set)
+ for (section, group) in records.items():
+ for records in group.values():
+ db[section].add(PPCMultiRecord(records))
+
self.__db = db
+ self.__mdwndb = mdwndb
+ self.__fieldsdb = fieldsdb
+
return super().__init__()
def __getitem__(self, key):
+ def exact_match(key, record):
+ for name in record.names:
+ if name == key:
+ return True
+
+ return False
+
+ def Rc_match(key, record):
+ if not key.endswith("."):
+ return False
+
+ if not record.Rc is _RCOE.RC:
+ return False
+
+ return exact_match(key[:-1], record)
+
+ def LK_match(key, record):
+ if not key.endswith("l"):
+ return False
+
+ if "lk" not in record.flags:
+ return False
+
+ return exact_match(key[:-1], record)
+
+ def AA_match(key, record):
+ if not key.endswith("a"):
+ return False
+
+ if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
+ return False
+
+ if self.__mdwndb[key]["AA"] is None:
+ return False
+
+ return (exact_match(key[:-1], record) or
+ LK_match(key[:-1], record))
+
for (section, records) in self.__db.items():
for record in records:
- for name in record.names:
- if ((key == name) or
- ((record.rc is _RC.RC) and
- key.endswith(".") and
- name == key[:-1])):
- return (section, record)
- raise self.__class__.KeyError(key)
+ if (exact_match(key, record) or
+ Rc_match(key, record) or
+ LK_match(key, record) or
+ AA_match(key, record)):
+ return (section, record)
+ return (None, None)
-class SVP64Database:
- class KeyError(KeyError):
- pass
+class SVP64Database:
def __init__(self, root, ppcdb):
db = set()
pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
path = (prefix / _pathlib.Path(name))
with open(path, "r", encoding="UTF-8") as stream:
db.update(parse(stream, SVP64Record.CSV))
+
self.__db = {record.name:record for record in db}
+ self.__ppcdb = ppcdb
+
return super().__init__()
def __getitem__(self, key):
- for name in key:
+ (_, record) = self.__ppcdb[key]
+ if record is None:
+ return None
+
+ for name in record.names:
record = self.__db.get(name, None)
if record is not None:
return record
- raise self.__class__.KeyError(key)
-
-
-class FieldsDatabase:
- def __init__(self):
- db = {}
- df = _DecodeFields()
- df.create_specs()
- for (form, fields) in df.instrs.items():
- if form in {"DQE", "TX"}:
- continue
- if form == "all":
- form = "NONE"
- db[_Form[form]] = Fields(fields)
- self.__db = db
- return super().__init__()
-
- def __getitem__(self, key):
- return self.__db.__getitem__(key)
-
-class MarkdownDatabase:
- def __init__(self):
- db = {}
- for (name, desc) in _ISA():
- operands = []
- if desc.regs:
- (dynamic, *static) = desc.regs
- operands.extend(dynamic)
- operands.extend(static)
- db[name] = Operands(operands)
- self.__db = db
- return super().__init__()
-
- def __iter__(self):
- yield from self.__db.items()
-
- def __getitem__(self, key):
- return self.__db.__getitem__(key)
+ return None
class Database:
mdwndb = MarkdownDatabase()
fieldsdb = FieldsDatabase()
- ppcdb = PPCDatabase(root)
- svp64db = SVP64Database(root, ppcdb)
+ ppcdb = PPCDatabase(root=root, mdwndb=mdwndb, fieldsdb=fieldsdb)
+ svp64db = SVP64Database(root=root, ppcdb=ppcdb)
db = set()
- unknown_ppcdb = set()
- unknown_svp64 = set()
for (name, operands) in mdwndb:
- try:
- (section, ppc) = ppcdb[name]
- svp64 = svp64db[ppc.names]
- fields = fieldsdb[ppc.form]
- record = Record(name=name,
- section=section, ppc=ppc, svp64=svp64,
- operands=operands, fields=fields)
- db.add(record)
- except PPCDatabase.KeyError:
- unknown_ppcdb.add(name)
- except SVP64Database.KeyError:
- unknown_svp64.add(name)
+ (section, ppc) = ppcdb[name]
+ if ppc is None:
+ continue
+ svp64 = svp64db[name]
+ fields = fieldsdb[ppc.form]
+ record = Record(name=name,
+ section=section, ppc=ppc, svp64=svp64,
+ operands=operands, fields=fields)
+ db.add(record)
self.__db = tuple(sorted(db))