sv_binutils: fix metaclass arguments
[openpower-isa.git] / src / openpower / sv / sv_binutils.py
1 import abc as _abc
2 import argparse as _argparse
3 import dataclasses as _dataclasses
4 import enum as _enum
5
6 from openpower.decoder.power_enums import (
7 In1Sel as _In1Sel,
8 In2Sel as _In2Sel,
9 In3Sel as _In3Sel,
10 OutSel as _OutSel,
11 CRInSel as _CRInSel,
12 CROutSel as _CROutSel,
13 SVPtype as _SVPtype,
14 SVEtype as _SVEtype,
15 SVEXTRA as _SVEXTRA,
16 RC as _RC,
17 )
18 from openpower.consts import SVP64MODE as _SVP64MODE
19 from openpower.decoder.power_svp64 import SVP64RM as _SVP64RM
20 from openpower.decoder.isa.caller import SVP64RMFields as _SVP64RMFields
21 from openpower.decoder.isa.caller import SVP64PrefixFields as _SVP64PrefixFields
22 from openpower.decoder.selectable_int import SelectableIntMapping
23
24
25 DISCLAIMER = (
26 "/*",
27 " * this file is auto-generated, do not edit",
28 " * https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/sv/sv_binutils.py",
29 " * part of Libre-SOC, sponsored by NLnet",
30 " */",
31 )
32
33
34 def indent(strings):
35 return map(lambda string: (" " + string), strings)
36
37
38 class CTypeMeta(type):
39 def __new__(metacls, name, bases, attrs, typedef=None):
40 cls = super().__new__(metacls, name, bases, attrs)
41 cls.__typedef = typedef
42
43 return cls
44
45 def __getitem__(cls, size):
46 name = f"{cls.__name__}[{'' if size is Ellipsis else size}]"
47 return type(name, (Array,), {}, type=cls, size=size)
48
49 @property
50 def c_typedef(cls):
51 return cls.__typedef
52
53 @_abc.abstractmethod
54 def c_decl(cls):
55 yield from ()
56
57 def c_var(cls, name, prefix="", suffix=""):
58 yield f"{prefix}{cls.c_typedef} {name}{suffix}"
59
60
61 class ArrayMeta(CTypeMeta):
62 def __new__(metacls, name, bases, attrs, type, size):
63 cls = super().__new__(metacls, name, bases, attrs)
64 cls.__type = type
65 cls.__ellipsis = (size is Ellipsis)
66 cls.__size = 0 if cls.__ellipsis else size
67
68 return cls
69
70 def __len__(cls):
71 return cls.__size
72
73 @property
74 def c_type(cls):
75 return cls.__type
76
77 def c_decl(cls):
78 size = "" if cls.__ellipsis else f"{cls.__size}"
79 yield f"{cls.c_type.c_typedef}[{size}]"
80
81 def c_var(cls, name, prefix="", suffix=""):
82 size = "" if cls.__ellipsis else f"{cls.__size}"
83 yield f"{prefix}{cls.c_type.c_typedef} {name}[{size}]{suffix}"
84
85
86 class CType(metaclass=CTypeMeta):
87 @_abc.abstractmethod
88 def c_value(self, prefix="", suffix=""):
89 yield from ()
90
91
92 class Array(CType, tuple, metaclass=ArrayMeta, type=CType, size=0):
93 def c_value(self, prefix="", suffix=""):
94 yield f"{prefix}{{"
95 for (index, item) in enumerate(self):
96 yield from indent(item.c_value(prefix=f"[{index}] = ", suffix=","))
97 yield f"}}{suffix}"
98
99
100 class EnumMeta(_enum.EnumMeta, CTypeMeta):
101 def __call__(metacls, name, entries, tag=None, **kwargs):
102 if isinstance(entries, type) and issubclass(entries, _enum.Enum):
103 entries = dict(entries.__members__)
104 if isinstance(entries, dict):
105 entries = tuple(entries.items())
106 if tag is None:
107 tag = f"svp64_{name.lower()}"
108
109 cls = super().__call__(value=name, names=entries, **kwargs)
110 cls.__tag = tag
111 return cls
112
113 @property
114 def c_typedef(cls):
115 return f"enum {cls.c_tag}"
116
117 @property
118 def c_tag(cls):
119 return cls.__tag
120
121 def c_var(cls, name, prefix="", suffix=""):
122 yield f"{prefix}{cls.c_typedef} {name}{suffix}"
123
124
125 class Enum(CType, _enum.Enum, metaclass=EnumMeta):
126 @property
127 def c_name(self):
128 return f"{self.__class__.c_tag.upper()}_{self.name.upper()}"
129
130 @classmethod
131 def c_decl(cls):
132 yield f"{cls.c_typedef} {{"
133 for item in cls:
134 yield from indent(item.c_value(suffix=","))
135 yield f"}};"
136
137 def c_value(self, prefix="", suffix=""):
138 yield f"{prefix}{self.c_name}{suffix}"
139
140
141 In1Sel = Enum("In1Sel", _In1Sel)
142 In2Sel = Enum("In2Sel", _In2Sel)
143 In3Sel = Enum("In3Sel", _In3Sel)
144 OutSel = Enum("OutSel", _OutSel)
145 CRInSel = Enum("CRInSel", _CRInSel)
146 CROutSel = Enum("CROutSel", _CROutSel)
147 SVPType = Enum("SVPType", _SVPtype)
148 SVEType = Enum("SVEType", _SVEtype)
149 SVEXTRA = Enum("SVEXTRA", _SVEXTRA)
150
151
152 class Constant(CType, _enum.Enum, metaclass=EnumMeta):
153 @classmethod
154 def c_decl(cls):
155 yield f"/* {cls.c_tag.upper()} constants */"
156 for (key, item) in cls.__members__.items():
157 key = f"{cls.c_tag.upper()}_{key.upper()}"
158 value = f"0x{item.value:08x}U"
159 yield f"#define {key} {value}"
160
161 def c_value(self, prefix="", suffix=""):
162 yield f"{prefix}{self.__class__.c_tag.upper()}_{self.name.upper()}{suffix}"
163
164
165 Mode = Constant("Mode", _SVP64MODE)
166
167
168 class StructMeta(CTypeMeta):
169 def __new__(metacls, name, bases, attrs, tag=None, **kwargs):
170 if tag is None:
171 tag = f"svp64_{name.lower()}"
172 if "typedef" not in kwargs:
173 kwargs["typedef"] = f"struct {tag}"
174
175 cls = super().__new__(metacls, name, bases, attrs, **kwargs)
176 cls.__tag = tag
177
178 return cls
179
180 @property
181 def c_tag(cls):
182 return cls.__tag
183
184 def c_decl(cls):
185 yield f"{cls.c_typedef} {{"
186 for field in _dataclasses.fields(cls):
187 yield from indent(field.type.c_var(name=f"{field.name}", suffix=";"))
188 yield f"}};"
189
190
191 @_dataclasses.dataclass(eq=True, frozen=True)
192 class Struct(CType, metaclass=StructMeta):
193 def c_value(self, prefix="", suffix=""):
194 yield f"{prefix}{{"
195 for field in _dataclasses.fields(self):
196 name = field.name
197 attr = getattr(self, name)
198 yield from indent(attr.c_value(prefix=f".{name} = ", suffix=","))
199 yield f"}}{suffix}"
200
201
202 class Integer(CType, str):
203 def c_value(self, prefix="", suffix=""):
204 yield f"{prefix}{self}{suffix}"
205
206
207 class Byte(Integer, typedef="uint8_t"):
208 pass
209
210
211 class Size(Integer, typedef="size_t"):
212 pass
213
214
215 class Name(CType, str):
216 def __repr__(self):
217 escaped = self.replace("\"", "\\\"")
218 return f"\"{escaped}\""
219
220 def c_value(self, prefix="", suffix=""):
221 yield f"{prefix}{self!r}{suffix}"
222
223 @classmethod
224 def c_var(cls, name, prefix="", suffix=""):
225 yield f"{prefix}const char *{name}{suffix}"
226
227
228 @_dataclasses.dataclass(eq=True, frozen=True)
229 class Record(Struct):
230 in1: In1Sel
231 in2: In2Sel
232 in3: In3Sel
233 out: OutSel
234 out2: OutSel
235 cr_in: CRInSel
236 cr_out: CROutSel
237 sv_ptype: SVPType
238 sv_etype: SVEType
239 sv_in1: SVEXTRA
240 sv_in2: SVEXTRA
241 sv_in3: SVEXTRA
242 sv_out: SVEXTRA
243 sv_out2: SVEXTRA
244 sv_cr_in: SVEXTRA
245 sv_cr_out: SVEXTRA
246
247 @classmethod
248 def c_decl(cls):
249 bits_all = 0
250 yield f"struct svp64_record {{"
251 for field in _dataclasses.fields(cls):
252 bits = len(field.type).bit_length()
253 yield from indent([f"uint64_t {field.name} : {bits};"])
254 bits_all += bits
255 bits_rsvd = (64 - (bits_all % 64))
256 if bits_rsvd:
257 yield from indent([f"uint64_t : {bits_rsvd};"])
258 yield f"}};"
259
260
261 @_dataclasses.dataclass(eq=True, frozen=True)
262 class Entry(Struct):
263 name: Name
264 record: Record
265
266 def __lt__(self, other):
267 if not isinstance(other, self.__class__):
268 return NotImplemented
269
270 return self.name < other.name
271
272
273 @_dataclasses.dataclass(eq=True, frozen=True)
274 class Field(Struct):
275 length: Size
276 mapping: Byte[32]
277
278
279
280 class FieldsMeta(CTypeMeta):
281 def __new__(metacls, name, bases, attrs, base=SelectableIntMapping):
282 def flatten(mapping, parent=""):
283 for (key, value) in mapping.items():
284 key = f"{parent}_{key}" if parent else key
285 if isinstance(value, dict):
286 yield from flatten(mapping=value, parent=key)
287 else:
288 yield (key.upper(), value)
289
290 mapping = dict(base)
291 fields = dict(flatten(mapping=mapping))
292 keys = ((key, index) for (index, key) in enumerate(fields))
293 enum_cls = Enum(name, entries=keys, tag=f"svp64_{name.lower()}_type")
294
295 def field(item):
296 (key, value) = item
297 length = Size(len(value))
298 mapping = Byte[32](map(lambda bit: Byte((base.bits - 1) - bit), reversed(value)))
299 return (key, Field(length=length, mapping=mapping))
300
301 typedef = mapping.pop("typedef", Field.c_typedef)
302 cls = super().__new__(metacls, name, bases, attrs, typedef=typedef)
303 cls.__enum = enum_cls
304 cls.__fields = dict(map(field, zip(enum_cls, fields.values())))
305
306 return cls
307
308 def __iter__(cls):
309 for (key, value) in cls.__fields.items():
310 yield (key, value)
311
312 def c_decl(cls):
313 yield from cls.__enum.c_decl()
314
315 def c_var(cls, name, prefix="", suffix=""):
316 yield from Field.c_var(name=name, prefix=prefix, suffix=suffix)
317
318
319 class Fields(metaclass=FieldsMeta):
320 def c_value(self, prefix="", suffix=""):
321 yield f"{prefix}{{"
322 for (key, value) in self.__class__:
323 yield from indent(value.c_value(prefix=f"[{key.c_name}] = ", suffix=","))
324 yield f"}}{suffix}"
325
326
327 class Prefix(Fields, base=_SVP64PrefixFields):
328 pass
329
330
331 class RM(Fields, base=_SVP64RMFields):
332 pass
333
334
335 class Codegen(_enum.Enum):
336 PPC_SVP64_H = _enum.auto()
337 PPC_SVP64_OPC_C = _enum.auto()
338
339 @classmethod
340 def _missing_(cls, value):
341 return {
342 "ppc-svp64.h": Codegen.PPC_SVP64_H,
343 "ppc-svp64-opc.c": Codegen.PPC_SVP64_OPC_C,
344 }.get(value)
345
346 def __str__(self):
347 return {
348 Codegen.PPC_SVP64_H: "ppc-svp64.h",
349 Codegen.PPC_SVP64_OPC_C: "ppc-svp64-opc.c",
350 }[self]
351
352 def generate(self, entries):
353 def ppc_svp64_h(entries, num_entries):
354 yield from DISCLAIMER
355 yield ""
356
357 yield f"#ifndef {self.name}"
358 yield f"#define {self.name}"
359 yield ""
360
361 yield "#include <stdint.h>"
362 yield ""
363
364 yield "#ifdef __cplusplus"
365 yield "extern \"C\" {"
366 yield "#endif"
367 yield ""
368
369 enums = (
370 In1Sel, In2Sel, In3Sel, OutSel,
371 CRInSel, CROutSel,
372 SVPType, SVEType, SVEXTRA,
373 Mode,
374 )
375 for enum in enums:
376 yield from enum.c_decl()
377 yield ""
378
379 structs = (Field, Record, Entry, Prefix, RM)
380 for struct in structs:
381 yield from struct.c_decl()
382 yield ""
383
384 for name in ("in1", "in2", "in3", "out", "out2", "cr_in", "cr_out"):
385 yield "unsigned char"
386 yield f"svp64_record_{name}_opsel(const struct svp64_record *record);"
387 yield ""
388
389 yield from entries.__class__.c_var("svp64_entries", prefix="extern const ", suffix=";")
390 yield from num_entries.__class__.c_var("svp64_num_entries", prefix="extern const ", suffix=";")
391 yield ""
392
393 yield f"#define SVP64_NAME_MAX {max(map(lambda entry: len(entry.name), entries))}"
394 yield ""
395
396 yield "#ifdef __cplusplus"
397 yield "}"
398 yield "#endif"
399 yield ""
400
401 yield f"#endif /* {self.name} */"
402 yield ""
403
404 def ppc_svp64_opc_c(entries, num_entries):
405 yield from DISCLAIMER
406 yield ""
407
408 yield "#include \"opcode/ppc-svp64.h\""
409 yield ""
410
411 def opsel(enum, name, table):
412 sep = (max(map(len, list(table.values()) + ["UNUSED"])) + 1)
413 c_tag = f"svp64_{enum.__name__.lower()}"
414 yield "unsigned char"
415 yield f"svp64_record_{name}_opsel(const struct svp64_record *record)"
416 yield "{"
417 yield from indent(["static const unsigned char table[] = {"])
418 for key in enum:
419 value = table.get(key, "UNUSED")
420 c_value = f"{c_tag.upper()}_{key.name.upper()}"
421 yield from indent(indent([f"{value:{sep}}, /* {c_value} */"]))
422 yield from indent(["};"])
423 yield ""
424 yield from indent([f"return table[record->{name}];"])
425 yield "}"
426 yield ""
427
428 yield from opsel(In1Sel, "in1", {
429 In1Sel.RA: "RA",
430 In1Sel.RA_OR_ZERO: "RA",
431 In1Sel.SPR: "SPR",
432 In1Sel.RS: "RS",
433 In1Sel.FRA: "FRA",
434 In1Sel.FRS: "FRS",
435 })
436 yield from opsel(In2Sel, "in2", {
437 In2Sel.RB: "RB",
438 In2Sel.SPR: "SPR",
439 In2Sel.RS: "RS",
440 In2Sel.FRB: "FRB",
441 })
442 yield from opsel(In3Sel, "in3", {
443 In3Sel.RS: "RS",
444 In3Sel.RB: "RB",
445 In3Sel.FRS: "FRS",
446 In3Sel.FRC: "FRC",
447 In3Sel.RC: "RC",
448 In3Sel.RT: "RT",
449 })
450 for name in ("out", "out2"):
451 yield from opsel(OutSel, name, {
452 OutSel.RT: "RT",
453 OutSel.RA: "RA",
454 OutSel.SPR: "SPR",
455 OutSel.RT_OR_ZERO: "RT",
456 OutSel.FRT: "FRT",
457 OutSel.FRS: "FRS",
458 })
459 yield from opsel(CRInSel, "cr_in", {
460 CRInSel.BI: "BI",
461 CRInSel.BFA: "BFA",
462 CRInSel.BC: "CRB",
463 CRInSel.WHOLE_REG: "FXM",
464 })
465 yield from opsel(CROutSel, "cr_out", {
466 CROutSel.BF: "BF",
467 CROutSel.BT: "BT",
468 CROutSel.WHOLE_REG: "FXM",
469 })
470
471 yield from entries.__class__.c_var("svp64_entries", prefix="const ", suffix=" = \\")
472 yield from entries.c_value(prefix="", suffix=";")
473 yield ""
474 yield from num_entries.__class__.c_var("svp64_num_entries", prefix="const ", suffix=" = \\")
475 yield from indent(num_entries.c_value(suffix=";"))
476 yield ""
477
478 for mapping in (Prefix, RM):
479 name = mapping.__name__.lower()
480 yield from mapping.c_var(name=f"svp64_{name}_entries", prefix="static ", suffix="[] = \\")
481 yield from mapping().c_value(suffix=";")
482 yield ""
483 yield ""
484
485 entries = Entry[...](entries)
486 num_entries = Size("(sizeof (svp64_entries) / sizeof (svp64_entries[0])")
487
488 return {
489 Codegen.PPC_SVP64_H: ppc_svp64_h,
490 Codegen.PPC_SVP64_OPC_C: ppc_svp64_opc_c,
491 }[self](entries, num_entries)
492
493
494 ISA = _SVP64RM()
495 FIELDS = {field.name:field.type for field in _dataclasses.fields(Record)}
496 FIELDS.update({field.name:field.type for field in _dataclasses.fields(Entry)})
497
498 def parse(path):
499 visited = set()
500
501 def name_filter(name):
502 if name.startswith("l") and name.endswith("br"):
503 return False
504 if name in {"mcrxr", "mcrxrx", "darn"}:
505 return False
506 if name in {"bctar", "bcctr"}:
507 return False
508 if "rfid" in name:
509 return False
510 if name in {"setvl"}:
511 return False
512 if name in visited:
513 return False
514
515 visited.add(name)
516
517 return True
518
519 def item_mapper(item):
520 (key, value) = item
521 key = key.lower().replace(" ", "_")
522 cls = FIELDS.get(key, object)
523 if not isinstance(value, cls):
524 if issubclass(cls, _enum.Enum):
525 value = {item.name:item for item in cls}[value]
526 else:
527 value = cls(value)
528 return (key, value)
529
530 def item_filter(item):
531 (key, _) = item
532 return (key in FIELDS)
533
534 for record in ISA.get_svp64_csv(path):
535 names = record.pop("comment").split("=")[-1].split("/")
536 names = set(filter(name_filter, names))
537 if names:
538 rc = _RC[record["rc"] if record["rc"] else "NONE"]
539 if rc is _RC.RC:
540 names.update({f"{name}." for name in names})
541 record = dict(filter(item_filter, map(item_mapper, record.items())))
542 for name in map(Name, names):
543 yield Entry(name=name, record=Record(**record))
544
545
546 def main(codegen):
547 entries = []
548 paths = (
549 "minor_19.csv",
550 "minor_30.csv",
551 "minor_31.csv",
552 "minor_58.csv",
553 "minor_62.csv",
554 "minor_22.csv",
555 "minor_5.csv",
556 "minor_63.csv",
557 "minor_59.csv",
558 "major.csv",
559 "extra.csv",
560 )
561 for path in paths:
562 entries.extend(parse(path))
563 entries = sorted(frozenset(entries))
564
565 for line in codegen.generate(entries):
566 print(line)
567
568
569 if __name__ == "__main__":
570 parser = _argparse.ArgumentParser()
571 parser.add_argument("codegen", type=Codegen, choices=Codegen, help="code generator")
572
573 args = vars(parser.parse_args())
574 main(**args)