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;"])
280 yield from indent(["return ("])
282 for (dst
, src
) in enumerate(reversed(field
)):
283 src
= (64 - (src
+ 1))
284 dst
= f
"UINT64_C({dst})"
285 src
= f
"UINT64_C({src})"
286 action
= f
"(((value >> {src}) & UINT64_C(1)) << {dst})"
287 actions
.append(action
)
288 for action
in indent(indent(actions
[:-1])):
290 yield from indent(indent([f
"{actions[-1]}"]))
291 yield from indent([");"])
295 def setter(path
, field
):
296 mask
= ((2 ** 64) - 1)
298 mask
&= ~
(1 << (64 - (bit
+ 1)))
299 action
= mangle(path
, "set")
300 yield "static inline void"
301 yield f
"{mangle(path, 'set')}({cls.c_typedef} *insn, uint64_t value)"
303 yield from indent([f
"insn->value &= UINT64_C(0x{mask:016x});"])
305 for (src
, dst
) in enumerate(reversed(field
)):
306 dst
= (64 - (dst
+ 1))
307 dst
= f
"UINT64_C({dst})"
308 src
= f
"UINT64_C({src})"
309 action
= f
"(((value >> {src}) & UINT64_C(1)) << {dst})"
310 actions
.append(action
)
311 yield from indent(["insn->value |= ("])
312 for action
in indent(indent(actions
[:-1])):
314 yield from indent(indent([f
"{actions[-1]}"]))
315 yield from indent([");"])
319 yield from super().c_decl()
321 for (path
, field
) in _SVP64Instruction
.traverse():
322 yield from getter(path
, field
)
323 yield from setter(path
, field
)
326 class Name(Object
, str, c_typedef
="const char *"):
328 escaped
= self
.replace("\"", "\\\"")
329 return f
"\"{escaped}\""
331 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
332 yield f
"{prefix}{self!r}{suffix}"
335 def c_var(cls
, name
, prefix
="", suffix
=""):
336 return f
"{prefix}const char *{name}{suffix}"
339 @_dataclasses.dataclass(eq
=True, frozen
=True)
340 class Opcode(Struct
):
342 def __new__(cls
, value
):
343 if isinstance(value
, int):
344 value
= f
"0x{value:08x}"
345 return super().__new
__(cls
, value
)
348 def __new__(cls
, value
):
349 if isinstance(value
, int):
350 value
= f
"0x{value:08x}"
351 return super().__new
__(cls
, value
)
357 @_dataclasses.dataclass(eq
=True, frozen
=True)
373 extra_idx_out2
: Extra
374 extra_idx_cr_in
: Extra
375 extra_idx_cr_out
: Extra
380 yield f
"struct svp64_desc {{"
381 for field
in _dataclasses
.fields(cls
):
382 bits
= len(field
.type).bit_length()
383 yield from indent([f
"uint64_t {field.name} : {bits};"])
385 bits_rsvd
= (64 - (bits_all
% 64))
387 yield from indent([f
"uint64_t : {bits_rsvd};"])
391 @_dataclasses.dataclass(eq
=True, frozen
=True)
392 class Record(Struct
):
397 def __lt__(self
, other
):
398 if not isinstance(other
, self
.__class
__):
399 return NotImplemented
401 return self
.name
< other
.name
404 class Codegen(_enum
.Enum
):
405 PPC_SVP64_GEN_H
= "include/opcode/ppc-svp64-gen.h"
406 PPC_SVP64_OPC_GEN_C
= "opcodes/ppc-svp64-opc-gen.c"
411 def generate(self
, records
):
412 def ppc_svp64_h(records
, num_records
):
413 disclaimer
= DISCLAIMER
.format(path
=str(self
),
414 desc
="Header file for PowerPC opcode table (SVP64 extensions)")
415 yield from disclaimer
.splitlines()
418 yield f
"#ifndef {self.name}"
419 yield f
"#define {self.name}"
422 yield "#include <stdint.h>"
425 yield "#ifdef __cplusplus"
426 yield "extern \"C\" {"
431 In1Sel
, In2Sel
, In3Sel
, OutSel
,
437 yield from enum
.c_decl()
440 for cls
in (Instruction
, Desc
, Opcode
, Record
):
441 yield from cls
.c_decl()
444 yield records
.c_var("svp64_records",
445 prefix
="extern const ", suffix
=";")
446 yield num_records
.c_var("svp64_num_records",
447 prefix
="extern const ", suffix
=";")
450 yield "extern const struct powerpc_pd_reg svp64_regs[];"
451 yield Size
.c_var("svp64_num_regs", prefix
="extern const ", suffix
=";")
454 yield "#ifdef __cplusplus"
459 yield f
"#endif /* {self.name} */"
461 def ppc_svp64_opc_c(records
, num_records
):
462 disclaimer
= DISCLAIMER
.format(path
=str(self
),
463 desc
="PowerPC opcode list (SVP64 extensions)")
464 yield from disclaimer
.splitlines()
467 yield "#include \"opcode/ppc-svp64.h\""
470 def opindex(enum
, name
, table
):
471 sep
= (max(map(len, list(table
.values()) + ["UNUSED"])) + 1)
472 c_tag
= f
"svp64_{enum.__name__.lower()}"
473 yield "static inline ppc_opindex_t"
474 yield f
"svp64_desc_{name}_opindex(const struct svp64_desc *desc)"
476 yield from indent(["static const ppc_opindex_t table[] = {"])
478 value
= table
.get(key
, "UNUSED")
479 yield from indent(indent([f
"{value:{sep}}, /* {key.c_name} */"]))
480 yield from indent(["};"])
482 yield from indent([f
"return table[desc->{name}];"])
486 yield from opindex(In1Sel
, "in1", {
488 In1Sel
.RA_OR_ZERO
: "RA0",
494 yield from opindex(In2Sel
, "in2", {
500 yield from opindex(In3Sel
, "in3", {
508 for name
in ("out", "out2"):
509 yield from opindex(OutSel
, name
, {
513 OutSel
.RT_OR_ZERO
: "RT",
517 yield from opindex(CRInSel
, "cr_in", {
521 CRInSel
.WHOLE_REG
: "FXM",
523 yield from opindex(CROutSel
, "cr_out", {
526 CROutSel
.WHOLE_REG
: "FXM",
529 yield records
.c_var("svp64_records",
530 prefix
="const ", suffix
=" = \\")
531 yield from records
.c_value(prefix
="", suffix
=";")
533 yield num_records
.c_var("svp64_num_records",
534 prefix
="const ", suffix
=" = \\")
535 yield from indent(num_records
.c_value(suffix
=";"))
538 yield "const struct powerpc_pd_reg svp64_regs[] = {"
540 for (category
, count
, flags
) in sorted((
541 ("r", 128, "PPC_OPERAND_GPR"),
542 ("f", 128, "PPC_OPERAND_FPR"),
543 ("cr", 128, "PPC_OPERAND_CR_REG"),
545 for index
in range(count
):
546 regs
[f
"{category}{index}"] = (index
, flags
)
547 regs
[f
"{category}.{index}"] = (index
, flags
)
548 for (name
, (index
, flags
)) in sorted(regs
.items()):
549 yield from indent([f
"{{\"{name}\", {index}, {flags}}},"])
553 num_regs
= Size("(sizeof (svp64_regs) / sizeof (svp64_regs[0]))")
554 yield Size
.c_var("svp64_num_regs",
555 prefix
="const ", suffix
=" = \\")
556 yield from indent(num_regs
.c_value(suffix
=";"))
558 records
= Array
[Record
, ...](records
)
559 num_records
= Size("(sizeof (svp64_records) / sizeof (svp64_records[0]))")
562 Codegen
.PPC_SVP64_GEN_H
: ppc_svp64_h
,
563 Codegen
.PPC_SVP64_OPC_GEN_C
: ppc_svp64_opc_c
,
564 }[self
](records
, num_records
)
568 fields
= {field
.name
:field
.type for field
in _dataclasses
.fields(Desc
)}
570 for insn
in filter(lambda insn
: insn
.svp64
is not None, db
):
573 for (key
, cls
) in fields
.items():
574 value
= getattr(insn
, key
)
576 if (((cls
is EType
) and (value
is _SVEtype
.NONE
)) or
577 ((cls
is Extra
) and (value
is _SVExtra
.Idx_1_2
))):
581 if issubclass(cls
, _enum
.Enum
):
582 value
= cls
[value
.name
]
590 name
= Name(f
"sv.{insn.name}")
591 value
= Opcode
.Value(insn
.opcode
.value
)
592 mask
= Opcode
.Mask(insn
.opcode
.mask
)
593 opcode
= Opcode(value
=value
, mask
=mask
)
596 yield Record(name
=name
, opcode
=opcode
, desc
=desc
)
600 db
= _Database(_find_wiki_dir())
601 for line
in codegen
.generate(records(db
)):
605 if __name__
== "__main__":
606 parser
= _argparse
.ArgumentParser()
607 parser
.add_argument("codegen",
608 type=Codegen
, choices
=Codegen
,
609 help="code generator")
611 args
= vars(parser
.parse_args())