sv_binutils: introduce helper classes
authorDmitry Selyutin <dmitry.selyutin@3mdeb.com>
Thu, 30 Dec 2021 16:55:33 +0000 (16:55 +0000)
committerDmitry Selyutin <dmitry.selyutin@3mdeb.com>
Wed, 5 Jan 2022 16:35:10 +0000 (16:35 +0000)
src/openpower/sv/sv_binutils.py

index dc85cc4bacbcc8f004852615716e8bfb160c85f7..5990c103ced621c2118be9edc4996c894512777c 100644 (file)
@@ -1,3 +1,4 @@
+import abc as _abc
 import argparse as _argparse
 import codecs as _codecs
 import dataclasses as _dataclasses
@@ -5,40 +6,135 @@ import enum as _enum
 import pathlib as _pathlib
 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,
 )
 
 
+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, str):
+    def c_value(self, prefix="", suffix=""):
+        yield f"{prefix}\"{self}\"{suffix}"
+
+    @classmethod
+    def c_var(cls, name):
+        yield f"const char *{name};"
+
+
+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:
-    opcode: str
-    ptype: _SVPtype
-    etype: _SVEtype
-    in1: _In1Sel
-    in2: _In2Sel
-    in3: _In3Sel
-    out: _OutSel
-    out2: _OutSel
-    cr_in: _CRInSel
-    cr_out: _CROutSel
-    sv_in1: _SVEXTRA
-    sv_in2: _SVEXTRA
-    sv_in3: _SVEXTRA
-    sv_out: _SVEXTRA
-    sv_out2: _SVEXTRA
-    sv_cr_in: _SVEXTRA
-    sv_cr_out: _SVEXTRA
-    name: str
+    name: Name
+    opcode: Opcode
+    in1: In1Sel
+    in2: In2Sel
+    in3: In3Sel
+    out: OutSel
+    out2: OutSel
+    cr_in: CRInSel
+    cr_out: CROutSel
+    ptype: SVPType
+    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
+
+    @classmethod
+    def c_decl(cls):
+        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};"])
+            else:
+                yield from indent(field.type.c_var(name=field.name))
+        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};"
 
 
 def regex_enum(enum):
@@ -92,16 +188,12 @@ def parse(stream):
         if match is not None:
             entry = match.groupdict()
             for field in _dataclasses.fields(Entry):
-                cls = field.type
                 key = field.name
                 value = entry[key]
-                if issubclass(cls, _enum.Enum):
-                    value = {item.name:item for item in cls}[value]
-                elif key == "opcode":
-                    if value.startswith("2#"):
-                        value = value[2:-1]
+                if issubclass(field.type, _enum.Enum):
+                    value = {item.name:item for item in field.type}[value]
                 else:
-                    value = cls(value)
+                    value = field.type(value)
                 entry[key] = value
             yield Entry(**entry)