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