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