2 import argparse
as _argparse
3 import dataclasses
as _dataclasses
5 import operator
as _operator
7 from openpower
.decoder
.power_enums
import (
13 CROutSel
as _CROutSel
,
19 from openpower
.consts
import SVP64MODE
as _SVP64MODE
20 from openpower
.decoder
.power_svp64
import SVP64RM
as _SVP64RM
21 from openpower
.decoder
.isa
.caller
import SVP64RMFields
as _SVP64RMFields
22 from openpower
.decoder
.isa
.caller
import SVP64PrefixFields
as _SVP64PrefixFields
23 from openpower
.decoder
.selectable_int
import SelectableIntMapping
28 Copyright (C) 2022 Free Software Foundation, Inc.
29 Written by Dmitry Selyutin (ghostmansd).
30 Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073.
32 This file is part of the GNU opcodes library.
34 This library is free software; you can redistribute it and/or modify
35 it under the terms of the GNU General Public License as published by
36 the Free Software Foundation; either version 3, or (at your option)
39 It is distributed in the hope that it will be useful, but WITHOUT
40 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
41 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
42 License for more details.
44 You should have received a copy of the GNU General Public License
45 along with this file; see the file COPYING. If not, write to the
46 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
47 MA 02110-1301, USA. */\
52 return map(lambda string
: (" " + string
), strings
)
55 class CTypeMeta(type):
56 def __new__(metacls
, name
, bases
, attrs
, typedef
=None):
57 cls
= super().__new
__(metacls
, name
, bases
, attrs
)
58 cls
.__typedef
= typedef
62 def __getitem__(cls
, size
):
63 name
= f
"{cls.__name__}[{'' if size is Ellipsis else size}]"
64 return type(name
, (Array
,), {}, type=cls
, size
=size
)
74 def c_var(cls
, name
, prefix
="", suffix
=""):
75 return f
"{prefix}{cls.c_typedef} {name}{suffix}"
78 class ArrayMeta(CTypeMeta
):
79 def __new__(metacls
, name
, bases
, attrs
, type, size
, **kwargs
):
80 cls
= super().__new
__(metacls
, name
, bases
, attrs
, **kwargs
)
82 cls
.__ellipsis
= (size
is Ellipsis)
83 cls
.__size
= 0 if cls
.__ellipsis
else size
91 size
= "" if cls
.__ellipsis
else f
"{cls.__size}"
92 yield f
"{cls.__type.c_typedef}[{size}]"
94 def c_var(cls
, name
, prefix
="", suffix
=""):
95 size
= "" if cls
.__ellipsis
else f
"{cls.__size}"
96 return f
"{prefix}{cls.__type.c_typedef} {name}[{size}]{suffix}"
99 class BitmapMeta(CTypeMeta
):
100 def __new__(metacls
, name
, bases
, attrs
,
101 typedef
="uint64_t", bits
=0, **kwargs
):
102 cls
= super().__new
__(metacls
, name
, bases
, attrs
,
103 typedef
=typedef
, **kwargs
)
110 def c_var(cls
, name
, prefix
="", suffix
=""):
111 return f
"{prefix}{cls.c_typedef} {name} : {cls.__bits}{suffix}"
114 class CType(metaclass
=CTypeMeta
):
116 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
120 class Array(CType
, tuple, metaclass
=ArrayMeta
, type=CType
, size
=...):
121 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
123 for (index
, item
) in enumerate(self
):
124 yield from indent(item
.c_value(suffix
=","))
128 class Bitmap(metaclass
=BitmapMeta
):
132 class Void(CType
, typedef
="void"):
133 def c_var(cls
, name
, prefix
="", suffix
=""):
134 raise NotImplementedError
137 class EnumMeta(_enum
.EnumMeta
, CTypeMeta
):
138 def __call__(metacls
, name
, entries
, tag
=None, exclude
=None, **kwargs
):
140 exclude
= frozenset()
141 if isinstance(entries
, type) and issubclass(entries
, _enum
.Enum
):
142 # Use __members__, not __iter__, otherwise aliases are lost.
143 entries
= dict(entries
.__members
__)
144 if isinstance(entries
, dict):
145 entries
= tuple(entries
.items())
146 entries
= ((key
, value
) for (key
, value
) in entries
if key
not in exclude
)
148 tag
= f
"svp64_{name.lower()}"
150 cls
= super().__call
__(value
=name
, names
=entries
, **kwargs
)
157 return f
"enum {cls.c_tag}"
164 yield f
"{cls.c_typedef} {{"
166 yield from indent(item
.c_value(suffix
=","))
169 def c_var(cls
, name
, prefix
="", suffix
=""):
170 return f
"{prefix}{cls.c_typedef} {name}{suffix}"
173 class Enum(CType
, _enum
.Enum
, metaclass
=EnumMeta
):
176 return f
"{self.__class__.c_tag.upper()}_{self.name.upper()}"
178 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
179 yield f
"{prefix}{self.c_name}{suffix}"
182 In1Sel
= Enum("In1Sel", _In1Sel
, tag
="svp64_in1_sel")
183 In2Sel
= Enum("In2Sel", _In2Sel
, tag
="svp64_in2_sel")
184 In3Sel
= Enum("In3Sel", _In3Sel
, tag
="svp64_in3_sel")
185 OutSel
= Enum("OutSel", _OutSel
, tag
="svp64_out_sel")
186 CRInSel
= Enum("CRInSel", _CRInSel
, tag
="svp64_cr_in_sel")
187 CROutSel
= Enum("CROutSel", _CROutSel
, tag
="svp64_cr_out_sel")
188 PType
= Enum("PType", _SVPtype
, tag
="svp64_ptype")
189 EType
= Enum("EType", _SVEtype
, tag
="svp64_etype", exclude
="NONE")
190 Extra
= Enum("Extra", _SVEXTRA
, tag
="svp64_extra", exclude
="Idx_1_2")
193 class Constant(CType
, _enum
.Enum
, metaclass
=EnumMeta
):
196 yield f
"/* {cls.c_tag.upper()} constants */"
197 # Use __members__, not __iter__, otherwise aliases are lost.
198 for (key
, item
) in cls
.__members
__.items():
199 key
= f
"{cls.c_tag.upper()}_{key.upper()}"
200 value
= f
"0x{item.value:08x}U"
201 yield f
"#define {key} {value}"
203 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
204 yield f
"{prefix}{self.__class__.c_tag.upper()}_{self.c_name.upper()}{suffix}"
207 Mode
= Constant("Mode", _SVP64MODE
)
210 class StructMeta(CTypeMeta
):
211 def __new__(metacls
, name
, bases
, attrs
, tag
=None, **kwargs
):
213 tag
= f
"svp64_{name.lower()}"
214 if "typedef" not in kwargs
:
215 kwargs
["typedef"] = f
"struct {tag}"
217 cls
= super().__new
__(metacls
, name
, bases
, attrs
, **kwargs
)
227 yield f
"{cls.c_typedef} {{"
228 for field
in _dataclasses
.fields(cls
):
229 yield from indent([field
.type.c_var(name
=f
"{field.name}",
234 @_dataclasses.dataclass(eq
=True, frozen
=True)
235 class Struct(CType
, metaclass
=StructMeta
):
236 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
238 for field
in _dataclasses
.fields(self
):
240 attr
= getattr(self
, name
)
241 yield from indent(attr
.c_value(prefix
=f
".{name} = ", suffix
=","))
245 class Integer(CType
, str):
246 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
247 yield f
"{prefix}{self}{suffix}"
250 class Byte(Integer
, typedef
="uint8_t"):
254 class Size(Integer
, typedef
="size_t"):
258 class UInt32(Integer
, typedef
="uint32_t"):
262 class Name(CType
, str):
264 escaped
= self
.replace("\"", "\\\"")
265 return f
"\"{escaped}\""
267 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
268 yield f
"{prefix}{self!r}{suffix}"
271 def c_var(cls
, name
, prefix
="", suffix
=""):
272 return f
"{prefix}const char *{name}{suffix}"
275 @_dataclasses.dataclass(eq
=True, frozen
=True)
276 class Record(Struct
):
297 yield f
"struct svp64_record {{"
298 for field
in _dataclasses
.fields(cls
):
299 bits
= len(field
.type).bit_length()
300 yield from indent([f
"uint64_t {field.name} : {bits};"])
302 bits_rsvd
= (64 - (bits_all
% 64))
304 yield from indent([f
"uint64_t : {bits_rsvd};"])
308 @_dataclasses.dataclass(eq
=True, frozen
=True)
313 def __lt__(self
, other
):
314 if not isinstance(other
, self
.__class
__):
315 return NotImplemented
317 return self
.name
< other
.name
320 class FunctionMeta(CTypeMeta
):
321 def __new__(metacls
, name
, bases
, attrs
, rv
, args
):
322 cls
= super().__new
__(metacls
, name
, bases
, attrs
)
328 def c_var(cls
, name
, prefix
="", suffix
=""):
329 rv
= cls
.__rv
.c_typedef
330 args
= ", ".join(arg_cls
.c_var(arg_name
) \
331 for (arg_name
, arg_cls
) in cls
.__args
)
332 return f
"{prefix}{rv} {name}({args}){suffix}"
335 class FieldsMappingMeta(EnumMeta
):
336 class HelperMeta(FunctionMeta
):
337 def __new__(metacls
, name
, bases
, attrs
, rv
, args
, enum
):
338 cls
= super().__new
__(metacls
, name
, bases
, attrs
, rv
=rv
, args
=args
)
343 short_c_tag
= cls
.__enum
.c_tag
[:-len("_field")]
344 # Use __members__, not __iter__, otherwise aliases are lost.
345 for (name
, value
) in cls
.__enum
.__members
__.items():
346 yield (f
"{short_c_tag}_{name}".upper(), value
)
348 class GetterMeta(HelperMeta
):
349 def __new__(metacls
, name
, bases
, attrs
, enum
, struct
):
350 return super().__new
__(metacls
, name
, bases
, attrs
,
351 enum
=enum
, rv
=UInt32
, args
=(
356 class SetterMeta(HelperMeta
):
357 def __new__(metacls
, name
, bases
, attrs
, enum
, struct
):
358 return super().__new
__(metacls
, name
, bases
, attrs
, enum
=enum
,
360 ("*storage", struct
),
365 def __call__(metacls
, name
, base
=SelectableIntMapping
, **kwargs
):
366 def flatten(mapping
, parent
=""):
367 for (key
, value
) in mapping
.items():
368 key
= f
"{parent}_{key}" if parent
else key
369 if isinstance(value
, dict):
370 yield from flatten(mapping
=value
, parent
=key
)
372 value
= map(lambda bit
: bit
, reversed(value
))
373 # value = map(lambda bit: ((base.bits - 1) - bit),
375 yield (key
.upper(), tuple(value
))
377 tag
= f
"svp64_{name.lower()}"
378 fields
= dict(flatten(mapping
=dict(base
)))
379 bitmap
= type(name
, (Bitmap
,), {}, typedef
="uint32_t", bits
=base
.bits
)
380 struct
= _dataclasses
.make_dataclass(name
, (("value", bitmap
),),
381 bases
=(Struct
,), frozen
=True, eq
=True)
383 cls
= super().__call
__(name
=name
, entries
=fields
, tag
=f
"{tag}_field",
386 def c_value(fields
, stmt
):
387 yield "switch (field) {"
388 for (field_name
, field_value
) in fields
:
389 yield from indent([f
"case {field_name}:"])
390 yield from indent(indent(map(stmt
,
391 enumerate(field_value
.value
))))
392 yield from indent(indent(["break;"]))
395 class Getter(metaclass
=FieldsMappingMeta
.GetterMeta
,
396 enum
=cls
, struct
=struct
):
397 def c_value(self
, prefix
="", suffix
=""):
400 UInt32
.c_var(name
="result", suffix
=" = UINT32_C(0);"),
401 UInt32
.c_var(name
="origin", suffix
=" = storage.value;"),
404 yield from indent(c_value(fields
=self
.__class
__,
405 stmt
=lambda kv
: f
"result |= SVP64_FIELD_GET(origin, {kv[1]}, {kv[0]});"))
407 yield from indent(["return result;"])
410 class Setter(metaclass
=FieldsMappingMeta
.SetterMeta
,
411 enum
=cls
, struct
=struct
):
412 def c_value(self
, prefix
="", suffix
=""):
415 UInt32
.c_var(name
="result", suffix
=" = storage->value;"),
418 yield from indent(c_value(fields
=self
.__class
__,
419 stmt
=lambda kv
: f
"SVP64_FIELD_SET(&result, value, {kv[0]}, {kv[1]});"))
421 yield from indent(["storage->value = result;"])
425 cls
.__struct
= struct
426 cls
.__getter
= Getter()
427 cls
.__setter
= Setter()
440 yield f
"{cls.c_typedef} {{"
441 for field_name
in cls
.__members
__.keys():
442 short_c_tag
= cls
.c_tag
[:-len("_field")]
443 yield from indent([f
"{short_c_tag}_{field_name},".upper()])
445 yield from cls
.__struct
.c_decl()
446 yield cls
.__getter
.__class
__.c_var(name
=f
"{cls.__tag}_get", suffix
=";")
447 yield cls
.__setter
.__class
__.c_var(name
=f
"{cls.__tag}_set", suffix
=";")
450 class FieldsMapping(Enum
, metaclass
=FieldsMappingMeta
):
453 short_c_tag
= self
.__class
__.c_tag
[:-len("_field")]
454 return f
"{short_c_tag}_{self.name}".upper()
457 Prefix
= FieldsMapping("Prefix", base
=_SVP64PrefixFields
)
458 RM
= FieldsMapping("RM", base
=_SVP64RMFields
)
461 class Codegen(_enum
.Enum
):
462 PPC_SVP64_H
= _enum
.auto()
463 PPC_SVP64_OPC_C
= _enum
.auto()
466 def _missing_(cls
, value
):
468 "ppc-svp64.h": Codegen
.PPC_SVP64_H
,
469 "ppc-svp64-opc.c": Codegen
.PPC_SVP64_OPC_C
,
474 Codegen
.PPC_SVP64_H
: "ppc-svp64.h",
475 Codegen
.PPC_SVP64_OPC_C
: "ppc-svp64-opc.c",
478 def generate(self
, entries
):
479 def ppc_svp64_h(entries
, num_entries
):
480 disclaimer
= DISCLAIMER
.format(path
=str(self
),
481 desc
="Header file for PowerPC opcode table (SVP64 extensions)")
482 yield from disclaimer
.splitlines()
485 yield f
"#ifndef {self.name}"
486 yield f
"#define {self.name}"
489 yield "#include <stdint.h>"
492 yield "#ifdef __cplusplus"
493 yield "extern \"C\" {"
498 In1Sel
, In2Sel
, In3Sel
, OutSel
,
504 yield from enum
.c_decl()
507 for cls
in (Record
, Entry
, Prefix
, RM
):
508 yield from cls
.c_decl()
511 for name
in ("in1", "in2", "in3", "out", "out2", "cr_in", "cr_out"):
512 yield "ppc_opindex_t"
513 yield f
"svp64_record_{name}_opindex(const struct svp64_record *record);"
516 yield entries
.__class
__.c_var("svp64_entries",
517 prefix
="extern const ", suffix
=";")
518 yield num_entries
.__class
__.c_var("svp64_num_entries",
519 prefix
="extern const ", suffix
=";")
522 yield f
"#define SVP64_NAME_MAX {max(map(lambda entry: len(entry.name), entries))}"
525 yield "#ifdef __cplusplus"
530 yield f
"#endif /* {self.name} */"
533 def ppc_svp64_opc_c(entries
, num_entries
):
534 disclaimer
= DISCLAIMER
.format(path
=str(self
),
535 desc
="PowerPC opcode list (SVP64 extensions)")
536 yield from disclaimer
.splitlines()
539 yield "#include \"opcode/ppc-svp64.h\""
542 def opindex(enum
, name
, table
):
543 sep
= (max(map(len, list(table
.values()) + ["UNUSED"])) + 1)
544 c_tag
= f
"svp64_{enum.__name__.lower()}"
545 yield "ppc_opindex_t"
546 yield f
"svp64_record_{name}_opindex(const struct svp64_record *record)"
548 yield from indent(["static const ppc_opindex_t table[] = {"])
550 value
= table
.get(key
, "UNUSED")
551 yield from indent(indent([f
"{value:{sep}}, /* {key.c_name} */"]))
552 yield from indent(["};"])
554 yield from indent([f
"return table[record->{name}];"])
558 yield from opindex(In1Sel
, "in1", {
560 In1Sel
.RA_OR_ZERO
: "RA",
566 yield from opindex(In2Sel
, "in2", {
572 yield from opindex(In3Sel
, "in3", {
580 for name
in ("out", "out2"):
581 yield from opindex(OutSel
, name
, {
585 OutSel
.RT_OR_ZERO
: "RT",
589 yield from opindex(CRInSel
, "cr_in", {
593 CRInSel
.WHOLE_REG
: "FXM",
595 yield from opindex(CROutSel
, "cr_out", {
598 CROutSel
.WHOLE_REG
: "FXM",
601 yield entries
.__class
__.c_var("svp64_entries",
602 prefix
="const ", suffix
=" = \\")
603 yield from entries
.c_value(prefix
="", suffix
=";")
605 yield num_entries
.__class
__.c_var("svp64_num_entries",
606 prefix
="const ", suffix
=" = \\")
607 yield from indent(num_entries
.c_value(suffix
=";"))
610 bit_shl
= lambda val
, pos
: f
"({val} << UINT32_C({pos}))"
611 bit_shr
= lambda val
, pos
: f
"({val} >> UINT32_C({pos}))"
612 bit_get
= lambda val
, pos
: f
"({bit_shr(val, pos)} & UINT32_C(1))"
613 bit_or
= lambda lhs
, rhs
: f
"({lhs} | {rhs})"
614 bit_and
= lambda lhs
, rhs
: f
"({lhs} & {rhs})"
615 bit_not
= lambda val
: f
"~({val})"
621 bit_and("VALUE", bit_not(bit_shl("UINT32_C(1)", "BIT"))),
625 ("VALUE", "SRC", "DST"),
626 bit_shl(bit_get("VALUE", "SRC"), "DST"),
630 ("ORIGIN", "SRC", "DST"),
631 "SVP64_FIELD_REMAP(ORIGIN, SRC, DST)",
635 ("RESULT", "VALUE", "SRC", "DST"),
636 ("do { (*RESULT) = " + bit_or(
637 lhs
="SVP64_FIELD_CLEAR(*(RESULT), DST)",
638 rhs
="SVP64_FIELD_REMAP(VALUE, SRC, DST)",
639 ) + "; } while (0)"),
642 for (name
, args
, body
) in macros
:
643 yield f
"#define {name}({', '.join(args)}) \\"
644 yield from indent([body
])
647 for cls
in (Prefix
, RM
):
652 for (mode
, subcls
) in table
.items():
653 yield subcls
.__class
__.c_var(name
=f
"svp64_{cls.__name__.lower()}_{mode}")
654 yield from subcls
.c_value()
657 for name
in map(_operator
.itemgetter(0), macros
):
658 yield f
"#undef {name}"
662 entries
= Entry
[...](entries
)
663 num_entries
= Size("(sizeof (svp64_entries) / sizeof (svp64_entries[0]))")
666 Codegen
.PPC_SVP64_H
: ppc_svp64_h
,
667 Codegen
.PPC_SVP64_OPC_C
: ppc_svp64_opc_c
,
668 }[self
](entries
, num_entries
)
672 FIELDS
= {field
.name
:field
.type for field
in _dataclasses
.fields(Record
)}
677 def name_filter(name
):
678 if name
.startswith("l") and name
.endswith("br"):
680 if name
in {"mcrxr", "mcrxrx", "darn"}:
682 if name
in {"bctar", "bcctr"}:
686 if name
in {"setvl"}:
695 for data
in ISA
.get_svp64_csv(path
):
696 comment
= data
.pop("comment")
697 names
= comment
.split("=")[-1].split("/")
698 names
= set(filter(name_filter
, names
))
701 rc
= _RC
[data
["rc"] if data
["rc"] else "NONE"]
703 names
.update({f
"{name}." for name
in names
})
706 for (key
, value
) in data
.items():
707 key
= key
.lower().replace(" ", "_")
708 cls
= FIELDS
.get(key
)
712 if ((cls
is EType
and value
== "NONE") or
713 (cls
is Extra
and value
== "Idx_1_2")):
717 if not isinstance(value
, cls
):
718 if issubclass(cls
, _enum
.Enum
):
719 value
= {item
.name
:item
for item
in cls
}[value
]
727 record
= Record(**record
)
728 for name
in map(Name
, names
):
729 yield Entry(name
=name
, record
=record
)
748 entries
.extend(parse(path
))
749 entries
= sorted(frozenset(entries
))
751 for line
in codegen
.generate(entries
):
755 if __name__
== "__main__":
756 parser
= _argparse
.ArgumentParser()
757 parser
.add_argument("codegen",
758 type=Codegen
, choices
=Codegen
,
759 help="code generator")
761 args
= vars(parser
.parse_args())