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