1 import argparse
as _argparse
2 import dataclasses
as _dataclasses
8 _sys
.path
.append(_os
.path
.dirname(_os
.path
.realpath(__file__
)) + "/../../")
10 from openpower
.decoder
.power_enums
import (
16 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
25 from openpower
.decoder
.power_insn
import SVP64Instruction
as _SVP64Instruction
30 Copyright (C) 2022 Free Software Foundation, Inc.
31 Written by Dmitry Selyutin (ghostmansd).
32 Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073.
34 This file is part of the GNU opcodes library.
36 This library is free software; you can redistribute it and/or modify
37 it under the terms of the GNU General Public License as published by
38 the Free Software Foundation; either version 3, or (at your option)
41 It is distributed in the hope that it will be useful, but WITHOUT
42 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
43 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
44 License for more details.
46 You should have received a copy of the GNU General Public License
47 along with this file; see the file COPYING. If not, write to the
48 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
49 MA 02110-1301, USA. */\
54 return map(lambda string
: (" " + string
), strings
)
57 class ObjectMeta(type):
58 def __new__(metacls
, clsname
, bases
, ns
,
59 c_typedef
="void", **kwargs
):
60 if c_typedef
== "void":
62 if (hasattr(base
, "c_typedef") and
63 (base
.c_typedef
!= "void")):
64 c_typedef
= base
.c_typedef
67 ns
.setdefault("c_typedef", c_typedef
)
70 return super().__new
__(metacls
, clsname
, bases
, ns
)
73 class Object(metaclass
=ObjectMeta
):
79 def c_var(cls
, name
, prefix
="", suffix
=""):
80 return f
"{prefix}{cls.c_typedef} {name}{suffix}"
82 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
86 class ArrayMeta(ObjectMeta
):
87 def __new__(metacls
, clsname
, bases
, ns
,
88 c_base
, c_size
, **kwargs
):
89 if c_size
is Ellipsis:
90 clsname
= f
"{clsname}[]"
92 clsname
= f
"{clsname}[{c_size}]"
94 return super().__new
__(metacls
, clsname
, bases
, ns
,
95 c_typedef
=c_base
.c_typedef
, c_base
=c_base
, c_size
=c_size
, **kwargs
)
97 def __getitem__(cls
, key
):
98 (c_base
, c_size
) = key
99 return cls
.__class
__(cls
.__name
__, (cls
,), {},
100 c_base
=c_base
, c_size
=c_size
)
103 class Array(Object
, tuple, metaclass
=ArrayMeta
,
104 c_base
=Object
, c_size
=...):
107 if cls
.c_size
is Ellipsis:
111 yield f
"{cls.c_base.c_typedef}[{size}]"
114 def c_var(cls
, name
, prefix
="", suffix
=""):
115 if cls
.c_size
is Ellipsis:
119 return f
"{prefix}{cls.c_base.c_typedef} {name}[{size}]{suffix}"
121 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
124 yield from indent(item
.c_value(suffix
=","))
128 class Void(Object
, c_typedef
="void"):
129 def c_var(cls
, name
, prefix
="", suffix
=""):
130 raise NotImplementedError
133 class EnumMeta(_enum
.EnumMeta
, ObjectMeta
):
134 def __call__(cls
, clsname
, entries
,
135 c_tag
=None, c_typedef
=None, exclude
=None):
137 exclude
= frozenset()
138 if isinstance(entries
, type) and issubclass(entries
, _enum
.Enum
):
139 # Use __members__, not __iter__, otherwise aliases are lost.
140 entries
= dict(entries
.__members
__)
141 if isinstance(entries
, dict):
142 entries
= tuple(entries
.items())
143 entries
= ((key
, value
) for (key
, value
) in entries
if key
not in exclude
)
146 c_tag
= f
"svp64_{clsname.lower()}"
147 if c_typedef
is None:
148 c_typedef
= f
"enum {c_tag}"
150 base
= ObjectMeta(cls
.__name
__, (), {},
151 c_tag
=c_tag
, c_typedef
=c_typedef
)
153 return super().__call
__(value
=clsname
, names
=entries
, type=base
)
156 class Enum(Object
, _enum
.Enum
, metaclass
=EnumMeta
):
159 return f
"{self.c_tag.upper()}_{self.name.upper()}"
163 yield f
"{cls.c_typedef} {{"
165 yield from indent(item
.c_value(suffix
=","))
168 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
169 yield f
"{prefix}{self.c_name}{suffix}"
172 def c_var(cls
, name
, prefix
="", suffix
=""):
173 return f
"{prefix}{cls.c_typedef} {name}{suffix}"
176 In1Sel
= Enum("In1Sel", _In1Sel
, c_tag
="svp64_in1_sel")
177 In2Sel
= Enum("In2Sel", _In2Sel
, c_tag
="svp64_in2_sel")
178 In3Sel
= Enum("In3Sel", _In3Sel
, c_tag
="svp64_in3_sel")
179 OutSel
= Enum("OutSel", _OutSel
, c_tag
="svp64_out_sel")
180 CRInSel
= Enum("CRInSel", _CRInSel
, c_tag
="svp64_cr_in_sel")
181 CROutSel
= Enum("CROutSel", _CROutSel
, c_tag
="svp64_cr_out_sel")
182 PType
= Enum("PType", _SVPtype
, c_tag
="svp64_ptype")
183 EType
= Enum("EType", _SVEtype
, c_tag
="svp64_etype", exclude
="NONE")
184 Extra
= Enum("Extra", _SVExtra
, c_tag
="svp64_extra", exclude
="Idx_1_2")
185 Function
= Enum("Function", _Function
, c_tag
="svp64_function")
188 class Constant(_enum
.Enum
, metaclass
=EnumMeta
):
191 yield f
"/* {cls.c_tag.upper()} constants */"
192 # Use __members__, not __iter__, otherwise aliases are lost.
193 for (key
, item
) in cls
.__members
__.items():
194 key
= f
"{cls.c_tag.upper()}_{key.upper()}"
195 value
= f
"0x{item.value:08x}U"
196 yield f
"#define {key} {value}"
198 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
199 yield f
"{prefix}{self.c_tag.upper()}_{self.c_name.upper()}{suffix}"
202 Mode
= Constant("Mode", _SVP64MODE
)
205 class StructMeta(ObjectMeta
):
206 def __new__(metacls
, clsname
, bases
, ns
,
207 c_tag
=None, c_typedef
=None):
210 c_tag
= f
"svp64_{clsname.lower()}"
211 if c_typedef
is None:
212 c_typedef
= f
"struct {c_tag}"
214 return super().__new
__(metacls
, clsname
, bases
, ns
,
215 c_typedef
=c_typedef
, c_tag
=c_tag
)
218 @_dataclasses.dataclass(eq
=True, frozen
=True)
219 class Struct(Object
, metaclass
=StructMeta
):
222 def transform(field
):
223 return field
.type.c_var(name
=f
"{field.name}", suffix
=";")
225 yield f
"{cls.c_typedef} {{"
226 yield from indent(map(transform
, _dataclasses
.fields(cls
)))
229 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
231 for field
in _dataclasses
.fields(self
):
233 attr
= getattr(self
, name
)
234 yield from indent(attr
.c_value(prefix
=f
".{name} = ", suffix
=","))
238 class Integer(Object
, str):
239 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
240 yield f
"{prefix}{self}{suffix}"
243 class Byte(Integer
, c_typedef
="uint8_t"):
247 class Size(Integer
, c_typedef
="size_t"):
251 class UInt32(Integer
, c_typedef
="uint32_t"):
255 class UInt64(Integer
, c_typedef
="uint64_t"):
259 @_dataclasses.dataclass(eq
=True, frozen
=True)
260 class Instruction(Struct
, c_tag
="svp64_insn"):
265 def mangle(path
, action
):
266 if path
.endswith("]"):
268 for symbol
in (".", "[", "]"):
269 path
= path
.replace(symbol
, "_")
271 return f
"{cls.c_tag}_{action}_{path}"
273 return f
"{cls.c_tag}_{action}"
275 def getter(path
, field
):
276 yield "static inline uint64_t"
277 yield f
"{mangle(path, 'get')}(const {cls.c_typedef} *insn)"
279 yield from indent(["uint64_t value = insn->value;"])
281 yield from indent(["return ("])
283 for (dst
, src
) in enumerate(reversed(field
)):
284 src
= (64 - (src
+ 1))
285 dst
= f
"UINT64_C({dst})"
286 src
= f
"UINT64_C({src})"
287 action
= f
"(((value >> {src}) & UINT64_C(1)) << {dst})"
288 actions
.append(action
)
289 for action
in indent(indent(actions
)):
291 yield from indent(indent(["UINT64_C(0)"]))
292 yield from indent([");"])
296 def setter(path
, field
):
297 mask
= ((2 ** 64) - 1)
299 mask
&= ~
(1 << (64 - (bit
+ 1)))
300 action
= mangle(path
, "set")
301 yield "static inline void"
302 yield f
"{mangle(path, 'set')}({cls.c_typedef} *insn, uint64_t value)"
304 yield from indent([f
"insn->value &= UINT64_C(0x{mask:016x});"])
306 for (src
, dst
) in enumerate(reversed(field
)):
307 dst
= (64 - (dst
+ 1))
308 dst
= f
"UINT64_C({dst})"
309 src
= f
"UINT64_C({src})"
310 action
= f
"(((value >> {src}) & UINT64_C(1)) << {dst})"
311 actions
.append(action
)
312 yield from indent(["insn->value |= ("])
313 for action
in indent(indent(actions
)):
315 yield from indent(indent(["UINT64_C(0)"]))
316 yield from indent([");"])
320 yield from super().c_decl()
322 for (path
, field
) in _SVP64Instruction
.traverse():
323 yield from getter(path
, field
)
324 yield from setter(path
, field
)
327 class Name(Object
, str, c_typedef
="const char *"):
329 escaped
= self
.replace("\"", "\\\"")
330 return f
"\"{escaped}\""
332 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
333 yield f
"{prefix}{self!r}{suffix}"
336 def c_var(cls
, name
, prefix
="", suffix
=""):
337 return f
"{prefix}const char *{name}{suffix}"
340 @_dataclasses.dataclass(eq
=True, frozen
=True)
341 class Opcode(Struct
):
343 def __new__(cls
, value
):
344 if isinstance(value
, int):
345 value
= f
"0x{value:08x}"
346 return super().__new
__(cls
, value
)
349 def __new__(cls
, value
):
350 if isinstance(value
, int):
351 value
= f
"0x{value:08x}"
352 return super().__new
__(cls
, value
)
358 @_dataclasses.dataclass(eq
=True, frozen
=True)
381 yield f
"struct svp64_desc {{"
382 for field
in _dataclasses
.fields(cls
):
383 bits
= len(field
.type).bit_length()
384 yield from indent([f
"uint64_t {field.name} : {bits};"])
386 bits_rsvd
= (64 - (bits_all
% 64))
388 yield from indent([f
"uint64_t : {bits_rsvd};"])
392 @_dataclasses.dataclass(eq
=True, frozen
=True)
393 class Record(Struct
):
398 def __lt__(self
, other
):
399 if not isinstance(other
, self
.__class
__):
400 return NotImplemented
402 return self
.name
< other
.name
405 class Codegen(_enum
.Enum
):
406 PPC_SVP64_GEN_H
= "include/opcode/ppc-svp64-gen.h"
407 PPC_SVP64_OPC_GEN_C
= "opcodes/ppc-svp64-opc-gen.c"
412 def generate(self
, records
):
413 def ppc_svp64_h(records
, num_records
):
414 disclaimer
= DISCLAIMER
.format(path
=str(self
),
415 desc
="Header file for PowerPC opcode table (SVP64 extensions)")
416 yield from disclaimer
.splitlines()
419 yield f
"#ifndef {self.name}"
420 yield f
"#define {self.name}"
423 yield "#include <stdint.h>"
426 yield "#ifdef __cplusplus"
427 yield "extern \"C\" {"
432 In1Sel
, In2Sel
, In3Sel
, OutSel
,
438 yield from enum
.c_decl()
441 for cls
in (Instruction
, Desc
, Opcode
, Record
):
442 yield from cls
.c_decl()
445 yield records
.c_var("svp64_records",
446 prefix
="extern const ", suffix
=";")
447 yield num_records
.c_var("svp64_num_records",
448 prefix
="extern const ", suffix
=";")
451 yield "extern const struct powerpc_pd_reg svp64_regs[];"
452 yield Size
.c_var("svp64_num_regs", prefix
="extern const ", suffix
=";")
455 yield "#ifdef __cplusplus"
460 yield f
"#endif /* {self.name} */"
462 def ppc_svp64_opc_c(records
, num_records
):
463 disclaimer
= DISCLAIMER
.format(path
=str(self
),
464 desc
="PowerPC opcode list (SVP64 extensions)")
465 yield from disclaimer
.splitlines()
468 yield "#include \"opcode/ppc-svp64.h\""
471 def opindex(enum
, name
, table
):
472 sep
= (max(map(len, list(table
.values()) + ["UNUSED"])) + 1)
473 c_tag
= f
"svp64_{enum.__name__.lower()}"
474 yield "static inline ppc_opindex_t"
475 yield f
"svp64_desc_{name}_opindex(const struct svp64_desc *desc)"
477 yield from indent(["static const ppc_opindex_t table[] = {"])
479 value
= table
.get(key
, "UNUSED")
480 yield from indent(indent([f
"{value:{sep}}, /* {key.c_name} */"]))
481 yield from indent(["};"])
483 yield from indent([f
"return table[desc->{name}];"])
487 yield from opindex(In1Sel
, "in1", {
489 In1Sel
.RA_OR_ZERO
: "RA0",
495 yield from opindex(In2Sel
, "in2", {
501 yield from opindex(In3Sel
, "in3", {
509 for name
in ("out", "out2"):
510 yield from opindex(OutSel
, name
, {
514 OutSel
.RT_OR_ZERO
: "RT",
518 yield from opindex(CRInSel
, "cr_in", {
522 CRInSel
.WHOLE_REG
: "FXM",
524 yield from opindex(CROutSel
, "cr_out", {
527 CROutSel
.WHOLE_REG
: "FXM",
530 yield records
.c_var("svp64_records",
531 prefix
="const ", suffix
=" = \\")
532 yield from records
.c_value(prefix
="", suffix
=";")
534 yield num_records
.c_var("svp64_num_records",
535 prefix
="const ", suffix
=" = \\")
536 yield from indent(num_records
.c_value(suffix
=";"))
539 yield "const struct powerpc_pd_reg svp64_regs[] = {"
541 for (category
, count
, flags
) in sorted((
542 ("r", 128, "PPC_OPERAND_GPR"),
543 ("f", 128, "PPC_OPERAND_FPR"),
544 ("cr", 128, "PPC_OPERAND_CR_REG"),
546 for index
in range(count
):
547 regs
[f
"{category}{index}"] = (index
, flags
)
548 regs
[f
"{category}.{index}"] = (index
, flags
)
549 for (name
, (index
, flags
)) in sorted(regs
.items()):
550 yield from indent([f
"{{\"{name}\", {index}, {flags}}},"])
554 num_regs
= Size("(sizeof (svp64_regs) / sizeof (svp64_regs[0]))")
555 yield Size
.c_var("svp64_num_regs",
556 prefix
="const ", suffix
=" = \\")
557 yield from indent(num_regs
.c_value(suffix
=";"))
559 records
= Array
[Record
, ...](records
)
560 num_records
= Size("(sizeof (svp64_records) / sizeof (svp64_records[0]))")
563 Codegen
.PPC_SVP64_GEN_H
: ppc_svp64_h
,
564 Codegen
.PPC_SVP64_OPC_GEN_C
: ppc_svp64_opc_c
,
565 }[self
](records
, num_records
)
569 fields
= {field
.name
:field
.type for field
in _dataclasses
.fields(Desc
)}
571 for insn
in filter(lambda insn
: insn
.svp64
is not None, db
):
574 for (key
, cls
) in fields
.items():
575 value
= getattr(insn
, key
)
577 if (((cls
is EType
) and (value
is _SVEtype
.NONE
)) or
578 ((cls
is Extra
) and (value
is _SVExtra
.Idx_1_2
))):
582 if issubclass(cls
, _enum
.Enum
):
583 value
= cls
[value
.name
]
591 name
= Name(f
"sv.{insn.name}")
592 value
= Opcode
.Value(insn
.opcode
.value
)
593 mask
= Opcode
.Mask(insn
.opcode
.mask
)
594 opcode
= Opcode(value
=value
, mask
=mask
)
597 yield Record(name
=name
, opcode
=opcode
, desc
=desc
)
601 db
= _Database(_find_wiki_dir())
602 for line
in codegen
.generate(records(db
)):
606 if __name__
== "__main__":
607 parser
= _argparse
.ArgumentParser()
608 parser
.add_argument("codegen",
609 type=Codegen
, choices
=Codegen
,
610 help="code generator")
612 args
= vars(parser
.parse_args())