import collections as _collections
-import copy as _copy
import csv as _csv
import dataclasses as _dataclasses
import enum as _enum
)
from openpower.decoder.selectable_int import (
SelectableInt as _SelectableInt,
+ selectconcat as _selectconcat,
)
# TODO: these should be present in the decoder module.
-from openpower.decoder.isa.caller import (
- SVP64PrefixFields as _SVP64PrefixFields,
- SVP64RMFields as _SVP64RMFields,
+from openpower.decoder.power_fields import (
+ Field as _Field,
+ Mapping as _Mapping,
)
return self.svp64.etype
-class Instruction(_SelectableInt):
- def __init__(self, value, bits=None, byteorder="little", db=None):
- if isinstance(value, _SelectableInt):
- if bits is not None:
- raise ValueError(bits)
- bits = value.bits
- value = value.value
- else:
- if bits is None:
- bits = 32
- if isinstance(value, bytes):
- value = int.from_bytes(value, byteorder=str(byteorder))
- if not isinstance(bits, int):
- raise ValueError(bits)
+class Instruction(_Mapping):
+ @classmethod
+ def integer(cls, value=0, bits=None, byteorder="little"):
+ if isinstance(value, (int, bytes)) and not isinstance(bits, int):
+ raise ValueError(bits)
- if not isinstance(value, int):
- raise ValueError(value)
+ if isinstance(value, bytes):
+ if ((len(value) * 8) != bits):
+ raise ValueError(f"bit length mismatch")
+ value = int.from_bytes(value, byteorder=byteorder)
- if db is not None and not isinstance(db, Database):
- raise ValueError(db)
+ if isinstance(value, int):
+ value = _SelectableInt(value=value, bits=bits)
+ elif isinstance(value, Instruction):
+ value = value.storage
- self.__db = db
+ if not isinstance(value, _SelectableInt):
+ raise ValueError(value)
+ if bits is None:
+ bits = len(cls)
+ if len(value) != bits:
+ raise ValueError(value)
- return super().__init__(value=value, bits=bits)
+ value = _SelectableInt(value=value, bits=bits)
- def __repr__(self):
- return f"{self.__class__.__name__}({self.value:08x})"
+ return cls(storage=value)
- def disassemble(self):
- if self.dbrecord is None:
- yield f".long 0x{self.value:08x}"
- else:
- yield f".long 0x{self.value:08x} # {self.dbrecord.name}"
+ def __hash__(self):
+ return hash(int(self))
- @property
- def major(self):
- return self[0:6]
+ def disassemble(self, db):
+ raise NotImplementedError
- @property
- def dbrecord(self):
- if self.__db is None:
- return None
- try:
- return self.__db[int(self)]
- except KeyError:
- return None
+class WordInstruction(Instruction):
+ class PO(_Mapping):
+ _: _Field = range(0, 6)
-class PrefixedInstruction(Instruction):
- def __init__(self, prefix, suffix, byteorder="little", db=None):
- insn = _functools.partial(Instruction, byteorder=byteorder, db=db)
- (prefix, suffix) = map(insn, (prefix, suffix))
- value = ((prefix.value << 32) | suffix.value)
-
- return super().__init__(value=value, bits=64,
- byteorder=byteorder, db=db)
+ _: _Field = range(0, 32)
+ po: PO
- def __repr__(self):
- return f"{self.__class__.__name__}({self.value:016x})"
+ @classmethod
+ def integer(cls, value, byteorder="little"):
+ return super().integer(bits=32, value=value, byteorder=byteorder)
- def disassemble(self):
- if self.dbrecord is None:
- yield f".llong 0x{self.value:08x}"
+ def disassemble(self, db):
+ record = db[self]
+ if record is None:
+ yield f".long 0x{int(self):08x}"
else:
- yield f".llong 0x{self.value:08x} # {self.dbrecord.name}"
+ yield f".long 0x{int(self):08x} # {record.name}"
- @property
- def prefix(self):
- return Instruction(self[0:32])
- @property
- def suffix(self):
- return Instruction(self[32:64])
+class PrefixedInstruction(Instruction):
+ class Prefix(WordInstruction.remap(range(0, 32))):
+ pass
- @property
- def major(self):
- return self.suffix.major
+ class Suffix(WordInstruction.remap(range(32, 64))):
+ pass
- @property
- def dbrecord(self):
- return self.suffix.dbrecord
+ _: _Field = range(64)
+ prefix: Prefix
+ suffix: Suffix
+ po: Suffix.PO = Suffix.po
+ @classmethod
+ def integer(cls, value, byteorder="little"):
+ return super().integer(bits=64, value=value, byteorder=byteorder)
-class SVP64Instruction(PrefixedInstruction):
- class PrefixError(ValueError):
- pass
+ @classmethod
+ def pair(cls, prefix=0, suffix=0, byteorder="little"):
+ def transform(value):
+ return WordInstruction.integer(value=value,
+ byteorder=byteorder)[0:32]
- class Prefix(Instruction, _SVP64PrefixFields):
- class RM(_SVP64RMFields):
- @property
- def sv_mode(self):
- return (self.mode & 0b11)
+ (prefix, suffix) = map(transform, (prefix, suffix))
+ value = _selectconcat(prefix, suffix)
- @property
- def rm(self):
- return self.__class__.RM(super().rm)
+ return super().integer(value=value)
- class Suffix(Instruction):
- pass
+ def disassemble(self, db):
+ record = db[self.suffix]
+ if record is None:
+ yield f".long 0x{int(self.prefix):08x}"
+ yield f".long 0x{int(self.suffix):08x}"
+ else:
+ yield f".llong 0x{int(self):08x} # {record.name}"
- def __init__(self, prefix, suffix, byteorder="little", db=None):
- insn = _functools.partial(Instruction, byteorder=byteorder, db=db)
- (prefix, suffix) = map(insn, (prefix, suffix))
- prefix = SVP64Instruction.Prefix(value=prefix)
- if prefix.pid != 0b11:
- raise SVP64Instruction.PrefixError(prefix)
+class SVP64Instruction(PrefixedInstruction):
+ class Prefix(PrefixedInstruction.Prefix):
+ """SVP64 Prefix: https://libre-soc.org/openpower/sv/svp64/"""
+ class RM(_Mapping):
+ """SVP64 RM: https://libre-soc.org/openpower/sv/svp64/"""
+ _: _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),
+ )
- return super().__init__(prefix=prefix, suffix=suffix,
- byteorder=byteorder, db=db)
+ # Backward compatibility
+ spr: _Field = _
- def disassemble(self):
- if self.dbrecord is None:
- yield f".llong 0x{self.value:08x}"
- else:
- yield f".llong 0x{self.value:08x} # sv.{self.dbrecord.name}"
+ id: _Field = (7, 9)
+ rm: RM = ((6, 8) + tuple(range(10, 32)))
- @property
- def prefix(self):
- return self.__class__.Prefix(super().prefix)
+ # Backward compatibility
+ insn: PrefixedInstruction.Prefix
- @property
- def suffix(self):
- return self.__class__.Suffix(super().suffix)
+ prefix: Prefix
+
+ def disassemble(self, db):
+ record = db[self.suffix]
+ if record is None:
+ yield f".llong 0x{int(self):08x}"
+ else:
+ yield f".llong 0x{int(self):08x} # sv.{record.name}"
class Database:
def __getitem__(self, key):
if isinstance(key, Opcode):
return self.__opcodes.__getitem__(key)
- elif isinstance(key, int):
+ elif isinstance(key, (int, Instruction)):
+ ikey = int(key)
for (opcode, insn) in self.__opcodes.items():
if ((opcode.value & opcode.mask) ==
- (key & opcode.mask)):
+ (ikey & opcode.mask)):
return insn
raise KeyError(key)
elif isinstance(key, str):
from openpower.decoder.power_insn import (
Database as _Database,
Instruction as _Instruction,
+ WordInstruction as _WordInstruction,
PrefixedInstruction as _PrefixedInstruction,
SVP64Instruction as _SVP64Instruction,
)
+from openpower.decoder.selectable_int import (
+ SelectableInt as _SelectableInt,
+ FieldSelectableInt as _FieldSelectableInt
+)
class ByteOrder(_enum.Enum):
def load(ifile, byteorder, **_):
- db = _Database(_find_wiki_dir())
+ byteorder = str(byteorder)
- def load(ifile):
+ while True:
prefix = ifile.read(4)
length = len(prefix)
if length == 0:
- return None
+ return
elif length < 4:
raise IOError(prefix)
- prefix = _Instruction(value=prefix, byteorder=byteorder, db=db)
- if prefix.major != 0x1:
- return prefix
+ prefix = _WordInstruction.integer(value=prefix, byteorder=byteorder)
suffix = ifile.read(4)
length = len(suffix)
if length == 0:
- return prefix
+ yield prefix
elif length < 4:
raise IOError(suffix)
- try:
- return _SVP64Instruction(prefix=prefix, suffix=suffix,
- byteorder=byteorder, db=db)
- except _SVP64Instruction.PrefixError:
- return _PrefixedInstruction(prefix=prefix, suffix=suffix,
- byteorder=byteorder, db=db)
+ suffix = _WordInstruction.integer(value=suffix, byteorder=byteorder)
- while True:
- insn = load(ifile)
- if insn is None:
- break
- yield insn
+ if prefix.po == 0x1:
+ insn = _SVP64Instruction.pair(prefix=prefix, suffix=suffix)
+ if insn.prefix.id != 0b11:
+ insn = _PrefixedInstruction.pair(prefix=prefix, suffix=suffix)
+ yield insn
+ else:
+ yield prefix
+ yield suffix
def dump(insns, **_):
+ db = _Database(_find_wiki_dir())
for insn in insns:
- yield from insn.disassemble()
+ yield from insn.disassemble(db=db)
def main():