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