From 20caf84ba1a8413ffed18cc3ffd7b2b0f5043309 Mon Sep 17 00:00:00 2001 From: Dmitry Selyutin Date: Fri, 19 Aug 2022 13:48:20 +0300 Subject: [PATCH] power_insn: switch to new fields --- src/openpower/decoder/power_insn.py | 213 ++++++++++++++------------- src/openpower/sv/trans/pysvp64dis.py | 40 ++--- 2 files changed, 132 insertions(+), 121 deletions(-) diff --git a/src/openpower/decoder/power_insn.py b/src/openpower/decoder/power_insn.py index 5e9e8b06..411ec02e 100644 --- a/src/openpower/decoder/power_insn.py +++ b/src/openpower/decoder/power_insn.py @@ -1,5 +1,4 @@ import collections as _collections -import copy as _copy import csv as _csv import dataclasses as _dataclasses import enum as _enum @@ -37,12 +36,13 @@ from openpower.decoder.power_enums import ( ) 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, ) @@ -533,130 +533,138 @@ class Record: 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: @@ -772,10 +780,11 @@ 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): diff --git a/src/openpower/sv/trans/pysvp64dis.py b/src/openpower/sv/trans/pysvp64dis.py index 67833b35..cf627220 100644 --- a/src/openpower/sv/trans/pysvp64dis.py +++ b/src/openpower/sv/trans/pysvp64dis.py @@ -9,9 +9,14 @@ from openpower.decoder.power_enums import ( 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): @@ -23,42 +28,39 @@ 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(): -- 2.30.2