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