sv_binutils: hack
[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 CROutSel as _CROutSel,
17 SVPtype as _SVPtype,
18 SVEtype as _SVEtype,
19 SVExtra as _SVExtra,
20 Function as _Function,
21 find_wiki_dir as _find_wiki_dir,
22 )
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
26
27
28 DISCLAIMER = """\
29 /* {path} -- {desc}
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.
33
34 This file is part of the GNU opcodes library.
35
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)
39 any later version.
40
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.
45
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. */\
50 """
51
52
53 def indent(strings):
54 return map(lambda string: (" " + string), strings)
55
56
57 class ObjectMeta(type):
58 def __new__(metacls, clsname, bases, ns,
59 c_typedef="void", **kwargs):
60 if c_typedef == "void":
61 for base in bases:
62 if (hasattr(base, "c_typedef") and
63 (base.c_typedef != "void")):
64 c_typedef = base.c_typedef
65 break
66
67 ns.setdefault("c_typedef", c_typedef)
68 ns.update(kwargs)
69
70 return super().__new__(metacls, clsname, bases, ns)
71
72
73 class Object(metaclass=ObjectMeta):
74 @classmethod
75 def c_decl(cls):
76 yield from ()
77
78 @classmethod
79 def c_var(cls, name, prefix="", suffix=""):
80 return f"{prefix}{cls.c_typedef} {name}{suffix}"
81
82 def c_value(self, *, prefix="", suffix="", **kwargs):
83 yield from ()
84
85
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}[]"
91 else:
92 clsname = f"{clsname}[{c_size}]"
93
94 return super().__new__(metacls, clsname, bases, ns,
95 c_typedef=c_base.c_typedef, c_base=c_base, c_size=c_size, **kwargs)
96
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)
101
102
103 class Array(Object, tuple, metaclass=ArrayMeta,
104 c_base=Object, c_size=...):
105 @classmethod
106 def c_decl(cls):
107 if cls.c_size is Ellipsis:
108 size = ""
109 else:
110 size = f"{len(cls)}"
111 yield f"{cls.c_base.c_typedef}[{size}]"
112
113 @classmethod
114 def c_var(cls, name, prefix="", suffix=""):
115 if cls.c_size is Ellipsis:
116 size = ""
117 else:
118 size = f"{len(cls)}"
119 return f"{prefix}{cls.c_base.c_typedef} {name}[{size}]{suffix}"
120
121 def c_value(self, *, prefix="", suffix="", **kwargs):
122 yield f"{prefix}{{"
123 for item in self:
124 yield from indent(item.c_value(suffix=","))
125 yield f"}}{suffix}"
126
127
128 class Void(Object, c_typedef="void"):
129 def c_var(cls, name, prefix="", suffix=""):
130 raise NotImplementedError
131
132
133 class EnumMeta(_enum.EnumMeta, ObjectMeta):
134 def __call__(cls, clsname, entries,
135 c_tag=None, c_typedef=None, exclude=None):
136 if exclude is 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)
144
145 if c_tag is None:
146 c_tag = f"svp64_{clsname.lower()}"
147 if c_typedef is None:
148 c_typedef = f"enum {c_tag}"
149
150 base = ObjectMeta(cls.__name__, (), {},
151 c_tag=c_tag, c_typedef=c_typedef)
152
153 return super().__call__(value=clsname, names=entries, type=base)
154
155
156 class Enum(Object, _enum.Enum, metaclass=EnumMeta):
157 @property
158 def c_name(self):
159 return f"{self.c_tag.upper()}_{self.name.upper()}"
160
161 @classmethod
162 def c_decl(cls):
163 yield f"{cls.c_typedef} {{"
164 for item in cls:
165 yield from indent(item.c_value(suffix=","))
166 yield f"}};"
167
168 def c_value(self, *, prefix="", suffix="", **kwargs):
169 yield f"{prefix}{self.c_name}{suffix}"
170
171 @classmethod
172 def c_var(cls, name, prefix="", suffix=""):
173 return f"{prefix}{cls.c_typedef} {name}{suffix}"
174
175
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")
186
187
188 class Constant(_enum.Enum, metaclass=EnumMeta):
189 @classmethod
190 def c_decl(cls):
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}"
197
198 def c_value(self, *, prefix="", suffix="", **kwargs):
199 yield f"{prefix}{self.c_tag.upper()}_{self.c_name.upper()}{suffix}"
200
201
202 Mode = Constant("Mode", _SVP64MODE)
203
204
205 class StructMeta(ObjectMeta):
206 def __new__(metacls, clsname, bases, ns,
207 c_tag=None, c_typedef=None):
208
209 if c_tag is None:
210 c_tag = f"svp64_{clsname.lower()}"
211 if c_typedef is None:
212 c_typedef = f"struct {c_tag}"
213
214 return super().__new__(metacls, clsname, bases, ns,
215 c_typedef=c_typedef, c_tag=c_tag)
216
217
218 @_dataclasses.dataclass(eq=True, frozen=True)
219 class Struct(Object, metaclass=StructMeta):
220 @classmethod
221 def c_decl(cls):
222 def transform(field):
223 return field.type.c_var(name=f"{field.name}", suffix=";")
224
225 yield f"{cls.c_typedef} {{"
226 yield from indent(map(transform, _dataclasses.fields(cls)))
227 yield f"}};"
228
229 def c_value(self, *, prefix="", suffix="", **kwargs):
230 yield f"{prefix}{{"
231 for field in _dataclasses.fields(self):
232 name = field.name
233 attr = getattr(self, name)
234 yield from indent(attr.c_value(prefix=f".{name} = ", suffix=","))
235 yield f"}}{suffix}"
236
237
238 class Integer(Object, str):
239 def c_value(self, *, prefix="", suffix="", **kwargs):
240 yield f"{prefix}{self}{suffix}"
241
242
243 class Byte(Integer, c_typedef="uint8_t"):
244 pass
245
246
247 class Size(Integer, c_typedef="size_t"):
248 pass
249
250
251 class UInt32(Integer, c_typedef="uint32_t"):
252 pass
253
254
255 class UInt64(Integer, c_typedef="uint64_t"):
256 pass
257
258
259 @_dataclasses.dataclass(eq=True, frozen=True)
260 class Instruction(Struct, c_tag="svp64_insn"):
261 value: UInt64
262
263 @classmethod
264 def c_decl(cls):
265 def mangle(path, action):
266 if path.endswith("]"):
267 path = path[:-1]
268 for symbol in (".", "[", "]"):
269 path = path.replace(symbol, "_")
270 if path != "":
271 return f"{cls.c_tag}_{action}_{path}"
272 else:
273 return f"{cls.c_tag}_{action}"
274
275 def getter(path, field):
276 yield "static inline uint64_t"
277 yield f"{mangle(path, 'get')}(const {cls.c_typedef} *insn)"
278 yield "{"
279 yield from indent(["uint64_t value = insn->value;"])
280 yield ""
281 yield from indent(["return ("])
282 actions = []
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)):
290 yield f"{action} |"
291 yield from indent(indent(["UINT64_C(0)"]))
292 yield from indent([");"])
293 yield "}"
294 yield ""
295
296 def setter(path, field):
297 mask = ((2 ** 64) - 1)
298 for bit in field:
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)"
303 yield "{"
304 yield from indent([f"insn->value &= UINT64_C(0x{mask:016x});"])
305 actions = []
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)):
314 yield f"{action} |"
315 yield from indent(indent(["UINT64_C(0)"]))
316 yield from indent([");"])
317 yield "}"
318 yield ""
319
320 yield from super().c_decl()
321 yield ""
322 for (path, field) in _SVP64Instruction.traverse():
323 yield from getter(path, field)
324 yield from setter(path, field)
325
326
327 class Name(Object, str, c_typedef="const char *"):
328 def __repr__(self):
329 escaped = self.replace("\"", "\\\"")
330 return f"\"{escaped}\""
331
332 def c_value(self, *, prefix="", suffix="", **kwargs):
333 yield f"{prefix}{self!r}{suffix}"
334
335 @classmethod
336 def c_var(cls, name, prefix="", suffix=""):
337 return f"{prefix}const char *{name}{suffix}"
338
339
340 @_dataclasses.dataclass(eq=True, frozen=True)
341 class Opcode(Struct):
342 class Value(UInt32):
343 def __new__(cls, value):
344 if isinstance(value, int):
345 value = f"0x{value:08x}"
346 return super().__new__(cls, value)
347
348 class Mask(UInt32):
349 def __new__(cls, value):
350 if isinstance(value, int):
351 value = f"0x{value:08x}"
352 return super().__new__(cls, value)
353
354 value: Value
355 mask: Mask
356
357
358 @_dataclasses.dataclass(eq=True, frozen=True)
359 class Desc(Struct):
360 function: Function
361 in1: In1Sel
362 in2: In2Sel
363 in3: In3Sel
364 out: OutSel
365 out2: OutSel
366 cr_in: CRInSel
367 cr_out: CROutSel
368 sv_ptype: PType
369 sv_etype: EType
370 sv_in1: Extra
371 sv_in2: Extra
372 sv_in3: Extra
373 sv_out: Extra
374 sv_out2: Extra
375 sv_cr_in: Extra
376 sv_cr_out: Extra
377
378 @classmethod
379 def c_decl(cls):
380 bits_all = 0
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};"])
385 bits_all += bits
386 bits_rsvd = (64 - (bits_all % 64))
387 if bits_rsvd:
388 yield from indent([f"uint64_t : {bits_rsvd};"])
389 yield f"}};"
390
391
392 @_dataclasses.dataclass(eq=True, frozen=True)
393 class Record(Struct):
394 name: Name
395 opcode: Opcode
396 desc: Desc
397
398 def __lt__(self, other):
399 if not isinstance(other, self.__class__):
400 return NotImplemented
401
402 return self.name < other.name
403
404
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"
408
409 def __str__(self):
410 return self.value
411
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()
417 yield ""
418
419 yield f"#ifndef {self.name}"
420 yield f"#define {self.name}"
421 yield ""
422
423 yield "#include <stdint.h>"
424 yield ""
425
426 yield "#ifdef __cplusplus"
427 yield "extern \"C\" {"
428 yield "#endif"
429 yield ""
430
431 enums = (
432 In1Sel, In2Sel, In3Sel, OutSel,
433 CRInSel, CROutSel,
434 PType, EType, Extra,
435 Mode, Function,
436 )
437 for enum in enums:
438 yield from enum.c_decl()
439 yield ""
440
441 for cls in (Instruction, Desc, Opcode, Record):
442 yield from cls.c_decl()
443 yield ""
444
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=";")
449 yield ""
450
451 yield "extern const struct powerpc_pd_reg svp64_regs[];"
452 yield Size.c_var("svp64_num_regs", prefix="extern const ", suffix=";")
453 yield ""
454
455 yield "#ifdef __cplusplus"
456 yield "}"
457 yield "#endif"
458 yield ""
459
460 yield f"#endif /* {self.name} */"
461
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()
466 yield ""
467
468 yield "#include \"opcode/ppc-svp64.h\""
469 yield ""
470
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)"
476 yield "{"
477 yield from indent(["static const ppc_opindex_t table[] = {"])
478 for key in enum:
479 value = table.get(key, "UNUSED")
480 yield from indent(indent([f"{value:{sep}}, /* {key.c_name} */"]))
481 yield from indent(["};"])
482 yield ""
483 yield from indent([f"return table[desc->{name}];"])
484 yield "}"
485 yield ""
486
487 yield from opindex(In1Sel, "in1", {
488 In1Sel.RA: "RA",
489 In1Sel.RA_OR_ZERO: "RA0",
490 In1Sel.SPR: "SPR",
491 In1Sel.RS: "RS",
492 In1Sel.FRA: "FRA",
493 In1Sel.FRS: "FRS",
494 })
495 yield from opindex(In2Sel, "in2", {
496 In2Sel.RB: "RB",
497 In2Sel.SPR: "SPR",
498 In2Sel.RS: "RS",
499 In2Sel.FRB: "FRB",
500 })
501 yield from opindex(In3Sel, "in3", {
502 In3Sel.RS: "RS",
503 In3Sel.RB: "RB",
504 In3Sel.FRS: "FRS",
505 In3Sel.FRC: "FRC",
506 In3Sel.RC: "RC",
507 In3Sel.RT: "RT",
508 })
509 for name in ("out", "out2"):
510 yield from opindex(OutSel, name, {
511 OutSel.RT: "RT",
512 OutSel.RA: "RA",
513 OutSel.SPR: "SPR",
514 OutSel.RT_OR_ZERO: "RT",
515 OutSel.FRT: "FRT",
516 OutSel.FRS: "FRS",
517 })
518 yield from opindex(CRInSel, "cr_in", {
519 CRInSel.BI: "BI",
520 CRInSel.BFA: "BFA",
521 CRInSel.BC: "BC",
522 CRInSel.WHOLE_REG: "FXM",
523 })
524 yield from opindex(CROutSel, "cr_out", {
525 CROutSel.BF: "BF",
526 CROutSel.BT: "BT",
527 CROutSel.WHOLE_REG: "FXM",
528 })
529
530 yield records.c_var("svp64_records",
531 prefix="const ", suffix=" = \\")
532 yield from records.c_value(prefix="", suffix=";")
533 yield ""
534 yield num_records.c_var("svp64_num_records",
535 prefix="const ", suffix=" = \\")
536 yield from indent(num_records.c_value(suffix=";"))
537 yield ""
538
539 yield "const struct powerpc_pd_reg svp64_regs[] = {"
540 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"),
545 )):
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}}},"])
551 yield "};"
552 yield ""
553
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=";"))
558
559 records = Array[Record, ...](records)
560 num_records = Size("(sizeof (svp64_records) / sizeof (svp64_records[0]))")
561
562 yield from {
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)
566
567
568 def records(db):
569 fields = {field.name:field.type for field in _dataclasses.fields(Desc)}
570
571 for insn in filter(lambda insn: insn.svp64 is not None, db):
572 desc = {}
573
574 for (key, cls) in fields.items():
575 value = getattr(insn, key)
576
577 if (((cls is EType) and (value is _SVEtype.NONE)) or
578 ((cls is Extra) and (value is _SVExtra.Idx_1_2))):
579 desc = None
580 break
581
582 if issubclass(cls, _enum.Enum):
583 value = cls[value.name]
584 else:
585 value = cls(value)
586 desc[key] = value
587
588 if desc is None:
589 continue
590
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)
595 desc = Desc(**desc)
596
597 yield Record(name=name, opcode=opcode, desc=desc)
598
599
600 def main(codegen):
601 db = _Database(_find_wiki_dir())
602 for line in codegen.generate(records(db)):
603 print(line)
604
605
606 if __name__ == "__main__":
607 parser = _argparse.ArgumentParser()
608 parser.add_argument("codegen",
609 type=Codegen, choices=Codegen,
610 help="code generator")
611
612 args = vars(parser.parse_args())
613 main(**args)