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 CRIn2Sel
as _CRIn2Sel
,
17 CROutSel
as _CROutSel
,
22 find_wiki_dir
as _find_wiki_dir
,
24 from openpower
.consts
import SVP64MODE
as _SVP64MODE
25 from openpower
.insndb
.core
import Database
as _Database
26 from openpower
.insndb
.core
import SVP64Instruction
as _SVP64Instruction
31 Copyright (C) 2022 Free Software Foundation, Inc.
32 Written by Dmitry Selyutin (ghostmansd).
33 Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073.
35 This file is part of the GNU opcodes library.
37 This library is free software; you can redistribute it and/or modify
38 it under the terms of the GNU General Public License as published by
39 the Free Software Foundation; either version 3, or (at your option)
42 It is distributed in the hope that it will be useful, but WITHOUT
43 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
44 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
45 License for more details.
47 You should have received a copy of the GNU General Public License
48 along with this file; see the file COPYING. If not, write to the
49 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
50 MA 02110-1301, USA. */\
55 return map(lambda string
: (" " + string
), strings
)
58 class ObjectMeta(type):
59 def __new__(metacls
, clsname
, bases
, ns
,
60 c_typedef
="void", **kwargs
):
61 if c_typedef
== "void":
63 if (hasattr(base
, "c_typedef") and
64 (base
.c_typedef
!= "void")):
65 c_typedef
= base
.c_typedef
68 ns
.setdefault("c_typedef", c_typedef
)
71 return super().__new
__(metacls
, clsname
, bases
, ns
)
74 class Object(metaclass
=ObjectMeta
):
80 def c_var(cls
, name
, prefix
="", suffix
=""):
81 return f
"{prefix}{cls.c_typedef} {name}{suffix}"
83 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
87 class ArrayMeta(ObjectMeta
):
88 def __new__(metacls
, clsname
, bases
, ns
,
89 c_base
, c_size
, **kwargs
):
90 if c_size
is Ellipsis:
91 clsname
= f
"{clsname}[]"
93 clsname
= f
"{clsname}[{c_size}]"
95 return super().__new
__(metacls
, clsname
, bases
, ns
,
96 c_typedef
=c_base
.c_typedef
, c_base
=c_base
, c_size
=c_size
, **kwargs
)
98 def __getitem__(cls
, key
):
99 (c_base
, c_size
) = key
100 return cls
.__class
__(cls
.__name
__, (cls
,), {},
101 c_base
=c_base
, c_size
=c_size
)
104 class Array(Object
, tuple, metaclass
=ArrayMeta
,
105 c_base
=Object
, c_size
=...):
108 if cls
.c_size
is Ellipsis:
112 yield f
"{cls.c_base.c_typedef}[{size}]"
115 def c_var(cls
, name
, prefix
="", suffix
=""):
116 if cls
.c_size
is Ellipsis:
120 return f
"{prefix}{cls.c_base.c_typedef} {name}[{size}]{suffix}"
122 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
125 yield from indent(item
.c_value(suffix
=","))
129 class Void(Object
, c_typedef
="void"):
130 def c_var(cls
, name
, prefix
="", suffix
=""):
131 raise NotImplementedError
134 class EnumMeta(_enum
.EnumMeta
, ObjectMeta
):
135 def __call__(cls
, clsname
, entries
,
136 c_tag
=None, c_typedef
=None, exclude
=None):
138 exclude
= frozenset()
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())
144 entries
= ((key
, value
) for (key
, value
) in entries
if key
not in exclude
)
147 c_tag
= f
"svp64_{clsname.lower()}"
148 if c_typedef
is None:
149 c_typedef
= f
"enum {c_tag}"
151 base
= ObjectMeta(cls
.__name
__, (), {},
152 c_tag
=c_tag
, c_typedef
=c_typedef
)
154 return super().__call
__(value
=clsname
, names
=entries
, type=base
)
157 class Enum(Object
, _enum
.Enum
, metaclass
=EnumMeta
):
160 return f
"{self.c_tag.upper()}_{self.name.upper()}"
164 yield f
"{cls.c_typedef} {{"
166 yield from indent(item
.c_value(suffix
=","))
169 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
170 yield f
"{prefix}{self.c_name}{suffix}"
173 def c_var(cls
, name
, prefix
="", suffix
=""):
174 return f
"{prefix}{cls.c_typedef} {name}{suffix}"
177 In1Sel
= Enum("In1Sel", _In1Sel
, c_tag
="svp64_in1_sel")
178 In2Sel
= Enum("In2Sel", _In2Sel
, c_tag
="svp64_in2_sel")
179 In3Sel
= Enum("In3Sel", _In3Sel
, c_tag
="svp64_in3_sel")
180 OutSel
= Enum("OutSel", _OutSel
, c_tag
="svp64_out_sel")
181 CRInSel
= Enum("CRInSel", _CRInSel
, c_tag
="svp64_cr_in_sel")
182 CRIn2Sel
= Enum("CRIn2Sel", _CRIn2Sel
, c_tag
="svp64_cr_in2_sel")
183 CROutSel
= Enum("CROutSel", _CROutSel
, c_tag
="svp64_cr_out_sel")
184 PType
= Enum("PType", _SVPType
, c_tag
="svp64_ptype")
185 EType
= Enum("EType", _SVEType
, c_tag
="svp64_etype", exclude
="NONE")
186 Extra
= Enum("Extra", _SVExtra
, c_tag
="svp64_extra", exclude
="Idx_1_2")
187 Mode
= Enum("Mode", _SVMode
, c_tag
="svp64_mode")
190 class Constant(_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.c_tag.upper()}_{self.c_name.upper()}{suffix}"
204 ModeConst
= Constant("Mode", _SVP64MODE
)
207 class StructMeta(ObjectMeta
):
208 def __new__(metacls
, clsname
, bases
, ns
,
209 c_tag
=None, c_typedef
=None):
212 c_tag
= f
"svp64_{clsname.lower()}"
213 if c_typedef
is None:
214 c_typedef
= f
"struct {c_tag}"
216 return super().__new
__(metacls
, clsname
, bases
, ns
,
217 c_typedef
=c_typedef
, c_tag
=c_tag
)
220 @_dataclasses.dataclass(eq
=True, frozen
=True)
221 class Struct(Object
, metaclass
=StructMeta
):
224 def transform(field
):
225 return field
.type.c_var(name
=f
"{field.name}", suffix
=";")
227 yield f
"{cls.c_typedef} {{"
228 yield from indent(map(transform
, _dataclasses
.fields(cls
)))
231 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
233 for field
in _dataclasses
.fields(self
):
235 attr
= getattr(self
, name
)
236 yield from indent(attr
.c_value(prefix
=f
".{name} = ", suffix
=","))
240 class Integer(Object
, str):
241 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
242 yield f
"{prefix}{self}{suffix}"
245 class Byte(Integer
, c_typedef
="uint8_t"):
249 class Size(Integer
, c_typedef
="size_t"):
253 class UInt32(Integer
, c_typedef
="uint32_t"):
257 class UInt64(Integer
, c_typedef
="uint64_t"):
261 @_dataclasses.dataclass(eq
=True, frozen
=True)
262 class Instruction(Struct
, c_tag
="svp64_insn"):
267 def mangle(path
, action
):
268 if path
.endswith("]"):
270 for symbol
in (".", "[", "]"):
271 path
= path
.replace(symbol
, "_")
273 return f
"{cls.c_tag}_{action}_{path}"
275 return f
"{cls.c_tag}_{action}"
277 def getter(path
, field
):
278 yield "static inline uint64_t"
279 yield f
"{mangle(path, 'get')}(const {cls.c_typedef} *insn)"
281 yield from indent(["uint64_t value = insn->value;"])
282 yield from indent(["return ("])
284 for (dst
, src
) in enumerate(reversed(field
)):
285 src
= (64 - (src
+ 1))
286 dst
= f
"UINT64_C({dst})"
287 src
= f
"UINT64_C({src})"
288 action
= f
"(((value >> {src}) & UINT64_C(1)) << {dst})"
289 actions
.append(action
)
290 for action
in indent(indent(actions
[:-1])):
292 yield from indent(indent([f
"{actions[-1]}"]))
293 yield from indent([");"])
297 def setter(path
, field
):
298 mask
= ((2 ** 64) - 1)
300 mask
&= ~
(1 << (64 - (bit
+ 1)))
301 action
= mangle(path
, "set")
302 yield "static inline void"
303 yield f
"{mangle(path, 'set')}({cls.c_typedef} *insn, uint64_t value)"
305 yield from indent([f
"insn->value &= UINT64_C(0x{mask:016x});"])
307 for (src
, dst
) in enumerate(reversed(field
)):
308 dst
= (64 - (dst
+ 1))
309 dst
= f
"UINT64_C({dst})"
310 src
= f
"UINT64_C({src})"
311 action
= f
"(((value >> {src}) & UINT64_C(1)) << {dst})"
312 actions
.append(action
)
313 yield from indent(["insn->value |= ("])
314 for action
in indent(indent(actions
[:-1])):
316 yield from indent(indent([f
"{actions[-1]}"]))
317 yield from indent([");"])
321 yield from super().c_decl()
323 for (path
, field
) in _SVP64Instruction
.traverse(path
=""):
324 yield from getter(path
, field
)
325 yield from setter(path
, field
)
328 class Name(Object
, str, c_typedef
="const char *"):
330 escaped
= self
.replace("\"", "\\\"")
331 return f
"\"{escaped}\""
333 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
334 yield f
"{prefix}{self!r}{suffix}"
337 def c_var(cls
, name
, prefix
="", suffix
=""):
338 return f
"{prefix}const char *{name}{suffix}"
341 class BooleanMeta(ObjectMeta
):
346 class Boolean(Object
, metaclass
=BooleanMeta
):
347 def __init__(self
, value
):
348 self
.__state
= bool(value
)
349 return super().__init
__()
355 return self
.__state
.__repr
__()
359 return "true" if self
else "false"
363 return "true" if self
else "false"
365 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
366 yield f
"{prefix}{self.value}{suffix}"
369 def c_var(cls
, name
, prefix
="", suffix
=""):
370 return f
"{prefix}bool {name}{suffix}"
373 @_dataclasses.dataclass(eq
=True, frozen
=True)
390 extra_idx_out2
: Extra
391 extra_idx_cr_in
: Extra
392 extra_idx_cr_in2
: Extra
393 extra_idx_cr_out
: Extra
399 yield f
"struct svp64_desc {{"
400 for field
in _dataclasses
.fields(cls
):
401 bits
= len(field
.type).bit_length()
402 yield from indent([f
"uint64_t {field.name} : {bits};"])
404 bits_rsvd
= (64 - (bits_all
% 64))
406 yield from indent([f
"uint64_t : {bits_rsvd};"])
410 @_dataclasses.dataclass(eq
=True, frozen
=True)
411 class Opcode(Struct
):
413 def __new__(cls
, value
):
414 if isinstance(value
, int):
415 value
= f
"0x{value:08x}"
416 return super().__new
__(cls
, value
)
419 def __new__(cls
, value
):
420 if isinstance(value
, int):
421 value
= f
"0x{value:08x}"
422 return super().__new
__(cls
, value
)
428 class Opcodes(Object
, c_typedef
="const struct svp64_opcode *"):
429 def __init__(self
, offset
):
430 self
.__offset
= offset
431 return super().__init
__()
434 return f
"{self.__class__.__name__}({self.__offset})"
437 def c_var(cls
, name
, prefix
="", suffix
=""):
438 return f
"{prefix}{cls.c_typedef}{name}{suffix}"
442 yield "const struct svp64_opcode *opcodes;"
444 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
445 yield f
"{prefix}&svp64_opcodes[{self.__offset}]{suffix}"
448 @_dataclasses.dataclass(eq
=True, frozen
=True)
449 class Record(Struct
):
455 def __lt__(self
, other
):
456 if not isinstance(other
, self
.__class
__):
457 return NotImplemented
459 return self
.name
< other
.name
462 class Codegen(_enum
.Enum
):
463 PPC_SVP64_GEN_H
= "include/opcode/ppc-svp64-gen.h"
464 PPC_SVP64_OPC_GEN_C
= "opcodes/ppc-svp64-opc-gen.c"
469 def generate(self
, opcodes
, records
):
470 def ppc_svp64_h(opcodes
, nr_opcodes
, records
, nr_records
):
471 disclaimer
= DISCLAIMER
.format(path
=str(self
),
472 desc
="Header file for PowerPC opcode table (SVP64 extensions)")
473 yield from disclaimer
.splitlines()
476 yield f
"#ifndef {self.name}"
477 yield f
"#define {self.name}"
480 yield "#include <stdint.h>"
483 yield "#ifdef __cplusplus"
484 yield "extern \"C\" {"
489 In1Sel
, In2Sel
, In3Sel
, OutSel
,
490 CRInSel
, CRIn2Sel
, CROutSel
,
495 yield from enum
.c_decl()
498 for cls
in (Instruction
, Desc
, Opcode
, Record
):
499 yield from cls
.c_decl()
502 yield opcodes
.c_var("svp64_opcodes",
503 prefix
="extern const ", suffix
=";")
504 yield nr_opcodes
.c_var("svp64_nr_opcodes",
505 prefix
="extern const ", suffix
=";")
508 yield records
.c_var("svp64_records",
509 prefix
="extern const ", suffix
=";")
510 yield nr_records
.c_var("svp64_nr_records",
511 prefix
="extern const ", suffix
=";")
514 yield "extern const struct powerpc_pd_reg svp64_regs[];"
515 yield Size
.c_var("svp64_num_regs", prefix
="extern const ", suffix
=";")
518 yield "#ifdef __cplusplus"
523 yield f
"#endif /* {self.name} */"
525 def ppc_svp64_opc_c(opcodes
, nr_opcodes
, records
, nr_records
):
526 disclaimer
= DISCLAIMER
.format(path
=str(self
),
527 desc
="PowerPC opcode list (SVP64 extensions)")
528 yield from disclaimer
.splitlines()
531 yield "#include <stdbool.h>"
532 yield "#include \"opcode/ppc-svp64.h\""
535 def opindex(enum
, name
, table
):
536 sep
= (max(map(len, list(table
.values()) + ["UNUSED"])) + 1)
537 c_tag
= f
"svp64_{enum.__name__.lower()}"
538 yield "static inline ppc_opindex_t"
539 yield f
"svp64_desc_{name}_opindex(const struct svp64_desc *desc)"
541 yield from indent(["static const ppc_opindex_t table[] = {"])
543 value
= table
.get(key
, "UNUSED")
544 yield from indent(indent([f
"{value:{sep}}, /* {key.c_name} */"]))
545 yield from indent(["};"])
547 yield from indent([f
"return table[desc->{name}];"])
551 yield from opindex(In1Sel
, "in1", {
553 In1Sel
.RA_OR_ZERO
: "RA0",
559 yield from opindex(In2Sel
, "in2", {
565 yield from opindex(In3Sel
, "in3", {
573 for name
in ("out", "out2"):
574 yield from opindex(OutSel
, name
, {
578 OutSel
.RT_OR_ZERO
: "RT",
583 yield from opindex(CRInSel
, "cr_in", {
588 CRInSel
.WHOLE_REG
: "FXM",
590 yield from opindex(CRIn2Sel
, "cr_in2", {
593 yield from opindex(CROutSel
, "cr_out", {
596 CROutSel
.WHOLE_REG
: "FXM",
599 yield opcodes
.c_var("svp64_opcodes",
600 prefix
="const ", suffix
=" = \\")
601 yield from opcodes
.c_value(prefix
="", suffix
=";")
603 yield nr_opcodes
.c_var("svp64_nr_opcodes",
604 prefix
="const ", suffix
=" = \\")
605 yield from indent(nr_opcodes
.c_value(suffix
=";"))
608 yield records
.c_var("svp64_records",
609 prefix
="const ", suffix
=" = \\")
610 yield from records
.c_value(prefix
="", suffix
=";")
612 yield nr_records
.c_var("svp64_nr_records",
613 prefix
="const ", suffix
=" = \\")
614 yield from indent(nr_records
.c_value(suffix
=";"))
617 yield "const struct powerpc_pd_reg svp64_regs[] = {"
619 for (category
, count
, flags
) in sorted((
620 ("r", 128, "PPC_OPERAND_GPR"),
621 ("f", 128, "PPC_OPERAND_FPR"),
622 ("cr", 128, "PPC_OPERAND_CR_REG"),
624 for index
in range(count
):
625 regs
[f
"{category}{index}"] = (index
, flags
)
626 regs
[f
"{category}.{index}"] = (index
, flags
)
627 for (name
, (index
, flags
)) in sorted(regs
.items()):
628 yield from indent([f
"{{\"{name}\", {index}, {flags}}},"])
632 num_regs
= Size("(sizeof (svp64_regs) / sizeof (svp64_regs[0]))")
633 yield Size
.c_var("svp64_num_regs",
634 prefix
="const ", suffix
=" = \\")
635 yield from indent(num_regs
.c_value(suffix
=";"))
637 opcodes
= Array
[Opcode
, ...](opcodes
)
638 nr_opcodes
= Size("(sizeof (svp64_opcodes) / sizeof (svp64_opcodes[0]))")
640 records
= Array
[Record
, ...](records
)
641 nr_records
= Size("(sizeof (svp64_records) / sizeof (svp64_records[0]))")
644 Codegen
.PPC_SVP64_GEN_H
: ppc_svp64_h
,
645 Codegen
.PPC_SVP64_OPC_GEN_C
: ppc_svp64_opc_c
,
646 }[self
](opcodes
, nr_opcodes
, records
, nr_records
)
652 fields
= {field
.name
:field
.type for field
in _dataclasses
.fields(Desc
)}
654 for insn
in filter(lambda insn
: insn
.svp64
is not None, db
):
657 for (key
, cls
) in fields
.items():
658 value
= getattr(insn
, key
)
660 if (((cls
is EType
) and (value
is _SVEType
.NONE
)) or
661 ((cls
is Extra
) and (value
is _SVExtra
.Idx_1_2
))):
665 if issubclass(cls
, Boolean
):
666 value
= Boolean(value
)
667 elif issubclass(cls
, _enum
.Enum
):
668 value
= cls
[value
.name
]
676 name
= Name(f
"sv.{insn.name}")
677 offset
= len(opcodes
)
678 for opcode
in insn
.opcodes
:
679 value
= Opcode
.Value(opcode
.value
)
680 mask
= Opcode
.Mask(opcode
.mask
)
681 opcode
= Opcode(value
=value
, mask
=mask
)
682 opcodes
.append(opcode
)
685 record
= Record(name
=name
, desc
=desc
,
686 opcodes
=Opcodes(offset
), nr_opcodes
=Size(len(insn
.opcodes
)))
687 records
.append(record
)
689 return (opcodes
, records
)
693 db
= _Database(_find_wiki_dir())
694 (opcodes
, records
) = collect(db
)
695 for line
in codegen
.generate(opcodes
, records
):
699 if __name__
== "__main__":
700 parser
= _argparse
.ArgumentParser()
701 parser
.add_argument("codegen",
702 type=Codegen
, choices
=Codegen
,
703 help="code generator")
705 args
= vars(parser
.parse_args())