import abc as _abc
import argparse as _argparse
+import builtins as _builtins
import dataclasses as _dataclasses
import enum as _enum
-import re as _re
from openpower.decoder.power_enums import (
In1Sel as _In1Sel,
SVPtype as _SVPtype,
SVEtype as _SVEtype,
SVEXTRA as _SVEXTRA,
+ RC as _RC,
)
+from openpower.consts import SVP64MODE as _SVP64MODE
from openpower.decoder.power_svp64 import SVP64RM as _SVP64RM
DISCLAIMER = (
"/*",
" * this file is auto-generated, do not edit",
- " * http://libre-soc.org/openpower/sv_binutiks.py",
+ " * 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",
" */",
)
return map(lambda string: (" " + string), strings)
-class CType:
- @classmethod
+class CTypeMeta(type):
+ def __new__(metacls, name, bases, attrs, typedef=None):
+ cls = super().__new__(metacls, name, bases, attrs)
+ cls.__typedef = typedef
+
+ return cls
+
+ def __getitem__(cls, size):
+ name = f"{cls.__name__}[{'' if size is Ellipsis else size}]"
+ return type(name, (Array,), {}, type=cls, size=size)
+
+ @property
+ def c_typedef(cls):
+ return cls.__typedef
+
@_abc.abstractmethod
- def c_decl(self, name):
- pass
+ def c_decl(cls):
+ yield from ()
+
+ def c_var(cls, name, prefix="", suffix=""):
+ yield f"{prefix}{cls.c_typedef} {name}{suffix}"
+
+
+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
+
+ def __len__(cls):
+ return cls.__size
+
+ @property
+ def c_type(cls):
+ return cls.__type
+
+ def c_decl(cls):
+ size = "" if cls.__ellipsis else f"{cls.__size}"
+ yield f"{cls.c_type.c_typedef}[{size}]"
+
+ 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}"
+
+class CType(metaclass=CTypeMeta):
@_abc.abstractmethod
def c_value(self, prefix="", suffix=""):
- pass
+ yield from ()
- @classmethod
- @_abc.abstractmethod
- def c_var(self, name):
- pass
+class Array(CType, tuple, metaclass=ArrayMeta, type=CType, size=0):
+ def c_value(self, prefix="", suffix=""):
+ yield f"{prefix}{{"
+ for (index, item) in enumerate(self):
+ yield from indent(item.c_value(prefix=f"[{index}] = ", suffix=","))
+ yield f"}}{suffix}"
+
+
+class EnumMeta(_enum.EnumMeta, CTypeMeta):
+ def __call__(metacls, name, entries, tag=None, **kwargs):
+ if isinstance(entries, type) and issubclass(entries, _enum.Enum):
+ entries = dict(entries.__members__)
+ if isinstance(entries, dict):
+ entries = tuple(entries.items())
+ if tag is None:
+ tag = f"svp64_{name.lower()}"
+
+ cls = super().__call__(value=name, names=entries, **kwargs)
+ cls.__tag = tag
+ return cls
-class Enum(CType, _enum.Enum):
+ @property
+ def c_typedef(cls):
+ return f"enum {cls.c_tag}"
+
+ @property
+ def c_tag(cls):
+ return cls.__tag
+
+ def c_var(cls, name, prefix="", suffix=""):
+ yield f"{prefix}{cls.c_typedef} {name}{suffix}"
+
+
+class Enum(CType, _enum.Enum, metaclass=EnumMeta):
@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}"
+ yield f"{prefix}{self.__class__.c_tag.upper()}_{self.name.upper()}{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)
+
+
+class Constant(CType, _enum.Enum, metaclass=EnumMeta):
@classmethod
- def c_var(cls, name):
- c_tag = f"svp64_{cls.__name__.lower()}"
- yield f"enum {c_tag} {name}"
+ def c_decl(cls):
+ yield f"/* {cls.c_tag.upper()} constants */"
+ 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}"
-# 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})
+Mode = Constant("Mode", _SVP64MODE)
-class Opcode(CType):
- def __init__(self, value, mask, bits):
- self.__value = value
- self.__mask = mask
- self.__bits = bits
- return super().__init__()
+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}"
- @property
- def value(self):
- return self.__value
+ cls = super().__new__(metacls, name, bases, attrs, **kwargs)
+ cls.__tag = tag
- @property
- def mask(self):
- return self.__mask
+ return cls
@property
- def bits(self):
- return self.__bits
+ def c_tag(cls):
+ return cls.__tag
- def __repr__(self):
- fmt = f"{{value:0{self.bits}b}}:{{mask:0{self.bits}b}}"
- return fmt.format(value=self.value, mask=self.mask)
-
- @classmethod
def c_decl(cls):
- yield f"struct svp64_opcode {{"
- yield from indent([
- "uint32_t value;",
- "uint32_t mask;",
- ])
+ yield f"{cls.c_typedef} {{"
+ for field in _dataclasses.fields(cls):
+ yield from indent(field.type.c_var(name=f"{field.name}", suffix=";"))
yield f"}};"
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class Struct(CType, metaclass=StructMeta):
def c_value(self, prefix="", suffix=""):
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 IntegerOpcode(Opcode):
- def __init__(self, integer):
- value = int(integer, 0)
- bits = max(1, value.bit_length())
- mask = int(("1" * bits), 2)
+class Integer(CType, int):
+ def c_value(self, prefix="", suffix=""):
+ yield f"{prefix}{self}{suffix}"
- return super().__init__(value=value, mask=mask, bits=bits)
+class Byte(Integer, 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
- return super().__init__(value=value, mask=mask, bits=bits)
+class Size(Integer, typedef="size_t"):
+ pass
class Name(CType, str):
yield f"{prefix}{self!r}{suffix}"
@classmethod
- def c_var(cls, name):
- yield f"const char *{name}"
+ def c_var(cls, name, prefix="", suffix=""):
+ yield f"{prefix}const char *{name}{suffix}"
@_dataclasses.dataclass(eq=True, frozen=True)
-class Entry(CType):
- name: Name
- opcode: Opcode
+class Record(Struct):
in1: In1Sel
in2: In2Sel
in3: In3Sel
sv_cr_in: SVEXTRA
sv_cr_out: SVEXTRA
- def __lt__(self, other):
- if not isinstance(other, self.__class__):
- return NotImplemented
- return self.name < other.name
-
@classmethod
def c_decl(cls):
bits_all = 0
- yield f"struct svp64_entry {{"
+ yield f"struct svp64_record {{"
for field in _dataclasses.fields(cls):
- if issubclass(field.type, Enum):
- bits = len(field.type).bit_length()
- yield from indent([f"uint64_t {field.name} : {bits};"])
- bits_all += bits
- else:
- yield from indent(field.type.c_var(name=f"{field.name};"))
+ bits = len(field.type).bit_length()
+ yield from indent([f"uint64_t {field.name} : {bits};"])
+ bits_all += bits
bits_rsvd = (64 - (bits_all % 64))
if bits_rsvd:
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}"
- @classmethod
- def c_var(cls, name):
- yield f"struct svp64_entry {name}"
+@_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
class Codegen(_enum.Enum):
- PPC_OPC_SVP64_H = _enum.auto()
- PPC_OPC_SVP64_C = _enum.auto()
+ PPC_SVP64_H = _enum.auto()
+ PPC_SVP64_OPC_C = _enum.auto()
@classmethod
def _missing_(cls, value):
return {
- "ppc-opc-svp64.h": Codegen.PPC_OPC_SVP64_H,
- "ppc-opc-svp64.c": Codegen.PPC_OPC_SVP64_C,
- }[value]
+ "ppc-svp64.h": Codegen.PPC_SVP64_H,
+ "ppc-svp64-opc.c": Codegen.PPC_SVP64_OPC_C,
+ }.get(value)
def __str__(self):
return {
- Codegen.PPC_OPC_SVP64_H: "ppc-opc-svp64.h",
- Codegen.PPC_OPC_SVP64_C: "ppc-opc-svp64.c",
+ Codegen.PPC_SVP64_H: "ppc-svp64.h",
+ Codegen.PPC_SVP64_OPC_C: "ppc-svp64-opc.c",
}[self]
def generate(self, entries):
- def ppc_opc_svp64_h(entries):
+ def ppc_svp64_h(entries):
yield from DISCLAIMER
yield ""
yield f"#define {self.name}"
yield ""
- yield from Opcode.c_decl()
+ yield "#include <stdint.h>"
+ yield ""
+
+ yield "#ifdef __cplusplus"
+ yield "extern \"C\" {"
+ yield "#endif"
yield ""
enums = (
In1Sel, In2Sel, In3Sel, OutSel,
CRInSel, CROutSel,
SVPType, SVEType, SVEXTRA,
+ Mode,
)
for enum in enums:
yield from enum.c_decl()
yield ""
+ yield from Record.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 from Entry.c_decl()
yield ""
+ yield "extern const struct svp64_entry svp64_entries[];"
+ yield "extern const unsigned int svp64_num_entries;"
+ yield ""
+
+ yield f"#define SVP64_NAME_MAX {max(map(lambda entry: len(entry.name), entries))}"
+ yield ""
+
+ yield "#ifdef __cplusplus"
+ yield "}"
+ yield "#endif"
+ yield ""
+
yield f"#endif /* {self.name} */"
yield ""
- def ppc_opc_svp64_c(entries):
- yield from ()
+ def ppc_svp64_opc_c(entries):
+ yield from DISCLAIMER
+ yield ""
+
+ yield "#include \"opcode/ppc-svp64.h\""
+ yield ""
+
+ def opsel(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 "{"
+ yield from indent(["static const unsigned char 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(["};"])
+ yield ""
+ yield from indent([f"return table[record->{name}];"])
+ yield "}"
+ yield ""
+
+ yield from opsel(In1Sel, "in1", {
+ In1Sel.RA: "RA",
+ In1Sel.RA_OR_ZERO: "RA",
+ In1Sel.SPR: "SPR",
+ In1Sel.RS: "RS",
+ In1Sel.FRA: "FRA",
+ In1Sel.FRS: "FRS",
+ })
+ yield from opsel(In2Sel, "in2", {
+ In2Sel.RB: "RB",
+ In2Sel.SPR: "SPR",
+ In2Sel.RS: "RS",
+ In2Sel.FRB: "FRB",
+ })
+ yield from opsel(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 opsel(OutSel, name, {
+ OutSel.RT: "RT",
+ OutSel.RA: "RA",
+ OutSel.SPR: "SPR",
+ OutSel.RT_OR_ZERO: "RT",
+ OutSel.FRT: "FRT",
+ OutSel.FRS: "FRS",
+ })
+ yield from opsel(CRInSel, "cr_in", {
+ CRInSel.BI: "BI",
+ CRInSel.BFA: "BFA",
+ CRInSel.BC: "CRB",
+ CRInSel.WHOLE_REG: "FXM",
+ })
+ yield from opsel(CROutSel, "cr_out", {
+ CROutSel.BF: "BF",
+ CROutSel.BT: "BT",
+ CROutSel.WHOLE_REG: "FXM",
+ })
+
+ 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"}};"
+ yield ""
+
+ yield "const unsigned int svp64_num_entries = \\"
+ yield " sizeof (svp64_entries) / sizeof (svp64_entries[0]);"
+ yield ""
return {
- Codegen.PPC_OPC_SVP64_H: ppc_opc_svp64_h,
- Codegen.PPC_OPC_SVP64_C: ppc_opc_svp64_c,
+ 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<opcode>{PATTERN_VHDL_BINARY}|{PATTERN_DECIMAL}|{PATTERN_PARTIAL_BINARY})",
- r"\s?=>\s?",
- r"\(",
- r",\s".join((
- rf"(?P<ptype>{regex_enum(_SVPtype)})",
- rf"(?P<etype>{regex_enum(_SVEtype)})",
- rf"(?P<in1>{regex_enum(_In1Sel)})",
- rf"(?P<in2>{regex_enum(_In2Sel)})",
- rf"(?P<in3>{regex_enum(_In3Sel)})",
- rf"(?P<out>{regex_enum(_OutSel)})",
- rf"(?P<out2>{regex_enum(_OutSel)})",
- rf"(?P<cr_in>{regex_enum(_CRInSel)})",
- rf"(?P<cr_out>{regex_enum(_CROutSel)})",
- rf"(?P<sv_in1>{regex_enum(_SVEXTRA)})",
- rf"(?P<sv_in2>{regex_enum(_SVEXTRA)})",
- rf"(?P<sv_in3>{regex_enum(_SVEXTRA)})",
- rf"(?P<sv_out>{regex_enum(_SVEXTRA)})",
- rf"(?P<sv_out2>{regex_enum(_SVEXTRA)})",
- rf"(?P<sv_cr_in>{regex_enum(_SVEXTRA)})",
- rf"(?P<sv_cr_out>{regex_enum(_SVEXTRA)})",
- )),
- r"\)",
- r",",
- r"\s?--\s?",
- r"(?P<name>[A-Za-z0-9_\./]+)",
- r"\s*$",
-))
-REGEX = _re.compile(PATTERN)
+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()
-ISA = _SVP64RM()
-FIELDS = {field.name:field for field in _dataclasses.fields(Entry)}
-def parse(path, opcode_cls):
- for entry in ISA.get_svp64_csv(path):
- # skip instructions that are not suitable
- name = entry["name"] = entry.pop("comment").split("=")[-1]
+ def name_filter(name):
if name.startswith("l") and name.endswith("br"):
- continue
+ return False
if name in {"mcrxr", "mcrxrx", "darn"}:
- continue
+ return False
if name in {"bctar", "bcctr"}:
- continue
+ return False
if "rfid" in name:
- continue
+ return False
if name in {"setvl"}:
- continue
+ return False
+ if name in visited:
+ return False
- entry = {key.lower().replace(" ", "_"):value for (key, value) in entry.items()}
- for (key, value) in tuple(entry.items()):
- key = key.lower().replace(" ", "_")
- if key not in FIELDS:
- entry.pop(key)
+ 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]
else:
- field = FIELDS[key]
- if issubclass(field.type, _enum.Enum):
- value = {item.name:item for item in field.type}[value]
- elif issubclass(field.type, Opcode):
- value = opcode_cls(value)
- else:
- value = field.type(value)
- entry[key] = value
+ value = cls(value)
+ return (key, value)
+
+ def item_filter(item):
+ (key, _) = item
+ return (key in FIELDS)
- yield Entry(**entry)
+ 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))
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(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):
print(line)