X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fopenpower%2Fdecoder%2Fpower_insn.py;h=bfaf2fa751216c70b5f4ad9942d14365e8d0cfe1;hb=b85e3da773bc38f4365746dfa28484f5845842db;hp=0f96c81c0068df0d696612c6b2603c58ef7a556f;hpb=819107502ee13f7223af242c4d2936935f3fb77b;p=openpower-isa.git diff --git a/src/openpower/decoder/power_insn.py b/src/openpower/decoder/power_insn.py index 0f96c81c..bfaf2fa7 100644 --- a/src/openpower/decoder/power_insn.py +++ b/src/openpower/decoder/power_insn.py @@ -3,6 +3,7 @@ import csv as _csv 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 @@ -21,6 +22,7 @@ from openpower.decoder.power_enums import ( In3Sel as _In3Sel, OutSel as _OutSel, CRInSel as _CRInSel, + CRIn2Sel as _CRIn2Sel, CROutSel as _CROutSel, LDSTLen as _LDSTLen, LDSTMode as _LDSTMode, @@ -86,22 +88,37 @@ def dataclass(cls, record, keymap=None, typemap=None): @_functools.total_ordering @_dataclasses.dataclass(eq=True, frozen=True) class Opcode: - class Value(int): - def __repr__(self): - if self.bit_length() <= 32: - return f"0x{self:08x}" - else: - return f"0x{self:016x}" + class Integer(int): + def __new__(cls, value): + if isinstance(value, str): + value = int(value, 0) + if not isinstance(value, int): + raise ValueError(value) + + if value.bit_length() > 64: + raise ValueError(value) + + return super().__new__(cls, value) + + def __str__(self): + return super().__repr__() - class Mask(int): def __repr__(self): - if self.bit_length() <= 32: - return f"0x{self:08x}" - else: - return f"0x{self:016x}" + return f"{self:0{self.bit_length()}b}" + + def bit_length(self): + if super().bit_length() > 32: + return 64 + return 32 + + class Value(Integer): + pass + + class Mask(Integer): + pass value: Value - mask: Mask = None + mask: Mask def __lt__(self, other): if not isinstance(other, Opcode): @@ -109,39 +126,41 @@ class Opcode: return ((self.value, self.mask) < (other.value, other.mask)) def __post_init__(self): - (value, mask) = (self.value, self.mask) - - if isinstance(value, Opcode): - if mask is not None: - raise ValueError(mask) - (value, mask) = (value.value, value.mask) - elif isinstance(value, str): - if mask is not None: - raise ValueError(mask) - value = int(value, 0) - - if not isinstance(value, int): - raise ValueError(value) - if mask is None: - mask = value - if not isinstance(mask, int): - raise ValueError(mask) + if self.value.bit_length() != self.mask.bit_length(): + raise ValueError("bit length mismatch") - object.__setattr__(self, "value", self.__class__.Value(value)) - object.__setattr__(self, "mask", self.__class__.Mask(mask)) + def __repr__(self): + def pattern(value, mask, bit_length): + for bit in range(bit_length): + if ((mask & (1 << (bit_length - bit - 1))) == 0): + yield "-" + elif (value & (1 << (bit_length - bit - 1))): + yield "1" + else: + yield "0" + + return "".join(pattern(self.value, self.mask, self.value.bit_length())) class IntegerOpcode(Opcode): def __init__(self, value): - if isinstance(value, str): - value = int(value, 0) - return super().__init__(value=value, mask=None) + if value.startswith("0b"): + mask = int(("1" * len(value[2:])), 2) + else: + mask = 0b111111 + + value = Opcode.Value(value) + mask = Opcode.Mask(mask) + + return super().__init__(value=value, mask=mask) class PatternOpcode(Opcode): - def __init__(self, value): - (pattern, value, mask) = (value, 0, 0) + def __init__(self, pattern): + if not isinstance(pattern, str): + raise ValueError(pattern) + (value, mask) = (0, 0) for symbol in pattern: if symbol not in {"0", "1", "-"}: raise ValueError(pattern) @@ -152,22 +171,8 @@ class PatternOpcode(Opcode): value >>= 1 mask >>= 1 - return super().__init__(value=value, mask=mask) - - -class FieldsOpcode(Opcode): - def __init__(self, fields): - def field(opcode, field): - (value, mask) = opcode - (field, bits) = field - shifts = map(lambda bit: (31 - bit), reversed(tuple(bits))) - for (index, shift) in enumerate(shifts): - bit = ((field & (1 << index)) != 0) - value |= (bit << shift) - mask |= (1 << shift) - return (value, mask) - - (value, mask) = _functools.reduce(field, fields, (0, 0)) + value = Opcode.Value(value) + mask = Opcode.Mask(mask) return super().__init__(value=value, mask=mask) @@ -208,6 +213,7 @@ class PPCRecord: in3: _In3Sel = _In3Sel.NONE out: _OutSel = _OutSel.NONE cr_in: _CRInSel = _CRInSel.NONE + cr_in2: _CRIn2Sel = _CRIn2Sel.NONE cr_out: _CROutSel = _CROutSel.NONE cry_in: _CryIn = _CryIn.ZERO ldst_len: _LDSTLen = _LDSTLen.NONE @@ -229,10 +235,15 @@ class PPCRecord: } @classmethod - def CSV(cls, record, opcode_cls=Opcode): + def CSV(cls, record, opcode_cls): typemap = {field.name:field.type for field in _dataclasses.fields(cls)} typemap["opcode"] = opcode_cls + if record["CR in"] == "BA_BB": + record["cr_in"] = "BA" + record["cr_in2"] = "BB" + del record["CR in"] + flags = set() for flag in frozenset(PPCRecord.Flags): if bool(record.pop(flag, "")): @@ -248,38 +259,11 @@ class PPCRecord: return frozenset(self.comment.split("=")[-1].split("/")) -class PPCMultiRecord(frozenset): - @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) - +class PPCMultiRecord(tuple): def __getattr__(self, attr): - return getattr(self.unified, attr) + if attr == "opcode": + raise AttributeError(attr) + return getattr(self[0], attr) @_dataclasses.dataclass(eq=True, frozen=True) @@ -330,6 +314,7 @@ class SVP64Record: out: _OutSel = _OutSel.NONE out2: _OutSel = _OutSel.NONE cr_in: _CRInSel = _CRInSel.NONE + cr_in2: _CRIn2Sel = _CRIn2Sel.NONE cr_out: _CROutSel = _CROutSel.NONE extra: ExtraMap = ExtraMap() conditions: str = "" @@ -346,11 +331,19 @@ class SVP64Record: @classmethod def CSV(cls, record): - for key in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"): + for key in frozenset({ + "in1", "in2", "in3", "CR in", + "out", "out2", "CR out", + }): value = record[key] if value == "0": record[key] = "NONE" + if record["CR in"] == "BA_BB": + record["cr_in"] = "BA" + record["cr_in2"] = "BB" + del record["CR in"] + extra = [] for idx in range(0, 4): extra.append(record.pop(f"{idx}")) @@ -369,7 +362,7 @@ class SVP64Record: ) if key not in frozenset({ - "in1", "in2", "in3", "cr_in", + "in1", "in2", "in3", "cr_in", "cr_in2", "out", "out2", "cr_out", }): raise KeyError(key) @@ -437,6 +430,9 @@ class BitSel: def __iter__(self): yield from range(self.start, (self.end + 1)) + def __reversed__(self): + return tuple(reversed(tuple(self))) + @property def start(self): return self.__start @@ -477,14 +473,18 @@ class Section: return (bin(self) if self else "None") path: _pathlib.Path - opcode: Opcode bitsel: BitSel suffix: Suffix mode: Mode + opcode: IntegerOpcode = None @classmethod def CSV(cls, record): - return dataclass(cls, record) + typemap = {field.name:field.type for field in _dataclasses.fields(cls)} + if record["opcode"] == "NONE": + typemap["opcode"] = lambda _: None + + return dataclass(cls, record, typemap=typemap) class Fields: @@ -517,16 +517,18 @@ class Fields: class Operand: name: str + def span(self, record): + return record.fields[self.name] + def disassemble(self, insn, record, verbosity=Verbosity.NORMAL, indent=""): raise NotImplementedError -@_dataclasses.dataclass(eq=True, frozen=True) class DynamicOperand(Operand): def disassemble(self, insn, record, verbosity=Verbosity.NORMAL, indent=""): - span = record.fields[self.name] + span = self.span(record=record) if isinstance(insn, SVP64Instruction): span = tuple(map(lambda bit: (bit + 32), span)) value = insn[span] @@ -540,9 +542,21 @@ class DynamicOperand(Operand): yield str(int(value)) -@_dataclasses.dataclass(eq=True, frozen=True) -class ImmediateOperand(DynamicOperand): - pass +class SignedOperand(DynamicOperand): + def disassemble(self, insn, record, + verbosity=Verbosity.NORMAL, indent=""): + span = self.span(record=record) + if isinstance(insn, SVP64Instruction): + span = tuple(map(lambda bit: (bit + 32), span)) + value = insn[span] + + if verbosity >= Verbosity.VERBOSE: + span = map(str, span) + yield f"{indent}{self.name}" + yield f"{indent}{indent}{int(value):0{value.bits}b}" + yield f"{indent}{indent}{', '.join(span)}" + else: + yield str(value.to_signed_int()) @_dataclasses.dataclass(eq=True, frozen=True) @@ -551,7 +565,7 @@ class StaticOperand(Operand): def disassemble(self, insn, record, verbosity=Verbosity.NORMAL, indent=""): - span = record.fields[self.name] + span = self.span(record=record) if isinstance(insn, SVP64Instruction): span = tuple(map(lambda bit: (bit + 32), span)) value = insn[span] @@ -565,17 +579,49 @@ class StaticOperand(Operand): yield str(int(value)) -@_dataclasses.dataclass(eq=True, frozen=True) -class DynamicOperandReg(DynamicOperand): - def spec(self, insn, record, merge): +class ImmediateOperand(DynamicOperand): + pass + + +class NonZeroOperand(DynamicOperand): + def disassemble(self, insn, record, + verbosity=Verbosity.NORMAL, indent=""): + span = self.span(record=record) + if isinstance(insn, SVP64Instruction): + span = tuple(map(lambda bit: (bit + 32), span)) + value = insn[span] + + if verbosity >= Verbosity.VERBOSE: + span = map(str, span) + yield f"{indent}{self.name}" + yield f"{indent}{indent}{int(value):0{value.bits}b}" + yield f"{indent}{indent}{', '.join(span)}" + else: + yield str(int(value) + 1) + + +class RegisterOperand(DynamicOperand): + def sv_spec_enter(self, value, span): + return (value, span) + + def sv_spec_leave(self, value, span, origin_value, origin_span): + return (value, span) + + def spec(self, insn, record): vector = False - span = record.fields[self.name] + span = self.span(record=record) if isinstance(insn, SVP64Instruction): span = tuple(map(lambda bit: (bit + 32), span)) value = insn[span] + span = tuple(map(str, span)) if isinstance(insn, SVP64Instruction): + (origin_value, origin_span) = (value, span) + (value, span) = self.sv_spec_enter(value=value, span=span) + extra_idx = self.extra_idx(record=record) + if extra_idx is _SVExtra.NONE: + return (vector, value, span) if record.etype is _SVEtype.EXTRA3: spec = insn.prefix.rm.extra3[extra_idx] @@ -586,7 +632,6 @@ class DynamicOperandReg(DynamicOperand): if spec != 0: vector = bool(spec[0]) - span = tuple(map(str, span)) spec_span = spec.__class__ if record.etype is _SVEtype.EXTRA3: spec_span = tuple(map(str, spec_span[1, 2])) @@ -602,9 +647,22 @@ class DynamicOperandReg(DynamicOperand): else: raise ValueError(record.etype) - (value, span) = merge(vector, value, span, spec, spec_span) + vector_shift = (2 + (5 - value.bits)) + scalar_shift = value.bits + spec_shift = (5 - value.bits) - span = tuple(map(str, span)) + bits = (len(span) + len(spec_span)) + value = _SelectableInt(value=value.value, bits=bits) + spec = _SelectableInt(value=spec.value, bits=bits) + if vector: + value = ((value << vector_shift) | (spec << spec_shift)) + span = (span + spec_span + ((spec_shift * ('{0}',)))) + else: + value = ((spec << scalar_shift) | value) + span = ((spec_shift * ('{0}',)) + spec_span + span) + + (value, span) = self.sv_spec_leave(value=value, span=span, + origin_value=origin_value, origin_span=origin_span) return (vector, value, span) @@ -614,7 +672,7 @@ class DynamicOperandReg(DynamicOperand): def extra_idx(self, record): for key in frozenset({ - "in1", "in2", "in3", "cr_in", + "in1", "in2", "in3", "cr_in", "cr_in2", "out", "out2", "cr_out", }): extra_reg = record.svp64.extra_reg(key=key) @@ -628,7 +686,8 @@ class DynamicOperandReg(DynamicOperand): (vector, value, span) = self.spec(insn=insn, record=record) if verbosity >= Verbosity.VERBOSE: - yield f"{indent}{self.name}" + 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}{', '.join(span)}" if isinstance(insn, SVP64Instruction): @@ -638,34 +697,12 @@ class DynamicOperandReg(DynamicOperand): else: etype = repr(record.etype).lower() yield f"{indent}{indent}{etype}{extra_idx!r}" - yield f"{indent}type" - yield f"{indent}{indent}{'vector' if vector else 'scalar'}" else: vector = "*" if vector else "" yield f"{vector}{prefix}{int(value)}" -class DynamicOperandGPRFPR(DynamicOperandReg): - def spec(self, insn, record): - def merge(vector, value, span, spec, spec_span): - bits = (len(span) + len(spec_span)) - value = _SelectableInt(value=value.value, bits=bits) - spec = _SelectableInt(value=spec.value, bits=bits) - if vector: - value = ((value << 2) | spec) - span = (span + spec_span) - else: - value = ((spec << 5) | value) - span = (spec_span + span) - - value = _SelectableInt(value=value, bits=bits) - - return (value, span) - - return super().spec(insn=insn, record=record, merge=merge) - - -class DynamicOperandGPR(DynamicOperandGPRFPR): +class GPROperand(RegisterOperand): def disassemble(self, insn, record, verbosity=Verbosity.NORMAL, indent=""): prefix = "" if (verbosity <= Verbosity.SHORT) else "r" @@ -674,8 +711,7 @@ class DynamicOperandGPR(DynamicOperandGPRFPR): verbosity=verbosity, indent=indent) -@_dataclasses.dataclass(eq=True, frozen=True) -class DynamicOperandFPR(DynamicOperandGPRFPR): +class FPROperand(RegisterOperand): def disassemble(self, insn, record, verbosity=Verbosity.NORMAL, indent=""): prefix = "" if (verbosity <= Verbosity.SHORT) else "f" @@ -684,28 +720,44 @@ class DynamicOperandFPR(DynamicOperandGPRFPR): verbosity=verbosity, indent=indent) -@_dataclasses.dataclass(eq=True, frozen=True) -class DynamicOperandTargetAddr(DynamicOperandReg): +class CR3Operand(RegisterOperand): + pass + + +class CR5Operand(RegisterOperand): + def sv_spec_enter(self, value, span): + value = _SelectableInt(value=(value.value >> 2), bits=3) + return (value, span) + + def sv_spec_leave(self, value, span, origin_value, origin_span): + value = _selectconcat(value, origin_value[3:5]) + span += origin_span + return (value, span) + + +class TargetAddrOperand(RegisterOperand): def disassemble(self, insn, record, field, verbosity=Verbosity.NORMAL, indent=""): - span = record.fields[field] + span = self.span(record=record) if isinstance(insn, SVP64Instruction): span = tuple(map(lambda bit: (bit + 32), span)) value = insn[span] if verbosity >= Verbosity.VERBOSE: span = tuple(map(str, span)) - yield f"{indent}{self.name}" - yield f"{indent}{indent}{int(value):0{value.bits}b}00" - yield f"{indent}{indent}{', '.join(span + ('{0}', '{0}'))}" - yield f"{indent}{indent}target_addr = EXTS({field} || 0b00))" + yield f"{indent}{self.name} = EXTS({field} || 0b00))" + yield f"{indent}{indent}{field}" + yield f"{indent}{indent}{indent}{int(value):0{value.bits}b}00" + yield f"{indent}{indent}{indent}{', '.join(span + ('{0}', '{0}'))}" else: - yield hex(int(_selectconcat(value, - _SelectableInt(value=0b00, bits=2)))) + yield hex(_selectconcat(value, + _SelectableInt(value=0b00, bits=2)).to_signed_int()) -@_dataclasses.dataclass(eq=True, frozen=True) -class DynamicOperandTargetAddrLI(DynamicOperandTargetAddr): +class TargetAddrOperandLI(TargetAddrOperand): + def span(self, record): + return record.fields["LI"] + def disassemble(self, insn, record, verbosity=Verbosity.NORMAL, indent=""): return super().disassemble(field="LI", @@ -713,7 +765,10 @@ class DynamicOperandTargetAddrLI(DynamicOperandTargetAddr): verbosity=verbosity, indent=indent) -class DynamicOperandTargetAddrBD(DynamicOperandTargetAddr): +class TargetAddrOperandBD(TargetAddrOperand): + def span(self, record): + return record.fields["BD"] + def disassemble(self, insn, record, verbosity=Verbosity.NORMAL, indent=""): return super().disassemble(field="BD", @@ -721,17 +776,71 @@ class DynamicOperandTargetAddrBD(DynamicOperandTargetAddr): verbosity=verbosity, indent=indent) +class DOperandDX(SignedOperand): + def span(self, record): + operands = map(DynamicOperand, ("d0", "d1", "d2")) + spans = map(lambda operand: operand.span(record=record), operands) + return sum(spans, tuple()) + + def disassemble(self, insn, record, + verbosity=Verbosity.NORMAL, indent=""): + span = self.span(record=record) + if isinstance(insn, SVP64Instruction): + span = tuple(map(lambda bit: (bit + 32), span)) + value = insn[span] + + if verbosity >= Verbosity.VERBOSE: + yield f"{indent}D" + mapping = { + "d0": "[0:9]", + "d1": "[10:15]", + "d2": "[16]", + } + for (subname, subspan) in mapping.items(): + operand = DynamicOperand(name=subname) + span = operand.span(record=record) + if isinstance(insn, SVP64Instruction): + span = tuple(map(lambda bit: (bit + 32), 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}{', '.join(span)}" + else: + yield str(value.to_signed_int()) + + class Operands(tuple): 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}, + custom_insns = { + "b": {"target_addr": TargetAddrOperandLI}, + "ba": {"target_addr": TargetAddrOperandLI}, + "bl": {"target_addr": TargetAddrOperandLI}, + "bla": {"target_addr": TargetAddrOperandLI}, + "bc": {"target_addr": TargetAddrOperandBD}, + "bca": {"target_addr": TargetAddrOperandBD}, + "bcl": {"target_addr": TargetAddrOperandBD}, + "bcla": {"target_addr": TargetAddrOperandBD}, + "addpcis": {"D": DOperandDX}, + "fishmv": {"D": DOperandDX}, + "fmvis": {"D": DOperandDX}, + } + custom_fields = { + "SVi": NonZeroOperand, + "SVd": NonZeroOperand, + "SVxd": NonZeroOperand, + "SVyd": NonZeroOperand, + "SVzd": NonZeroOperand, + "BD": SignedOperand, + "D": SignedOperand, + "DQ": SignedOperand, + "DS": SignedOperand, + "SI": SignedOperand, + "IB": SignedOperand, + "LI": SignedOperand, + "SIM": SignedOperand, + "SVD": SignedOperand, + "SVDS": SignedOperand, } operands = [] @@ -753,15 +862,21 @@ class Operands(tuple): 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 custom_fields: + dynamic_cls = custom_fields[operand] + if insn in custom_insns and operand in custom_insns[insn]: + dynamic_cls = custom_insns[insn][operand] if operand in _RegType.__members__: regtype = _RegType[operand] if regtype is _RegType.GPR: - dynamic_cls = DynamicOperandGPR + dynamic_cls = GPROperand elif regtype is _RegType.FPR: - dynamic_cls = DynamicOperandFPR + dynamic_cls = FPROperand + if regtype is _RegType.CR_BIT: # 5-bit + dynamic_cls = CR5Operand + if regtype is _RegType.CR_REG: # actually CR Field, 3-bit + dynamic_cls = CR3Operand operand = dynamic_cls(name=operand) operands.append(operand) @@ -791,6 +906,24 @@ class Operands(tuple): yield operand +class PCode: + def __init__(self, iterable): + self.__pcode = tuple(iterable) + return super().__init__() + + def __iter__(self): + yield from self.__pcode + + def __repr__(self): + return self.__pcode.__repr__() + + +@_dataclasses.dataclass(eq=True, frozen=True) +class MarkdownRecord: + pcode: PCode + operands: Operands + + @_functools.total_ordering @_dataclasses.dataclass(eq=True, frozen=True) class Record: @@ -798,27 +931,49 @@ class Record: section: Section ppc: PPCRecord fields: Fields - operands: Operands + mdwn: MarkdownRecord svp64: SVP64Record = None def __lt__(self, other): if not isinstance(other, Record): return NotImplemented - return (self.opcode < other.opcode) + return (min(self.opcodes) < min(other.opcodes)) - @cached_property - def opcode(self): - fields = [] - if self.section.opcode: - fields += [(self.section.opcode.value, BitSel((0, 5)))] - fields += [(self.ppc.opcode.value, self.section.bitsel)] - else: - fields += [(self.ppc.opcode.value, self.section.bitsel)] + @property + def opcodes(self): + def opcode(ppc): + value = ([0] * 32) + mask = ([0] * 32) - for operand in self.operands.static: - fields += [(operand.value, self.fields[operand.name])] + PO = self.section.opcode + if PO is not None: + for (src, dst) in enumerate(reversed(BitSel((0, 5)))): + value[dst] = int((PO.value & (1 << src)) != 0) + mask[dst] = int((PO.mask & (1 << src)) != 0) - return FieldsOpcode(fields) + XO = ppc.opcode + for (src, dst) in enumerate(reversed(self.section.bitsel)): + value[dst] = int((XO.value & (1 << src)) != 0) + mask[dst] = int((XO.mask & (1 << src)) != 0) + + for operand in self.mdwn.operands.static: + for (src, dst) in enumerate(reversed(operand.span(record=self))): + value[dst] = int((operand.value & (1 << src)) != 0) + mask[dst] = 1 + + value = Opcode.Value(int(("".join(map(str, value))), 2)) + mask = Opcode.Mask(int(("".join(map(str, mask))), 2)) + + return Opcode(value=value, mask=mask) + + return tuple(sorted(map(opcode, self.ppc))) + + def match(self, key): + for opcode in self.opcodes: + if ((opcode.value & opcode.mask) == + (key & opcode.mask)): + return True + return False @property def function(self): @@ -850,6 +1005,10 @@ class Record: def cr_in(self): return self.ppc.cr_in + @property + def cr_in2(self): + return self.ppc.cr_in2 + @property def cr_out(self): return self.ppc.cr_out @@ -899,6 +1058,16 @@ class Instruction(_Mapping): def __hash__(self): return hash(int(self)) + def __getitem__(self, key): + return self.storage.__getitem__(key) + + def __setitem__(self, key, value): + return self.storage.__setitem__(key, value) + + def bytes(self, byteorder="little"): + nr_bytes = (self.storage.bits // 8) + return int(self).to_bytes(nr_bytes, byteorder=byteorder) + def record(self, db): record = db[self] if record is None: @@ -929,7 +1098,7 @@ class Instruction(_Mapping): imm = False imm_name = "" imm_value = "" - for operand in record.operands.dynamic: + for operand in record.mdwn.operands.dynamic: name = operand.name dis = operand.disassemble(insn=self, record=record, verbosity=min(verbosity, Verbosity.NORMAL)) @@ -947,7 +1116,7 @@ class Instruction(_Mapping): def static_operands(self, db): record = self.record(db=db) - for operand in record.operands.static: + for operand in record.mdwn.operands.static: yield (operand.name, operand.value) def disassemble(self, db, @@ -972,14 +1141,6 @@ class WordInstruction(Instruction): bits.append(bit) return "".join(map(str, bits)) - def opcode(self, db): - record = self.record(db=db) - return f"0x{record.opcode.value:08x}" - - def mask(self, db): - record = self.record(db=db) - return f"0x{record.opcode.mask:08x}" - def disassemble(self, db, byteorder="little", verbosity=Verbosity.NORMAL): @@ -991,7 +1152,7 @@ class WordInstruction(Instruction): blob = " ".join(map(lambda byte: f"{byte:02x}", blob)) blob += " " - record = self.record(db=db) + record = db[self] if record is None: yield f"{blob}.long 0x{integer:08x}" return @@ -1007,20 +1168,20 @@ class WordInstruction(Instruction): indent = (" " * 4) binary = self.binary spec = self.spec(db=db, prefix="") - opcode = self.opcode(db=db) - mask = self.mask(db=db) yield f"{indent}spec" yield f"{indent}{indent}{spec}" + yield f"{indent}pcode" + for stmt in record.mdwn.pcode: + yield f"{indent}{indent}{stmt}" 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: + yield f"{indent}opcodes" + for opcode in record.opcodes: + yield f"{indent}{indent}{opcode!r}" + for operand in record.mdwn.operands: yield from operand.disassemble(insn=self, record=record, verbosity=verbosity, indent=indent) yield "" @@ -1051,185 +1212,11 @@ class PrefixedInstruction(Instruction): (prefix, suffix) = map(transform, (prefix, suffix)) value = _selectconcat(prefix, suffix) - return super().integer(value=value) + return super().integer(bits=64, value=value) 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 Extra(_Mapping): @@ -1277,12 +1264,7 @@ class Extra3(Extra): self[key].assign(value) -class RM(_Mapping): - class Mode(Mode): - normal: NormalMode - ldst_imm: LDSTImmMode - ldst_idx: LDSTIdxMode - +class BaseRM(_Mapping): _: _Field = range(24) mmode: _Field = (0,) mask: _Field = range(1, 4) @@ -1296,142 +1278,420 @@ class RM(_Mapping): extra2: Extra2.remap(range(10, 19)) extra3: Extra3.remap(range(10, 19)) + def disassemble(self, verbosity=Verbosity.NORMAL): + if verbosity >= Verbosity.VERBOSE: + indent = (" " * 4) + for (name, value, members) in self.traverse(path="RM"): + yield f"{name}" + yield f"{indent}{int(value):0{value.bits}b}" + yield f"{indent}{', '.join(map(str, members))}" -class SVP64Instruction(PrefixedInstruction): - """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/""" - class Prefix(PrefixedInstruction.Prefix): - id: _Field = (7, 9) - rm: RM.remap((6, 8) + tuple(range(10, 32))) - prefix: Prefix +class NormalRM(BaseRM): + class simple(BaseRM): + """normal: simple mode""" + dz: BaseRM.mode[3] + sz: BaseRM.mode[4] - @property - def binary(self): - bits = [] - for idx in range(64): - bit = int(self[idx]) - bits.append(bit) - return "".join(map(str, bits)) + class smr(BaseRM): + """normal: scalar reduce mode (mapreduce), SUBVL=1""" + RG: BaseRM.mode[4] - def opcode(self, db): - return self.suffix.opcode(db=db) + class pmr(BaseRM): + """normal: parallel reduce mode (mapreduce), SUBVL=1""" + pass - def mask(self, db): - return self.suffix.mask(db=db) + class svmr(BaseRM): + """normal: subvector reduce mode, SUBVL>1""" + SVM: BaseRM.mode[3] + + class pu(BaseRM): + """normal: Pack/Unpack mode, SUBVL>1""" + SVM: BaseRM.mode[3] + + class ffrc1(BaseRM): + """normal: Rc=1: ffirst CR sel""" + inv: BaseRM.mode[2] + CR: BaseRM.mode[3, 4] + + class ffrc0(BaseRM): + """normal: Rc=0: ffirst z/nonz""" + inv: BaseRM.mode[2] + VLi: BaseRM.mode[3] + RC1: BaseRM.mode[4] + + class sat(BaseRM): + """normal: sat mode: N=0/1 u/s, SUBVL=1""" + N: BaseRM.mode[2] + dz: BaseRM.mode[3] + sz: BaseRM.mode[4] + + class satx(BaseRM): + """normal: sat mode: N=0/1 u/s, SUBVL>1""" + N: BaseRM.mode[2] + zz: BaseRM.mode[3] + dz: BaseRM.mode[3] + sz: BaseRM.mode[3] + + class satpu(BaseRM): + """normal: Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1""" + N: BaseRM.mode[2] + zz: BaseRM.mode[3] + dz: BaseRM.mode[3] + sz: BaseRM.mode[3] + + class prrc1(BaseRM): + """normal: Rc=1: pred-result CR sel""" + inv: BaseRM.mode[2] + CR: BaseRM.mode[3, 4] + + class prrc0(BaseRM): + """normal: Rc=0: pred-result z/nonz""" + inv: BaseRM.mode[2] + zz: BaseRM.mode[3] + RC1: BaseRM.mode[4] + dz: BaseRM.mode[3] + sz: BaseRM.mode[3] - def mode(self, db): - record = self.record(db=db) + simple: simple + smr: smr + pmr: pmr + svmr: svmr + pu: pu + ffrc1: ffrc1 + ffrc0: ffrc0 + sat: sat + satx: satx + satpu: satpu + prrc1: prrc1 + prrc0: prrc0 - Rc = False - if record.operands["Rc"] is not None: - Rc = bool(self[record.fields["Rc"]]) - record = self.record(db=db) - subvl = self.prefix.rm.subvl - mode = self.prefix.rm.mode - sel = mode.sel +class LDSTImmRM(BaseRM): + class simple(BaseRM): + """ld/st immediate: simple mode""" + zz: BaseRM.mode[3] + els: BaseRM.mode[4] + dz: BaseRM.mode[3] + sz: BaseRM.mode[3] + + class spu(BaseRM): + """ld/st immediate: Structured Pack/Unpack""" + zz: BaseRM.mode[3] + els: BaseRM.mode[4] + dz: BaseRM.mode[3] + sz: BaseRM.mode[3] + + class ffrc1(BaseRM): + """ld/st immediate: Rc=1: ffirst CR sel""" + inv: BaseRM.mode[2] + CR: BaseRM.mode[3, 4] + + class ffrc0(BaseRM): + """ld/st immediate: Rc=0: ffirst z/nonz""" + inv: BaseRM.mode[2] + els: BaseRM.mode[3] + RC1: BaseRM.mode[4] + + class sat(BaseRM): + """ld/st immediate: sat mode: N=0/1 u/s""" + N: BaseRM.mode[2] + zz: BaseRM.mode[3] + els: BaseRM.mode[4] + dz: BaseRM.mode[3] + sz: BaseRM.mode[3] + + class prrc1(BaseRM): + """ld/st immediate: Rc=1: pred-result CR sel""" + inv: BaseRM.mode[2] + CR: BaseRM.mode[3, 4] + + class prrc0(BaseRM): + """ld/st immediate: Rc=0: pred-result z/nonz""" + inv: BaseRM.mode[2] + els: BaseRM.mode[3] + RC1: BaseRM.mode[4] + + simple: simple + spu: spu + ffrc1: ffrc1 + ffrc0: ffrc0 + sat: sat + prrc1: prrc1 + prrc0: prrc0 + + +class LDSTIdxRM(BaseRM): + class simple(BaseRM): + """ld/st index: simple mode""" + SEA: BaseRM.mode[2] + sz: BaseRM.mode[3] + dz: BaseRM.mode[3] + + class stride(BaseRM): + """ld/st index: strided (scalar only source)""" + SEA: BaseRM.mode[2] + dz: BaseRM.mode[3] + sz: BaseRM.mode[4] + + class sat(BaseRM): + """ld/st index: sat mode: N=0/1 u/s""" + N: BaseRM.mode[2] + dz: BaseRM.mode[3] + sz: BaseRM.mode[4] + + class prrc1(BaseRM): + """ld/st index: Rc=1: pred-result CR sel""" + inv: BaseRM.mode[2] + CR: BaseRM.mode[3, 4] + + class prrc0(BaseRM): + """ld/st index: Rc=0: pred-result z/nonz""" + inv: BaseRM.mode[2] + zz: BaseRM.mode[3] + RC1: BaseRM.mode[4] + dz: BaseRM.mode[3] + sz: BaseRM.mode[3] + + simple: simple + stride: stride + sat: sat + prrc1: prrc1 + prrc0: prrc0 + + +class CROpRM(BaseRM): + class simple(BaseRM): + """cr_op: simple mode""" + sz: BaseRM[6] + SNZ: BaseRM[7] + RG: BaseRM[20] + dz: BaseRM[22] + + class smr(BaseRM): + """cr_op: scalar reduce mode (mapreduce), SUBVL=1""" + sz: BaseRM[6] + SNZ: BaseRM[7] + RG: BaseRM[20] + + class svmr(BaseRM): + """cr_op: subvector reduce mode, SUBVL>1""" + zz: BaseRM[6] + SNZ: BaseRM[7] + RG: BaseRM[20] + SVM: BaseRM[22] + dz: BaseRM[6] + sz: BaseRM[6] + + class reserved(BaseRM): + """cr_op: reserved""" + zz: BaseRM[6] + SNZ: BaseRM[7] + RG: BaseRM[20] + dz: BaseRM[6] + sz: BaseRM[6] + + class ff3(BaseRM): + """cr_op: ffirst 3-bit mode""" + zz: BaseRM[6] + SNZ: BaseRM[7] + VLI: BaseRM[20] + inv: BaseRM[21] + CR: BaseRM[22, 23] + dz: BaseRM[6] + sz: BaseRM[6] + + class ff5(BaseRM): + """cr_op: ffirst 5-bit mode""" + zz: BaseRM[6] + SNZ: BaseRM[7] + VLI: BaseRM[20] + inv: BaseRM[21] + dz: BaseRM[22] + dz: BaseRM[6] + sz: BaseRM[6] + + simple: simple + smr: smr + svmr: svmr + reserved: reserved + ff3: ff3 + ff5: ff5 + + +class BranchBaseRM(BaseRM): + ALL: BaseRM[4] + SNZ: BaseRM[5] + SL: BaseRM[17] + SLu: BaseRM[18] + LRu: BaseRM[22] + sz: BaseRM[23] + + +class BranchRM(BranchBaseRM): + class simple(BranchBaseRM): + """branch: simple mode""" + pass + + class vls(BranchBaseRM): + """branch: VLSET mode""" + VSb: BaseRM[7] + VLI: BaseRM[21] + + class ctr(BranchBaseRM): + """branch: CTR-test mode""" + CTi: BaseRM[6] + + class ctrvls(vls, ctr): + """branch: CTR-test+VLSET mode""" + pass + + +class RM(BaseRM): + normal: NormalRM + ldst_imm: LDSTImmRM + ldst_idx: LDSTIdxRM + cr_op: CROpRM + + def select(self, record, Rc): + rm = self if record.svp64.mode is _SVMode.NORMAL: - mode = mode.normal - if sel == 0b00: - if mode[2] == 0b0: - mode = mode.simple + rm = rm.normal + if rm.mode[0:2] == 0b00: + if rm.mode[2] == 0b0: + rm = rm.simple else: - if subvl == 0b00: - if mode[3] == 0b0: - mode = mode.smr + if self.subvl == 0b00: + if rm.mode[3] == 0b0: + rm = rm.smr else: - mode = mode.pmr + rm = rm.pmr else: - if mode[4] == 0b0: - mode = mode.svmr + if rm.mode[4] == 0b0: + rm = rm.svmr else: - mode = mode.pu - elif sel == 0b01: + rm = rm.pu + elif rm.mode[0:2] == 0b01: if Rc: - mode = mode.ffrc1 + rm = rm.ffrc1 else: - mode = mode.ffrc0 - elif sel == 0b10: - if subvl == 0b00: - mode = mode.sat + rm = rm.ffrc0 + elif rm.mode[0:2] == 0b10: + if self.subvl == 0b00: + rm = rm.sat else: - if mode[4]: - mode = mode.satx + if rm.mode[4]: + rm = rm.satx else: - mode = mode.satpu - elif sel == 0b11: + rm = rm.satpu + elif rm.mode[0:2] == 0b11: if Rc: - mode = mode.prrc1 + rm = rm.prrc1 else: - mode = mode.prrc0 + rm = rm.prrc0 + elif record.svp64.mode is _SVMode.LDST_IMM: - mode = mode.ldst_imm - if sel == 0b00: - if mode[2] == 0b0: - mode = mode.simple + rm = rm.ldst_imm + if rm.mode[0:2] == 0b00: + if rm.mode[2] == 0b0: + rm = rm.simple else: - mode = mode.spu - elif sel == 0b01: + rm = rm.spu + elif rm.mode[0:2] == 0b01: if Rc: - mode = mode.ffrc1 + rm = rm.ffrc1 else: - mode = mode.ffrc0 - elif sel == 0b10: - mode = mode.sat - elif sel == 0b11: + rm = rm.ffrc0 + elif rm.mode[0:2] == 0b10: + rm = rm.sat + elif rm.mode[0:2] == 0b11: if Rc: - mode = mode.prrc1 + rm = rm.prrc1 else: - mode = mode.prrc0 + rm = rm.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: + rm = rm.ldst_idx + if rm.mode[0:2] == 0b00: + rm = rm.simple + elif rm.mode[0:2] == 0b01: + rm = rm.stride + elif rm.mode[0:2] == 0b10: + rm = rm.sat + elif rm.mode[0:2] == 0b11: if Rc: - mode = mode.prrc1 + rm = rm.prrc1 else: - mode = mode.prrc0 - - modes = { - NormalMode.simple: "normal: simple", - NormalMode.smr: "normal: smr", - NormalMode.pmr: "normal: pmr", - NormalMode.svmr: "normal: svmr", - NormalMode.pu: "normal: pu", - NormalMode.ffrc1: "normal: ffrc1", - NormalMode.ffrc0: "normal: ffrc0", - NormalMode.sat: "normal: sat", - NormalMode.satx: "normal: satx", - NormalMode.satpu: "normal: satpu", - NormalMode.prrc1: "normal: prrc1", - NormalMode.prrc0: "normal: prrc0", - LDSTImmMode.simple: "ld/st imm: simple", - LDSTImmMode.spu: "ld/st imm: spu", - LDSTImmMode.ffrc1: "ld/st imm: ffrc1", - LDSTImmMode.ffrc0: "ld/st imm: ffrc0", - LDSTImmMode.sat: "ld/st imm: sat", - LDSTImmMode.prrc1: "ld/st imm: prrc1", - LDSTImmMode.prrc0: "ld/st imm: prrc0", - LDSTIdxMode.simple: "ld/st idx simple", - LDSTIdxMode.stride: "ld/st idx stride", - LDSTIdxMode.sat: "ld/st idx sat", - LDSTIdxMode.prrc1: "ld/st idx prrc1", - LDSTIdxMode.prrc0: "ld/st idx prrc0", - } - for (cls, desc) in modes.items(): - if isinstance(mode, cls): - return (mode, desc) + rm = rm.prrc0 + + elif record.svp64.mode is _SVMode.CROP: + rm = rm.cr_op + if rm[19] == 0b0: + if rm[21] == 0b0: + rm = rm.simple + else: + if self.subvl == 0: + rm = rm.smr + else: + if rm[23] == 0b0: + rm = rm.svmr + else: + rm = rm.reserved + else: + regtype = None + for idx in range(0, 4): + for entry in record.svp64.extra[idx]: + if entry.regtype is _SVExtraRegType.DST: + if regtype is not None: + raise ValueError(record.svp64) + regtype = _RegType(entry.reg) + if regtype is _RegType.CR_REG: + rm = rm.ff5 + elif regtype is _RegType.CR_BIT: + rm = rm.ff3 + else: + raise ValueError(record.svp64) - if record.svp64.mode is _SVMode.BRANCH: - return (self.prefix.rm.mode, "branch") + elif record.svp64.mode is _SVMode.BRANCH: + if rm[19] == 0b0: + if rm[20] == 0b0: + rm = rm.simple + else: + rm = rm.vls + else: + if rm[20] == 0b0: + rm = rm.ctr + else: + rm = rm.ctrvls + + if rm.__class__ is self.__class__: + raise ValueError(self) + + return rm + + +class SVP64Instruction(PrefixedInstruction): + """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/""" + class Prefix(PrefixedInstruction.Prefix): + id: _Field = (7, 9) + rm: RM.remap((6, 8) + tuple(range(10, 32))) + + prefix: Prefix + + def record(self, db): + record = db[self.suffix] + if record is None: + raise KeyError(self) + return record - raise ValueError(self) + @property + def binary(self): + bits = [] + for idx in range(64): + bit = int(self[idx]) + bits.append(bit) + return "".join(map(str, bits)) def disassemble(self, db, byteorder="little", @@ -1444,9 +1704,9 @@ class SVP64Instruction(PrefixedInstruction): blob = " ".join(map(lambda byte: f"{byte:02x}", blob)) return f"{blob} " + record = self.record(db=db) blob_prefix = blob(int(self.prefix)) blob_suffix = blob(int(self.suffix)) - record = self.record(db=db) 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}" @@ -1458,18 +1718,24 @@ class SVP64Instruction(PrefixedInstruction): yield f"{blob_prefix}sv.{record.name} {','.join(operands)}" else: yield f"{blob_prefix}{record.name}" - yield f"{blob_suffix}" + if blob_suffix: + yield f"{blob_suffix}" - (mode, mode_desc) = self.mode(db=db) + Rc = False + if record.mdwn.operands["Rc"] is not None: + Rc = bool(self.suffix[record.fields["Rc"]]) + rm = self.prefix.rm.select(record=record, Rc=Rc) if verbosity >= Verbosity.VERBOSE: indent = (" " * 4) binary = self.binary spec = self.spec(db=db, prefix="sv.") - opcode = self.opcode(db=db) - mask = self.mask(db=db) + yield f"{indent}spec" yield f"{indent}{indent}{spec}" + yield f"{indent}pcode" + for stmt in record.mdwn.pcode: + yield f"{indent}{indent}{stmt}" yield f"{indent}binary" yield f"{indent}{indent}[0:8] {binary[0:8]}" yield f"{indent}{indent}[8:16] {binary[8:16]}" @@ -1479,16 +1745,16 @@ class SVP64Instruction(PrefixedInstruction): 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: + yield f"{indent}opcodes" + for opcode in record.opcodes: + yield f"{indent}{indent}{opcode!r}" + for operand in record.mdwn.operands: yield from operand.disassemble(insn=self, record=record, verbosity=verbosity, indent=indent) - - yield f"{indent}mode" - yield f"{indent}{indent}{mode_desc}" + yield f"{indent}RM" + yield f"{indent}{indent}{rm.__doc__}" + for line in rm.disassemble(verbosity=verbosity): + yield f"{indent}{indent}{line}" yield "" @@ -1511,13 +1777,20 @@ class MarkdownDatabase: (dynamic, *static) = desc.regs operands.extend(dynamic) operands.extend(static) - db[name] = Operands(insn=name, iterable=operands) + pcode = PCode(iterable=desc.pcode) + operands = Operands(insn=name, iterable=operands) + db[name] = MarkdownRecord(pcode=pcode, operands=operands) + self.__db = db + return super().__init__() def __iter__(self): yield from self.__db.items() + def __contains__(self, key): + return self.__db.__contains__(key) + def __getitem__(self, key): return self.__db.__getitem__(key) @@ -1563,67 +1836,64 @@ class PPCDatabase: for insn in parse(stream, factory): records[section][insn.comment].add(insn) - db = dd(set) + sections = dd(set) for (section, group) in records.items(): for records in group.values(): - db[section].add(PPCMultiRecord(records)) + sections[section].add(PPCMultiRecord(records)) + + db = {} + for (section, records) in sections.items(): + for record in records: + def exact_match(names): + for name in names: + if name in mdwndb: + yield name + + def Rc_match(names): + for name in names: + if f"{name}." in mdwndb: + yield f"{name}." + yield name + + def LK_match(names): + if "lk" not in record.flags: + yield from names + return + + for name in names: + if f"{name}l" in mdwndb: + yield f"{name}l" + yield name + + def AA_match(names): + if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}: + yield from names + return + + for name in names: + operands = mdwndb[name].operands["AA"] + if ((operands is not None) and + (f"{name}a" in mdwndb)): + yield f"{name}a" + yield name + + def reductor(names, match): + return match(names) + + matches = (exact_match, Rc_match, LK_match, AA_match) + + names = _functools.reduce(reductor, matches, record.names) + for name in names: + db[name] = (section, record) self.__db = db self.__mdwndb = mdwndb return super().__init__() + @_functools.lru_cache(maxsize=512, typed=False) 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: - if exact_match(key, record): - return (section, record) - - for record in records: - if (Rc_match(key, record) or - LK_match(key, record) or - AA_match(key, record)): - return (section, record) - - return (None, None) + return self.__db.get(key, (None, None)) class SVP64Database: @@ -1658,14 +1928,16 @@ class SVP64Database: class Database: def __init__(self, root): root = _pathlib.Path(root) - mdwndb = MarkdownDatabase() fieldsdb = FieldsDatabase() ppcdb = PPCDatabase(root=root, mdwndb=mdwndb) svp64db = SVP64Database(root=root, ppcdb=ppcdb) db = set() - for (name, operands) in mdwndb: + names = {} + opcodes = _collections.defaultdict(set) + + for (name, mdwn) in mdwndb: (section, ppc) = ppcdb[name] if ppc is None: continue @@ -1673,10 +1945,17 @@ class Database: fields = fieldsdb[ppc.form] record = Record(name=name, section=section, ppc=ppc, svp64=svp64, - operands=operands, fields=fields) + mdwn=mdwn, fields=fields) db.add(record) + names[record.name] = record + PO = section.opcode + if PO is None: + PO = ppc[0].opcode + opcodes[PO.value].add(record) - self.__db = tuple(sorted(db)) + self.__db = db + self.__names = names + self.__opcodes = opcodes return super().__init__() @@ -1694,18 +1973,12 @@ class Database: def __getitem__(self, key): if isinstance(key, (int, Instruction)): key = int(key) - for record in self: - opcode = record.opcode - if ((opcode.value & opcode.mask) == - (key & opcode.mask)): - return record - return None - elif isinstance(key, Opcode): - for record in self: - if record.opcode == key: - return record + XO = int(_SelectableInt(value=int(key), bits=32)[0:6]) + for record in self.__opcodes[XO]: + if record.match(key=key): + return record + elif isinstance(key, str): - for record in self: - if record.name == key: - return record + return self.__names[key] + return None