X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fopenpower%2Fsv%2Fsv_binutils.py;h=b4dea0acf62ed1419fb36cda661c99f2b702d3ee;hb=b1bb73777b241c9f77059b6a9e6828b5571757be;hp=7c9244b400d8a8841acf1ad4e53be0ed4b0f83ec;hpb=07977c5f1ff68b4fdfac713c5528a88a1e3616d5;p=openpower-isa.git diff --git a/src/openpower/sv/sv_binutils.py b/src/openpower/sv/sv_binutils.py index 7c9244b4..b4dea0ac 100644 --- a/src/openpower/sv/sv_binutils.py +++ b/src/openpower/sv/sv_binutils.py @@ -1,8 +1,11 @@ -import abc as _abc import argparse as _argparse import dataclasses as _dataclasses import enum as _enum -import re as _re + +import os as _os +import sys as _sys + +_sys.path.append(_os.path.dirname(_os.path.realpath(__file__)) + "/../../") from openpower.decoder.power_enums import ( In1Sel as _In1Sel, @@ -10,187 +13,390 @@ from openpower.decoder.power_enums import ( In3Sel as _In3Sel, OutSel as _OutSel, CRInSel as _CRInSel, + CRIn2Sel as _CRIn2Sel, CROutSel as _CROutSel, - SVPtype as _SVPtype, - SVEtype as _SVEtype, - SVEXTRA as _SVEXTRA, + SVPType as _SVPType, + SVEType as _SVEType, + SVExtra as _SVExtra, + SVMode as _SVMode, + find_wiki_dir as _find_wiki_dir, ) -from openpower.decoder.power_svp64 import SVP64RM as _SVP64RM +from openpower.consts import SVP64MODE as _SVP64MODE +from openpower.decoder.power_insn import Database as _Database +from openpower.decoder.power_insn import SVP64Instruction as _SVP64Instruction -DISCLAIMER = ( - "/*", - " * this file is auto-generated, do not edit", - " * https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/sv/sv_binutils.py", - " * part of Libre-SOC, sponsored by NLnet", - " */", -) +DISCLAIMER = """\ +/* {path} -- {desc} + Copyright (C) 2022 Free Software Foundation, Inc. + Written by Dmitry Selyutin (ghostmansd). + Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this file; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */\ +""" def indent(strings): - return map(lambda string: (" " + string), strings) + return map(lambda string: (" " + string), strings) + + +class ObjectMeta(type): + def __new__(metacls, clsname, bases, ns, + c_typedef="void", **kwargs): + if c_typedef == "void": + for base in bases: + if (hasattr(base, "c_typedef") and + (base.c_typedef != "void")): + c_typedef = base.c_typedef + break + ns.setdefault("c_typedef", c_typedef) + ns.update(kwargs) + + return super().__new__(metacls, clsname, bases, ns) + + +class Object(metaclass=ObjectMeta): + @classmethod + def c_decl(cls): + yield from () -class CType: @classmethod - @_abc.abstractmethod - def c_decl(self, name): - pass + def c_var(cls, name, prefix="", suffix=""): + return f"{prefix}{cls.c_typedef} {name}{suffix}" + + def c_value(self, *, prefix="", suffix="", **kwargs): + yield from () + + +class ArrayMeta(ObjectMeta): + def __new__(metacls, clsname, bases, ns, + c_base, c_size, **kwargs): + if c_size is Ellipsis: + clsname = f"{clsname}[]" + else: + clsname = f"{clsname}[{c_size}]" + + return super().__new__(metacls, clsname, bases, ns, + c_typedef=c_base.c_typedef, c_base=c_base, c_size=c_size, **kwargs) - @_abc.abstractmethod - def c_value(self, prefix="", suffix=""): - pass + def __getitem__(cls, key): + (c_base, c_size) = key + return cls.__class__(cls.__name__, (cls,), {}, + c_base=c_base, c_size=c_size) + +class Array(Object, tuple, metaclass=ArrayMeta, + c_base=Object, c_size=...): @classmethod - @_abc.abstractmethod - def c_var(self, name): - pass + def c_decl(cls): + if cls.c_size is Ellipsis: + size = "" + else: + size = f"{len(cls)}" + yield f"{cls.c_base.c_typedef}[{size}]" + + @classmethod + def c_var(cls, name, prefix="", suffix=""): + if cls.c_size is Ellipsis: + size = "" + else: + size = f"{len(cls)}" + return f"{prefix}{cls.c_base.c_typedef} {name}[{size}]{suffix}" + + def c_value(self, *, prefix="", suffix="", **kwargs): + yield f"{prefix}{{" + for item in self: + yield from indent(item.c_value(suffix=",")) + yield f"}}{suffix}" + + +class Void(Object, c_typedef="void"): + def c_var(cls, name, prefix="", suffix=""): + raise NotImplementedError -class Enum(CType, _enum.Enum): +class EnumMeta(_enum.EnumMeta, ObjectMeta): + def __call__(cls, clsname, entries, + c_tag=None, c_typedef=None, exclude=None): + if exclude is None: + exclude = frozenset() + if isinstance(entries, type) and issubclass(entries, _enum.Enum): + # Use __members__, not __iter__, otherwise aliases are lost. + entries = dict(entries.__members__) + if isinstance(entries, dict): + entries = tuple(entries.items()) + entries = ((key, value) for (key, value) in entries if key not in exclude) + + if c_tag is None: + c_tag = f"svp64_{clsname.lower()}" + if c_typedef is None: + c_typedef = f"enum {c_tag}" + + base = ObjectMeta(cls.__name__, (), {}, + c_tag=c_tag, c_typedef=c_typedef) + + return super().__call__(value=clsname, names=entries, type=base) + + +class Enum(Object, _enum.Enum, metaclass=EnumMeta): + @property + def c_name(self): + return f"{self.c_tag.upper()}_{self.name.upper()}" + @classmethod def c_decl(cls): - c_tag = f"svp64_{cls.__name__.lower()}" - yield f"enum {c_tag} {{" + yield f"{cls.c_typedef} {{" for item in cls: yield from indent(item.c_value(suffix=",")) yield f"}};" - def c_value(self, prefix="", suffix=""): - c_tag = f"svp64_{self.__class__.__name__.lower()}" - yield f"{prefix}{c_tag.upper()}_{self.name.upper()}{suffix}" + def c_value(self, *, prefix="", suffix="", **kwargs): + yield f"{prefix}{self.c_name}{suffix}" @classmethod - def c_var(cls, name): - c_tag = f"svp64_{cls.__name__.lower()}" - yield f"enum {c_tag} {name}" + def c_var(cls, name, prefix="", suffix=""): + return f"{prefix}{cls.c_typedef} {name}{suffix}" + +In1Sel = Enum("In1Sel", _In1Sel, c_tag="svp64_in1_sel") +In2Sel = Enum("In2Sel", _In2Sel, c_tag="svp64_in2_sel") +In3Sel = Enum("In3Sel", _In3Sel, c_tag="svp64_in3_sel") +OutSel = Enum("OutSel", _OutSel, c_tag="svp64_out_sel") +CRInSel = Enum("CRInSel", _CRInSel, c_tag="svp64_cr_in_sel") +CRIn2Sel = Enum("CRIn2Sel", _CRIn2Sel, c_tag="svp64_cr_in2_sel") +CROutSel = Enum("CROutSel", _CROutSel, c_tag="svp64_cr_out_sel") +PType = Enum("PType", _SVPType, c_tag="svp64_ptype") +EType = Enum("EType", _SVEType, c_tag="svp64_etype", exclude="NONE") +Extra = Enum("Extra", _SVExtra, c_tag="svp64_extra", exclude="Idx_1_2") +Mode = Enum("Mode", _SVMode, c_tag="svp64_mode") -# Python forbids inheriting from enum unless it's empty. -In1Sel = Enum("In1Sel", {item.name:item.value for item in _In1Sel}) -In2Sel = Enum("In2Sel", {item.name:item.value for item in _In2Sel}) -In3Sel = Enum("In3Sel", {item.name:item.value for item in _In3Sel}) -OutSel = Enum("OutSel", {item.name:item.value for item in _OutSel}) -CRInSel = Enum("CRInSel", {item.name:item.value for item in _CRInSel}) -CROutSel = Enum("CROutSel", {item.name:item.value for item in _CROutSel}) -SVPType = Enum("SVPType", {item.name:item.value for item in _SVPtype}) -SVEType = Enum("SVEType", {item.name:item.value for item in _SVEtype}) -SVEXTRA = Enum("SVEXTRA", {item.name:item.value for item in _SVEXTRA}) +class Constant(_enum.Enum, metaclass=EnumMeta): + @classmethod + def c_decl(cls): + yield f"/* {cls.c_tag.upper()} constants */" + # Use __members__, not __iter__, otherwise aliases are lost. + for (key, item) in cls.__members__.items(): + key = f"{cls.c_tag.upper()}_{key.upper()}" + value = f"0x{item.value:08x}U" + yield f"#define {key} {value}" -class Opcode(CType): - def __init__(self, value, mask, bits): - self.__value = value - self.__mask = mask - self.__bits = bits + def c_value(self, *, prefix="", suffix="", **kwargs): + yield f"{prefix}{self.c_tag.upper()}_{self.c_name.upper()}{suffix}" - return super().__init__() - @property - def value(self): - return self.__value +ModeConst = Constant("Mode", _SVP64MODE) - @property - def mask(self): - return self.__mask - @property - def bits(self): - return self.__bits +class StructMeta(ObjectMeta): + def __new__(metacls, clsname, bases, ns, + c_tag=None, c_typedef=None): - def __repr__(self): - fmt = f"{{value:0{self.bits}b}}:{{mask:0{self.bits}b}}" - return fmt.format(value=self.value, mask=self.mask) + if c_tag is None: + c_tag = f"svp64_{clsname.lower()}" + if c_typedef is None: + c_typedef = f"struct {c_tag}" - def __lt__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented + return super().__new__(metacls, clsname, bases, ns, + c_typedef=c_typedef, c_tag=c_tag) - return self.__value < other.__value +@_dataclasses.dataclass(eq=True, frozen=True) +class Struct(Object, metaclass=StructMeta): @classmethod def c_decl(cls): - yield f"struct svp64_opcode {{" - yield from indent([ - "uint32_t value;", - "uint32_t mask;", - ]) + def transform(field): + return field.type.c_var(name=f"{field.name}", suffix=";") + + yield f"{cls.c_typedef} {{" + yield from indent(map(transform, _dataclasses.fields(cls))) yield f"}};" - def c_value(self, prefix="", suffix=""): + def c_value(self, *, prefix="", suffix="", **kwargs): yield f"{prefix}{{" - yield from indent([ - f".value = UINT32_C(0x{self.value:08X}),", - f".mask = UINT32_C(0x{self.mask:08X}),", - ]) + for field in _dataclasses.fields(self): + name = field.name + attr = getattr(self, name) + yield from indent(attr.c_value(prefix=f".{name} = ", suffix=",")) yield f"}}{suffix}" - @classmethod - def c_var(cls, name): - yield f"struct svp64_opcode {name}" +class Integer(Object, str): + def c_value(self, *, prefix="", suffix="", **kwargs): + yield f"{prefix}{self}{suffix}" -class IntegerOpcode(Opcode): - def __init__(self, integer): - value = int(integer, 0) - bits = max(1, value.bit_length()) - mask = int(("1" * bits), 2) - return super().__init__(value=value, mask=mask, bits=bits) +class Byte(Integer, c_typedef="uint8_t"): + pass -class PatternOpcode(Opcode): - def __init__(self, pattern): - value = 0 - mask = 0 - bits = len(pattern) - for bit in pattern: - value |= (bit == "1") - mask |= (bit != "-") - value <<= 1 - mask <<= 1 - value >>= 1 - mask >>= 1 +class Size(Integer, c_typedef="size_t"): + pass - return super().__init__(value=value, mask=mask, bits=bits) +class UInt32(Integer, c_typedef="uint32_t"): + pass -class Name(CType, str): + +class UInt64(Integer, c_typedef="uint64_t"): + pass + + +@_dataclasses.dataclass(eq=True, frozen=True) +class Instruction(Struct, c_tag="svp64_insn"): + value: UInt64 + + @classmethod + def c_decl(cls): + def mangle(path, action): + if path.endswith("]"): + path = path[:-1] + for symbol in (".", "[", "]"): + path = path.replace(symbol, "_") + if path != "": + return f"{cls.c_tag}_{action}_{path}" + else: + return f"{cls.c_tag}_{action}" + + def getter(path, field): + yield "static inline uint64_t" + yield f"{mangle(path, 'get')}(const {cls.c_typedef} *insn)" + yield "{" + yield from indent(["uint64_t value = insn->value;"]) + yield from indent(["return ("]) + actions = [] + for (dst, src) in enumerate(reversed(field)): + src = (64 - (src + 1)) + dst = f"UINT64_C({dst})" + src = f"UINT64_C({src})" + action = f"(((value >> {src}) & UINT64_C(1)) << {dst})" + actions.append(action) + for action in indent(indent(actions[:-1])): + yield f"{action} |" + yield from indent(indent([f"{actions[-1]}"])) + yield from indent([");"]) + yield "}" + yield "" + + def setter(path, field): + mask = ((2 ** 64) - 1) + for bit in field: + mask &= ~(1 << (64 - (bit + 1))) + action = mangle(path, "set") + yield "static inline void" + yield f"{mangle(path, 'set')}({cls.c_typedef} *insn, uint64_t value)" + yield "{" + yield from indent([f"insn->value &= UINT64_C(0x{mask:016x});"]) + actions = [] + for (src, dst) in enumerate(reversed(field)): + dst = (64 - (dst + 1)) + dst = f"UINT64_C({dst})" + src = f"UINT64_C({src})" + action = f"(((value >> {src}) & UINT64_C(1)) << {dst})" + actions.append(action) + yield from indent(["insn->value |= ("]) + for action in indent(indent(actions[:-1])): + yield f"{action} |" + yield from indent(indent([f"{actions[-1]}"])) + yield from indent([");"]) + yield "}" + yield "" + + yield from super().c_decl() + yield "" + for (path, field) in _SVP64Instruction.traverse(path=""): + yield from getter(path, field) + yield from setter(path, field) + + +class Name(Object, str, c_typedef="const char *"): def __repr__(self): escaped = self.replace("\"", "\\\"") return f"\"{escaped}\"" - def c_value(self, prefix="", suffix=""): + def c_value(self, *, prefix="", suffix="", **kwargs): yield f"{prefix}{self!r}{suffix}" @classmethod - def c_var(cls, name): - yield f"const char *{name}" + def c_var(cls, name, prefix="", suffix=""): + return f"{prefix}const char *{name}{suffix}" + + +class BooleanMeta(ObjectMeta): + def __len__(cls): + return 1 + + +class Boolean(Object, metaclass=BooleanMeta): + def __init__(self, value): + self.__state = bool(value) + return super().__init__() + + def __bool__(self): + return self.__state + + def __repr__(self): + return self.__state.__repr__() + + @property + def name(self): + return "true" if self else "false" + + @property + def value(self): + return "true" if self else "false" + + def c_value(self, *, prefix="", suffix="", **kwargs): + yield f"{prefix}{self.value}{suffix}" + + @classmethod + def c_var(cls, name, prefix="", suffix=""): + return f"{prefix}bool {name}{suffix}" @_dataclasses.dataclass(eq=True, frozen=True) -class Record(CType): +class Desc(Struct): + mode: Mode in1: In1Sel in2: In2Sel in3: In3Sel out: OutSel out2: OutSel cr_in: CRInSel + cr_in2: CRIn2Sel cr_out: CROutSel - sv_ptype: SVPType - sv_etype: SVEType - sv_in1: SVEXTRA - sv_in2: SVEXTRA - sv_in3: SVEXTRA - sv_out: SVEXTRA - sv_out2: SVEXTRA - sv_cr_in: SVEXTRA - sv_cr_out: SVEXTRA + ptype: PType + etype: EType + extra_idx_in1: Extra + extra_idx_in2: Extra + extra_idx_in3: Extra + extra_idx_out: Extra + extra_idx_out2: Extra + extra_idx_cr_in: Extra + extra_idx_cr_in2: Extra + extra_idx_cr_out: Extra + Rc: Boolean @classmethod def c_decl(cls): bits_all = 0 - yield f"struct svp64_record {{" + yield f"struct svp64_desc {{" for field in _dataclasses.fields(cls): bits = len(field.type).bit_length() yield from indent([f"uint64_t {field.name} : {bits};"]) @@ -200,23 +406,51 @@ class Record(CType): yield from indent([f"uint64_t : {bits_rsvd};"]) yield f"}};" - def c_value(self, prefix="", suffix=""): - yield f"{prefix}{{" - for field in _dataclasses.fields(self): - name = field.name - attr = getattr(self, name) - yield from indent(attr.c_value(prefix=f".{name} = ", suffix=",")) - yield f"}}{suffix}" + +@_dataclasses.dataclass(eq=True, frozen=True) +class Opcode(Struct): + class Value(UInt32): + def __new__(cls, value): + if isinstance(value, int): + value = f"0x{value:08x}" + return super().__new__(cls, value) + + class Mask(UInt32): + def __new__(cls, value): + if isinstance(value, int): + value = f"0x{value:08x}" + return super().__new__(cls, value) + + value: Value + mask: Mask + + +class Opcodes(Object, c_typedef="const struct svp64_opcode *"): + def __init__(self, offset): + self.__offset = offset + return super().__init__() + + def __repr__(self): + return f"{self.__class__.__name__}({self.__offset})" @classmethod - def c_var(cls, name): - yield f"struct svp64_record {name}" + def c_var(cls, name, prefix="", suffix=""): + return f"{prefix}{cls.c_typedef}{name}{suffix}" + + @classmethod + def c_decl(cls): + yield "const struct svp64_opcode *opcodes;" + + def c_value(self, *, prefix="", suffix="", **kwargs): + yield f"{prefix}&svp64_opcodes[{self.__offset}]{suffix}" @_dataclasses.dataclass(eq=True, frozen=True) -class Entry(CType): +class Record(Struct): name: Name - record: Record + desc: Desc + opcodes: Opcodes + nr_opcodes: Size def __lt__(self, other): if not isinstance(other, self.__class__): @@ -224,46 +458,19 @@ class Entry(CType): return self.name < other.name - @classmethod - def c_decl(cls): - yield f"struct svp64_entry {{" - for field in _dataclasses.fields(cls): - yield from indent(field.type.c_var(name=f"{field.name};")) - yield f"}};" - - def c_value(self, prefix="", suffix=""): - yield f"{prefix}{{" - for field in _dataclasses.fields(self): - name = field.name - attr = getattr(self, name) - yield from indent(attr.c_value(prefix=f".{name} = ", suffix=",")) - yield f"}}{suffix}" - - @classmethod - def c_var(cls, name): - yield f"struct svp64_entry {name}" - class Codegen(_enum.Enum): - PPC_SVP64_H = _enum.auto() - PPC_SVP64_OPC_C = _enum.auto() - - @classmethod - def _missing_(cls, value): - return { - "ppc-svp64.h": Codegen.PPC_SVP64_H, - "ppc-svp64-opc.c": Codegen.PPC_SVP64_OPC_C, - }.get(value) + PPC_SVP64_GEN_H = "include/opcode/ppc-svp64-gen.h" + PPC_SVP64_OPC_GEN_C = "opcodes/ppc-svp64-opc-gen.c" def __str__(self): - return { - Codegen.PPC_SVP64_H: "ppc-svp64.h", - Codegen.PPC_SVP64_OPC_C: "ppc-svp64-opc.c", - }[self] - - def generate(self, entries): - def ppc_svp64_h(entries): - yield from DISCLAIMER + return self.value + + def generate(self, opcodes, records): + def ppc_svp64_h(opcodes, nr_opcodes, records, nr_records): + disclaimer = DISCLAIMER.format(path=str(self), + desc="Header file for PowerPC opcode table (SVP64 extensions)") + yield from disclaimer.splitlines() yield "" yield f"#ifndef {self.name}" @@ -280,24 +487,32 @@ class Codegen(_enum.Enum): enums = ( In1Sel, In2Sel, In3Sel, OutSel, - CRInSel, CROutSel, - SVPType, SVEType, SVEXTRA, + CRInSel, CRIn2Sel, CROutSel, + PType, EType, Extra, + Mode, ModeConst, ) for enum in enums: yield from enum.c_decl() yield "" - yield from Record.c_decl() - yield "" + for cls in (Instruction, Desc, Opcode, Record): + yield from cls.c_decl() + yield "" - yield from Entry.c_decl() + yield opcodes.c_var("svp64_opcodes", + prefix="extern const ", suffix=";") + yield nr_opcodes.c_var("svp64_nr_opcodes", + prefix="extern const ", suffix=";") yield "" - yield "extern const struct svp64_entry svp64_entries[];" - yield "extern const unsigned int svp64_num_entries;" + yield records.c_var("svp64_records", + prefix="extern const ", suffix=";") + yield nr_records.c_var("svp64_nr_records", + prefix="extern const ", suffix=";") yield "" - yield f"#define SVP64_NAME_MAX {max(map(lambda entry: len(entry.name), entries))}" + yield "extern const struct powerpc_pd_reg svp64_regs[];" + yield Size.c_var("svp64_num_regs", prefix="extern const ", suffix=";") yield "" yield "#ifdef __cplusplus" @@ -306,140 +521,186 @@ class Codegen(_enum.Enum): yield "" yield f"#endif /* {self.name} */" - yield "" - def ppc_svp64_opc_c(entries): - yield from DISCLAIMER + def ppc_svp64_opc_c(opcodes, nr_opcodes, records, nr_records): + disclaimer = DISCLAIMER.format(path=str(self), + desc="PowerPC opcode list (SVP64 extensions)") + yield from disclaimer.splitlines() yield "" + yield "#include " yield "#include \"opcode/ppc-svp64.h\"" yield "" - yield "const struct svp64_entry svp64_entries[] = {" - for (index, entry) in enumerate(entries): - yield from indent(entry.c_value(prefix=f"[{index}] = ", suffix=",")) - yield f"}};" + def opindex(enum, name, table): + sep = (max(map(len, list(table.values()) + ["UNUSED"])) + 1) + c_tag = f"svp64_{enum.__name__.lower()}" + yield "static inline ppc_opindex_t" + yield f"svp64_desc_{name}_opindex(const struct svp64_desc *desc)" + yield "{" + yield from indent(["static const ppc_opindex_t table[] = {"]) + for key in enum: + value = table.get(key, "UNUSED") + yield from indent(indent([f"{value:{sep}}, /* {key.c_name} */"])) + yield from indent(["};"]) + yield "" + yield from indent([f"return table[desc->{name}];"]) + yield "}" + yield "" + + yield from opindex(In1Sel, "in1", { + In1Sel.RA: "RA", + In1Sel.RA_OR_ZERO: "RA0", + In1Sel.SPR: "SPR", + In1Sel.RS: "RS", + In1Sel.FRA: "FRA", + In1Sel.FRS: "FRS", + }) + yield from opindex(In2Sel, "in2", { + In2Sel.RB: "RB", + In2Sel.SPR: "SPR", + In2Sel.RS: "RS", + In2Sel.FRB: "FRB", + }) + yield from opindex(In3Sel, "in3", { + In3Sel.RS: "RS", + In3Sel.RB: "RB", + In3Sel.FRS: "FRS", + In3Sel.FRC: "FRC", + In3Sel.RC: "RC", + In3Sel.RT: "RT", + }) + for name in ("out", "out2"): + yield from opindex(OutSel, name, { + OutSel.RT: "RT", + OutSel.RA: "RA", + OutSel.SPR: "SPR", + OutSel.RT_OR_ZERO: "RT", + OutSel.FRT: "FRT", + OutSel.FRS: "FRS", + OutSel.RS: "RS", + }) + yield from opindex(CRInSel, "cr_in", { + CRInSel.BI: "BI", + CRInSel.BFA: "BFA", + CRInSel.BC: "BC", + CRInSel.BA: "BA", + CRInSel.WHOLE_REG: "FXM", + }) + yield from opindex(CRIn2Sel, "cr_in2", { + CRIn2Sel.BB: "BB", + }) + yield from opindex(CROutSel, "cr_out", { + CROutSel.BF: "BF", + CROutSel.BT: "BT", + CROutSel.WHOLE_REG: "FXM", + }) + + yield opcodes.c_var("svp64_opcodes", + prefix="const ", suffix=" = \\") + yield from opcodes.c_value(prefix="", suffix=";") + yield "" + yield nr_opcodes.c_var("svp64_nr_opcodes", + prefix="const ", suffix=" = \\") + yield from indent(nr_opcodes.c_value(suffix=";")) + yield "" + + yield records.c_var("svp64_records", + prefix="const ", suffix=" = \\") + yield from records.c_value(prefix="", suffix=";") + yield "" + yield nr_records.c_var("svp64_nr_records", + prefix="const ", suffix=" = \\") + yield from indent(nr_records.c_value(suffix=";")) yield "" - yield "const unsigned int svp64_num_entries = \\" - yield " sizeof (svp64_entries) / sizeof (svp64_entries[0]);" + yield "const struct powerpc_pd_reg svp64_regs[] = {" + regs = {} + for (category, count, flags) in sorted(( + ("r", 128, "PPC_OPERAND_GPR"), + ("f", 128, "PPC_OPERAND_FPR"), + ("cr", 128, "PPC_OPERAND_CR_REG"), + )): + for index in range(count): + regs[f"{category}{index}"] = (index, flags) + regs[f"{category}.{index}"] = (index, flags) + for (name, (index, flags)) in sorted(regs.items()): + yield from indent([f"{{\"{name}\", {index}, {flags}}},"]) + yield "};" yield "" - return { - Codegen.PPC_SVP64_H: ppc_svp64_h, - Codegen.PPC_SVP64_OPC_C: ppc_svp64_opc_c, - }[self](entries) - - -def regex_enum(enum): - assert issubclass(enum, _enum.Enum) - return "|".join(item.name for item in enum) - - -PATTERN_VHDL_BINARY = r"(?:2#[01]+#)" -PATTERN_DECIMAL = r"(?:[0-9]+)" -PATTERN_PARTIAL_BINARY = r"(?:[01-]+)" - -# Examples of the entries to be caught by the pattern below: -# 2 => (P2, EXTRA3, RA_OR_ZERO, NONE, NONE, RT, NONE, NONE, NONE, Idx1, NONE, NONE, Idx0, NONE, NONE, NONE), -- lwz -# -----10110 => (P2, EXTRA3, NONE, FRB, NONE, FRT, NONE, NONE, CR1, NONE, Idx1, NONE, Idx0, NONE, NONE, Idx0), -- fsqrts -# 2#0000000000# => (P2, EXTRA3, NONE, NONE, NONE, NONE, NONE, BFA, BF, NONE, NONE, NONE, NONE, NONE, Idx1, Idx0), -- mcrf -PATTERN = "".join(( - r"^\s*", - rf"(?P{PATTERN_VHDL_BINARY}|{PATTERN_DECIMAL}|{PATTERN_PARTIAL_BINARY})", - r"\s?=>\s?", - r"\(", - r",\s".join(( - rf"(?P{regex_enum(_SVPtype)})", - rf"(?P{regex_enum(_SVEtype)})", - rf"(?P{regex_enum(_In1Sel)})", - rf"(?P{regex_enum(_In2Sel)})", - rf"(?P{regex_enum(_In3Sel)})", - rf"(?P{regex_enum(_OutSel)})", - rf"(?P{regex_enum(_OutSel)})", - rf"(?P{regex_enum(_CRInSel)})", - rf"(?P{regex_enum(_CROutSel)})", - rf"(?P{regex_enum(_SVEXTRA)})", - rf"(?P{regex_enum(_SVEXTRA)})", - rf"(?P{regex_enum(_SVEXTRA)})", - rf"(?P{regex_enum(_SVEXTRA)})", - rf"(?P{regex_enum(_SVEXTRA)})", - rf"(?P{regex_enum(_SVEXTRA)})", - rf"(?P{regex_enum(_SVEXTRA)})", - )), - r"\)", - r",", - r"\s?--\s?", - r"(?P[A-Za-z0-9_\./]+)", - r"\s*$", -)) -REGEX = _re.compile(PATTERN) - - -ISA = _SVP64RM() -FIELDS = {field.name:field for field in _dataclasses.fields(Record)} -FIELDS.update({field.name:field for field in _dataclasses.fields(Entry)}) -def parse(path, opcode_cls): - for record in ISA.get_svp64_csv(path): - opcode = opcode_cls(record.pop("opcode")) - names = record.pop("comment").split("=")[-1] - for name in map(Name, names.split("/")): - if name.startswith("l") and name.endswith("br"): - continue - if name in {"mcrxr", "mcrxrx", "darn"}: - continue - if name in {"bctar", "bcctr"}: - continue - if "rfid" in name: - continue - if name in {"setvl"}: - continue - - record = {key.lower().replace(" ", "_"):value for (key, value) in record.items()} - for (key, value) in tuple(record.items()): - key = key.lower().replace(" ", "_") - if key not in FIELDS: - record.pop(key) - continue - - field = FIELDS[key] - if not isinstance(value, field.type): - if issubclass(field.type, _enum.Enum): - value = {item.name:item for item in field.type}[value] - else: - value = field.type(value) - - record[key] = value - - yield Entry(name=name, record=Record(**record)) + num_regs = Size("(sizeof (svp64_regs) / sizeof (svp64_regs[0]))") + yield Size.c_var("svp64_num_regs", + prefix="const ", suffix=" = \\") + yield from indent(num_regs.c_value(suffix=";")) + + opcodes = Array[Opcode, ...](opcodes) + nr_opcodes = Size("(sizeof (svp64_opcodes) / sizeof (svp64_opcodes[0]))") + + records = Array[Record, ...](records) + nr_records = Size("(sizeof (svp64_records) / sizeof (svp64_records[0]))") + + yield from { + Codegen.PPC_SVP64_GEN_H: ppc_svp64_h, + Codegen.PPC_SVP64_OPC_GEN_C: ppc_svp64_opc_c, + }[self](opcodes, nr_opcodes, records, nr_records) + + +def collect(db): + opcodes = [] + records = [] + fields = {field.name:field.type for field in _dataclasses.fields(Desc)} + + for insn in filter(lambda insn: insn.svp64 is not None, db): + desc = {} + + for (key, cls) in fields.items(): + value = getattr(insn, key) + + if (((cls is EType) and (value is _SVEType.NONE)) or + ((cls is Extra) and (value is _SVExtra.Idx_1_2))): + desc = None + break + + if issubclass(cls, Boolean): + value = Boolean(value) + elif issubclass(cls, _enum.Enum): + value = cls[value.name] + else: + value = cls(value) + desc[key] = value + + if desc is None: + continue + + name = Name(f"sv.{insn.name}") + offset = len(opcodes) + for opcode in insn.opcodes: + value = Opcode.Value(opcode.value) + mask = Opcode.Mask(opcode.mask) + opcode = Opcode(value=value, mask=mask) + opcodes.append(opcode) + desc = Desc(**desc) + + record = Record(name=name, desc=desc, + opcodes=Opcodes(offset), nr_opcodes=Size(len(insn.opcodes))) + records.append(record) + + return (opcodes, records) def main(codegen): - entries = [] - table = { - "minor_19.csv": IntegerOpcode, - "minor_30.csv": IntegerOpcode, - "minor_31.csv": IntegerOpcode, - "minor_58.csv": IntegerOpcode, - "minor_62.csv": IntegerOpcode, - "minor_22.csv": IntegerOpcode, - "minor_5.csv": PatternOpcode, - "minor_63.csv": PatternOpcode, - "minor_59.csv": PatternOpcode, - "major.csv": IntegerOpcode, - "extra.csv": PatternOpcode, - } - for (path, opcode_cls) in table.items(): - entries.extend(parse(path, opcode_cls)) - entries = sorted(frozenset(entries)) - - for line in codegen.generate(entries): + db = _Database(_find_wiki_dir()) + (opcodes, records) = collect(db) + for line in codegen.generate(opcodes, records): print(line) if __name__ == "__main__": parser = _argparse.ArgumentParser() - parser.add_argument("codegen", type=Codegen, choices=Codegen, help="code generator") + parser.add_argument("codegen", + type=Codegen, choices=Codegen, + help="code generator") args = vars(parser.parse_args()) main(**args)