6ace71b20e7b5cb08c51919c6f8e35e394c72341
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
,
21 Function
as _Function
,
22 find_wiki_dir
as _find_wiki_dir
,
24 from openpower
.consts
import SVP64MODE
as _SVP64MODE
25 from openpower
.decoder
.power_insn
import Database
as _Database
26 from openpower
.decoder
.power_insn
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 Function
= Enum("Function", _Function
, c_tag
="svp64_function")
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 Mode
= 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():
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 @_dataclasses.dataclass(eq
=True, frozen
=True)
358 extra_idx_out2
: Extra
359 extra_idx_cr_in
: Extra
360 extra_idx_cr_out
: Extra
365 yield f
"struct svp64_desc {{"
366 for field
in _dataclasses
.fields(cls
):
367 bits
= len(field
.type).bit_length()
368 yield from indent([f
"uint64_t {field.name} : {bits};"])
370 bits_rsvd
= (64 - (bits_all
% 64))
372 yield from indent([f
"uint64_t : {bits_rsvd};"])
376 @_dataclasses.dataclass(eq
=True, frozen
=True)
377 class Opcode(Struct
):
379 def __new__(cls
, value
):
380 if isinstance(value
, int):
381 value
= f
"0x{value:08x}"
382 return super().__new
__(cls
, value
)
385 def __new__(cls
, value
):
386 if isinstance(value
, int):
387 value
= f
"0x{value:08x}"
388 return super().__new
__(cls
, value
)
394 class Opcodes(Object
, c_typedef
="const struct svp64_opcode *"):
395 def __init__(self
, offset
):
396 self
.__offset
= offset
397 return super().__init
__()
400 def c_var(cls
, name
, prefix
="", suffix
=""):
401 return f
"{prefix}{cls.c_typedef}{name}{suffix}"
405 yield "const struct svp64_opcode *opcodes;"
407 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
408 yield f
"{prefix}&svp64_opcodes[{self.__offset}]{suffix}"
411 @_dataclasses.dataclass(eq
=True, frozen
=True)
412 class Record(Struct
):
418 def __lt__(self
, other
):
419 if not isinstance(other
, self
.__class
__):
420 return NotImplemented
422 return self
.name
< other
.name
425 class Codegen(_enum
.Enum
):
426 PPC_SVP64_GEN_H
= "include/opcode/ppc-svp64-gen.h"
427 PPC_SVP64_OPC_GEN_C
= "opcodes/ppc-svp64-opc-gen.c"
432 def generate(self
, opcodes
, records
):
433 def ppc_svp64_h(opcodes
, nr_opcodes
, records
, nr_records
):
434 disclaimer
= DISCLAIMER
.format(path
=str(self
),
435 desc
="Header file for PowerPC opcode table (SVP64 extensions)")
436 yield from disclaimer
.splitlines()
439 yield f
"#ifndef {self.name}"
440 yield f
"#define {self.name}"
443 yield "#include <stdint.h>"
446 yield "#ifdef __cplusplus"
447 yield "extern \"C\" {"
452 In1Sel
, In2Sel
, In3Sel
, OutSel
,
458 yield from enum
.c_decl()
461 for cls
in (Instruction
, Desc
, Opcode
, Record
):
462 yield from cls
.c_decl()
465 yield opcodes
.c_var("svp64_opcodes",
466 prefix
="extern const ", suffix
=";")
467 yield nr_opcodes
.c_var("svp64_nr_opcodes",
468 prefix
="extern const ", suffix
=";")
471 yield records
.c_var("svp64_records",
472 prefix
="extern const ", suffix
=";")
473 yield nr_records
.c_var("svp64_nr_records",
474 prefix
="extern const ", suffix
=";")
477 yield "extern const struct powerpc_pd_reg svp64_regs[];"
478 yield Size
.c_var("svp64_num_regs", prefix
="extern const ", suffix
=";")
481 yield "#ifdef __cplusplus"
486 yield f
"#endif /* {self.name} */"
488 def ppc_svp64_opc_c(opcodes
, nr_opcodes
, records
, nr_records
):
489 disclaimer
= DISCLAIMER
.format(path
=str(self
),
490 desc
="PowerPC opcode list (SVP64 extensions)")
491 yield from disclaimer
.splitlines()
494 yield "#include \"opcode/ppc-svp64.h\""
497 def opindex(enum
, name
, table
):
498 sep
= (max(map(len, list(table
.values()) + ["UNUSED"])) + 1)
499 c_tag
= f
"svp64_{enum.__name__.lower()}"
500 yield "static inline ppc_opindex_t"
501 yield f
"svp64_desc_{name}_opindex(const struct svp64_desc *desc)"
503 yield from indent(["static const ppc_opindex_t table[] = {"])
505 value
= table
.get(key
, "UNUSED")
506 yield from indent(indent([f
"{value:{sep}}, /* {key.c_name} */"]))
507 yield from indent(["};"])
509 yield from indent([f
"return table[desc->{name}];"])
513 yield from opindex(In1Sel
, "in1", {
515 In1Sel
.RA_OR_ZERO
: "RA0",
521 yield from opindex(In2Sel
, "in2", {
527 yield from opindex(In3Sel
, "in3", {
535 for name
in ("out", "out2"):
536 yield from opindex(OutSel
, name
, {
540 OutSel
.RT_OR_ZERO
: "RT",
544 yield from opindex(CRInSel
, "cr_in", {
548 CRInSel
.WHOLE_REG
: "FXM",
550 yield from opindex(CROutSel
, "cr_out", {
553 CROutSel
.WHOLE_REG
: "FXM",
556 yield opcodes
.c_var("svp64_opcodes",
557 prefix
="const ", suffix
=" = \\")
558 yield from opcodes
.c_value(prefix
="", suffix
=";")
560 yield nr_opcodes
.c_var("svp64_nr_opcodes",
561 prefix
="const ", suffix
=" = \\")
562 yield from indent(nr_opcodes
.c_value(suffix
=";"))
565 yield records
.c_var("svp64_records",
566 prefix
="const ", suffix
=" = \\")
567 yield from records
.c_value(prefix
="", suffix
=";")
569 yield nr_records
.c_var("svp64_nr_records",
570 prefix
="const ", suffix
=" = \\")
571 yield from indent(nr_records
.c_value(suffix
=";"))
574 yield "const struct powerpc_pd_reg svp64_regs[] = {"
576 for (category
, count
, flags
) in sorted((
577 ("r", 128, "PPC_OPERAND_GPR"),
578 ("f", 128, "PPC_OPERAND_FPR"),
579 ("cr", 128, "PPC_OPERAND_CR_REG"),
581 for index
in range(count
):
582 regs
[f
"{category}{index}"] = (index
, flags
)
583 regs
[f
"{category}.{index}"] = (index
, flags
)
584 for (name
, (index
, flags
)) in sorted(regs
.items()):
585 yield from indent([f
"{{\"{name}\", {index}, {flags}}},"])
589 num_regs
= Size("(sizeof (svp64_regs) / sizeof (svp64_regs[0]))")
590 yield Size
.c_var("svp64_num_regs",
591 prefix
="const ", suffix
=" = \\")
592 yield from indent(num_regs
.c_value(suffix
=";"))
594 opcodes
= Array
[Opcode
, ...](opcodes
)
595 nr_opcodes
= Size("(sizeof (svp64_opcodes) / sizeof (svp64_opcodes[0]))")
597 records
= Array
[Record
, ...](records
)
598 nr_records
= Size("(sizeof (svp64_records) / sizeof (svp64_records[0]))")
601 Codegen
.PPC_SVP64_GEN_H
: ppc_svp64_h
,
602 Codegen
.PPC_SVP64_OPC_GEN_C
: ppc_svp64_opc_c
,
603 }[self
](opcodes
, nr_opcodes
, records
, nr_records
)
609 fields
= {field
.name
:field
.type for field
in _dataclasses
.fields(Desc
)}
611 for insn
in filter(lambda insn
: insn
.svp64
is not None, db
):
614 for (key
, cls
) in fields
.items():
615 value
= getattr(insn
, key
)
617 if (((cls
is EType
) and (value
is _SVEtype
.NONE
)) or
618 ((cls
is Extra
) and (value
is _SVExtra
.Idx_1_2
))):
622 if issubclass(cls
, _enum
.Enum
):
623 value
= cls
[value
.name
]
631 name
= Name(f
"sv.{insn.name}")
632 offset
= len(opcodes
)
633 for opcode
in insn
.opcodes
:
634 value
= Opcode
.Value(opcode
.value
)
635 mask
= Opcode
.Mask(opcode
.mask
)
636 opcode
= Opcode(value
=value
, mask
=mask
)
637 opcodes
.append(opcode
)
640 record
= Record(name
=name
, desc
=desc
,
641 opcodes
=Opcodes(offset
), nr_opcodes
=Size(len(insn
.opcodes
)))
642 records
.append(record
)
644 return (opcodes
, records
)
648 db
= _Database(_find_wiki_dir())
649 (opcodes
, records
) = collect(db
)
650 for line
in codegen
.generate(opcodes
, records
):
654 if __name__
== "__main__":
655 parser
= _argparse
.ArgumentParser()
656 parser
.add_argument("codegen",
657 type=Codegen
, choices
=Codegen
,
658 help="code generator")
660 args
= vars(parser
.parse_args())