+import abc as _abc
import argparse as _argparse
-import codecs as _codecs
-import pathlib as _pathlib
+import dataclasses as _dataclasses
+import enum as _enum
import re as _re
-
from openpower.decoder.power_enums import (
- SVPtype as _SVPtype,
- SVEtype as _SVEtype,
In1Sel as _In1Sel,
In2Sel as _In2Sel,
In3Sel as _In3Sel,
OutSel as _OutSel,
CRInSel as _CRInSel,
CROutSel as _CROutSel,
+ SVPtype as _SVPtype,
+ SVEtype as _SVEtype,
SVEXTRA as _SVEXTRA,
)
+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",
+ " * part of Libre-SOC, sponsored by NLnet",
+ " */",
+)
+
+
+def indent(strings):
+ return map(lambda string: (" " + string), strings)
+
+
+class Field:
+ @classmethod
+ @_abc.abstractmethod
+ def c_decl(self, name):
+ pass
+
+ @_abc.abstractmethod
+ def c_value(self, prefix="", suffix=""):
+ pass
+
+ @classmethod
+ @_abc.abstractmethod
+ def c_var(self, name):
+ pass
+
+
+class Enum(Field, _enum.Enum):
+ @classmethod
+ def c_decl(cls):
+ c_tag = f"svp64_{cls.__name__.lower()}"
+ yield f"enum {c_tag} {{"
+ 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}"
+
+ @classmethod
+ def c_var(cls, name):
+ 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})
+
+
+class Opcode(Field):
+ def __init__(self, value, mask, bits):
+ self.__value = value
+ self.__mask = mask
+ self.__bits = bits
+
+ return super().__init__()
+
+ @property
+ def value(self):
+ return self.__value
+
+ @property
+ def mask(self):
+ return self.__mask
+
+ @property
+ def bits(self):
+ return self.__bits
+
+ 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"}};"
+
+ 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}),",
+ ])
+ 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)
+ return super().__init__(value=value, mask=mask, bits=bits)
+
+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 Name(Field, str):
+ def __repr__(self):
+ escaped = self.replace("\"", "\\\"")
+ return f"\"{escaped}\""
+
+ def c_value(self, prefix="", suffix=""):
+ yield f"{prefix}{self!r}{suffix}"
+
+ @classmethod
+ def c_var(cls, name):
+ yield f"const char *{name}"
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class Entry(Field):
+ name: Name
+ opcode: Opcode
+ in1: In1Sel
+ in2: In2Sel
+ in3: In3Sel
+ out: OutSel
+ out2: OutSel
+ cr_in: CRInSel
+ 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
+
+ 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 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_OPC_SVP64_H = _enum.auto()
+ PPC_OPC_SVP64_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]
+
+ def __str__(self):
+ return {
+ Codegen.PPC_OPC_SVP64_H: "ppc-opc-svp64.h",
+ Codegen.PPC_OPC_SVP64_C: "ppc-opc-svp64.c",
+ }[self]
+
+ def generate(self, entries):
+ def ppc_opc_svp64_h(entries):
+ yield from DISCLAIMER
+ yield ""
+
+ yield f"#ifndef {self.name}"
+ yield f"#define {self.name}"
+ yield ""
+
+ yield from Opcode.c_decl()
+ yield ""
+
+ enums = (
+ In1Sel, In2Sel, In3Sel, OutSel,
+ CRInSel, CROutSel,
+ SVPType, SVEType, SVEXTRA,
+ )
+ for enum in enums:
+ yield from enum.c_decl()
+ yield ""
+
+ yield from Entry.c_decl()
+ yield ""
+
+ yield f"#endif /* {self.name} */"
+ yield ""
+
+ def ppc_opc_svp64_c(entries):
+ yield from ()
+
+ return {
+ Codegen.PPC_OPC_SVP64_H: ppc_opc_svp64_h,
+ Codegen.PPC_OPC_SVP64_C: ppc_opc_svp64_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*",
- r"(?P<opcode>(?:2#[01]+#)|(?:[0-9]+)|(?:[01-]+))",
+ rf"(?P<opcode>{PATTERN_VHDL_BINARY}|{PATTERN_DECIMAL}|{PATTERN_PARTIAL_BINARY})",
r"\s?=>\s?",
r"\(",
r",\s".join((
- rf"(?P<ptype>{'|'.join(item.name for item in _SVPtype)})",
- rf"(?P<etype>{'|'.join(item.name for item in _SVEtype)})",
- rf"(?P<in1>{'|'.join(item.name for item in _In1Sel)})",
- rf"(?P<in2>{'|'.join(item.name for item in _In2Sel)})",
- rf"(?P<in3>{'|'.join(item.name for item in _In3Sel)})",
- rf"(?P<out>{'|'.join(item.name for item in _OutSel)})",
- rf"(?P<out2>{'|'.join(item.name for item in _OutSel)})",
- rf"(?P<cr_in>{'|'.join(item.name for item in _CRInSel)})",
- rf"(?P<cr_out>{'|'.join(item.name for item in _CROutSel)})",
- rf"(?P<sv_in1>{'|'.join(item.name for item in _SVEXTRA)})",
- rf"(?P<sv_in2>{'|'.join(item.name for item in _SVEXTRA)})",
- rf"(?P<sv_in3>{'|'.join(item.name for item in _SVEXTRA)})",
- rf"(?P<sv_out>{'|'.join(item.name for item in _SVEXTRA)})",
- rf"(?P<sv_out2>{'|'.join(item.name for item in _SVEXTRA)})",
- rf"(?P<sv_cr_in>{'|'.join(item.name for item in _SVEXTRA)})",
- rf"(?P<sv_cr_out>{'|'.join(item.name for item in _SVEXTRA)})",
+ 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<insn>[A-Za-z0-9_\./]+)",
+ r"(?P<name>[A-Za-z0-9_\./]+)",
r"\s*$",
))
REGEX = _re.compile(PATTERN)
-def parse(stream):
- for line in stream:
- match = REGEX.match(line)
- if match is not None:
- yield match.groupdict()
+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]
+ 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
+
+ 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)
+ 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)
-def main(vhdl):
- insns = []
- with _codecs.open(vhdl, "rb", "UTF-8") as stream:
- for insn in parse(stream):
- insns.append(insn)
+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)
- print(f"{len(insns)} instructions found")
+ for line in codegen.generate(entries):
+ print(line)
if __name__ == "__main__":
parser = _argparse.ArgumentParser()
- parser.add_argument("vhdl", type=_pathlib.Path, help="sv_decode.vhdl path")
+ parser.add_argument("codegen", type=Codegen, choices=Codegen, help="code generator")
args = vars(parser.parse_args())
main(**args)