import argparse as _argparse
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
pass
-class Enum(CType, _enum.Enum):
+class EnumMeta(_enum.EnumMeta):
+ def __call__(metacls, *args, **kwargs):
+ if len(args) > 1:
+ names = args[1]
+ else:
+ names = kwargs.pop("names")
+
+ if isinstance(names, type) and issubclass(names, _enum.Enum):
+ names = dict(names.__members__)
+ if isinstance(names, dict):
+ names = tuple(names.items())
+
+ return super().__call__(*args, names=names, **kwargs)
+
+
+class Enum(CType, _enum.Enum, metaclass=EnumMeta):
@classmethod
def c_decl(cls):
c_tag = f"svp64_{cls.__name__.lower()}"
yield f"enum {c_tag} {name}"
-# 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})
+In1Sel = Enum("In1Sel", names=_In1Sel.__members__.items())
+In2Sel = Enum("In2Sel", names=_In2Sel.__members__.items())
+In3Sel = Enum("In3Sel", names=_In3Sel.__members__.items())
+OutSel = Enum("OutSel", names=_OutSel.__members__.items())
+CRInSel = Enum("CRInSel", names=_CRInSel.__members__.items())
+CROutSel = Enum("CROutSel", names=_CROutSel.__members__.items())
+SVPType = Enum("SVPType", names=_SVPtype.__members__.items())
+SVEType = Enum("SVEType", names=_SVEtype.__members__.items())
+SVEXTRA = Enum("SVEXTRA", names=_SVEXTRA.__members__.items())
+
+
+class Constant(CType, _enum.Enum):
+ @classmethod
+ def c_decl(cls):
+ c_tag = f"svp64_{cls.__name__.lower()}"
+ yield f"/* {c_tag.upper()} constants */"
+ for (key, item) in cls.__members__.items():
+ key = f"{c_tag.upper()}_{key.upper()}"
+ value = f"0x{item.value:08x}U"
+ yield f"#define {key} {value}"
+
+ def c_value(self, prefix="", suffix=""):
+ c_tag = f"svp64_{self.__class__.__name__.lower()}"
+ yield f"{prefix}{c_tag.upper()}_{self.name.upper()}{suffix}"
+
+
+Mode = Constant("Mode", names=_SVP64MODE.__members__.items())
class Opcode(CType):
fmt = f"{{value:0{self.bits}b}}:{{mask:0{self.bits}b}}"
return fmt.format(value=self.value, mask=self.mask)
+ def __lt__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+
+ return self.__value < other.__value
+
@classmethod
def c_decl(cls):
yield f"struct svp64_opcode {{"
@_dataclasses.dataclass(eq=True, frozen=True)
-class Entry(CType):
- name: Name
- opcode: Opcode
+class Record(CType):
in1: In1Sel
in2: In2Sel
in3: In3Sel
sv_cr_in: SVEXTRA
sv_cr_out: SVEXTRA
+ @classmethod
+ def c_decl(cls):
+ bits_all = 0
+ yield f"struct svp64_record {{"
+ for field in _dataclasses.fields(cls):
+ 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_record {name}"
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class Entry(CType):
+ name: Name
+ record: Record
+
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 {{"
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_rsvd = (64 - (bits_all % 64))
- if bits_rsvd:
- yield from indent([f"uint64_t : {bits_rsvd};"])
+ yield from indent(field.type.c_var(name=f"{field.name};"))
yield f"}};"
def c_value(self, prefix="", suffix=""):
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 "#include <stdint.h>"
yield ""
- yield from Opcode.c_decl()
+ 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 ""
+
yield from Entry.c_decl()
yield ""
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):
+ def ppc_svp64_opc_c(entries):
yield from DISCLAIMER
yield ""
- yield "#include \"ppc-opc-svp64.h\""
+ yield "#include \"opcode/ppc-svp64.h\""
yield ""
- yield "const struct svp64_entry svp64_entries[] = {{"
+ 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 f"const unsigned int svp64_num_entries = {len(entries)};"
+ 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 for field in _dataclasses.fields(Entry)}
+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, opcode_cls):
- for entry in ISA.get_svp64_csv(path):
- # skip instructions that are not suitable
- name = entry["name"] = entry.pop("comment").split("=")[-1]
+ visited = set()
+
+ 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
+
+ visited.add(name)
+
+ return True
- 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)
+ 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
-
- yield Entry(**entry)
+ value = cls(value)
+ return (key, value)
+
+ def item_filter(item):
+ (key, _) = item
+ return (key in FIELDS)
+
+ for record in ISA.get_svp64_csv(path):
+ opcode = opcode_cls(record.pop("opcode"))
+ 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):