X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fopenpower%2Fsv%2Fsv_binutils.py;h=b4dea0acf62ed1419fb36cda661c99f2b702d3ee;hb=b1bb73777b241c9f77059b6a9e6828b5571757be;hp=736699634ab1384578be5901a22c5a178b86c2f6;hpb=ea16958e8fd1e6303ad3f5057839e17b069b5d2e;p=openpower-isa.git diff --git a/src/openpower/sv/sv_binutils.py b/src/openpower/sv/sv_binutils.py index 73669963..b4dea0ac 100644 --- a/src/openpower/sv/sv_binutils.py +++ b/src/openpower/sv/sv_binutils.py @@ -1,128 +1,164 @@ -import abc as _abc import argparse as _argparse -import builtins as _builtins import dataclasses as _dataclasses import enum as _enum +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, In2Sel as _In2Sel, In3Sel as _In3Sel, OutSel as _OutSel, CRInSel as _CRInSel, + CRIn2Sel as _CRIn2Sel, CROutSel as _CROutSel, - SVPtype as _SVPtype, - SVEtype as _SVEtype, - SVEXTRA as _SVEXTRA, - RC as _RC, + SVPType as _SVPType, + SVEType as _SVEType, + SVExtra as _SVExtra, + SVMode as _SVMode, + find_wiki_dir as _find_wiki_dir, ) from openpower.consts import SVP64MODE as _SVP64MODE -from openpower.decoder.power_svp64 import SVP64RM as _SVP64RM -from openpower.decoder.isa.caller import SVP64RMFields as _SVP64RMFields -from openpower.decoder.isa.caller import SVP64PrefixFields as _SVP64PrefixFields +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 CTypeMeta(type): - def __new__(metacls, name, bases, attrs, typedef=None): - cls = super().__new__(metacls, name, bases, attrs) - cls.__typedef = typedef +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 - return cls + ns.setdefault("c_typedef", c_typedef) + ns.update(kwargs) - def __getitem__(cls, size): - name = f"{cls.__name__}[{'' if size is Ellipsis else size}]" - return type(name, (Array,), {}, type=cls, size=size) + return super().__new__(metacls, clsname, bases, ns) - @property - def c_typedef(cls): - return cls.__typedef - @_abc.abstractmethod +class Object(metaclass=ObjectMeta): + @classmethod def c_decl(cls): yield from () + @classmethod def c_var(cls, name, prefix="", suffix=""): - yield f"{prefix}{cls.c_typedef} {name}{suffix}" + return f"{prefix}{cls.c_typedef} {name}{suffix}" + def c_value(self, *, prefix="", suffix="", **kwargs): + yield from () -class ArrayMeta(CTypeMeta): - def __new__(metacls, name, bases, attrs, type, size): - cls = super().__new__(metacls, name, bases, attrs) - cls.__type = type - cls.__ellipsis = (size is Ellipsis) - cls.__size = 0 if cls.__ellipsis else size - return cls +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}]" - def __len__(cls): - return cls.__size + return super().__new__(metacls, clsname, bases, ns, + c_typedef=c_base.c_typedef, c_base=c_base, c_size=c_size, **kwargs) + + def __getitem__(cls, key): + (c_base, c_size) = key + return cls.__class__(cls.__name__, (cls,), {}, + c_base=c_base, c_size=c_size) - @property - def c_type(cls): - return cls.__type +class Array(Object, tuple, metaclass=ArrayMeta, + c_base=Object, c_size=...): + @classmethod def c_decl(cls): - size = "" if cls.__ellipsis else f"{cls.__size}" - yield f"{cls.c_type.c_typedef}[{size}]" + 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=""): - size = "" if cls.__ellipsis else f"{cls.__size}" - yield f"{prefix}{cls.c_type.c_typedef} {name}[{size}]{suffix}" + if cls.c_size is Ellipsis: + size = "" + else: + size = f"{len(cls)}" + return f"{prefix}{cls.c_base.c_typedef} {name}[{size}]{suffix}" - -class CType(metaclass=CTypeMeta): - @_abc.abstractmethod - def c_value(self, prefix="", suffix=""): - yield from () - - -class Array(CType, tuple, metaclass=ArrayMeta, type=CType, size=0): - def c_value(self, prefix="", suffix=""): + def c_value(self, *, prefix="", suffix="", **kwargs): yield f"{prefix}{{" - for (index, item) in enumerate(self): - yield from indent(item.c_value(prefix=f"[{index}] = ", suffix=",")) + for item in self: + yield from indent(item.c_value(suffix=",")) yield f"}}{suffix}" -class EnumMeta(_enum.EnumMeta, CTypeMeta): - def __call__(metacls, name, entries, tag=None, **kwargs): +class Void(Object, c_typedef="void"): + def c_var(cls, name, prefix="", suffix=""): + raise NotImplementedError + + +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()) - if tag is None: - tag = f"svp64_{name.lower()}" + entries = ((key, value) for (key, value) in entries if key not in exclude) - cls = super().__call__(value=name, names=entries, **kwargs) - cls.__tag = tag - return cls + if c_tag is None: + c_tag = f"svp64_{clsname.lower()}" + if c_typedef is None: + c_typedef = f"enum {c_tag}" - @property - def c_typedef(cls): - return f"enum {cls.c_tag}" + base = ObjectMeta(cls.__name__, (), {}, + c_tag=c_tag, c_typedef=c_typedef) - @property - def c_tag(cls): - return cls.__tag + return super().__call__(value=clsname, names=entries, type=base) - def c_var(cls, name, prefix="", suffix=""): - yield f"{prefix}{cls.c_typedef} {name}{suffix}" +class Enum(Object, _enum.Enum, metaclass=EnumMeta): + @property + def c_name(self): + return f"{self.c_tag.upper()}_{self.name.upper()}" -class Enum(CType, _enum.Enum, metaclass=EnumMeta): @classmethod def c_decl(cls): yield f"{cls.c_typedef} {{" @@ -130,63 +166,69 @@ class Enum(CType, _enum.Enum, metaclass=EnumMeta): yield from indent(item.c_value(suffix=",")) yield f"}};" - def c_value(self, prefix="", suffix=""): - yield f"{prefix}{self.__class__.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, prefix="", suffix=""): + return f"{prefix}{cls.c_typedef} {name}{suffix}" -In1Sel = Enum("In1Sel", _In1Sel) -In2Sel = Enum("In2Sel", _In2Sel) -In3Sel = Enum("In3Sel", _In3Sel) -OutSel = Enum("OutSel", _OutSel) -CRInSel = Enum("CRInSel", _CRInSel) -CROutSel = Enum("CROutSel", _CROutSel) -SVPType = Enum("SVPType", _SVPtype) -SVEType = Enum("SVEType", _SVEtype) -SVEXTRA = Enum("SVEXTRA", _SVEXTRA) +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") -class Constant(CType, _enum.Enum, metaclass=EnumMeta): + +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}" - def c_value(self, prefix="", suffix=""): - yield f"{prefix}{self.__class__.c_tag.upper()}_{self.name.upper()}{suffix}" + def c_value(self, *, prefix="", suffix="", **kwargs): + yield f"{prefix}{self.c_tag.upper()}_{self.c_name.upper()}{suffix}" -Mode = Constant("Mode", _SVP64MODE) +ModeConst = Constant("Mode", _SVP64MODE) -class StructMeta(CTypeMeta): - def __new__(metacls, name, bases, attrs, tag=None, **kwargs): - if tag is None: - tag = f"svp64_{name.lower()}" - if "typedef" not in kwargs: - kwargs["typedef"] = f"struct {tag}" +class StructMeta(ObjectMeta): + def __new__(metacls, clsname, bases, ns, + c_tag=None, c_typedef=None): - cls = super().__new__(metacls, name, bases, attrs, **kwargs) - cls.__tag = tag + if c_tag is None: + c_tag = f"svp64_{clsname.lower()}" + if c_typedef is None: + c_typedef = f"struct {c_tag}" - return cls + return super().__new__(metacls, clsname, bases, ns, + c_typedef=c_typedef, c_tag=c_tag) - @property - def c_tag(cls): - return cls.__tag +@_dataclasses.dataclass(eq=True, frozen=True) +class Struct(Object, metaclass=StructMeta): + @classmethod def c_decl(cls): + def transform(field): + return field.type.c_var(name=f"{field.name}", suffix=";") + yield f"{cls.c_typedef} {{" - for field in _dataclasses.fields(cls): - yield from indent(field.type.c_var(name=f"{field.name}", suffix=";")) + yield from indent(map(transform, _dataclasses.fields(cls))) yield f"}};" - -@_dataclasses.dataclass(eq=True, frozen=True) -class Struct(CType, metaclass=StructMeta): - def c_value(self, prefix="", suffix=""): + def c_value(self, *, prefix="", suffix="", **kwargs): yield f"{prefix}{{" for field in _dataclasses.fields(self): name = field.name @@ -195,55 +237,166 @@ class Struct(CType, metaclass=StructMeta): yield f"}}{suffix}" -class Integer(CType, str): - def c_value(self, prefix="", suffix=""): +class Integer(Object, str): + def c_value(self, *, prefix="", suffix="", **kwargs): yield f"{prefix}{self}{suffix}" -class Byte(Integer, typedef="uint8_t"): +class Byte(Integer, c_typedef="uint8_t"): + pass + + +class Size(Integer, c_typedef="size_t"): + pass + + +class UInt32(Integer, c_typedef="uint32_t"): pass -class Size(Integer, typedef="size_t"): +class UInt64(Integer, c_typedef="uint64_t"): pass -class Name(CType, str): +@_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, prefix="", suffix=""): - yield f"{prefix}const char *{name}{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(Struct): +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};"]) @@ -255,98 +408,69 @@ class Record(Struct): @_dataclasses.dataclass(eq=True, frozen=True) -class Entry(Struct): - name: Name - record: Record - - def __lt__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - - return self.name < other.name - - -@_dataclasses.dataclass(eq=True, frozen=True) -class Field(Struct): - length: Size - mapping: Byte[32] - - - -class FieldsMeta(CTypeMeta): - def __new__(metacls, name, bases, attrs, **kwargs): - def flatten(mapping, parent=""): - for (key, value) in mapping.items(): - key = f"{parent}_{key}" if parent else key - if isinstance(value, dict): - yield from flatten(mapping=value, parent=key) - else: - yield (key.upper(), value) - - fields = dict(flatten(mapping=kwargs)) - keys = ((key, index) for (index, key) in enumerate(fields)) - enum_cls = Enum(name, entries=keys, tag=f"svp64_{name.lower()}_type") +class Opcode(Struct): + class Value(UInt32): + def __new__(cls, value): + if isinstance(value, int): + value = f"0x{value:08x}" + return super().__new__(cls, value) - def field(item): - (key, value) = item - length = Size(len(value.br)) - mapping = Byte[32](map(lambda bit: Byte((value.si.bits - 1) - bit), reversed(value.br))) - return (key, Field(length=length, mapping=mapping)) + class Mask(UInt32): + def __new__(cls, value): + if isinstance(value, int): + value = f"0x{value:08x}" + return super().__new__(cls, value) - typedef = kwargs.pop("typedef", Field.c_typedef) - cls = super().__new__(metacls, name, bases, attrs, typedef=typedef) - cls.__enum = enum_cls - cls.__fields = dict(map(field, zip(enum_cls, fields.values()))) + value: Value + mask: Mask - return cls - def __iter__(cls): - for (key, value) in cls.__fields.items(): - yield (key, value) +class Opcodes(Object, c_typedef="const struct svp64_opcode *"): + def __init__(self, offset): + self.__offset = offset + return super().__init__() - def c_decl(cls): - yield from cls.__enum.c_decl() + def __repr__(self): + return f"{self.__class__.__name__}({self.__offset})" + @classmethod def c_var(cls, name, prefix="", suffix=""): - yield from Field.c_var(name=name, prefix=prefix, suffix=suffix) + return f"{prefix}{cls.c_typedef}{name}{suffix}" + @classmethod + def c_decl(cls): + yield "const struct svp64_opcode *opcodes;" -class Fields(metaclass=FieldsMeta): - def c_value(self, prefix="", suffix=""): - yield f"{prefix}{{" - for (key, value) in self.__class__: - yield from indent(value.c_value(prefix=f"[{key.c_name}] = ", suffix=",")) - yield f"}}{suffix}" + def c_value(self, *, prefix="", suffix="", **kwargs): + yield f"{prefix}&svp64_opcodes[{self.__offset}]{suffix}" -class Prefix(Fields, **_SVP64PrefixFields(0)): - pass +@_dataclasses.dataclass(eq=True, frozen=True) +class Record(Struct): + name: Name + desc: Desc + opcodes: Opcodes + nr_opcodes: Size + def __lt__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented -class RM(Fields, **_SVP64RMFields(0)): - pass + return self.name < other.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, num_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}" @@ -363,29 +487,32 @@ class Codegen(_enum.Enum): enums = ( In1Sel, In2Sel, In3Sel, OutSel, - CRInSel, CROutSel, - SVPType, SVEType, SVEXTRA, - Mode, + CRInSel, CRIn2Sel, CROutSel, + PType, EType, Extra, + Mode, ModeConst, ) for enum in enums: yield from enum.c_decl() yield "" - structs = (Field, Record, Entry, Prefix, RM) - for struct in structs: - yield from struct.c_decl() + for cls in (Instruction, Desc, Opcode, Record): + yield from cls.c_decl() yield "" - for name in ("in1", "in2", "in3", "out", "out2", "cr_in", "cr_out"): - yield "unsigned char" - yield f"svp64_record_{name}_opsel(const struct svp64_record *record);" - yield "" + yield opcodes.c_var("svp64_opcodes", + prefix="extern const ", suffix=";") + yield nr_opcodes.c_var("svp64_nr_opcodes", + prefix="extern const ", suffix=";") + yield "" - yield from entries.__class__.c_var("svp64_entries", prefix="extern const ", suffix=";") - yield from num_entries.__class__.c_var("svp64_num_entries", prefix="extern const ", suffix=";") + 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" @@ -394,47 +521,48 @@ class Codegen(_enum.Enum): yield "" yield f"#endif /* {self.name} */" - yield "" - def ppc_svp64_opc_c(entries, num_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 "" - def opsel(enum, name, table): + def opindex(enum, name, table): sep = (max(map(len, list(table.values()) + ["UNUSED"])) + 1) c_tag = f"svp64_{enum.__name__.lower()}" - yield "unsigned char" - yield f"svp64_record_{name}_opsel(const struct svp64_record *record)" + yield "static inline ppc_opindex_t" + yield f"svp64_desc_{name}_opindex(const struct svp64_desc *desc)" yield "{" - yield from indent(["static const unsigned char table[] = {"]) + yield from indent(["static const ppc_opindex_t table[] = {"]) for key in enum: value = table.get(key, "UNUSED") - c_value = f"{c_tag.upper()}_{key.name.upper()}" - yield from indent(indent([f"{value:{sep}}, /* {c_value} */"])) + yield from indent(indent([f"{value:{sep}}, /* {key.c_name} */"])) yield from indent(["};"]) yield "" - yield from indent([f"return table[record->{name}];"]) + yield from indent([f"return table[desc->{name}];"]) yield "}" yield "" - yield from opsel(In1Sel, "in1", { + yield from opindex(In1Sel, "in1", { In1Sel.RA: "RA", - In1Sel.RA_OR_ZERO: "RA", + In1Sel.RA_OR_ZERO: "RA0", In1Sel.SPR: "SPR", In1Sel.RS: "RS", In1Sel.FRA: "FRA", In1Sel.FRS: "FRS", }) - yield from opsel(In2Sel, "in2", { + yield from opindex(In2Sel, "in2", { In2Sel.RB: "RB", In2Sel.SPR: "SPR", In2Sel.RS: "RS", In2Sel.FRB: "FRB", }) - yield from opsel(In3Sel, "in3", { + yield from opindex(In3Sel, "in3", { In3Sel.RS: "RS", In3Sel.RB: "RB", In3Sel.FRS: "FRS", @@ -443,120 +571,136 @@ class Codegen(_enum.Enum): In3Sel.RT: "RT", }) for name in ("out", "out2"): - yield from opsel(OutSel, name, { + 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 opsel(CRInSel, "cr_in", { + yield from opindex(CRInSel, "cr_in", { CRInSel.BI: "BI", CRInSel.BFA: "BFA", - CRInSel.BC: "CRB", + CRInSel.BC: "BC", + CRInSel.BA: "BA", CRInSel.WHOLE_REG: "FXM", }) - yield from opsel(CROutSel, "cr_out", { + 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 from entries.__class__.c_var("svp64_entries", prefix="const ", suffix=" = \\") - yield from entries.c_value(prefix="", suffix=";") + yield opcodes.c_var("svp64_opcodes", + prefix="const ", suffix=" = \\") + yield from opcodes.c_value(prefix="", suffix=";") yield "" - yield from num_entries.__class__.c_var("svp64_num_entries", prefix="const ", suffix=" = \\") - yield from indent(num_entries.c_value(suffix=";")) + yield nr_opcodes.c_var("svp64_nr_opcodes", + prefix="const ", suffix=" = \\") + yield from indent(nr_opcodes.c_value(suffix=";")) yield "" - entries = Entry[...](entries) - num_entries = Size("(sizeof (svp64_entries) / sizeof (svp64_entries[0])") - - return { - Codegen.PPC_SVP64_H: ppc_svp64_h, - Codegen.PPC_SVP64_OPC_C: ppc_svp64_opc_c, - }[self](entries, num_entries) - - -ISA = _SVP64RM() -FIELDS = {field.name:field.type for field in _dataclasses.fields(Record)} -FIELDS.update({field.name:field.type for field in _dataclasses.fields(Entry)}) - -def parse(path): - visited = set() - - def name_filter(name): - if name.startswith("l") and name.endswith("br"): - return False - if name in {"mcrxr", "mcrxrx", "darn"}: - return False - if name in {"bctar", "bcctr"}: - return False - if "rfid" in name: - return False - if name in {"setvl"}: - return False - if name in visited: - return False - - visited.add(name) - - return True - - def item_mapper(item): - (key, value) = item - key = key.lower().replace(" ", "_") - cls = FIELDS.get(key, object) - if not isinstance(value, cls): - if issubclass(cls, _enum.Enum): - value = {item.name:item for item in cls}[value] + 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 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 "" + + 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) - return (key, 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) - def item_filter(item): - (key, _) = item - return (key in FIELDS) + record = Record(name=name, desc=desc, + opcodes=Opcodes(offset), nr_opcodes=Size(len(insn.opcodes))) + records.append(record) - for record in ISA.get_svp64_csv(path): - names = record.pop("comment").split("=")[-1].split("/") - names = set(filter(name_filter, names)) - if names: - rc = _RC[record["rc"] if record["rc"] else "NONE"] - if rc is _RC.RC: - names.update({f"{name}." for name in names}) - record = dict(filter(item_filter, map(item_mapper, record.items()))) - for name in map(Name, names): - yield Entry(name=name, record=Record(**record)) + return (opcodes, records) def main(codegen): - entries = [] - paths = ( - "minor_19.csv", - "minor_30.csv", - "minor_31.csv", - "minor_58.csv", - "minor_62.csv", - "minor_22.csv", - "minor_5.csv", - "minor_63.csv", - "minor_59.csv", - "major.csv", - "extra.csv", - ) - for path in paths: - entries.extend(parse(path)) - 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)