sv_binutils: introduce Array class
[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
21
22 DISCLAIMER = (
23 "/*",
24 " * this file is auto-generated, do not edit",
25 " * https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/sv/sv_binutils.py",
26 " * part of Libre-SOC, sponsored by NLnet",
27 " */",
28 )
29
30
31 def indent(strings):
32 return map(lambda string: (" " + string), strings)
33
34
35 class CTypeMeta(type):
36 def __new__(metacls, name, bases, attrs, typedef=None):
37 cls = super().__new__(metacls, name, bases, attrs)
38 cls.__typedef = typedef
39
40 return cls
41
42 @property
43 def c_typedef(cls):
44 return cls.__typedef
45
46 @_abc.abstractmethod
47 def c_decl(cls):
48 pass
49
50 @_abc.abstractmethod
51 def c_var(cls, name):
52 pass
53
54
55 class CType(metaclass=CTypeMeta):
56 @_abc.abstractmethod
57 def c_value(self, prefix="", suffix=""):
58 pass
59
60
61 class EnumMeta(_enum.EnumMeta, CTypeMeta):
62 def __call__(metacls, name, entries, tag=None, **kwargs):
63 if isinstance(entries, type) and issubclass(entries, _enum.Enum):
64 entries = dict(entries.__members__)
65 if isinstance(entries, dict):
66 entries = tuple(entries.items())
67 if tag is None:
68 tag = f"svp64_{name.lower()}"
69
70 cls = super().__call__(value=name, names=entries, **kwargs)
71 cls.__tag = tag
72 return cls
73
74 @property
75 def c_typedef(cls):
76 return f"enum {cls.c_tag}"
77
78 @property
79 def c_tag(cls):
80 return cls.__tag
81
82
83 class Enum(CType, _enum.Enum, metaclass=EnumMeta):
84 @classmethod
85 def c_decl(cls):
86 yield f"{cls.c_typedef} {{"
87 for item in cls:
88 yield from indent(item.c_value(suffix=","))
89 yield f"}};"
90
91 def c_value(self, prefix="", suffix=""):
92 yield f"{prefix}{self.__class__.c_tag.upper()}_{self.name.upper()}{suffix}"
93
94 @classmethod
95 def c_var(cls, name):
96 yield f"{cls.c_typedef} {name}"
97
98
99 In1Sel = Enum("In1Sel", _In1Sel)
100 In2Sel = Enum("In2Sel", _In2Sel)
101 In3Sel = Enum("In3Sel", _In3Sel)
102 OutSel = Enum("OutSel", _OutSel)
103 CRInSel = Enum("CRInSel", _CRInSel)
104 CROutSel = Enum("CROutSel", _CROutSel)
105 SVPType = Enum("SVPType", _SVPtype)
106 SVEType = Enum("SVEType", _SVEtype)
107 SVEXTRA = Enum("SVEXTRA", _SVEXTRA)
108
109
110 class Constant(CType, _enum.Enum, metaclass=EnumMeta):
111 @classmethod
112 def c_decl(cls):
113 yield f"/* {cls.c_tag.upper()} constants */"
114 for (key, item) in cls.__members__.items():
115 key = f"{cls.c_tag.upper()}_{key.upper()}"
116 value = f"0x{item.value:08x}U"
117 yield f"#define {key} {value}"
118
119 def c_value(self, prefix="", suffix=""):
120 yield f"{prefix}{self.__class__.c_tag.upper()}_{self.name.upper()}{suffix}"
121
122
123 Mode = Constant("Mode", _SVP64MODE)
124
125
126 class StructMeta(CTypeMeta):
127 def __new__(metacls, name, bases, attrs, tag=None, **kwargs):
128 if tag is None:
129 tag = f"svp64_{name.lower()}"
130 if "typedef" not in kwargs:
131 kwargs["typedef"] = f"struct {tag}"
132
133 cls = super().__new__(metacls, name, bases, attrs, **kwargs)
134 cls.__tag = tag
135
136 return cls
137
138 @property
139 def c_tag(cls):
140 return cls.__tag
141
142 def c_decl(cls):
143 yield f"{cls.c_typedef} {{"
144 for field in _dataclasses.fields(cls):
145 yield from indent(field.type.c_var(name=f"{field.name};"))
146 yield f"}};"
147
148 def c_var(cls, name):
149 yield f"{cls.c_typedef} {name}"
150
151
152 @_dataclasses.dataclass(eq=True, frozen=True)
153 class Struct(CType, metaclass=StructMeta):
154 def c_value(self, prefix="", suffix=""):
155 yield f"{prefix}{{"
156 for field in _dataclasses.fields(self):
157 name = field.name
158 attr = getattr(self, name)
159 yield from indent(attr.c_value(prefix=f".{name} = ", suffix=","))
160 yield f"}}{suffix}"
161
162
163 class IntegerMeta(CTypeMeta):
164 def c_decl(cls):
165 yield "#include <stdint.h>"
166
167 def c_var(cls, name):
168 yield f"{cls.c_typedef} {name}"
169
170
171 class Integer(CType, int, metaclass=IntegerMeta):
172 def c_value(self, prefix="", suffix=""):
173 yield f"{prefix}{self}{suffix}"
174
175
176 class ArrayMeta(CTypeMeta):
177 def __new__(metacls, name, bases, attrs, type=CType, size=0):
178 cls = super().__new__(metacls, name, bases, attrs)
179 cls.__type = type
180 cls.__size = size
181
182 return cls
183
184 def __call__(cls, type, size):
185 name = f"{cls.__name__}[{type.__name__}]"
186 return ArrayMeta.__new__(ArrayMeta, name, (cls,), {}, type=type, size=size)
187
188 def __len__(cls):
189 return cls.__size
190
191 @property
192 def c_type(cls):
193 return cls.__type
194
195 def c_decl(cls):
196 count = f"{cls.__size}" if cls.__size else ""
197 yield f"{cls.c_type.c_typedef}[{count}]"
198
199 def c_var(cls, name):
200 count = f"{cls.__size}" if cls.__size else ""
201 yield f"{cls.c_type.c_typedef} {name}[{count}]"
202
203
204 class Array(CType, tuple, metaclass=ArrayMeta):
205 def c_value(self, prefix="", suffix=""):
206 items = []
207 for item in map(self.__class__.c_type, self):
208 items.extend(item.c_value())
209 yield f"{prefix}{{{', '.join(items)}}}{suffix}"
210
211
212 class Opcode(CType):
213 def __init__(self, value, mask, bits):
214 self.__value = value
215 self.__mask = mask
216 self.__bits = bits
217
218 return super().__init__()
219
220 @property
221 def value(self):
222 return self.__value
223
224 @property
225 def mask(self):
226 return self.__mask
227
228 @property
229 def bits(self):
230 return self.__bits
231
232 def __repr__(self):
233 fmt = f"{{value:0{self.bits}b}}:{{mask:0{self.bits}b}}"
234 return fmt.format(value=self.value, mask=self.mask)
235
236 def __lt__(self, other):
237 if not isinstance(other, self.__class__):
238 return NotImplemented
239
240 return self.__value < other.__value
241
242 @classmethod
243 def c_decl(cls):
244 yield f"struct svp64_opcode {{"
245 yield from indent([
246 "uint32_t value;",
247 "uint32_t mask;",
248 ])
249 yield f"}};"
250
251 def c_value(self, prefix="", suffix=""):
252 yield f"{prefix}{{"
253 yield from indent([
254 f".value = UINT32_C(0x{self.value:08X}),",
255 f".mask = UINT32_C(0x{self.mask:08X}),",
256 ])
257 yield f"}}{suffix}"
258
259 @classmethod
260 def c_var(cls, name):
261 yield f"struct svp64_opcode {name}"
262
263
264 class IntegerOpcode(Opcode):
265 def __init__(self, integer):
266 value = int(integer, 0)
267 bits = max(1, value.bit_length())
268 mask = int(("1" * bits), 2)
269
270 return super().__init__(value=value, mask=mask, bits=bits)
271
272
273 class PatternOpcode(Opcode):
274 def __init__(self, pattern):
275 value = 0
276 mask = 0
277 bits = len(pattern)
278 for bit in pattern:
279 value |= (bit == "1")
280 mask |= (bit != "-")
281 value <<= 1
282 mask <<= 1
283 value >>= 1
284 mask >>= 1
285
286 return super().__init__(value=value, mask=mask, bits=bits)
287
288
289 class Name(CType, str):
290 def __repr__(self):
291 escaped = self.replace("\"", "\\\"")
292 return f"\"{escaped}\""
293
294 def c_value(self, prefix="", suffix=""):
295 yield f"{prefix}{self!r}{suffix}"
296
297 @classmethod
298 def c_var(cls, name):
299 yield f"const char *{name}"
300
301
302 @_dataclasses.dataclass(eq=True, frozen=True)
303 class Record(Struct):
304 in1: In1Sel
305 in2: In2Sel
306 in3: In3Sel
307 out: OutSel
308 out2: OutSel
309 cr_in: CRInSel
310 cr_out: CROutSel
311 sv_ptype: SVPType
312 sv_etype: SVEType
313 sv_in1: SVEXTRA
314 sv_in2: SVEXTRA
315 sv_in3: SVEXTRA
316 sv_out: SVEXTRA
317 sv_out2: SVEXTRA
318 sv_cr_in: SVEXTRA
319 sv_cr_out: SVEXTRA
320
321 @classmethod
322 def c_decl(cls):
323 bits_all = 0
324 yield f"struct svp64_record {{"
325 for field in _dataclasses.fields(cls):
326 bits = len(field.type).bit_length()
327 yield from indent([f"uint64_t {field.name} : {bits};"])
328 bits_all += bits
329 bits_rsvd = (64 - (bits_all % 64))
330 if bits_rsvd:
331 yield from indent([f"uint64_t : {bits_rsvd};"])
332 yield f"}};"
333
334
335 @_dataclasses.dataclass(eq=True, frozen=True)
336 class Entry(Struct):
337 name: Name
338 record: Record
339
340 def __lt__(self, other):
341 if not isinstance(other, self.__class__):
342 return NotImplemented
343
344 return self.name < other.name
345
346
347 class Codegen(_enum.Enum):
348 PPC_SVP64_H = _enum.auto()
349 PPC_SVP64_OPC_C = _enum.auto()
350
351 @classmethod
352 def _missing_(cls, value):
353 return {
354 "ppc-svp64.h": Codegen.PPC_SVP64_H,
355 "ppc-svp64-opc.c": Codegen.PPC_SVP64_OPC_C,
356 }.get(value)
357
358 def __str__(self):
359 return {
360 Codegen.PPC_SVP64_H: "ppc-svp64.h",
361 Codegen.PPC_SVP64_OPC_C: "ppc-svp64-opc.c",
362 }[self]
363
364 def generate(self, entries):
365 def ppc_svp64_h(entries):
366 yield from DISCLAIMER
367 yield ""
368
369 yield f"#ifndef {self.name}"
370 yield f"#define {self.name}"
371 yield ""
372
373 yield "#include <stdint.h>"
374 yield ""
375
376 yield "#ifdef __cplusplus"
377 yield "extern \"C\" {"
378 yield "#endif"
379 yield ""
380
381 enums = (
382 In1Sel, In2Sel, In3Sel, OutSel,
383 CRInSel, CROutSel,
384 SVPType, SVEType, SVEXTRA,
385 Mode,
386 )
387 for enum in enums:
388 yield from enum.c_decl()
389 yield ""
390
391 yield from Record.c_decl()
392 yield ""
393
394 for name in ("in1", "in2", "in3", "out", "out2", "cr_in", "cr_out"):
395 yield "unsigned char"
396 yield f"svp64_record_{name}_opsel(const struct svp64_record *record);"
397 yield ""
398
399 yield from Entry.c_decl()
400 yield ""
401
402 yield "extern const struct svp64_entry svp64_entries[];"
403 yield "extern const unsigned int svp64_num_entries;"
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):
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 "const struct svp64_entry svp64_entries[] = {"
485 for (index, entry) in enumerate(entries):
486 yield from indent(entry.c_value(prefix=f"[{index}] = ", suffix=","))
487 yield f"}};"
488 yield ""
489
490 yield "const unsigned int svp64_num_entries = \\"
491 yield " sizeof (svp64_entries) / sizeof (svp64_entries[0]);"
492 yield ""
493
494 return {
495 Codegen.PPC_SVP64_H: ppc_svp64_h,
496 Codegen.PPC_SVP64_OPC_C: ppc_svp64_opc_c,
497 }[self](entries)
498
499
500 ISA = _SVP64RM()
501 FIELDS = {field.name:field.type for field in _dataclasses.fields(Record)}
502 FIELDS.update({field.name:field.type for field in _dataclasses.fields(Entry)})
503
504 def parse(path, opcode_cls):
505 visited = set()
506
507 def name_filter(name):
508 if name.startswith("l") and name.endswith("br"):
509 return False
510 if name in {"mcrxr", "mcrxrx", "darn"}:
511 return False
512 if name in {"bctar", "bcctr"}:
513 return False
514 if "rfid" in name:
515 return False
516 if name in {"setvl"}:
517 return False
518 if name in visited:
519 return False
520
521 visited.add(name)
522
523 return True
524
525 def item_mapper(item):
526 (key, value) = item
527 key = key.lower().replace(" ", "_")
528 cls = FIELDS.get(key, object)
529 if not isinstance(value, cls):
530 if issubclass(cls, _enum.Enum):
531 value = {item.name:item for item in cls}[value]
532 else:
533 value = cls(value)
534 return (key, value)
535
536 def item_filter(item):
537 (key, _) = item
538 return (key in FIELDS)
539
540 for record in ISA.get_svp64_csv(path):
541 opcode = opcode_cls(record.pop("opcode"))
542 names = record.pop("comment").split("=")[-1].split("/")
543 names = set(filter(name_filter, names))
544 if names:
545 rc = _RC[record["rc"] if record["rc"] else "NONE"]
546 if rc is _RC.RC:
547 names.update({f"{name}." for name in names})
548 record = dict(filter(item_filter, map(item_mapper, record.items())))
549 for name in map(Name, names):
550 yield Entry(name=name, record=Record(**record))
551
552
553 def main(codegen):
554 entries = []
555 table = {
556 "minor_19.csv": IntegerOpcode,
557 "minor_30.csv": IntegerOpcode,
558 "minor_31.csv": IntegerOpcode,
559 "minor_58.csv": IntegerOpcode,
560 "minor_62.csv": IntegerOpcode,
561 "minor_22.csv": IntegerOpcode,
562 "minor_5.csv": PatternOpcode,
563 "minor_63.csv": PatternOpcode,
564 "minor_59.csv": PatternOpcode,
565 "major.csv": IntegerOpcode,
566 "extra.csv": PatternOpcode,
567 }
568 for (path, opcode_cls) in table.items():
569 entries.extend(parse(path, opcode_cls))
570 entries = sorted(frozenset(entries))
571
572 for line in codegen.generate(entries):
573 print(line)
574
575
576 if __name__ == "__main__":
577 parser = _argparse.ArgumentParser()
578 parser.add_argument("codegen", type=Codegen, choices=Codegen, help="code generator")
579
580 args = vars(parser.parse_args())
581 main(**args)