sv_binutils: introduce Integer class
[openpower-isa.git] / src / openpower / sv / sv_binutils.py
index e11c9f4738f7f590f3b6b0eabd94316dd09e75c7..6b0a9776f682729209e5f458ca02741b9de45680 100644 (file)
@@ -32,83 +32,139 @@ def indent(strings):
     return map(lambda string: ("    " + string), strings)
 
 
-class CType:
-    @classmethod
+class CTypeMeta(type):
     @_abc.abstractmethod
-    def c_decl(self, name):
+    def c_decl(cls):
         pass
 
     @_abc.abstractmethod
-    def c_value(self, prefix="", suffix=""):
+    def c_var(cls, name):
         pass
 
-    @classmethod
+
+class CType(metaclass=CTypeMeta):
     @_abc.abstractmethod
-    def c_var(self, name):
+    def c_value(self, prefix="", suffix=""):
         pass
 
 
-class EnumMeta(_enum.EnumMeta):
-    def __call__(metacls, *args, **kwargs):
-        if len(args) > 1:
-            names = args[1]
-        else:
-            names = kwargs.pop("names")
+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()}"
 
-        if isinstance(names, type) and issubclass(names, _enum.Enum):
-            names = dict(names.__members__)
-        if isinstance(names, dict):
-            names = tuple(names.items())
+        cls = super().__call__(value=name, names=entries, **kwargs)
+        cls.__tag = tag
+        return cls
 
-        return super().__call__(*args, names=names, **kwargs)
+    @property
+    def c_tag(cls):
+        return cls.__tag
 
 
 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"enum {cls.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}"
+        yield f"{prefix}{self.__class__.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}"
+        yield f"enum {cls.c_tag} {name}"
 
 
-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())
+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):
+class Constant(CType, _enum.Enum, metaclass=EnumMeta):
     @classmethod
     def c_decl(cls):
-        c_tag = f"svp64_{cls.__name__.lower()}"
-        yield f"/* {c_tag.upper()} constants */"
+        yield f"/* {cls.c_tag.upper()} constants */"
         for (key, item) in cls.__members__.items():
-            key = f"{c_tag.upper()}_{key.upper()}"
+            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=""):
-        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}"
+
+
+Mode = Constant("Mode", _SVP64MODE)
 
 
-Mode = Constant("Mode", names=_SVP64MODE.__members__.items())
+class StructMeta(CTypeMeta):
+    def __new__(metacls, name, bases, attrs, tag=None):
+        if tag is None:
+            tag = f"svp64_{name.lower()}"
+
+        cls = super().__new__(metacls, name, bases, attrs)
+        cls.__tag = tag
+
+        return cls
+
+    @property
+    def c_tag(cls):
+        return cls.__tag
+
+    def c_decl(cls):
+        yield f"struct {cls.c_tag} {{"
+        for field in _dataclasses.fields(cls):
+            yield from indent(field.type.c_var(name=f"{field.name};"))
+        yield f"}};"
+
+    def c_var(cls, name):
+        yield f"struct {cls.c_tag} {name}"
+
+
+@_dataclasses.dataclass(eq=True, frozen=True)
+class Struct(CType, metaclass=StructMeta):
+    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}"
+
+
+class IntegerMeta(CTypeMeta):
+    def __new__(metacls, name, bases, attrs, typedef=None):
+        cls = super().__new__(metacls, name, bases, attrs)
+        cls.__typedef = typedef
+
+        return cls
+
+    @property
+    def c_typedef(cls):
+        return cls.__typedef
+
+    def c_decl(cls):
+        yield "#include <stdint.h>"
+
+    def c_var(cls, name):
+        yield f"{cls.c_typedef} {name}"
+
+
+class Integer(CType, int, metaclass=IntegerMeta):
+    def c_value(self, prefix="", suffix=""):
+        yield f"{prefix}{self}{suffix}"
 
 
 class Opcode(CType):
@@ -202,7 +258,7 @@ class Name(CType, str):
 
 
 @_dataclasses.dataclass(eq=True, frozen=True)
-class Record(CType):
+class Record(Struct):
     in1: In1Sel
     in2: In2Sel
     in3: In3Sel
@@ -233,21 +289,9 @@ class Record(CType):
             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):
+class Entry(Struct):
     name: Name
     record: Record
 
@@ -257,25 +301,6 @@ class Entry(CType):
 
         return self.name < other.name
 
-    @classmethod
-    def c_decl(cls):
-        yield f"struct svp64_entry {{"
-        for field in _dataclasses.fields(cls):
-            yield from indent(field.type.c_var(name=f"{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}"
-
 
 class Codegen(_enum.Enum):
     PPC_SVP64_H = _enum.auto()
@@ -324,6 +349,11 @@ class Codegen(_enum.Enum):
             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 ""
 
@@ -349,6 +379,66 @@ class Codegen(_enum.Enum):
             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=","))