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, **kwargs
):
139 if isinstance(entries
, type) and issubclass(entries
, _enum
.Enum
):
140 # Use __members__, not __iter__, otherwise aliases are lost.
141 entries
= dict(entries
.__members
__)
142 if isinstance(entries
, dict):
143 entries
= tuple(entries
.items())
145 tag
= f
"svp64_{name.lower()}"
147 cls
= super().__call
__(value
=name
, names
=entries
, **kwargs
)
154 return f
"enum {cls.c_tag}"
161 yield f
"{cls.c_typedef} {{"
163 yield from indent(item
.c_value(suffix
=","))
166 def c_var(cls
, name
, prefix
="", suffix
=""):
167 return f
"{prefix}{cls.c_typedef} {name}{suffix}"
170 class Enum(CType
, _enum
.Enum
, metaclass
=EnumMeta
):
173 return f
"{self.__class__.c_tag.upper()}_{self.name.upper()}"
175 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
176 yield f
"{prefix}{self.c_name}{suffix}"
179 In1Sel
= Enum("In1Sel", _In1Sel
)
180 In2Sel
= Enum("In2Sel", _In2Sel
)
181 In3Sel
= Enum("In3Sel", _In3Sel
)
182 OutSel
= Enum("OutSel", _OutSel
)
183 CRInSel
= Enum("CRInSel", _CRInSel
)
184 CROutSel
= Enum("CROutSel", _CROutSel
)
185 SVPType
= Enum("SVPType", _SVPtype
)
186 SVEType
= Enum("SVEType", _SVEtype
)
187 SVEXTRA
= Enum("SVEXTRA", _SVEXTRA
)
190 class Constant(CType
, _enum
.Enum
, metaclass
=EnumMeta
):
193 yield f
"/* {cls.c_tag.upper()} constants */"
194 # Use __members__, not __iter__, otherwise aliases are lost.
195 for (key
, item
) in cls
.__members
__.items():
196 key
= f
"{cls.c_tag.upper()}_{key.upper()}"
197 value
= f
"0x{item.value:08x}U"
198 yield f
"#define {key} {value}"
200 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
201 yield f
"{prefix}{self.__class__.c_tag.upper()}_{self.name.upper()}{suffix}"
204 Mode
= Constant("Mode", _SVP64MODE
)
207 class StructMeta(CTypeMeta
):
208 def __new__(metacls
, name
, bases
, attrs
, tag
=None, **kwargs
):
210 tag
= f
"svp64_{name.lower()}"
211 if "typedef" not in kwargs
:
212 kwargs
["typedef"] = f
"struct {tag}"
214 cls
= super().__new
__(metacls
, name
, bases
, attrs
, **kwargs
)
224 yield f
"{cls.c_typedef} {{"
225 for field
in _dataclasses
.fields(cls
):
226 yield from indent([field
.type.c_var(name
=f
"{field.name}",
231 @_dataclasses.dataclass(eq
=True, frozen
=True)
232 class Struct(CType
, metaclass
=StructMeta
):
233 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
235 for field
in _dataclasses
.fields(self
):
237 attr
= getattr(self
, name
)
238 yield from indent(attr
.c_value(prefix
=f
".{name} = ", suffix
=","))
242 class Integer(CType
, str):
243 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
244 yield f
"{prefix}{self}{suffix}"
247 class Byte(Integer
, typedef
="uint8_t"):
251 class Size(Integer
, typedef
="size_t"):
255 class UInt32(Integer
, typedef
="uint32_t"):
259 class Name(CType
, str):
261 escaped
= self
.replace("\"", "\\\"")
262 return f
"\"{escaped}\""
264 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
265 yield f
"{prefix}{self!r}{suffix}"
268 def c_var(cls
, name
, prefix
="", suffix
=""):
269 return f
"{prefix}const char *{name}{suffix}"
272 @_dataclasses.dataclass(eq
=True, frozen
=True)
273 class Record(Struct
):
294 yield f
"struct svp64_record {{"
295 for field
in _dataclasses
.fields(cls
):
296 bits
= len(field
.type).bit_length()
297 yield from indent([f
"uint64_t {field.name} : {bits};"])
299 bits_rsvd
= (64 - (bits_all
% 64))
301 yield from indent([f
"uint64_t : {bits_rsvd};"])
305 @_dataclasses.dataclass(eq
=True, frozen
=True)
310 def __lt__(self
, other
):
311 if not isinstance(other
, self
.__class
__):
312 return NotImplemented
314 return self
.name
< other
.name
317 class FunctionMeta(CTypeMeta
):
318 def __new__(metacls
, name
, bases
, attrs
, rv
, args
):
319 cls
= super().__new
__(metacls
, name
, bases
, attrs
)
325 def c_var(cls
, name
, prefix
="", suffix
=""):
326 rv
= cls
.__rv
.c_typedef
327 args
= ", ".join(arg_cls
.c_var(arg_name
) \
328 for (arg_name
, arg_cls
) in cls
.__args
)
329 return f
"{prefix}{rv} {name}({args}){suffix}"
332 class FieldsMappingMeta(EnumMeta
):
333 class HelperMeta(FunctionMeta
):
334 def __new__(metacls
, name
, bases
, attrs
, rv
, args
, enum
):
335 cls
= super().__new
__(metacls
, name
, bases
, attrs
, rv
=rv
, args
=args
)
340 short_c_tag
= cls
.__enum
.c_tag
[:-len("_field")]
341 # Use __members__, not __iter__, otherwise aliases are lost.
342 for (name
, value
) in cls
.__enum
.__members
__.items():
343 yield (f
"{short_c_tag}_{name}".upper(), value
)
345 class GetterMeta(HelperMeta
):
346 def __new__(metacls
, name
, bases
, attrs
, enum
, struct
):
347 return super().__new
__(metacls
, name
, bases
, attrs
,
348 enum
=enum
, rv
=UInt32
, args
=(
353 class SetterMeta(HelperMeta
):
354 def __new__(metacls
, name
, bases
, attrs
, enum
, struct
):
355 return super().__new
__(metacls
, name
, bases
, attrs
, enum
=enum
,
357 ("*storage", struct
),
362 def __call__(metacls
, name
, base
=SelectableIntMapping
, **kwargs
):
363 def flatten(mapping
, parent
=""):
364 for (key
, value
) in mapping
.items():
365 key
= f
"{parent}_{key}" if parent
else key
366 if isinstance(value
, dict):
367 yield from flatten(mapping
=value
, parent
=key
)
369 value
= map(lambda bit
: bit
, reversed(value
))
370 # value = map(lambda bit: ((base.bits - 1) - bit),
372 yield (key
.upper(), tuple(value
))
374 tag
= f
"svp64_{name.lower()}"
375 fields
= dict(flatten(mapping
=dict(base
)))
376 bitmap
= type(name
, (Bitmap
,), {}, typedef
="uint32_t", bits
=base
.bits
)
377 struct
= _dataclasses
.make_dataclass(name
, (("value", bitmap
),),
378 bases
=(Struct
,), frozen
=True, eq
=True)
380 cls
= super().__call
__(name
=name
, entries
=fields
, tag
=f
"{tag}_field",
383 def c_value(fields
, stmt
):
384 yield "switch (field) {"
385 for (field_name
, field_value
) in fields
:
386 yield from indent([f
"case {field_name}:"])
387 yield from indent(indent(map(stmt
,
388 enumerate(field_value
.value
))))
389 yield from indent(indent(["break;"]))
392 class Getter(metaclass
=FieldsMappingMeta
.GetterMeta
,
393 enum
=cls
, struct
=struct
):
394 def c_value(self
, prefix
="", suffix
=""):
397 UInt32
.c_var(name
="result", suffix
=" = UINT32_C(0);"),
398 UInt32
.c_var(name
="origin", suffix
=" = storage.value;"),
401 yield from indent(c_value(fields
=self
.__class
__,
402 stmt
=lambda kv
: f
"result |= SVP64_FIELD_GET(origin, {kv[1]}, {kv[0]});"))
404 yield from indent(["return result;"])
407 class Setter(metaclass
=FieldsMappingMeta
.SetterMeta
,
408 enum
=cls
, struct
=struct
):
409 def c_value(self
, prefix
="", suffix
=""):
412 UInt32
.c_var(name
="result", suffix
=" = storage->value;"),
415 yield from indent(c_value(fields
=self
.__class
__,
416 stmt
=lambda kv
: f
"SVP64_FIELD_SET(&result, value, {kv[0]}, {kv[1]});"))
418 yield from indent(["storage->value = result;"])
422 cls
.__struct
= struct
423 cls
.__getter
= Getter()
424 cls
.__setter
= Setter()
437 yield f
"{cls.c_typedef} {{"
438 for field_name
in cls
.__members
__.keys():
439 short_c_tag
= cls
.c_tag
[:-len("_field")]
440 yield from indent([f
"{short_c_tag}_{field_name},".upper()])
442 yield from cls
.__struct
.c_decl()
443 yield cls
.__getter
.__class
__.c_var(name
=f
"{cls.__tag}_get", suffix
=";")
444 yield cls
.__setter
.__class
__.c_var(name
=f
"{cls.__tag}_set", suffix
=";")
447 class FieldsMapping(Enum
, metaclass
=FieldsMappingMeta
):
450 short_c_tag
= self
.__class
__.c_tag
[:-len("_field")]
451 return f
"{short_c_tag}_{self.name}".upper()
454 Prefix
= FieldsMapping("Prefix", base
=_SVP64PrefixFields
)
455 RM
= FieldsMapping("RM", base
=_SVP64RMFields
)
458 class Codegen(_enum
.Enum
):
459 PPC_SVP64_H
= _enum
.auto()
460 PPC_SVP64_OPC_C
= _enum
.auto()
463 def _missing_(cls
, value
):
465 "ppc-svp64.h": Codegen
.PPC_SVP64_H
,
466 "ppc-svp64-opc.c": Codegen
.PPC_SVP64_OPC_C
,
471 Codegen
.PPC_SVP64_H
: "ppc-svp64.h",
472 Codegen
.PPC_SVP64_OPC_C
: "ppc-svp64-opc.c",
475 def generate(self
, entries
):
476 def ppc_svp64_h(entries
, num_entries
):
477 disclaimer
= DISCLAIMER
.format(path
=str(self
),
478 desc
="Header file for PowerPC opcode table (SVP64 extensions)")
479 yield from disclaimer
.splitlines()
482 yield f
"#ifndef {self.name}"
483 yield f
"#define {self.name}"
486 yield "#include <stdint.h>"
489 yield "#ifdef __cplusplus"
490 yield "extern \"C\" {"
495 In1Sel
, In2Sel
, In3Sel
, OutSel
,
497 SVPType
, SVEType
, SVEXTRA
,
501 yield from enum
.c_decl()
504 for cls
in (Record
, Entry
, Prefix
, RM
):
505 yield from cls
.c_decl()
508 for name
in ("in1", "in2", "in3", "out", "out2", "cr_in", "cr_out"):
509 yield "unsigned char"
510 yield f
"svp64_record_{name}_opindex(const struct svp64_record *record);"
513 yield entries
.__class
__.c_var("svp64_entries",
514 prefix
="extern const ", suffix
=";")
515 yield num_entries
.__class
__.c_var("svp64_num_entries",
516 prefix
="extern const ", suffix
=";")
519 yield f
"#define SVP64_NAME_MAX {max(map(lambda entry: len(entry.name), entries))}"
522 yield "#ifdef __cplusplus"
527 yield f
"#endif /* {self.name} */"
530 def ppc_svp64_opc_c(entries
, num_entries
):
531 disclaimer
= DISCLAIMER
.format(path
=str(self
),
532 desc
="PowerPC opcode list (SVP64 extensions)")
533 yield from disclaimer
.splitlines()
536 yield "#include \"opcode/ppc-svp64.h\""
539 def opindex(enum
, name
, table
):
540 sep
= (max(map(len, list(table
.values()) + ["UNUSED"])) + 1)
541 c_tag
= f
"svp64_{enum.__name__.lower()}"
542 yield "unsigned char"
543 yield f
"svp64_record_{name}_opindex(const struct svp64_record *record)"
545 yield from indent(["static const unsigned char table[] = {"])
547 value
= table
.get(key
, "UNUSED")
548 c_value
= f
"{c_tag.upper()}_{key.name.upper()}"
549 yield from indent(indent([f
"{value:{sep}}, /* {c_value} */"]))
550 yield from indent(["};"])
552 yield from indent([f
"return table[record->{name}];"])
556 yield from opindex(In1Sel
, "in1", {
558 In1Sel
.RA_OR_ZERO
: "RA",
564 yield from opindex(In2Sel
, "in2", {
570 yield from opindex(In3Sel
, "in3", {
578 for name
in ("out", "out2"):
579 yield from opindex(OutSel
, name
, {
583 OutSel
.RT_OR_ZERO
: "RT",
587 yield from opindex(CRInSel
, "cr_in", {
591 CRInSel
.WHOLE_REG
: "FXM",
593 yield from opindex(CROutSel
, "cr_out", {
596 CROutSel
.WHOLE_REG
: "FXM",
599 yield entries
.__class
__.c_var("svp64_entries",
600 prefix
="const ", suffix
=" = \\")
601 yield from entries
.c_value(prefix
="", suffix
=";")
603 yield num_entries
.__class
__.c_var("svp64_num_entries",
604 prefix
="const ", suffix
=" = \\")
605 yield from indent(num_entries
.c_value(suffix
=";"))
608 bit_shl
= lambda val
, pos
: f
"({val} << UINT32_C({pos}))"
609 bit_shr
= lambda val
, pos
: f
"({val} >> UINT32_C({pos}))"
610 bit_get
= lambda val
, pos
: f
"({bit_shr(val, pos)} & UINT32_C(1))"
611 bit_or
= lambda lhs
, rhs
: f
"({lhs} | {rhs})"
612 bit_and
= lambda lhs
, rhs
: f
"({lhs} & {rhs})"
613 bit_not
= lambda val
: f
"~({val})"
619 bit_and("VALUE", bit_not(bit_shl("UINT32_C(1)", "BIT"))),
623 ("VALUE", "SRC", "DST"),
624 bit_shl(bit_get("VALUE", "SRC"), "DST"),
628 ("ORIGIN", "SRC", "DST"),
629 "SVP64_FIELD_REMAP(ORIGIN, SRC, DST)",
633 ("RESULT", "VALUE", "SRC", "DST"),
634 ("do { (*RESULT) = " + bit_or(
635 lhs
="SVP64_FIELD_CLEAR(*(RESULT), DST)",
636 rhs
="SVP64_FIELD_REMAP(VALUE, SRC, DST)",
637 ) + "; } while (0)"),
640 for (name
, args
, body
) in macros
:
641 yield f
"#define {name}({', '.join(args)}) \\"
642 yield from indent([body
])
645 for cls
in (Prefix
, RM
):
650 for (mode
, subcls
) in table
.items():
651 yield subcls
.__class
__.c_var(name
=f
"svp64_{cls.__name__.lower()}_{mode}")
652 yield from subcls
.c_value()
655 for name
in map(_operator
.itemgetter(0), macros
):
656 yield f
"#undef {name}"
660 entries
= Entry
[...](entries
)
661 num_entries
= Size("(sizeof (svp64_entries) / sizeof (svp64_entries[0]))")
664 Codegen
.PPC_SVP64_H
: ppc_svp64_h
,
665 Codegen
.PPC_SVP64_OPC_C
: ppc_svp64_opc_c
,
666 }[self
](entries
, num_entries
)
670 FIELDS
= {field
.name
:field
.type for field
in _dataclasses
.fields(Record
)}
671 FIELDS
.update({field
.name
:field
.type for field
in _dataclasses
.fields(Entry
)})
676 def name_filter(name
):
677 if name
.startswith("l") and name
.endswith("br"):
679 if name
in {"mcrxr", "mcrxrx", "darn"}:
681 if name
in {"bctar", "bcctr"}:
685 if name
in {"setvl"}:
694 def item_mapper(item
):
696 key
= key
.lower().replace(" ", "_")
697 cls
= FIELDS
.get(key
, object)
698 if not isinstance(value
, cls
):
699 if issubclass(cls
, _enum
.Enum
):
700 value
= {item
.name
:item
for item
in cls
}[value
]
705 def item_filter(item
):
707 return (key
in FIELDS
)
709 for record
in ISA
.get_svp64_csv(path
):
710 names
= record
.pop("comment").split("=")[-1].split("/")
711 names
= set(filter(name_filter
, names
))
713 rc
= _RC
[record
["rc"] if record
["rc"] else "NONE"]
715 names
.update({f
"{name}." for name
in names
})
716 record
= dict(filter(item_filter
, map(item_mapper
, record
.items())))
717 for name
in map(Name
, names
):
718 yield Entry(name
=name
, record
=Record(**record
))
737 entries
.extend(parse(path
))
738 entries
= sorted(frozenset(entries
))
740 for line
in codegen
.generate(entries
):
744 if __name__
== "__main__":
745 parser
= _argparse
.ArgumentParser()
746 parser
.add_argument("codegen",
747 type=Codegen
, choices
=Codegen
,
748 help="code generator")
750 args
= vars(parser
.parse_args())