sv_binutils: refactor fields generation
[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="", **kwargs):
98 yield from ()
99
100
101 class Array(CType, tuple, metaclass=ArrayMeta, type=CType, size=...):
102 def c_value(self, *, prefix="", suffix="", **kwargs):
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 Void(CType, typedef="void"):
114 def c_var(cls, name, prefix="", suffix=""):
115 raise NotImplementedError
116
117
118 class EnumMeta(_enum.EnumMeta, CTypeMeta):
119 def __call__(metacls, name, entries, tag=None, **kwargs):
120 if isinstance(entries, type) and issubclass(entries, _enum.Enum):
121 entries = dict(entries.__members__)
122 if isinstance(entries, dict):
123 entries = tuple(entries.items())
124 if tag is None:
125 tag = f"svp64_{name.lower()}"
126
127 cls = super().__call__(value=name, names=entries, **kwargs)
128 cls.__tag = tag
129
130 return cls
131
132 @property
133 def c_typedef(cls):
134 return f"enum {cls.c_tag}"
135
136 @property
137 def c_tag(cls):
138 return cls.__tag
139
140 def c_decl(cls):
141 yield f"{cls.c_typedef} {{"
142 for item in cls:
143 yield from indent(item.c_value(suffix=","))
144 yield f"}};"
145
146 def c_var(cls, name, prefix="", suffix=""):
147 return f"{prefix}{cls.c_typedef} {name}{suffix}"
148
149
150 class Enum(CType, _enum.Enum, metaclass=EnumMeta):
151 @property
152 def c_name(self):
153 return f"{self.__class__.c_tag.upper()}_{self.name.upper()}"
154
155 def c_value(self, *, prefix="", suffix="", **kwargs):
156 yield f"{prefix}{self.c_name}{suffix}"
157
158
159 In1Sel = Enum("In1Sel", _In1Sel)
160 In2Sel = Enum("In2Sel", _In2Sel)
161 In3Sel = Enum("In3Sel", _In3Sel)
162 OutSel = Enum("OutSel", _OutSel)
163 CRInSel = Enum("CRInSel", _CRInSel)
164 CROutSel = Enum("CROutSel", _CROutSel)
165 SVPType = Enum("SVPType", _SVPtype)
166 SVEType = Enum("SVEType", _SVEtype)
167 SVEXTRA = Enum("SVEXTRA", _SVEXTRA)
168
169
170 class Constant(CType, _enum.Enum, metaclass=EnumMeta):
171 @classmethod
172 def c_decl(cls):
173 yield f"/* {cls.c_tag.upper()} constants */"
174 for (key, item) in cls.__members__.items():
175 key = f"{cls.c_tag.upper()}_{key.upper()}"
176 value = f"0x{item.value:08x}U"
177 yield f"#define {key} {value}"
178
179 def c_value(self, *, prefix="", suffix="", **kwargs):
180 yield f"{prefix}{self.__class__.c_tag.upper()}_{self.name.upper()}{suffix}"
181
182
183 Mode = Constant("Mode", _SVP64MODE)
184
185
186 class StructMeta(CTypeMeta):
187 def __new__(metacls, name, bases, attrs, tag=None, **kwargs):
188 if tag is None:
189 tag = f"svp64_{name.lower()}"
190 if "typedef" not in kwargs:
191 kwargs["typedef"] = f"struct {tag}"
192
193 cls = super().__new__(metacls, name, bases, attrs, **kwargs)
194 cls.__tag = tag
195
196 return cls
197
198 @property
199 def c_tag(cls):
200 return cls.__tag
201
202 def c_decl(cls):
203 yield f"{cls.c_typedef} {{"
204 for field in _dataclasses.fields(cls):
205 yield from indent([field.type.c_var(name=f"{field.name}", suffix=";")])
206 yield f"}};"
207
208
209 @_dataclasses.dataclass(eq=True, frozen=True)
210 class Struct(CType, metaclass=StructMeta):
211 def c_value(self, *, prefix="", suffix="", **kwargs):
212 yield f"{prefix}{{"
213 for field in _dataclasses.fields(self):
214 name = field.name
215 attr = getattr(self, name)
216 yield from indent(attr.c_value(prefix=f".{name} = ", suffix=","))
217 yield f"}}{suffix}"
218
219
220 class Integer(CType, str):
221 def c_value(self, *, prefix="", suffix="", **kwargs):
222 yield f"{prefix}{self}{suffix}"
223
224
225 class Byte(Integer, typedef="uint8_t"):
226 pass
227
228
229 class Size(Integer, typedef="size_t"):
230 pass
231
232
233 class UInt32(Integer, typedef="uint32_t"):
234 pass
235
236
237 class Name(CType, str):
238 def __repr__(self):
239 escaped = self.replace("\"", "\\\"")
240 return f"\"{escaped}\""
241
242 def c_value(self, *, prefix="", suffix="", **kwargs):
243 yield f"{prefix}{self!r}{suffix}"
244
245 @classmethod
246 def c_var(cls, name, prefix="", suffix=""):
247 return f"{prefix}const char *{name}{suffix}"
248
249
250 @_dataclasses.dataclass(eq=True, frozen=True)
251 class Record(Struct):
252 in1: In1Sel
253 in2: In2Sel
254 in3: In3Sel
255 out: OutSel
256 out2: OutSel
257 cr_in: CRInSel
258 cr_out: CROutSel
259 sv_ptype: SVPType
260 sv_etype: SVEType
261 sv_in1: SVEXTRA
262 sv_in2: SVEXTRA
263 sv_in3: SVEXTRA
264 sv_out: SVEXTRA
265 sv_out2: SVEXTRA
266 sv_cr_in: SVEXTRA
267 sv_cr_out: SVEXTRA
268
269 @classmethod
270 def c_decl(cls):
271 bits_all = 0
272 yield f"struct svp64_record {{"
273 for field in _dataclasses.fields(cls):
274 bits = len(field.type).bit_length()
275 yield from indent([f"uint64_t {field.name} : {bits};"])
276 bits_all += bits
277 bits_rsvd = (64 - (bits_all % 64))
278 if bits_rsvd:
279 yield from indent([f"uint64_t : {bits_rsvd};"])
280 yield f"}};"
281
282
283 @_dataclasses.dataclass(eq=True, frozen=True)
284 class Entry(Struct):
285 name: Name
286 record: Record
287
288 def __lt__(self, other):
289 if not isinstance(other, self.__class__):
290 return NotImplemented
291
292 return self.name < other.name
293
294
295 class FunctionMeta(CTypeMeta):
296 def __new__(metacls, name, bases, attrs, rv, args):
297 cls = super().__new__(metacls, name, bases, attrs)
298 cls.__rv = rv
299 cls.__args = args
300
301 return cls
302
303 def c_var(cls, name, prefix="", suffix=""):
304 rv = cls.__rv.c_typedef
305 args = ", ".join(arg_cls.c_var(arg_name) for (arg_name, arg_cls) in cls.__args)
306 return f"{prefix}{rv} {name}({args}){suffix}"
307
308
309 class FieldsMappingMeta(EnumMeta):
310 class HelperMeta(FunctionMeta):
311 def __new__(metacls, name, bases, attrs, rv, args, enum):
312 cls = super().__new__(metacls, name, bases, attrs, rv=rv, args=args)
313 cls.__enum = enum
314 return cls
315
316 def __iter__(cls):
317 yield from cls.__enum
318
319 class GetterMeta(HelperMeta):
320 def __new__(metacls, name, bases, attrs, enum, struct):
321 return super().__new__(metacls, name, bases, attrs, enum=enum, rv=UInt32, args=(
322 ("storage", struct),
323 ("field", enum),
324 ))
325
326 class SetterMeta(HelperMeta):
327 def __new__(metacls, name, bases, attrs, enum, struct):
328 return super().__new__(metacls, name, bases, attrs, enum=enum, rv=Void, args=(
329 ("*storage", struct),
330 ("field", enum),
331 ("value", UInt32),
332 ))
333
334 def __call__(metacls, name, base=SelectableIntMapping, **kwargs):
335 def flatten(mapping, parent=""):
336 for (key, value) in mapping.items():
337 key = f"{parent}_{key}" if parent else key
338 if isinstance(value, dict):
339 yield from flatten(mapping=value, parent=key)
340 else:
341 value = map(lambda bit: bit, reversed(value))
342 # value = map(lambda bit: ((base.bits - 1) - bit), reversed(value))
343 yield (key.upper(), tuple(value))
344
345 tag = f"svp64_{name.lower()}"
346 fields = dict(flatten(mapping=dict(base)))
347 bitmap = type(name, (Bitmap,), {}, typedef="uint32_t", bits=base.bits)
348 struct = _dataclasses.make_dataclass(name, (("value", bitmap),),
349 bases=(Struct,), frozen=True, eq=True)
350
351 cls = super().__call__(name=name, entries=fields, tag=f"{tag}_field", **kwargs)
352
353 def c_value(fields, stmt):
354 yield "switch (field) {"
355 for field in fields:
356 label = "".join(field.c_value())
357 yield from indent([f"case {label}:"])
358 yield from indent(indent(map(stmt, enumerate(field.value))))
359 yield from indent(indent(["break;"]))
360 yield "}"
361
362 class Getter(metaclass=FieldsMappingMeta.GetterMeta, enum=cls, struct=struct):
363 def c_value(self, prefix="", suffix=""):
364 yield f"{prefix}{{"
365 yield from indent([
366 UInt32.c_var(name="result", suffix=" = UINT32_C(0);"),
367 UInt32.c_var(name="origin", suffix=" = storage.value;"),
368 ])
369 yield ""
370 yield from indent(c_value(fields=tuple(self.__class__),
371 stmt=lambda kv: f"result |= SVP64_FIELD_GET(origin, {kv[1]}, {kv[0]});"))
372 yield ""
373 yield from indent(["return result;"])
374 yield f"}}{suffix}"
375
376 class Setter(metaclass=FieldsMappingMeta.SetterMeta, enum=cls, struct=struct):
377 def c_value(self, prefix="", suffix=""):
378 yield f"{prefix}{{"
379 yield from indent([
380 UInt32.c_var(name="result", suffix=" = storage->value;"),
381 ])
382 yield ""
383 yield from indent(c_value(fields=tuple(self.__class__),
384 stmt=lambda kv: f"SVP64_FIELD_SET(&result, value, {kv[0]}, {kv[1]});"))
385 yield ""
386 yield from indent(["storage->value = result;"])
387 yield f"}}{suffix}"
388
389 cls.__tag = tag
390 cls.__struct = struct
391 cls.__getter = Getter()
392 cls.__setter = Setter()
393
394 return cls
395
396 @property
397 def c_getter(cls):
398 return cls.__getter
399
400 @property
401 def c_setter(cls):
402 return cls.__setter
403
404 def c_decl(cls):
405 yield from super().c_decl()
406 yield from cls.__struct.c_decl()
407 yield cls.__getter.__class__.c_var(name=f"{cls.__tag}_get", suffix=";")
408 yield cls.__setter.__class__.c_var(name=f"{cls.__tag}_set", suffix=";")
409
410
411 class FieldsMapping(Enum, metaclass=FieldsMappingMeta):
412 @property
413 def c_name(self):
414 short_c_tag = self.__class__.c_tag[:-len("_field")]
415 return f"{short_c_tag.upper()}_{self.name.upper()}"
416
417
418 Prefix = FieldsMapping("Prefix", base=_SVP64PrefixFields)
419 RM = FieldsMapping("RM", base=_SVP64RMFields)
420
421
422 class Codegen(_enum.Enum):
423 PPC_SVP64_H = _enum.auto()
424 PPC_SVP64_OPC_C = _enum.auto()
425
426 @classmethod
427 def _missing_(cls, value):
428 return {
429 "ppc-svp64.h": Codegen.PPC_SVP64_H,
430 "ppc-svp64-opc.c": Codegen.PPC_SVP64_OPC_C,
431 }.get(value)
432
433 def __str__(self):
434 return {
435 Codegen.PPC_SVP64_H: "ppc-svp64.h",
436 Codegen.PPC_SVP64_OPC_C: "ppc-svp64-opc.c",
437 }[self]
438
439 def generate(self, entries):
440 def ppc_svp64_h(entries, num_entries):
441 yield from DISCLAIMER
442 yield ""
443
444 yield f"#ifndef {self.name}"
445 yield f"#define {self.name}"
446 yield ""
447
448 yield "#include <stdint.h>"
449 yield ""
450
451 yield "#ifdef __cplusplus"
452 yield "extern \"C\" {"
453 yield "#endif"
454 yield ""
455
456 enums = (
457 In1Sel, In2Sel, In3Sel, OutSel,
458 CRInSel, CROutSel,
459 SVPType, SVEType, SVEXTRA,
460 Mode,
461 )
462 for enum in enums:
463 yield from enum.c_decl()
464 yield ""
465
466 for cls in (Record, Entry, Prefix, RM):
467 yield from cls.c_decl()
468 yield ""
469
470 for name in ("in1", "in2", "in3", "out", "out2", "cr_in", "cr_out"):
471 yield "unsigned char"
472 yield f"svp64_record_{name}_opsel(const struct svp64_record *record);"
473 yield ""
474
475 yield entries.__class__.c_var("svp64_entries", prefix="extern const ", suffix=";")
476 yield num_entries.__class__.c_var("svp64_num_entries", prefix="extern const ", suffix=";")
477 yield ""
478
479 yield f"#define SVP64_NAME_MAX {max(map(lambda entry: len(entry.name), entries))}"
480 yield ""
481
482 yield "#ifdef __cplusplus"
483 yield "}"
484 yield "#endif"
485 yield ""
486
487 yield f"#endif /* {self.name} */"
488 yield ""
489
490 def ppc_svp64_opc_c(entries, num_entries):
491 yield from DISCLAIMER
492 yield ""
493
494 yield "#include \"opcode/ppc-svp64.h\""
495 yield ""
496
497 def opsel(enum, name, table):
498 sep = (max(map(len, list(table.values()) + ["UNUSED"])) + 1)
499 c_tag = f"svp64_{enum.__name__.lower()}"
500 yield "unsigned char"
501 yield f"svp64_record_{name}_opsel(const struct svp64_record *record)"
502 yield "{"
503 yield from indent(["static const unsigned char table[] = {"])
504 for key in enum:
505 value = table.get(key, "UNUSED")
506 c_value = f"{c_tag.upper()}_{key.name.upper()}"
507 yield from indent(indent([f"{value:{sep}}, /* {c_value} */"]))
508 yield from indent(["};"])
509 yield ""
510 yield from indent([f"return table[record->{name}];"])
511 yield "}"
512 yield ""
513
514 yield from opsel(In1Sel, "in1", {
515 In1Sel.RA: "RA",
516 In1Sel.RA_OR_ZERO: "RA",
517 In1Sel.SPR: "SPR",
518 In1Sel.RS: "RS",
519 In1Sel.FRA: "FRA",
520 In1Sel.FRS: "FRS",
521 })
522 yield from opsel(In2Sel, "in2", {
523 In2Sel.RB: "RB",
524 In2Sel.SPR: "SPR",
525 In2Sel.RS: "RS",
526 In2Sel.FRB: "FRB",
527 })
528 yield from opsel(In3Sel, "in3", {
529 In3Sel.RS: "RS",
530 In3Sel.RB: "RB",
531 In3Sel.FRS: "FRS",
532 In3Sel.FRC: "FRC",
533 In3Sel.RC: "RC",
534 In3Sel.RT: "RT",
535 })
536 for name in ("out", "out2"):
537 yield from opsel(OutSel, name, {
538 OutSel.RT: "RT",
539 OutSel.RA: "RA",
540 OutSel.SPR: "SPR",
541 OutSel.RT_OR_ZERO: "RT",
542 OutSel.FRT: "FRT",
543 OutSel.FRS: "FRS",
544 })
545 yield from opsel(CRInSel, "cr_in", {
546 CRInSel.BI: "BI",
547 CRInSel.BFA: "BFA",
548 CRInSel.BC: "CRB",
549 CRInSel.WHOLE_REG: "FXM",
550 })
551 yield from opsel(CROutSel, "cr_out", {
552 CROutSel.BF: "BF",
553 CROutSel.BT: "BT",
554 CROutSel.WHOLE_REG: "FXM",
555 })
556
557 yield entries.__class__.c_var("svp64_entries", prefix="const ", suffix=" = \\")
558 yield from entries.c_value(prefix="", suffix=";")
559 yield ""
560 yield num_entries.__class__.c_var("svp64_num_entries", prefix="const ", suffix=" = \\")
561 yield from indent(num_entries.c_value(suffix=";"))
562 yield ""
563
564 bit_shl = lambda val, pos: f"({val} << UINT32_C({pos}))"
565 bit_shr = lambda val, pos: f"({val} >> UINT32_C({pos}))"
566 bit_get = lambda val, pos: f"({bit_shr(val, pos)} & UINT32_C(1))"
567 bit_or = lambda lhs, rhs: f"({lhs} | {rhs})"
568 bit_and = lambda lhs, rhs: f"({lhs} & {rhs})"
569 bit_not = lambda val: f"~({val})"
570
571 macros = {
572 "CLEAR(VALUE, BIT)":
573 bit_and("VALUE", bit_not(bit_shl("UINT32_C(1)", "BIT"))),
574 "REMAP(VALUE, SRC, DST)":
575 bit_shl(bit_get("VALUE", "SRC"), "DST"),
576 "GET(ORIGIN, SRC, DST)":
577 "SVP64_FIELD_REMAP(ORIGIN, SRC, DST)",
578 "SET(RESULT, VALUE, SRC, DST)":
579 " = ".join(["*(RESULT)", bit_or(
580 lhs="SVP64_FIELD_CLEAR(*(RESULT), DST)",
581 rhs="SVP64_FIELD_REMAP(VALUE, SRC, DST)",
582 )]),
583 }
584 for (call, body) in macros.items():
585 yield f"#define SVP64_FIELD_{call} \\"
586 yield from indent([body])
587 yield ""
588
589 for cls in (Prefix, RM):
590 for (mode, subcls) in {"get": cls.c_getter, "set": cls.c_setter}.items():
591 yield subcls.__class__.c_var(name=f"svp64_{cls.__name__.lower()}_{mode}")
592 yield from subcls.c_value()
593 yield ""
594
595
596 entries = Entry[...](entries)
597 num_entries = Size("(sizeof (svp64_entries) / sizeof (svp64_entries[0]))")
598
599 return {
600 Codegen.PPC_SVP64_H: ppc_svp64_h,
601 Codegen.PPC_SVP64_OPC_C: ppc_svp64_opc_c,
602 }[self](entries, num_entries)
603
604
605 ISA = _SVP64RM()
606 FIELDS = {field.name:field.type for field in _dataclasses.fields(Record)}
607 FIELDS.update({field.name:field.type for field in _dataclasses.fields(Entry)})
608
609 def parse(path):
610 visited = set()
611
612 def name_filter(name):
613 if name.startswith("l") and name.endswith("br"):
614 return False
615 if name in {"mcrxr", "mcrxrx", "darn"}:
616 return False
617 if name in {"bctar", "bcctr"}:
618 return False
619 if "rfid" in name:
620 return False
621 if name in {"setvl"}:
622 return False
623 if name in visited:
624 return False
625
626 visited.add(name)
627
628 return True
629
630 def item_mapper(item):
631 (key, value) = item
632 key = key.lower().replace(" ", "_")
633 cls = FIELDS.get(key, object)
634 if not isinstance(value, cls):
635 if issubclass(cls, _enum.Enum):
636 value = {item.name:item for item in cls}[value]
637 else:
638 value = cls(value)
639 return (key, value)
640
641 def item_filter(item):
642 (key, _) = item
643 return (key in FIELDS)
644
645 for record in ISA.get_svp64_csv(path):
646 names = record.pop("comment").split("=")[-1].split("/")
647 names = set(filter(name_filter, names))
648 if names:
649 rc = _RC[record["rc"] if record["rc"] else "NONE"]
650 if rc is _RC.RC:
651 names.update({f"{name}." for name in names})
652 record = dict(filter(item_filter, map(item_mapper, record.items())))
653 for name in map(Name, names):
654 yield Entry(name=name, record=Record(**record))
655
656
657 def main(codegen):
658 entries = []
659 paths = (
660 "minor_19.csv",
661 "minor_30.csv",
662 "minor_31.csv",
663 "minor_58.csv",
664 "minor_62.csv",
665 "minor_22.csv",
666 "minor_5.csv",
667 "minor_63.csv",
668 "minor_59.csv",
669 "major.csv",
670 "extra.csv",
671 )
672 for path in paths:
673 entries.extend(parse(path))
674 entries = sorted(frozenset(entries))
675
676 for line in codegen.generate(entries):
677 print(line)
678
679
680 if __name__ == "__main__":
681 parser = _argparse.ArgumentParser()
682 parser.add_argument("codegen", type=Codegen, choices=Codegen, help="code generator")
683
684 args = vars(parser.parse_args())
685 main(**args)