X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fopenpower%2Fsv%2Fsv_binutils.py;h=1c0e4106f202fa85f2ef71379c98fda0ac63c42d;hb=cbcde50a720aeba00bdb5f8e087cfbd532279f91;hp=6846076346d3bafac8202cfd378a4ec75d3f30e8;hpb=5daf93104a4fdc383fc4a3eabce416c624fa8e6b;p=openpower-isa.git diff --git a/src/openpower/sv/sv_binutils.py b/src/openpower/sv/sv_binutils.py index 68460763..1c0e4106 100644 --- a/src/openpower/sv/sv_binutils.py +++ b/src/openpower/sv/sv_binutils.py @@ -1,8 +1,8 @@ import abc as _abc import argparse as _argparse +import builtins as _builtins import dataclasses as _dataclasses import enum as _enum -import re as _re from openpower.decoder.power_enums import ( In1Sel as _In1Sel, @@ -14,7 +14,9 @@ from openpower.decoder.power_enums import ( 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 @@ -31,128 +33,177 @@ def indent(strings): return map(lambda string: (" " + string), strings) -class CType: - @classmethod +class CTypeMeta(type): + def __new__(metacls, name, bases, attrs, typedef=None): + cls = super().__new__(metacls, name, bases, attrs) + cls.__typedef = typedef + + return cls + + def __getitem__(cls, size): + name = f"{cls.__name__}[{'' if size is Ellipsis else size}]" + return type(name, (Array,), {}, type=cls, size=size) + + @property + def c_typedef(cls): + return cls.__typedef + @_abc.abstractmethod - def c_decl(self, name): - pass + def c_decl(cls): + yield from () + + def c_var(cls, name, prefix="", suffix=""): + yield f"{prefix}{cls.c_typedef} {name}{suffix}" + + +class ArrayMeta(CTypeMeta): + def __new__(metacls, name, bases, attrs, type, size): + cls = super().__new__(metacls, name, bases, attrs) + cls.__type = type + cls.__ellipsis = (size is Ellipsis) + cls.__size = 0 if cls.__ellipsis else size + + return cls + + def __len__(cls): + return cls.__size + @property + def c_type(cls): + return cls.__type + + def c_decl(cls): + size = "" if cls.__ellipsis else f"{cls.__size}" + yield f"{cls.c_type.c_typedef}[{size}]" + + def c_var(cls, name, prefix="", suffix=""): + size = "" if cls.__ellipsis else f"{cls.__size}" + yield f"{prefix}{cls.c_type.c_typedef} {name}[{size}]{suffix}" + + +class CType(metaclass=CTypeMeta): @_abc.abstractmethod def c_value(self, prefix="", suffix=""): - pass + yield from () - @classmethod - @_abc.abstractmethod - def c_var(self, name): - pass + +class Array(CType, tuple, metaclass=ArrayMeta, type=CType, size=0): + def c_value(self, prefix="", suffix=""): + yield f"{prefix}{{" + for (index, item) in enumerate(self): + yield from indent(item.c_value(prefix=f"[{index}] = ", suffix=",")) + yield f"}}{suffix}" + + +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()}" + + cls = super().__call__(value=name, names=entries, **kwargs) + cls.__tag = tag + return cls + + @property + def c_typedef(cls): + return f"enum {cls.c_tag}" + + @property + def c_tag(cls): + return cls.__tag + + def c_var(cls, name, prefix="", suffix=""): + yield f"{prefix}{cls.c_typedef} {name}{suffix}" -class Enum(CType, _enum.Enum): +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"{cls.c_typedef} {{" 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}" +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) -# 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 Constant(CType, _enum.Enum, metaclass=EnumMeta): + @classmethod + def c_decl(cls): + yield f"/* {cls.c_tag.upper()} constants */" + for (key, item) in cls.__members__.items(): + key = f"{cls.c_tag.upper()}_{key.upper()}" + value = f"0x{item.value:08x}U" + yield f"#define {key} {value}" -class Opcode(CType): - def __init__(self, value, mask, bits): - self.__value = value - self.__mask = mask - self.__bits = bits + def c_value(self, prefix="", suffix=""): + yield f"{prefix}{self.__class__.c_tag.upper()}_{self.name.upper()}{suffix}" - return super().__init__() - @property - def value(self): - return self.__value +Mode = Constant("Mode", _SVP64MODE) - @property - def mask(self): - return self.__mask - @property - def bits(self): - return self.__bits +class StructMeta(CTypeMeta): + def __new__(metacls, name, bases, attrs, tag=None, **kwargs): + if tag is None: + tag = f"svp64_{name.lower()}" + if "typedef" not in kwargs: + kwargs["typedef"] = f"struct {tag}" - def __repr__(self): - fmt = f"{{value:0{self.bits}b}}:{{mask:0{self.bits}b}}" - return fmt.format(value=self.value, mask=self.mask) + cls = super().__new__(metacls, name, bases, attrs, **kwargs) + cls.__tag = tag - def __lt__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented + return cls - return self.__value < other.__value + @property + def c_tag(cls): + return cls.__tag - @classmethod def c_decl(cls): - yield f"struct svp64_opcode {{" - yield from indent([ - "uint32_t value;", - "uint32_t mask;", - ]) + yield f"{cls.c_typedef} {{" + for field in _dataclasses.fields(cls): + yield from indent(field.type.c_var(name=f"{field.name}", suffix=";")) yield f"}};" + +@_dataclasses.dataclass(eq=True, frozen=True) +class Struct(CType, metaclass=StructMeta): 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}),", - ]) + 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_opcode {name}" - -class IntegerOpcode(Opcode): - def __init__(self, integer): - value = int(integer, 0) - bits = max(1, value.bit_length()) - mask = int(("1" * bits), 2) +class Integer(CType, int): + def c_value(self, prefix="", suffix=""): + yield f"{prefix}{self}{suffix}" - return super().__init__(value=value, mask=mask, bits=bits) +class Byte(Integer, typedef="uint8_t"): + pass -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 Size(Integer, typedef="size_t"): + pass class Name(CType, str): @@ -164,12 +215,12 @@ class Name(CType, str): yield f"{prefix}{self!r}{suffix}" @classmethod - def c_var(cls, name): - yield f"const char *{name}" + def c_var(cls, name, prefix="", suffix=""): + yield f"{prefix}const char *{name}{suffix}" @_dataclasses.dataclass(eq=True, frozen=True) -class Record(CType): +class Record(Struct): in1: In1Sel in2: In2Sel in3: In3Sel @@ -200,21 +251,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 @@ -224,25 +263,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() @@ -282,6 +302,7 @@ class Codegen(_enum.Enum): In1Sel, In2Sel, In3Sel, OutSel, CRInSel, CROutSel, SVPType, SVEType, SVEXTRA, + Mode, ) for enum in enums: yield from enum.c_decl() @@ -290,6 +311,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 "" @@ -315,6 +341,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=",")) @@ -331,110 +417,75 @@ class Codegen(_enum.Enum): }[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{PATTERN_VHDL_BINARY}|{PATTERN_DECIMAL}|{PATTERN_PARTIAL_BINARY})", - r"\s?=>\s?", - r"\(", - r",\s".join(( - rf"(?P{regex_enum(_SVPtype)})", - rf"(?P{regex_enum(_SVEtype)})", - rf"(?P{regex_enum(_In1Sel)})", - rf"(?P{regex_enum(_In2Sel)})", - rf"(?P{regex_enum(_In3Sel)})", - rf"(?P{regex_enum(_OutSel)})", - rf"(?P{regex_enum(_OutSel)})", - rf"(?P{regex_enum(_CRInSel)})", - rf"(?P{regex_enum(_CROutSel)})", - rf"(?P{regex_enum(_SVEXTRA)})", - rf"(?P{regex_enum(_SVEXTRA)})", - rf"(?P{regex_enum(_SVEXTRA)})", - rf"(?P{regex_enum(_SVEXTRA)})", - rf"(?P{regex_enum(_SVEXTRA)})", - rf"(?P{regex_enum(_SVEXTRA)})", - rf"(?P{regex_enum(_SVEXTRA)})", - )), - r"\)", - r",", - r"\s?--\s?", - r"(?P[A-Za-z0-9_\./]+)", - r"\s*$", -)) -REGEX = _re.compile(PATTERN) - - ISA = _SVP64RM() -FIELDS = {field.name:field for field in _dataclasses.fields(Record)} -FIELDS.update({field.name:field for field in _dataclasses.fields(Entry)}) -def parse(path, opcode_cls): +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): visited = set() + + def name_filter(name): + if name.startswith("l") and name.endswith("br"): + return False + if name in {"mcrxr", "mcrxrx", "darn"}: + return False + if name in {"bctar", "bcctr"}: + return False + if "rfid" in name: + return False + if name in {"setvl"}: + return False + if name in visited: + return False + + visited.add(name) + + return True + + 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: + 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] - for name in map(Name, names.split("/")): - 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 - - record = {key.lower().replace(" ", "_"):value for (key, value) in record.items()} - for (key, value) in tuple(record.items()): - key = key.lower().replace(" ", "_") - if key not in FIELDS: - record.pop(key) - continue - - field = FIELDS[key] - if not isinstance(value, field.type): - if issubclass(field.type, _enum.Enum): - value = {item.name:item for item in field.type}[value] - else: - value = field.type(value) - - record[key] = value - - if name not in visited: + 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)) - visited.add(name) - 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)) + paths = ( + "minor_19.csv", + "minor_30.csv", + "minor_31.csv", + "minor_58.csv", + "minor_62.csv", + "minor_22.csv", + "minor_5.csv", + "minor_63.csv", + "minor_59.csv", + "major.csv", + "extra.csv", + ) + for path in paths: + entries.extend(parse(path)) entries = sorted(frozenset(entries)) for line in codegen.generate(entries):