From a901b5512ae119abee24ac488796d5c854c4bc01 Mon Sep 17 00:00:00 2001 From: Dmitry Selyutin Date: Thu, 18 Aug 2022 14:44:38 +0300 Subject: [PATCH] selectable_int: refactor fields mappings --- src/openpower/decoder/isa/caller.py | 59 ++++----- src/openpower/decoder/power_insn.py | 4 +- src/openpower/decoder/selectable_int.py | 157 +++++++++++++----------- src/openpower/sv/trans/pysvp64dis.py | 4 +- src/openpower/sv/trans/svp64.py | 4 +- 5 files changed, 115 insertions(+), 113 deletions(-) diff --git a/src/openpower/decoder/isa/caller.py b/src/openpower/decoder/isa/caller.py index 5ab5a06a..d128d167 100644 --- a/src/openpower/decoder/isa/caller.py +++ b/src/openpower/decoder/isa/caller.py @@ -259,35 +259,29 @@ class PC: # SVP64 ReMap field -class SVP64RMFields(SelectableIntMapping, bits=24, fields={ - "spr": range(24), - # SVP64 RM fields: see https://libre-soc.org/openpower/sv/svp64/ - "mmode": (0,), - "mask": range(1, 4), - "elwidth": range(4, 6), - "ewsrc": range(6, 8), - "subvl": range(8, 10), - "extra": range(10, 19), - "mode": range(19, 24), - # these cover the same extra field, split into parts as EXTRA2 - "extra2": dict(enumerate([ +class SVP64RMFields(SelectableIntMapping): + """SVP64 RM: https://libre-soc.org/openpower/sv/svp64/""" + spr = range(24) + mmode = (0,) + mask = range(1, 4) + elwidth = range(4, 6) + ewsrc = range(6, 8) + subvl = range(8, 10) + extra = range(10, 19) + mode = range(19, 24) + extra2 = dict(enumerate([ range(10, 12), range(12, 14), range(14, 16), range(16, 18), - ])), - "smask": range(16, 19), - # and here as well, but EXTRA3 - "extra3": dict(enumerate([ + ])) + smask = range(16, 19) + extra3 = dict(enumerate([ range(10, 13), range(13, 16), range(16, 19), - ])), -}): + ])) - def __init__(self, value=0): - super().__init__(value=value) - self.spr = self SVP64RM_MMODE_SIZE = len(SVP64RMFields.mmode) @@ -301,20 +295,12 @@ SVP64RM_SMASK_SIZE = len(SVP64RMFields.smask) SVP64RM_MODE_SIZE = len(SVP64RMFields.mode) -# SVP64 Prefix fields: see https://libre-soc.org/openpower/sv/svp64/ -class SVP64PrefixFields(SelectableIntMapping, bits=32, fields={ - "insn": range(32), - # 6 bit major opcode EXT001, 2 bits "identifying" (7, 9), 24 SV ReMap - "major": range(0, 6), - "pid": (7, 9), - # SVP64 24-bit RM (ReMap) - "rm": ((6, 8) + tuple(range(10, 32))), -}): - - def __init__(self, value=0): - super().__init__(value=value) - self.insn = self - +class SVP64PrefixFields(SelectableIntMapping): + """SVP64 Prefix: https://libre-soc.org/openpower/sv/svp64/""" + insn = range(32) + major = range(0, 6) + pid = (7, 9) + rm = ((6, 8) + tuple(range(10, 32))) SV64P_MAJOR_SIZE = len(SVP64PrefixFields.major) SV64P_PID_SIZE = len(SVP64PrefixFields.pid) @@ -1008,8 +994,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers): # SVP64. first, check if the opcode is EXT001, and SVP64 id bits set yield Settle() opcode = yield self.dec2.dec.opcode_in - pfx = SVP64PrefixFields() # TODO should probably use SVP64PrefixDecoder - pfx.insn.value = opcode + pfx = SVP64PrefixFields(opcode) major = pfx.major.asint(msb0=True) # MSB0 inversion log("prefix test: opcode:", major, bin(major), pfx.insn[7] == 0b1, pfx.insn[9] == 0b1) diff --git a/src/openpower/decoder/power_insn.py b/src/openpower/decoder/power_insn.py index 244eac52..5e9e8b06 100644 --- a/src/openpower/decoder/power_insn.py +++ b/src/openpower/decoder/power_insn.py @@ -545,7 +545,7 @@ class Instruction(_SelectableInt): bits = 32 if isinstance(value, bytes): value = int.from_bytes(value, byteorder=str(byteorder)) - if not isinstance(bits, int) or (bits not in {32, 64}): + if not isinstance(bits, int): raise ValueError(bits) if not isinstance(value, int): @@ -620,7 +620,7 @@ class SVP64Instruction(PrefixedInstruction): class PrefixError(ValueError): pass - class Prefix(_SVP64PrefixFields, Instruction): + class Prefix(Instruction, _SVP64PrefixFields): class RM(_SVP64RMFields): @property def sv_mode(self): diff --git a/src/openpower/decoder/selectable_int.py b/src/openpower/decoder/selectable_int.py index a94bb43d..56ba07c3 100644 --- a/src/openpower/decoder/selectable_int.py +++ b/src/openpower/decoder/selectable_int.py @@ -127,10 +127,12 @@ class FieldSelectableInt: return self._op(xor, b) def __lt__(self, b): - return self._op(lt, b) + vi = self.get_range() + return onebit(lt(vi, b)) def __eq__(self, b): - return self._op(eq, b) + vi = self.get_range() + return onebit(eq(vi, b)) def get_range(self): vi = SelectableInt(0, len(self.br)) @@ -494,88 +496,103 @@ class SelectableInt: class SelectableIntMappingMeta(type): - @functools.total_ordering - class Field(FieldSelectableInt): - def __int__(self): - return self.asint(msb0=True) - - def __lt__(self, b): - return int(self).__lt__(b) - - def __eq__(self, b): - return int(self).__eq__(b) - - class FieldProperty: - def __init__(self, field): - self.__field = field - - def __repr__(self): - return self.__field.__repr__() + class Field(tuple): + def __call__(self, si): + return FieldSelectableInt(si=si, br=self) + + class FieldMapping(dict): + def __init__(self, items): + if isinstance(items, dict): + items = items.items() + + length = 0 + mapping = {} + Field = SelectableIntMappingMeta.Field + for (key, value) in items: + field = Field(value) + mapping[key] = field + length = max(length, len(field)) + + self.__length = length + + return super().__init__(mapping) + + def __iter__(self): + yield from self.items() + + def __len__(self): + return self.__length + + def __call__(self, si): + return {key:value(si=si) for (key, value) in self} + + def __new__(metacls, name, bases, attrs): + mapping = {} + valid = False + for base in reversed(bases): + if issubclass(base.__class__, metacls): + mapping.update(base) + if not valid and issubclass(base, SelectableInt): + valid = True + if not valid: + raise ValueError(bases) + + for (key, value) in tuple(attrs.items()): + if key.startswith("_"): + continue + if isinstance(value, dict): + value = metacls.FieldMapping(value) + elif isinstance(value, (list, tuple, range)): + value = metacls.Field(value) + else: + continue + mapping[key] = value + attrs[key] = value - def __get__(self, instance, owner): - if instance is None: - return self.__field + length = 0 + for (key, value) in mapping.items(): + length = max(length, len(value)) - cls = SelectableIntMappingMeta.Field - factory = lambda br: cls(si=instance, br=br) - if isinstance(self.__field, dict): - return {k:factory(br=v) for (k, v) in self.__field.items()} - else: - return factory(br=self.__field) + cls = super().__new__(metacls, name, bases, attrs) + cls.__length = length + cls.__mapping = mapping - class BitsProperty: - def __init__(self, bits): - self.__bits = bits + return cls - def __get__(self, instance, owner): - if instance is None: - return self.__bits - return instance.bits + def __len__(cls): + return cls.__length - def __repr__(self): - return self.__bits.__repr__() + def __contains__(cls, key): + return cls.__mapping.__contains__(key) - def __new__(metacls, name, bases, attrs, bits=None, fields=None): - if fields is None: - fields = {} + def __getitem__(cls, key): + return cls.__mapping.__getitem__(key) - def field(item): - (key, value) = item - if isinstance(value, dict): - value = dict(map(field, value.items())) - else: - value = tuple(value) - return (key, value) + def __iter__(cls): + yield from cls.__mapping.items() + if type(cls) is not SelectableIntMappingMeta: + yield from super().__iter__() - fields = dict(map(field, fields.items())) - for (key, value) in fields.items(): - attrs.setdefault(key, metacls.FieldProperty(value)) +class SelectableIntMapping(SelectableInt, metaclass=SelectableIntMappingMeta): + def __init__(self, value=0, bits=None): + if isinstance(value, SelectableInt): + value = value.value if bits is None: - for base in bases: - bits = getattr(base, "bits", None) - if bits is not None: - break - - if not isinstance(bits, int): + bits = len(self.__class__) + if bits != len(self.__class__): raise ValueError(bits) - attrs.setdefault("bits", metacls.BitsProperty(bits)) - cls = super().__new__(metacls, name, bases, attrs) - cls.__fields = fields - return cls + return super().__init__(value=value, bits=bits) - def __iter__(cls): - for (key, value) in cls.__fields.items(): - yield (key, value) + def __iter__(self): + for (name, _) in self.__class__: + yield (name, getattr(self, name)) - -class SelectableIntMapping(SelectableInt, - metaclass=SelectableIntMappingMeta, bits=0): - def __init__(self, value=0, bits=None): - if isinstance(value, int) and bits is None: - bits = self.__class__.bits - return super().__init__(value, bits) + def __getattribute__(self, attr): + if (attr != "__class__") and (attr in self.__class__): + return self.__class__[attr](si=self) + return super().__getattribute__(attr) def onebit(bit): diff --git a/src/openpower/sv/trans/pysvp64dis.py b/src/openpower/sv/trans/pysvp64dis.py index b8c0183a..67833b35 100644 --- a/src/openpower/sv/trans/pysvp64dis.py +++ b/src/openpower/sv/trans/pysvp64dis.py @@ -56,7 +56,7 @@ def load(ifile, byteorder, **_): yield insn -def dump(insns, ofile, **_): +def dump(insns, **_): for insn in insns: yield from insn.disassemble() @@ -76,7 +76,7 @@ def main(): byteorder = args["byteorder"] insns = load(ifile, byteorder) - for line in dump(insns, byteorder): + for line in dump(insns): print(line, file=ofile) diff --git a/src/openpower/sv/trans/svp64.py b/src/openpower/sv/trans/svp64.py index dc8fe9b5..15e47b67 100644 --- a/src/openpower/sv/trans/svp64.py +++ b/src/openpower/sv/trans/svp64.py @@ -1224,7 +1224,7 @@ class SVP64Asm: # nice debug printout. (and now for something completely different) # https://youtu.be/u0WOIwlXE9g?t=146 - svp64_rm_value = svp64_rm.spr.value + svp64_rm_value = int(svp64_rm) log("svp64_rm", hex(svp64_rm_value), bin(svp64_rm_value)) log(" mmode 0 :", bin(mmode)) log(" pmask 1-3 :", bin(pmask)) @@ -1251,7 +1251,7 @@ class SVP64Asm: svp64_prefix = SVP64PrefixFields() svp64_prefix.major.eq(SelectableInt(0x1, SV64P_MAJOR_SIZE)) svp64_prefix.pid.eq(SelectableInt(0b11, SV64P_PID_SIZE)) - svp64_prefix.rm.eq(svp64_rm.spr) + svp64_prefix.rm.eq(svp64_rm) # fiinally yield the svp64 prefix and the thingy. v3.0b opcode rc = '.' if rc_mode else '' -- 2.30.2