From 08b9fcb30e4caae40a37532e4a351b9b980289d6 Mon Sep 17 00:00:00 2001 From: Dmitry Selyutin Date: Thu, 15 Sep 2022 02:04:35 +0300 Subject: [PATCH] sv_binutils_fptrans: fptrans binutils generator --- src/openpower/sv/sv_binutils_fptrans.py | 196 ++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 src/openpower/sv/sv_binutils_fptrans.py diff --git a/src/openpower/sv/sv_binutils_fptrans.py b/src/openpower/sv/sv_binutils_fptrans.py new file mode 100644 index 00000000..9208cdf4 --- /dev/null +++ b/src/openpower/sv/sv_binutils_fptrans.py @@ -0,0 +1,196 @@ +import argparse as _argparse +import dataclasses as _dataclasses +import enum as _enum +import functools as _functools +import operator as _operator + +from openpower.decoder.power_enums import ( + FPTRANS_INSNS as _FPTRANS_INSNS, + Enum, + find_wiki_dir as _find_wiki_dir, +) +from openpower.decoder.selectable_int import ( + SelectableInt as _SelectableInt, +) +from openpower.decoder.power_insn import ( + Database as _Database, + StaticOperand as _StaticOperand, + WordInstruction as _WordInstruction, +) + + +@_dataclasses.dataclass(eq=True, frozen=True) +class StaticOperand: + name: str + value: int + span: tuple + + +@_dataclasses.dataclass(eq=True, frozen=True) +class DynamicOperand: + name: str + span: tuple + + +@_functools.total_ordering +@_dataclasses.dataclass(eq=True, frozen=True) +class Entry: + name: str + static_operands: tuple + dynamic_operands: tuple + + def __lt__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return ((self.PO, self.XO, self.Rc) < + (other.PO, other.XO, other.Rc)) + + @property + def PO(self): + for operand in self.static_operands: + if operand.name == "PO": + return operand.value + raise ValueError(self) + + @property + def XO(self): + for operand in self.static_operands: + if operand.name == "XO": + return operand.value + raise ValueError(self) + + @property + def Rc(self): + for operand in self.static_operands: + if operand.name == "Rc": + return operand.value + raise ValueError(self) + + +def collect(db): + fptrans = tuple(_FPTRANS_INSNS) + fptrans_Rc = tuple(map(lambda name: f"{name}.", fptrans)) + + def fptrans_match(insn): + return ((insn.name in fptrans) or (insn.name in fptrans_Rc)) + + for record in filter(fptrans_match, db): + if len(record.opcodes) > 1: + raise NotImplementedError(record.opcodes) + PO = record.section.opcode + if PO is None: + PO = tuple(record.ppc)[0].opcode + XO = None + else: + XO = tuple(record.ppc)[0].opcode + + @_dataclasses.dataclass(eq=True, frozen=True) + class POStaticOperand(_StaticOperand): + def __init__(self, PO): + value = (PO.value & PO.mask) + return super().__init__(name="PO", value=value) + + def span(self, record): + return tuple(range(0, 6)) + + @_dataclasses.dataclass(eq=True, frozen=True) + class XOStaticOperand(_StaticOperand): + def __init__(self, XO): + value = (XO.value & XO.mask) + return super().__init__(name="XO", value=value) + + def span(self, record): + return tuple(record.section.bitsel) + + static_operands = [POStaticOperand(PO=PO)] + if XO is not None: + static_operands.append(XOStaticOperand(XO=XO)) + static_operands.extend(record.mdwn.operands.static) + dynamic_operands = record.mdwn.operands.dynamic + + def static_operand(operand): + return StaticOperand(name=operand.name, + value=operand.value, span=operand.span(record=record)) + + def dynamic_operand(operand): + return DynamicOperand(name=operand.name, + span=operand.span(record=record)) + + static_operands = tuple(map(static_operand, static_operands)) + dynamic_operands = tuple(map(dynamic_operand, dynamic_operands)) + + yield Entry(name=record.name, + static_operands=static_operands, + dynamic_operands=dynamic_operands) + + +def opcodes(entry): + operands = entry.dynamic_operands + operands = ", ".join(operand.name for operand in operands) + string = ",\t".join(( + f"\"{entry.name}\"", + f"XRC({entry.PO},{entry.XO},{entry.Rc})", + "X_MASK", + "SVP64", + "PPCVLE", + f"{{{operands}}}", + )) + return f"{{{string}}}," + + +def asm(entry): + for (idx, operand) in enumerate(entry.dynamic_operands): + values = ([0] * len(entry.dynamic_operands)) + values[idx] = ((1 << len(operand.span)) - 1) + return f"{entry.name} {','.join(map(str, values))}" + + +def dis(entry): + def objdump(byte): + return f"{byte:02x}" + + for dynamic_operand in entry.dynamic_operands: + insn = _WordInstruction.integer(value=0) + for static_operand in entry.static_operands: + span = static_operand.span + insn[span] = static_operand.value + span = dynamic_operand.span + insn[span] = ((1 << len(span)) - 1) + big = " ".join(map(objdump, insn.bytes(byteorder="big"))) + little = " ".join(map(objdump, insn.bytes(byteorder="little"))) + return f".*\t({big}|{little}) \t{asm(entry)}" + + +class Mode(_enum.Enum): + OPCODES = "opcodes" + ASM = "asm" + DIS = "dis" + + def __str__(self): + return self.name.lower() + + +if __name__ == "__main__": + parser = _argparse.ArgumentParser() + parser.add_argument("mode", type=Mode, choices=Mode) + args = dict(vars(parser.parse_args())) + + mode = args["mode"] + db = _Database(_find_wiki_dir()) + entries = sorted(collect(db)) + + generator = { + Mode.OPCODES: opcodes, + Mode.ASM: asm, + Mode.DIS: dis, + }[mode] + if mode is Mode.DIS: + print("#as: -mlibresoc") + print("#objdump: -dr -Mlibresoc") + print("") + print(".*: file format .*") + print("") + print("") + + for line in map(generator, entries): + print(line) -- 2.30.2