sv_binutils: deprecate obsolete fields
[openpower-isa.git] / src / openpower / sv / sv_binutils.py
1 import abc as _abc
2 import argparse as _argparse
3 import collections as _collections
4 import dataclasses as _dataclasses
5 import enum as _enum
6 import functools as _functools
7 import operator as _operator
8
9 from openpower.decoder.power_enums import (
10 In1Sel as _In1Sel,
11 In2Sel as _In2Sel,
12 In3Sel as _In3Sel,
13 OutSel as _OutSel,
14 CRInSel as _CRInSel,
15 CROutSel as _CROutSel,
16 SVPtype as _SVPtype,
17 SVEtype as _SVEtype,
18 SVExtra as _SVExtra,
19 RC as _RC,
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
26
27 DISCLAIMER = """\
28 /* {path} -- {desc}
29 Copyright (C) 2022 Free Software Foundation, Inc.
30 Written by Dmitry Selyutin (ghostmansd).
31 Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073.
32
33 This file is part of the GNU opcodes library.
34
35 This library is free software; you can redistribute it and/or modify
36 it under the terms of the GNU General Public License as published by
37 the Free Software Foundation; either version 3, or (at your option)
38 any later version.
39
40 It is distributed in the hope that it will be useful, but WITHOUT
41 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
42 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
43 License for more details.
44
45 You should have received a copy of the GNU General Public License
46 along with this file; see the file COPYING. If not, write to the
47 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
48 MA 02110-1301, USA. */\
49 """
50
51
52 def indent(strings):
53 return map(lambda string: (" " + string), strings)
54
55
56 class CTypeMeta(type):
57 def __new__(metacls, name, bases, attrs, typedef="void"):
58 cls = super().__new__(metacls, name, bases, attrs)
59 if typedef == "void":
60 for base in bases:
61 if (hasattr(base, "c_typedef") and
62 (base.c_typedef != "void")):
63 typedef = base.c_typedef
64 break
65 cls.__typedef = typedef
66
67 return cls
68
69 def __getitem__(cls, size):
70 name = f"{cls.__name__}[{'' if size is Ellipsis else size}]"
71 return type(name, (Array,), {}, type=cls, size=size)
72
73 @property
74 def c_typedef(cls):
75 return cls.__typedef
76
77 @_abc.abstractmethod
78 def c_decl(cls):
79 yield from ()
80
81 def c_var(cls, name, prefix="", suffix=""):
82 return f"{prefix}{cls.c_typedef} {name}{suffix}"
83
84
85 class ArrayMeta(CTypeMeta):
86 def __new__(metacls, name, bases, attrs, type, size, **kwargs):
87 cls = super().__new__(metacls, name, bases, attrs, **kwargs)
88 cls.__type = type
89 cls.__ellipsis = (size is Ellipsis)
90 cls.__size = 0 if cls.__ellipsis else size
91
92 return cls
93
94 def __len__(cls):
95 return cls.__size
96
97 def c_decl(cls):
98 size = "" if cls.__ellipsis else f"{cls.__size}"
99 yield f"{cls.__type.c_typedef}[{size}]"
100
101 def c_var(cls, name, prefix="", suffix=""):
102 size = "" if cls.__ellipsis else f"{cls.__size}"
103 return f"{prefix}{cls.__type.c_typedef} {name}[{size}]{suffix}"
104
105
106 class BitmapMeta(CTypeMeta):
107 def __new__(metacls, name, bases, attrs,
108 typedef="uint64_t", bits=0, **kwargs):
109 cls = super().__new__(metacls,
110 name, bases, attrs, typedef=typedef, **kwargs)
111 cls.__bits = bits
112 return cls
113
114 def __len__(cls):
115 return cls.__bits
116
117 def c_var(cls, name, prefix="", suffix=""):
118 return f"{prefix}{cls.c_typedef} {name} : {cls.__bits}{suffix}"
119
120
121 class CType(metaclass=CTypeMeta):
122 @_abc.abstractmethod
123 def c_value(self, *, prefix="", suffix="", **kwargs):
124 yield from ()
125
126
127 class Array(CType, tuple, metaclass=ArrayMeta, type=CType, size=...):
128 def c_value(self, *, prefix="", suffix="", **kwargs):
129 yield f"{prefix}{{"
130 for (index, item) in enumerate(self):
131 yield from indent(item.c_value(suffix=","))
132 yield f"}}{suffix}"
133
134
135 class Bitmap(metaclass=BitmapMeta):
136 pass
137
138
139 class Void(CType, typedef="void"):
140 def c_var(cls, name, prefix="", suffix=""):
141 raise NotImplementedError
142
143
144 class EnumMeta(_enum.EnumMeta, CTypeMeta):
145 def __call__(metacls, name, entries, tag=None, exclude=None, **kwargs):
146 if exclude is None:
147 exclude = frozenset()
148 if isinstance(entries, type) and issubclass(entries, _enum.Enum):
149 # Use __members__, not __iter__, otherwise aliases are lost.
150 entries = dict(entries.__members__)
151 if isinstance(entries, dict):
152 entries = tuple(entries.items())
153 entries = ((key, value) for (key, value) in entries if key not in exclude)
154 if tag is None:
155 tag = f"svp64_{name.lower()}"
156
157 cls = super().__call__(value=name, names=entries, **kwargs)
158 cls.__tag = tag
159
160 return cls
161
162 @property
163 def c_typedef(cls):
164 return f"enum {cls.c_tag}"
165
166 @property
167 def c_tag(cls):
168 return cls.__tag
169
170 def c_decl(cls):
171 yield f"{cls.c_typedef} {{"
172 for item in cls:
173 yield from indent(item.c_value(suffix=","))
174 yield f"}};"
175
176 def c_var(cls, name, prefix="", suffix=""):
177 return f"{prefix}{cls.c_typedef} {name}{suffix}"
178
179
180 class Enum(CType, _enum.Enum, metaclass=EnumMeta):
181 @property
182 def c_name(self):
183 return f"{self.__class__.c_tag.upper()}_{self.name.upper()}"
184
185 def c_value(self, *, prefix="", suffix="", **kwargs):
186 yield f"{prefix}{self.c_name}{suffix}"
187
188
189 In1Sel = Enum("In1Sel", _In1Sel, tag="svp64_in1_sel")
190 In2Sel = Enum("In2Sel", _In2Sel, tag="svp64_in2_sel")
191 In3Sel = Enum("In3Sel", _In3Sel, tag="svp64_in3_sel")
192 OutSel = Enum("OutSel", _OutSel, tag="svp64_out_sel")
193 CRInSel = Enum("CRInSel", _CRInSel, tag="svp64_cr_in_sel")
194 CROutSel = Enum("CROutSel", _CROutSel, tag="svp64_cr_out_sel")
195 PType = Enum("PType", _SVPtype, tag="svp64_ptype")
196 EType = Enum("EType", _SVEtype, tag="svp64_etype", exclude="NONE")
197 Extra = Enum("Extra", _SVExtra, tag="svp64_extra", exclude="Idx_1_2")
198 Function = Enum("Function", _Function, tag="svp64_function")
199
200
201 class Constant(CType, _enum.Enum, metaclass=EnumMeta):
202 @classmethod
203 def c_decl(cls):
204 yield f"/* {cls.c_tag.upper()} constants */"
205 # Use __members__, not __iter__, otherwise aliases are lost.
206 for (key, item) in cls.__members__.items():
207 key = f"{cls.c_tag.upper()}_{key.upper()}"
208 value = f"0x{item.value:08x}U"
209 yield f"#define {key} {value}"
210
211 def c_value(self, *, prefix="", suffix="", **kwargs):
212 yield f"{prefix}{self.__class__.c_tag.upper()}_{self.c_name.upper()}{suffix}"
213
214
215 Mode = Constant("Mode", _SVP64MODE)
216
217
218 class StructMeta(CTypeMeta):
219 def __new__(metacls, name, bases, attrs, tag=None, **kwargs):
220 if tag is None:
221 tag = f"svp64_{name.lower()}"
222 if "typedef" not in kwargs:
223 kwargs["typedef"] = f"struct {tag}"
224
225 cls = super().__new__(metacls, name, bases, attrs, **kwargs)
226 cls.__tag = tag
227
228 return cls
229
230 @property
231 def c_tag(cls):
232 return cls.__tag
233
234 def c_decl(cls):
235 def transform(field):
236 return field.type.c_var(name=f"{field.name}", suffix=";")
237
238 yield f"{cls.c_typedef} {{"
239 yield from indent(map(transform, _dataclasses.fields(cls)))
240 yield f"}};"
241
242
243 @_dataclasses.dataclass(eq=True, frozen=True)
244 class Struct(CType, metaclass=StructMeta):
245 def c_value(self, *, prefix="", suffix="", **kwargs):
246 yield f"{prefix}{{"
247 for field in _dataclasses.fields(self):
248 name = field.name
249 attr = getattr(self, name)
250 yield from indent(attr.c_value(prefix=f".{name} = ", suffix=","))
251 yield f"}}{suffix}"
252
253
254 class Integer(CType, str):
255 def c_value(self, *, prefix="", suffix="", **kwargs):
256 yield f"{prefix}{self}{suffix}"
257
258
259 class Byte(Integer, typedef="uint8_t"):
260 pass
261
262
263 class Size(Integer, typedef="size_t"):
264 pass
265
266
267 class UInt32(Integer, typedef="uint32_t"):
268 pass
269
270
271 class Name(CType, str, typedef="const char *"):
272 def __repr__(self):
273 escaped = self.replace("\"", "\\\"")
274 return f"\"{escaped}\""
275
276 def c_value(self, *, prefix="", suffix="", **kwargs):
277 yield f"{prefix}{self!r}{suffix}"
278
279 @classmethod
280 def c_var(cls, name, prefix="", suffix=""):
281 return f"{prefix}const char *{name}{suffix}"
282
283
284 @_dataclasses.dataclass(eq=True, frozen=True)
285 class Opcode(Struct):
286 class Value(UInt32):
287 def __new__(cls, value):
288 if isinstance(value, int):
289 value = f"0x{value:08x}"
290 return super().__new__(cls, value)
291
292 class Mask(UInt32):
293 def __new__(cls, value):
294 if isinstance(value, int):
295 value = f"0x{value:08x}"
296 return super().__new__(cls, value)
297
298 value: Value
299 mask: Mask
300
301
302 @_dataclasses.dataclass(eq=True, frozen=True)
303 class Desc(Struct):
304 function: Function
305 in1: In1Sel
306 in2: In2Sel
307 in3: In3Sel
308 out: OutSel
309 out2: OutSel
310 cr_in: CRInSel
311 cr_out: CROutSel
312 sv_ptype: PType
313 sv_etype: EType
314 sv_in1: Extra
315 sv_in2: Extra
316 sv_in3: Extra
317 sv_out: Extra
318 sv_out2: Extra
319 sv_cr_in: Extra
320 sv_cr_out: Extra
321
322 @classmethod
323 def c_decl(cls):
324 bits_all = 0
325 yield f"struct svp64_desc {{"
326 for field in _dataclasses.fields(cls):
327 bits = len(field.type).bit_length()
328 yield from indent([f"uint64_t {field.name} : {bits};"])
329 bits_all += bits
330 bits_rsvd = (64 - (bits_all % 64))
331 if bits_rsvd:
332 yield from indent([f"uint64_t : {bits_rsvd};"])
333 yield f"}};"
334
335
336 @_dataclasses.dataclass(eq=True, frozen=True)
337 class Record(Struct):
338 name: Name
339 opcode: Opcode
340 desc: Desc
341
342 def __lt__(self, other):
343 if not isinstance(other, self.__class__):
344 return NotImplemented
345
346 return self.name < other.name
347
348
349 class Codegen(_enum.Enum):
350 PPC_SVP64_GEN_H = _enum.auto()
351 PPC_SVP64_OPC_GEN_C = _enum.auto()
352
353 @classmethod
354 def _missing_(cls, value):
355 return {
356 "ppc-svp64-gen.h": Codegen.PPC_SVP64_GEN_H,
357 "ppc-svp64-opc-gen.c": Codegen.PPC_SVP64_OPC_GEN_C,
358 }.get(value)
359
360 def __str__(self):
361 return {
362 Codegen.PPC_SVP64_GEN_H: "ppc-svp64-gen.h",
363 Codegen.PPC_SVP64_OPC_GEN_C: "ppc-svp64-opc-gen.c",
364 }[self]
365
366 def generate(self, records):
367 def ppc_svp64_h(records, num_records):
368 disclaimer = DISCLAIMER.format(path=str(self),
369 desc="Header file for PowerPC opcode table (SVP64 extensions)")
370 yield from disclaimer.splitlines()
371 yield ""
372
373 yield f"#ifndef {self.name}"
374 yield f"#define {self.name}"
375 yield ""
376
377 yield "#include <stdint.h>"
378 yield ""
379
380 yield "#ifdef __cplusplus"
381 yield "extern \"C\" {"
382 yield "#endif"
383 yield ""
384
385 enums = (
386 In1Sel, In2Sel, In3Sel, OutSel,
387 CRInSel, CROutSel,
388 PType, EType, Extra,
389 Mode, Function,
390 )
391 for enum in enums:
392 yield from enum.c_decl()
393 yield ""
394
395 for cls in (Desc, Opcode, Record, Instruction):
396 yield from cls.c_decl()
397 yield ""
398
399 yield records.__class__.c_var("svp64_records",
400 prefix="extern const ", suffix=";")
401 yield num_records.__class__.c_var("svp64_num_records",
402 prefix="extern const ", suffix=";")
403 yield ""
404
405 yield "extern const struct powerpc_pd_reg svp64_regs[];"
406 yield Size.c_var("svp64_num_regs", prefix="extern const ", suffix=";")
407 yield ""
408
409 yield "#ifdef __cplusplus"
410 yield "}"
411 yield "#endif"
412 yield ""
413
414 yield f"#endif /* {self.name} */"
415 yield ""
416
417 def ppc_svp64_opc_c(records, num_records):
418 disclaimer = DISCLAIMER.format(path=str(self),
419 desc="PowerPC opcode list (SVP64 extensions)")
420 yield from disclaimer.splitlines()
421 yield ""
422
423 yield "#include \"opcode/ppc-svp64.h\""
424 yield ""
425
426 def opindex(enum, name, table):
427 sep = (max(map(len, list(table.values()) + ["UNUSED"])) + 1)
428 c_tag = f"svp64_{enum.__name__.lower()}"
429 yield "static inline ppc_opindex_t"
430 yield f"svp64_desc_{name}_opindex(const struct svp64_desc *desc)"
431 yield "{"
432 yield from indent(["static const ppc_opindex_t table[] = {"])
433 for key in enum:
434 value = table.get(key, "UNUSED")
435 yield from indent(indent([f"{value:{sep}}, /* {key.c_name} */"]))
436 yield from indent(["};"])
437 yield ""
438 yield from indent([f"return table[desc->{name}];"])
439 yield "}"
440 yield ""
441
442 yield from opindex(In1Sel, "in1", {
443 In1Sel.RA: "RA",
444 In1Sel.RA_OR_ZERO: "RA0",
445 In1Sel.SPR: "SPR",
446 In1Sel.RS: "RS",
447 In1Sel.FRA: "FRA",
448 In1Sel.FRS: "FRS",
449 })
450 yield from opindex(In2Sel, "in2", {
451 In2Sel.RB: "RB",
452 In2Sel.SPR: "SPR",
453 In2Sel.RS: "RS",
454 In2Sel.FRB: "FRB",
455 })
456 yield from opindex(In3Sel, "in3", {
457 In3Sel.RS: "RS",
458 In3Sel.RB: "RB",
459 In3Sel.FRS: "FRS",
460 In3Sel.FRC: "FRC",
461 In3Sel.RC: "RC",
462 In3Sel.RT: "RT",
463 })
464 for name in ("out", "out2"):
465 yield from opindex(OutSel, name, {
466 OutSel.RT: "RT",
467 OutSel.RA: "RA",
468 OutSel.SPR: "SPR",
469 OutSel.RT_OR_ZERO: "RT",
470 OutSel.FRT: "FRT",
471 OutSel.FRS: "FRS",
472 })
473 yield from opindex(CRInSel, "cr_in", {
474 CRInSel.BI: "BI",
475 CRInSel.BFA: "BFA",
476 CRInSel.BC: "BC",
477 CRInSel.WHOLE_REG: "FXM",
478 })
479 yield from opindex(CROutSel, "cr_out", {
480 CROutSel.BF: "BF",
481 CROutSel.BT: "BT",
482 CROutSel.WHOLE_REG: "FXM",
483 })
484
485 yield records.__class__.c_var("svp64_records",
486 prefix="const ", suffix=" = \\")
487 yield from records.c_value(prefix="", suffix=";")
488 yield ""
489 yield num_records.__class__.c_var("svp64_num_records",
490 prefix="const ", suffix=" = \\")
491 yield from indent(num_records.c_value(suffix=";"))
492 yield ""
493
494 yield "const struct powerpc_pd_reg svp64_regs[] = {"
495 regs = {}
496 for (category, count, flags) in sorted((
497 ("r", 128, "PPC_OPERAND_GPR"),
498 ("f", 128, "PPC_OPERAND_FPR"),
499 ("cr", 128, "PPC_OPERAND_CR_REG"),
500 )):
501 for index in range(count):
502 regs[f"{category}{index}"] = (index, flags)
503 regs[f"{category}.{index}"] = (index, flags)
504 for (name, (index, flags)) in sorted(regs.items()):
505 yield from indent([f"{{\"{name}\", {index}, {flags}}},"])
506 yield "};"
507 yield ""
508
509 num_regs = Size("(sizeof (svp64_regs) / sizeof (svp64_regs[0]))")
510 yield Size.c_var("svp64_num_regs",
511 prefix="const ", suffix=" = \\")
512 yield from indent(num_regs.c_value(suffix=";"))
513 yield ""
514
515
516 records = Record[...](records)
517 num_records = Size("(sizeof (svp64_records) / sizeof (svp64_records[0]))")
518
519 return {
520 Codegen.PPC_SVP64_GEN_H: ppc_svp64_h,
521 Codegen.PPC_SVP64_OPC_GEN_C: ppc_svp64_opc_c,
522 }[self](records, num_records)
523
524
525 def records(db):
526 fields = {field.name:field.type for field in _dataclasses.fields(Desc)}
527
528 for insn in filter(lambda insn: insn.svp64 is not None, db):
529 desc = {}
530
531 for (key, cls) in fields.items():
532 value = getattr(insn, key)
533
534 if (((cls is EType) and (value is _SVEtype.NONE)) or
535 ((cls is Extra) and (value is _SVExtra.Idx_1_2))):
536 desc = None
537 break
538
539 if issubclass(cls, _enum.Enum):
540 value = cls[value.name]
541 else:
542 value = cls(value)
543 desc[key] = value
544
545 if desc is None:
546 continue
547
548 name = Name(f"sv.{insn.name}")
549 value = Opcode.Value(insn.opcode.value)
550 mask = Opcode.Mask(insn.opcode.mask)
551 opcode = Opcode(value=value, mask=mask)
552 desc = Desc(**desc)
553
554 yield Record(name=name, opcode=opcode, desc=desc)
555
556
557 def main(codegen):
558 db = _Database(_find_wiki_dir())
559 for line in codegen.generate(records(db)):
560 print(line)
561
562
563 if __name__ == "__main__":
564 parser = _argparse.ArgumentParser()
565 parser.add_argument("codegen",
566 type=Codegen, choices=Codegen,
567 help="code generator")
568
569 args = vars(parser.parse_args())
570 main(**args)