6ace71b20e7b5cb08c51919c6f8e35e394c72341
[openpower-isa.git] / src / openpower / sv / sv_binutils.py
1 import argparse as _argparse
2 import dataclasses as _dataclasses
3 import enum as _enum
4
5 import os as _os
6 import sys as _sys
7
8 _sys.path.append(_os.path.dirname(_os.path.realpath(__file__)) + "/../../")
9
10 from openpower.decoder.power_enums import (
11 In1Sel as _In1Sel,
12 In2Sel as _In2Sel,
13 In3Sel as _In3Sel,
14 OutSel as _OutSel,
15 CRInSel as _CRInSel,
16 CRIn2Sel as _CRIn2Sel,
17 CROutSel as _CROutSel,
18 SVPtype as _SVPtype,
19 SVEtype as _SVEtype,
20 SVExtra as _SVExtra,
21 Function as _Function,
22 find_wiki_dir as _find_wiki_dir,
23 )
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
27
28
29 DISCLAIMER = """\
30 /* {path} -- {desc}
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.
34
35 This file is part of the GNU opcodes library.
36
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)
40 any later version.
41
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.
46
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. */\
51 """
52
53
54 def indent(strings):
55 return map(lambda string: (" " + string), strings)
56
57
58 class ObjectMeta(type):
59 def __new__(metacls, clsname, bases, ns,
60 c_typedef="void", **kwargs):
61 if c_typedef == "void":
62 for base in bases:
63 if (hasattr(base, "c_typedef") and
64 (base.c_typedef != "void")):
65 c_typedef = base.c_typedef
66 break
67
68 ns.setdefault("c_typedef", c_typedef)
69 ns.update(kwargs)
70
71 return super().__new__(metacls, clsname, bases, ns)
72
73
74 class Object(metaclass=ObjectMeta):
75 @classmethod
76 def c_decl(cls):
77 yield from ()
78
79 @classmethod
80 def c_var(cls, name, prefix="", suffix=""):
81 return f"{prefix}{cls.c_typedef} {name}{suffix}"
82
83 def c_value(self, *, prefix="", suffix="", **kwargs):
84 yield from ()
85
86
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}[]"
92 else:
93 clsname = f"{clsname}[{c_size}]"
94
95 return super().__new__(metacls, clsname, bases, ns,
96 c_typedef=c_base.c_typedef, c_base=c_base, c_size=c_size, **kwargs)
97
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)
102
103
104 class Array(Object, tuple, metaclass=ArrayMeta,
105 c_base=Object, c_size=...):
106 @classmethod
107 def c_decl(cls):
108 if cls.c_size is Ellipsis:
109 size = ""
110 else:
111 size = f"{len(cls)}"
112 yield f"{cls.c_base.c_typedef}[{size}]"
113
114 @classmethod
115 def c_var(cls, name, prefix="", suffix=""):
116 if cls.c_size is Ellipsis:
117 size = ""
118 else:
119 size = f"{len(cls)}"
120 return f"{prefix}{cls.c_base.c_typedef} {name}[{size}]{suffix}"
121
122 def c_value(self, *, prefix="", suffix="", **kwargs):
123 yield f"{prefix}{{"
124 for item in self:
125 yield from indent(item.c_value(suffix=","))
126 yield f"}}{suffix}"
127
128
129 class Void(Object, c_typedef="void"):
130 def c_var(cls, name, prefix="", suffix=""):
131 raise NotImplementedError
132
133
134 class EnumMeta(_enum.EnumMeta, ObjectMeta):
135 def __call__(cls, clsname, entries,
136 c_tag=None, c_typedef=None, exclude=None):
137 if exclude is 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)
145
146 if c_tag is None:
147 c_tag = f"svp64_{clsname.lower()}"
148 if c_typedef is None:
149 c_typedef = f"enum {c_tag}"
150
151 base = ObjectMeta(cls.__name__, (), {},
152 c_tag=c_tag, c_typedef=c_typedef)
153
154 return super().__call__(value=clsname, names=entries, type=base)
155
156
157 class Enum(Object, _enum.Enum, metaclass=EnumMeta):
158 @property
159 def c_name(self):
160 return f"{self.c_tag.upper()}_{self.name.upper()}"
161
162 @classmethod
163 def c_decl(cls):
164 yield f"{cls.c_typedef} {{"
165 for item in cls:
166 yield from indent(item.c_value(suffix=","))
167 yield f"}};"
168
169 def c_value(self, *, prefix="", suffix="", **kwargs):
170 yield f"{prefix}{self.c_name}{suffix}"
171
172 @classmethod
173 def c_var(cls, name, prefix="", suffix=""):
174 return f"{prefix}{cls.c_typedef} {name}{suffix}"
175
176
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")
188
189
190 class Constant(_enum.Enum, metaclass=EnumMeta):
191 @classmethod
192 def c_decl(cls):
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}"
199
200 def c_value(self, *, prefix="", suffix="", **kwargs):
201 yield f"{prefix}{self.c_tag.upper()}_{self.c_name.upper()}{suffix}"
202
203
204 Mode = Constant("Mode", _SVP64MODE)
205
206
207 class StructMeta(ObjectMeta):
208 def __new__(metacls, clsname, bases, ns,
209 c_tag=None, c_typedef=None):
210
211 if c_tag is None:
212 c_tag = f"svp64_{clsname.lower()}"
213 if c_typedef is None:
214 c_typedef = f"struct {c_tag}"
215
216 return super().__new__(metacls, clsname, bases, ns,
217 c_typedef=c_typedef, c_tag=c_tag)
218
219
220 @_dataclasses.dataclass(eq=True, frozen=True)
221 class Struct(Object, metaclass=StructMeta):
222 @classmethod
223 def c_decl(cls):
224 def transform(field):
225 return field.type.c_var(name=f"{field.name}", suffix=";")
226
227 yield f"{cls.c_typedef} {{"
228 yield from indent(map(transform, _dataclasses.fields(cls)))
229 yield f"}};"
230
231 def c_value(self, *, prefix="", suffix="", **kwargs):
232 yield f"{prefix}{{"
233 for field in _dataclasses.fields(self):
234 name = field.name
235 attr = getattr(self, name)
236 yield from indent(attr.c_value(prefix=f".{name} = ", suffix=","))
237 yield f"}}{suffix}"
238
239
240 class Integer(Object, str):
241 def c_value(self, *, prefix="", suffix="", **kwargs):
242 yield f"{prefix}{self}{suffix}"
243
244
245 class Byte(Integer, c_typedef="uint8_t"):
246 pass
247
248
249 class Size(Integer, c_typedef="size_t"):
250 pass
251
252
253 class UInt32(Integer, c_typedef="uint32_t"):
254 pass
255
256
257 class UInt64(Integer, c_typedef="uint64_t"):
258 pass
259
260
261 @_dataclasses.dataclass(eq=True, frozen=True)
262 class Instruction(Struct, c_tag="svp64_insn"):
263 value: UInt64
264
265 @classmethod
266 def c_decl(cls):
267 def mangle(path, action):
268 if path.endswith("]"):
269 path = path[:-1]
270 for symbol in (".", "[", "]"):
271 path = path.replace(symbol, "_")
272 if path != "":
273 return f"{cls.c_tag}_{action}_{path}"
274 else:
275 return f"{cls.c_tag}_{action}"
276
277 def getter(path, field):
278 yield "static inline uint64_t"
279 yield f"{mangle(path, 'get')}(const {cls.c_typedef} *insn)"
280 yield "{"
281 yield from indent(["uint64_t value = insn->value;"])
282 yield from indent(["return ("])
283 actions = []
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])):
291 yield f"{action} |"
292 yield from indent(indent([f"{actions[-1]}"]))
293 yield from indent([");"])
294 yield "}"
295 yield ""
296
297 def setter(path, field):
298 mask = ((2 ** 64) - 1)
299 for bit in field:
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)"
304 yield "{"
305 yield from indent([f"insn->value &= UINT64_C(0x{mask:016x});"])
306 actions = []
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])):
315 yield f"{action} |"
316 yield from indent(indent([f"{actions[-1]}"]))
317 yield from indent([");"])
318 yield "}"
319 yield ""
320
321 yield from super().c_decl()
322 yield ""
323 for (path, field) in _SVP64Instruction.traverse():
324 yield from getter(path, field)
325 yield from setter(path, field)
326
327
328 class Name(Object, str, c_typedef="const char *"):
329 def __repr__(self):
330 escaped = self.replace("\"", "\\\"")
331 return f"\"{escaped}\""
332
333 def c_value(self, *, prefix="", suffix="", **kwargs):
334 yield f"{prefix}{self!r}{suffix}"
335
336 @classmethod
337 def c_var(cls, name, prefix="", suffix=""):
338 return f"{prefix}const char *{name}{suffix}"
339
340
341 @_dataclasses.dataclass(eq=True, frozen=True)
342 class Desc(Struct):
343 function: Function
344 in1: In1Sel
345 in2: In2Sel
346 in3: In3Sel
347 out: OutSel
348 out2: OutSel
349 cr_in: CRInSel
350 cr_in2: CRIn2Sel
351 cr_out: CROutSel
352 ptype: PType
353 etype: EType
354 extra_idx_in1: Extra
355 extra_idx_in2: Extra
356 extra_idx_in3: Extra
357 extra_idx_out: Extra
358 extra_idx_out2: Extra
359 extra_idx_cr_in: Extra
360 extra_idx_cr_out: Extra
361
362 @classmethod
363 def c_decl(cls):
364 bits_all = 0
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};"])
369 bits_all += bits
370 bits_rsvd = (64 - (bits_all % 64))
371 if bits_rsvd:
372 yield from indent([f"uint64_t : {bits_rsvd};"])
373 yield f"}};"
374
375
376 @_dataclasses.dataclass(eq=True, frozen=True)
377 class Opcode(Struct):
378 class Value(UInt32):
379 def __new__(cls, value):
380 if isinstance(value, int):
381 value = f"0x{value:08x}"
382 return super().__new__(cls, value)
383
384 class Mask(UInt32):
385 def __new__(cls, value):
386 if isinstance(value, int):
387 value = f"0x{value:08x}"
388 return super().__new__(cls, value)
389
390 value: Value
391 mask: Mask
392
393
394 class Opcodes(Object, c_typedef="const struct svp64_opcode *"):
395 def __init__(self, offset):
396 self.__offset = offset
397 return super().__init__()
398
399 @classmethod
400 def c_var(cls, name, prefix="", suffix=""):
401 return f"{prefix}{cls.c_typedef}{name}{suffix}"
402
403 @classmethod
404 def c_decl(cls):
405 yield "const struct svp64_opcode *opcodes;"
406
407 def c_value(self, *, prefix="", suffix="", **kwargs):
408 yield f"{prefix}&svp64_opcodes[{self.__offset}]{suffix}"
409
410
411 @_dataclasses.dataclass(eq=True, frozen=True)
412 class Record(Struct):
413 name: Name
414 desc: Desc
415 opcodes: Opcodes
416 nr_opcodes: Size
417
418 def __lt__(self, other):
419 if not isinstance(other, self.__class__):
420 return NotImplemented
421
422 return self.name < other.name
423
424
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"
428
429 def __str__(self):
430 return self.value
431
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()
437 yield ""
438
439 yield f"#ifndef {self.name}"
440 yield f"#define {self.name}"
441 yield ""
442
443 yield "#include <stdint.h>"
444 yield ""
445
446 yield "#ifdef __cplusplus"
447 yield "extern \"C\" {"
448 yield "#endif"
449 yield ""
450
451 enums = (
452 In1Sel, In2Sel, In3Sel, OutSel,
453 CRInSel, CROutSel,
454 PType, EType, Extra,
455 Mode, Function,
456 )
457 for enum in enums:
458 yield from enum.c_decl()
459 yield ""
460
461 for cls in (Instruction, Desc, Opcode, Record):
462 yield from cls.c_decl()
463 yield ""
464
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=";")
469 yield ""
470
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=";")
475 yield ""
476
477 yield "extern const struct powerpc_pd_reg svp64_regs[];"
478 yield Size.c_var("svp64_num_regs", prefix="extern const ", suffix=";")
479 yield ""
480
481 yield "#ifdef __cplusplus"
482 yield "}"
483 yield "#endif"
484 yield ""
485
486 yield f"#endif /* {self.name} */"
487
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()
492 yield ""
493
494 yield "#include \"opcode/ppc-svp64.h\""
495 yield ""
496
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)"
502 yield "{"
503 yield from indent(["static const ppc_opindex_t table[] = {"])
504 for key in enum:
505 value = table.get(key, "UNUSED")
506 yield from indent(indent([f"{value:{sep}}, /* {key.c_name} */"]))
507 yield from indent(["};"])
508 yield ""
509 yield from indent([f"return table[desc->{name}];"])
510 yield "}"
511 yield ""
512
513 yield from opindex(In1Sel, "in1", {
514 In1Sel.RA: "RA",
515 In1Sel.RA_OR_ZERO: "RA0",
516 In1Sel.SPR: "SPR",
517 In1Sel.RS: "RS",
518 In1Sel.FRA: "FRA",
519 In1Sel.FRS: "FRS",
520 })
521 yield from opindex(In2Sel, "in2", {
522 In2Sel.RB: "RB",
523 In2Sel.SPR: "SPR",
524 In2Sel.RS: "RS",
525 In2Sel.FRB: "FRB",
526 })
527 yield from opindex(In3Sel, "in3", {
528 In3Sel.RS: "RS",
529 In3Sel.RB: "RB",
530 In3Sel.FRS: "FRS",
531 In3Sel.FRC: "FRC",
532 In3Sel.RC: "RC",
533 In3Sel.RT: "RT",
534 })
535 for name in ("out", "out2"):
536 yield from opindex(OutSel, name, {
537 OutSel.RT: "RT",
538 OutSel.RA: "RA",
539 OutSel.SPR: "SPR",
540 OutSel.RT_OR_ZERO: "RT",
541 OutSel.FRT: "FRT",
542 OutSel.FRS: "FRS",
543 })
544 yield from opindex(CRInSel, "cr_in", {
545 CRInSel.BI: "BI",
546 CRInSel.BFA: "BFA",
547 CRInSel.BC: "BC",
548 CRInSel.WHOLE_REG: "FXM",
549 })
550 yield from opindex(CROutSel, "cr_out", {
551 CROutSel.BF: "BF",
552 CROutSel.BT: "BT",
553 CROutSel.WHOLE_REG: "FXM",
554 })
555
556 yield opcodes.c_var("svp64_opcodes",
557 prefix="const ", suffix=" = \\")
558 yield from opcodes.c_value(prefix="", suffix=";")
559 yield ""
560 yield nr_opcodes.c_var("svp64_nr_opcodes",
561 prefix="const ", suffix=" = \\")
562 yield from indent(nr_opcodes.c_value(suffix=";"))
563 yield ""
564
565 yield records.c_var("svp64_records",
566 prefix="const ", suffix=" = \\")
567 yield from records.c_value(prefix="", suffix=";")
568 yield ""
569 yield nr_records.c_var("svp64_nr_records",
570 prefix="const ", suffix=" = \\")
571 yield from indent(nr_records.c_value(suffix=";"))
572 yield ""
573
574 yield "const struct powerpc_pd_reg svp64_regs[] = {"
575 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"),
580 )):
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}}},"])
586 yield "};"
587 yield ""
588
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=";"))
593
594 opcodes = Array[Opcode, ...](opcodes)
595 nr_opcodes = Size("(sizeof (svp64_opcodes) / sizeof (svp64_opcodes[0]))")
596
597 records = Array[Record, ...](records)
598 nr_records = Size("(sizeof (svp64_records) / sizeof (svp64_records[0]))")
599
600 yield from {
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)
604
605
606 def collect(db):
607 opcodes = []
608 records = []
609 fields = {field.name:field.type for field in _dataclasses.fields(Desc)}
610
611 for insn in filter(lambda insn: insn.svp64 is not None, db):
612 desc = {}
613
614 for (key, cls) in fields.items():
615 value = getattr(insn, key)
616
617 if (((cls is EType) and (value is _SVEtype.NONE)) or
618 ((cls is Extra) and (value is _SVExtra.Idx_1_2))):
619 desc = None
620 break
621
622 if issubclass(cls, _enum.Enum):
623 value = cls[value.name]
624 else:
625 value = cls(value)
626 desc[key] = value
627
628 if desc is None:
629 continue
630
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)
638 desc = Desc(**desc)
639
640 record = Record(name=name, desc=desc,
641 opcodes=Opcodes(offset), nr_opcodes=Size(len(insn.opcodes)))
642 records.append(record)
643
644 return (opcodes, records)
645
646
647 def main(codegen):
648 db = _Database(_find_wiki_dir())
649 (opcodes, records) = collect(db)
650 for line in codegen.generate(opcodes, records):
651 print(line)
652
653
654 if __name__ == "__main__":
655 parser = _argparse.ArgumentParser()
656 parser.add_argument("codegen",
657 type=Codegen, choices=Codegen,
658 help="code generator")
659
660 args = vars(parser.parse_args())
661 main(**args)