sv_binutils: inherit Entry from Field
[openpower-isa.git] / src / openpower / sv / sv_binutils.py
index 2c22323bae6eac0a60e688c123320544b067e263..99346891873fc7ea5a1ef6e10497691486439c98 100644 (file)
@@ -1,11 +1,8 @@
 import abc as _abc
 import argparse as _argparse
-import codecs as _codecs
 import dataclasses as _dataclasses
 import enum as _enum
-import pathlib as _pathlib
 import re as _re
-import sys as _sys
 
 from openpower.decoder.power_enums import (
     In1Sel as _In1Sel,
@@ -18,6 +15,7 @@ from openpower.decoder.power_enums import (
     SVEtype as _SVEtype,
     SVEXTRA as _SVEXTRA,
 )
+from openpower.decoder.power_svp64 import SVP64RM as _SVP64RM
 
 
 DISCLAIMER = (
@@ -65,7 +63,7 @@ class Enum(Field, _enum.Enum):
     @classmethod
     def c_var(cls, name):
         c_tag = f"svp64_{cls.__name__.lower()}"
-        yield f"enum {c_tag} {name};"
+        yield f"enum {c_tag} {name}"
 
 
 # Python forbids inheriting from enum unless it's empty.
@@ -80,13 +78,75 @@ 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, str):
+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}\"{self}\"{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"const char *{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):
@@ -99,11 +159,11 @@ class Name(Field, str):
 
     @classmethod
     def c_var(cls, name):
-        yield f"const char *{name};"
+        yield f"const char *{name}"
 
 
 @_dataclasses.dataclass(eq=True, frozen=True)
-class Entry:
+class Entry(Field):
     name: Name
     opcode: Opcode
     in1: In1Sel
@@ -113,8 +173,8 @@ class Entry:
     out2: OutSel
     cr_in: CRInSel
     cr_out: CROutSel
-    ptype: SVPType
-    etype: SVEType
+    sv_ptype: SVPType
+    sv_etype: SVEType
     sv_in1: SVEXTRA
     sv_in2: SVEXTRA
     sv_in3: SVEXTRA
@@ -123,15 +183,25 @@ class Entry:
     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=field.name))
+                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=""):
@@ -144,7 +214,7 @@ class Entry:
 
     @classmethod
     def c_var(cls, name):
-        yield f"struct svp64_entry {name};"
+        yield f"struct svp64_entry {name}"
 
 
 class Codegen(_enum.Enum):
@@ -173,11 +243,13 @@ class Codegen(_enum.Enum):
             yield f"#define {self.name}"
             yield ""
 
+            yield from Opcode.c_decl()
+            yield ""
+
             enums = (
-                PType, EType,
                 In1Sel, In2Sel, In3Sel, OutSel,
                 CRInSel, CROutSel,
-                SVEXTRA,
+                SVPType, SVEType, SVEXTRA,
             )
             for enum in enums:
                 yield from enum.c_decl()
@@ -243,24 +315,60 @@ PATTERN = "".join((
 REGEX = _re.compile(PATTERN)
 
 
-def parse(stream):
-    for line in stream:
-        match = REGEX.match(line)
-        if match is not None:
-            entry = match.groupdict()
-            for field in _dataclasses.fields(Entry):
-                key = field.name
-                value = entry[key]
+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)
+
+        yield Entry(**entry)
 
 
 def main(codegen):
-    entries = tuple(parse(_sys.stdin))
+    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)
+
     for line in codegen.generate(entries):
         print(line)