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