2 import argparse
as _argparse
3 import collections
as _collections
4 import dataclasses
as _dataclasses
6 import functools
as _functools
7 import operator
as _operator
9 from openpower
.decoder
.power_enums
import (
15 CROutSel
as _CROutSel
,
20 Function
as _Function
,
21 find_wiki_dir
as _find_wiki_dir
,
23 from openpower
.consts
import SVP64MODE
as _SVP64MODE
24 from openpower
.decoder
.power_insn
import Database
as _Database
29 Copyright (C) 2022 Free Software Foundation, Inc.
30 Written by Dmitry Selyutin (ghostmansd).
31 Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073.
33 This file is part of the GNU opcodes library.
35 This library is free software; you can redistribute it and/or modify
36 it under the terms of the GNU General Public License as published by
37 the Free Software Foundation; either version 3, or (at your option)
40 It is distributed in the hope that it will be useful, but WITHOUT
41 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
42 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
43 License for more details.
45 You should have received a copy of the GNU General Public License
46 along with this file; see the file COPYING. If not, write to the
47 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
48 MA 02110-1301, USA. */\
53 return map(lambda string
: (" " + string
), strings
)
56 class CTypeMeta(type):
57 def __new__(metacls
, name
, bases
, attrs
, typedef
="void"):
58 cls
= super().__new
__(metacls
, name
, bases
, attrs
)
61 if (hasattr(base
, "c_typedef") and
62 (base
.c_typedef
!= "void")):
63 typedef
= base
.c_typedef
65 cls
.__typedef
= typedef
69 def __getitem__(cls
, size
):
70 name
= f
"{cls.__name__}[{'' if size is Ellipsis else size}]"
71 return type(name
, (Array
,), {}, type=cls
, size
=size
)
81 def c_var(cls
, name
, prefix
="", suffix
=""):
82 return f
"{prefix}{cls.c_typedef} {name}{suffix}"
85 class ArrayMeta(CTypeMeta
):
86 def __new__(metacls
, name
, bases
, attrs
, type, size
, **kwargs
):
87 cls
= super().__new
__(metacls
, name
, bases
, attrs
, **kwargs
)
89 cls
.__ellipsis
= (size
is Ellipsis)
90 cls
.__size
= 0 if cls
.__ellipsis
else size
98 size
= "" if cls
.__ellipsis
else f
"{cls.__size}"
99 yield f
"{cls.__type.c_typedef}[{size}]"
101 def c_var(cls
, name
, prefix
="", suffix
=""):
102 size
= "" if cls
.__ellipsis
else f
"{cls.__size}"
103 return f
"{prefix}{cls.__type.c_typedef} {name}[{size}]{suffix}"
106 class BitmapMeta(CTypeMeta
):
107 def __new__(metacls
, name
, bases
, attrs
,
108 typedef
="uint64_t", bits
=0, **kwargs
):
109 cls
= super().__new
__(metacls
,
110 name
, bases
, attrs
, typedef
=typedef
, **kwargs
)
117 def c_var(cls
, name
, prefix
="", suffix
=""):
118 return f
"{prefix}{cls.c_typedef} {name} : {cls.__bits}{suffix}"
121 class CType(metaclass
=CTypeMeta
):
123 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
127 class Array(CType
, tuple, metaclass
=ArrayMeta
, type=CType
, size
=...):
128 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
130 for (index
, item
) in enumerate(self
):
131 yield from indent(item
.c_value(suffix
=","))
135 class Bitmap(metaclass
=BitmapMeta
):
139 class Void(CType
, typedef
="void"):
140 def c_var(cls
, name
, prefix
="", suffix
=""):
141 raise NotImplementedError
144 class EnumMeta(_enum
.EnumMeta
, CTypeMeta
):
145 def __call__(metacls
, name
, entries
, tag
=None, exclude
=None, **kwargs
):
147 exclude
= frozenset()
148 if isinstance(entries
, type) and issubclass(entries
, _enum
.Enum
):
149 # Use __members__, not __iter__, otherwise aliases are lost.
150 entries
= dict(entries
.__members
__)
151 if isinstance(entries
, dict):
152 entries
= tuple(entries
.items())
153 entries
= ((key
, value
) for (key
, value
) in entries
if key
not in exclude
)
155 tag
= f
"svp64_{name.lower()}"
157 cls
= super().__call
__(value
=name
, names
=entries
, **kwargs
)
164 return f
"enum {cls.c_tag}"
171 yield f
"{cls.c_typedef} {{"
173 yield from indent(item
.c_value(suffix
=","))
176 def c_var(cls
, name
, prefix
="", suffix
=""):
177 return f
"{prefix}{cls.c_typedef} {name}{suffix}"
180 class Enum(CType
, _enum
.Enum
, metaclass
=EnumMeta
):
183 return f
"{self.__class__.c_tag.upper()}_{self.name.upper()}"
185 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
186 yield f
"{prefix}{self.c_name}{suffix}"
189 In1Sel
= Enum("In1Sel", _In1Sel
, tag
="svp64_in1_sel")
190 In2Sel
= Enum("In2Sel", _In2Sel
, tag
="svp64_in2_sel")
191 In3Sel
= Enum("In3Sel", _In3Sel
, tag
="svp64_in3_sel")
192 OutSel
= Enum("OutSel", _OutSel
, tag
="svp64_out_sel")
193 CRInSel
= Enum("CRInSel", _CRInSel
, tag
="svp64_cr_in_sel")
194 CROutSel
= Enum("CROutSel", _CROutSel
, tag
="svp64_cr_out_sel")
195 PType
= Enum("PType", _SVPtype
, tag
="svp64_ptype")
196 EType
= Enum("EType", _SVEtype
, tag
="svp64_etype", exclude
="NONE")
197 Extra
= Enum("Extra", _SVExtra
, tag
="svp64_extra", exclude
="Idx_1_2")
198 Function
= Enum("Function", _Function
, tag
="svp64_function")
201 class Constant(CType
, _enum
.Enum
, metaclass
=EnumMeta
):
204 yield f
"/* {cls.c_tag.upper()} constants */"
205 # Use __members__, not __iter__, otherwise aliases are lost.
206 for (key
, item
) in cls
.__members
__.items():
207 key
= f
"{cls.c_tag.upper()}_{key.upper()}"
208 value
= f
"0x{item.value:08x}U"
209 yield f
"#define {key} {value}"
211 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
212 yield f
"{prefix}{self.__class__.c_tag.upper()}_{self.c_name.upper()}{suffix}"
215 Mode
= Constant("Mode", _SVP64MODE
)
218 class StructMeta(CTypeMeta
):
219 def __new__(metacls
, name
, bases
, attrs
, tag
=None, **kwargs
):
221 tag
= f
"svp64_{name.lower()}"
222 if "typedef" not in kwargs
:
223 kwargs
["typedef"] = f
"struct {tag}"
225 cls
= super().__new
__(metacls
, name
, bases
, attrs
, **kwargs
)
235 def transform(field
):
236 return field
.type.c_var(name
=f
"{field.name}", suffix
=";")
238 yield f
"{cls.c_typedef} {{"
239 yield from indent(map(transform
, _dataclasses
.fields(cls
)))
243 @_dataclasses.dataclass(eq
=True, frozen
=True)
244 class Struct(CType
, metaclass
=StructMeta
):
245 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
247 for field
in _dataclasses
.fields(self
):
249 attr
= getattr(self
, name
)
250 yield from indent(attr
.c_value(prefix
=f
".{name} = ", suffix
=","))
254 class Integer(CType
, str):
255 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
256 yield f
"{prefix}{self}{suffix}"
259 class Byte(Integer
, typedef
="uint8_t"):
263 class Size(Integer
, typedef
="size_t"):
267 class UInt32(Integer
, typedef
="uint32_t"):
271 class Name(CType
, str, typedef
="const char *"):
273 escaped
= self
.replace("\"", "\\\"")
274 return f
"\"{escaped}\""
276 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
277 yield f
"{prefix}{self!r}{suffix}"
280 def c_var(cls
, name
, prefix
="", suffix
=""):
281 return f
"{prefix}const char *{name}{suffix}"
284 @_dataclasses.dataclass(eq
=True, frozen
=True)
285 class Opcode(Struct
):
287 def __new__(cls
, value
):
288 if isinstance(value
, int):
289 value
= f
"0x{value:08x}"
290 return super().__new
__(cls
, value
)
293 def __new__(cls
, value
):
294 if isinstance(value
, int):
295 value
= f
"0x{value:08x}"
296 return super().__new
__(cls
, value
)
302 @_dataclasses.dataclass(eq
=True, frozen
=True)
325 yield f
"struct svp64_desc {{"
326 for field
in _dataclasses
.fields(cls
):
327 bits
= len(field
.type).bit_length()
328 yield from indent([f
"uint64_t {field.name} : {bits};"])
330 bits_rsvd
= (64 - (bits_all
% 64))
332 yield from indent([f
"uint64_t : {bits_rsvd};"])
336 @_dataclasses.dataclass(eq
=True, frozen
=True)
337 class Record(Struct
):
342 def __lt__(self
, other
):
343 if not isinstance(other
, self
.__class
__):
344 return NotImplemented
346 return self
.name
< other
.name
349 class Codegen(_enum
.Enum
):
350 PPC_SVP64_GEN_H
= _enum
.auto()
351 PPC_SVP64_OPC_GEN_C
= _enum
.auto()
354 def _missing_(cls
, value
):
356 "ppc-svp64-gen.h": Codegen
.PPC_SVP64_GEN_H
,
357 "ppc-svp64-opc-gen.c": Codegen
.PPC_SVP64_OPC_GEN_C
,
362 Codegen
.PPC_SVP64_GEN_H
: "ppc-svp64-gen.h",
363 Codegen
.PPC_SVP64_OPC_GEN_C
: "ppc-svp64-opc-gen.c",
366 def generate(self
, records
):
367 def ppc_svp64_h(records
, num_records
):
368 disclaimer
= DISCLAIMER
.format(path
=str(self
),
369 desc
="Header file for PowerPC opcode table (SVP64 extensions)")
370 yield from disclaimer
.splitlines()
373 yield f
"#ifndef {self.name}"
374 yield f
"#define {self.name}"
377 yield "#include <stdint.h>"
380 yield "#ifdef __cplusplus"
381 yield "extern \"C\" {"
386 In1Sel
, In2Sel
, In3Sel
, OutSel
,
392 yield from enum
.c_decl()
395 for cls
in (Desc
, Opcode
, Record
, Instruction
):
396 yield from cls
.c_decl()
399 yield records
.__class
__.c_var("svp64_records",
400 prefix
="extern const ", suffix
=";")
401 yield num_records
.__class
__.c_var("svp64_num_records",
402 prefix
="extern const ", suffix
=";")
405 yield "extern const struct powerpc_pd_reg svp64_regs[];"
406 yield Size
.c_var("svp64_num_regs", prefix
="extern const ", suffix
=";")
409 yield "#ifdef __cplusplus"
414 yield f
"#endif /* {self.name} */"
417 def ppc_svp64_opc_c(records
, num_records
):
418 disclaimer
= DISCLAIMER
.format(path
=str(self
),
419 desc
="PowerPC opcode list (SVP64 extensions)")
420 yield from disclaimer
.splitlines()
423 yield "#include \"opcode/ppc-svp64.h\""
426 def opindex(enum
, name
, table
):
427 sep
= (max(map(len, list(table
.values()) + ["UNUSED"])) + 1)
428 c_tag
= f
"svp64_{enum.__name__.lower()}"
429 yield "static inline ppc_opindex_t"
430 yield f
"svp64_desc_{name}_opindex(const struct svp64_desc *desc)"
432 yield from indent(["static const ppc_opindex_t table[] = {"])
434 value
= table
.get(key
, "UNUSED")
435 yield from indent(indent([f
"{value:{sep}}, /* {key.c_name} */"]))
436 yield from indent(["};"])
438 yield from indent([f
"return table[desc->{name}];"])
442 yield from opindex(In1Sel
, "in1", {
444 In1Sel
.RA_OR_ZERO
: "RA0",
450 yield from opindex(In2Sel
, "in2", {
456 yield from opindex(In3Sel
, "in3", {
464 for name
in ("out", "out2"):
465 yield from opindex(OutSel
, name
, {
469 OutSel
.RT_OR_ZERO
: "RT",
473 yield from opindex(CRInSel
, "cr_in", {
477 CRInSel
.WHOLE_REG
: "FXM",
479 yield from opindex(CROutSel
, "cr_out", {
482 CROutSel
.WHOLE_REG
: "FXM",
485 yield records
.__class
__.c_var("svp64_records",
486 prefix
="const ", suffix
=" = \\")
487 yield from records
.c_value(prefix
="", suffix
=";")
489 yield num_records
.__class
__.c_var("svp64_num_records",
490 prefix
="const ", suffix
=" = \\")
491 yield from indent(num_records
.c_value(suffix
=";"))
494 yield "const struct powerpc_pd_reg svp64_regs[] = {"
496 for (category
, count
, flags
) in sorted((
497 ("r", 128, "PPC_OPERAND_GPR"),
498 ("f", 128, "PPC_OPERAND_FPR"),
499 ("cr", 128, "PPC_OPERAND_CR_REG"),
501 for index
in range(count
):
502 regs
[f
"{category}{index}"] = (index
, flags
)
503 regs
[f
"{category}.{index}"] = (index
, flags
)
504 for (name
, (index
, flags
)) in sorted(regs
.items()):
505 yield from indent([f
"{{\"{name}\", {index}, {flags}}},"])
509 num_regs
= Size("(sizeof (svp64_regs) / sizeof (svp64_regs[0]))")
510 yield Size
.c_var("svp64_num_regs",
511 prefix
="const ", suffix
=" = \\")
512 yield from indent(num_regs
.c_value(suffix
=";"))
516 records
= Record
[...](records
)
517 num_records
= Size("(sizeof (svp64_records) / sizeof (svp64_records[0]))")
520 Codegen
.PPC_SVP64_GEN_H
: ppc_svp64_h
,
521 Codegen
.PPC_SVP64_OPC_GEN_C
: ppc_svp64_opc_c
,
522 }[self
](records
, num_records
)
526 fields
= {field
.name
:field
.type for field
in _dataclasses
.fields(Desc
)}
528 for insn
in filter(lambda insn
: insn
.svp64
is not None, db
):
531 for (key
, cls
) in fields
.items():
532 value
= getattr(insn
, key
)
534 if (((cls
is EType
) and (value
is _SVEtype
.NONE
)) or
535 ((cls
is Extra
) and (value
is _SVExtra
.Idx_1_2
))):
539 if issubclass(cls
, _enum
.Enum
):
540 value
= cls
[value
.name
]
548 name
= Name(f
"sv.{insn.name}")
549 value
= Opcode
.Value(insn
.opcode
.value
)
550 mask
= Opcode
.Mask(insn
.opcode
.mask
)
551 opcode
= Opcode(value
=value
, mask
=mask
)
554 yield Record(name
=name
, opcode
=opcode
, desc
=desc
)
558 db
= _Database(_find_wiki_dir())
559 for line
in codegen
.generate(records(db
)):
563 if __name__
== "__main__":
564 parser
= _argparse
.ArgumentParser()
565 parser
.add_argument("codegen",
566 type=Codegen
, choices
=Codegen
,
567 help="code generator")
569 args
= vars(parser
.parse_args())