Revert "sv_binutils: introduce per-record validity flag"
[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 import re as _re
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 )
18 from openpower.decoder.power_svp64 import SVP64RM as _SVP64RM
19
20
21 DISCLAIMER = (
22 "/*",
23 " * this file is auto-generated, do not edit",
24 " * https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/sv/sv_binutils.py",
25 " * part of Libre-SOC, sponsored by NLnet",
26 " */",
27 )
28
29
30 def indent(strings):
31 return map(lambda string: (" " + string), strings)
32
33
34 class CType:
35 @classmethod
36 @_abc.abstractmethod
37 def c_decl(self, name):
38 pass
39
40 @_abc.abstractmethod
41 def c_value(self, prefix="", suffix=""):
42 pass
43
44 @classmethod
45 @_abc.abstractmethod
46 def c_var(self, name):
47 pass
48
49
50 class Enum(CType, _enum.Enum):
51 @classmethod
52 def c_decl(cls):
53 c_tag = f"svp64_{cls.__name__.lower()}"
54 yield f"enum {c_tag} {{"
55 for item in cls:
56 yield from indent(item.c_value(suffix=","))
57 yield f"}};"
58
59 def c_value(self, prefix="", suffix=""):
60 c_tag = f"svp64_{self.__class__.__name__.lower()}"
61 yield f"{prefix}{c_tag.upper()}_{self.name.upper()}{suffix}"
62
63 @classmethod
64 def c_var(cls, name):
65 c_tag = f"svp64_{cls.__name__.lower()}"
66 yield f"enum {c_tag} {name}"
67
68
69 # Python forbids inheriting from enum unless it's empty.
70 In1Sel = Enum("In1Sel", {item.name:item.value for item in _In1Sel})
71 In2Sel = Enum("In2Sel", {item.name:item.value for item in _In2Sel})
72 In3Sel = Enum("In3Sel", {item.name:item.value for item in _In3Sel})
73 OutSel = Enum("OutSel", {item.name:item.value for item in _OutSel})
74 CRInSel = Enum("CRInSel", {item.name:item.value for item in _CRInSel})
75 CROutSel = Enum("CROutSel", {item.name:item.value for item in _CROutSel})
76 SVPType = Enum("SVPType", {item.name:item.value for item in _SVPtype})
77 SVEType = Enum("SVEType", {item.name:item.value for item in _SVEtype})
78 SVEXTRA = Enum("SVEXTRA", {item.name:item.value for item in _SVEXTRA})
79
80
81 class Opcode(CType):
82 def __init__(self, value, mask, bits):
83 self.__value = value
84 self.__mask = mask
85 self.__bits = bits
86
87 return super().__init__()
88
89 @property
90 def value(self):
91 return self.__value
92
93 @property
94 def mask(self):
95 return self.__mask
96
97 @property
98 def bits(self):
99 return self.__bits
100
101 def __repr__(self):
102 fmt = f"{{value:0{self.bits}b}}:{{mask:0{self.bits}b}}"
103 return fmt.format(value=self.value, mask=self.mask)
104
105 def __lt__(self, other):
106 if not isinstance(other, self.__class__):
107 return NotImplemented
108
109 return self.__value < other.__value
110
111 @classmethod
112 def c_decl(cls):
113 yield f"struct svp64_opcode {{"
114 yield from indent([
115 "uint32_t value;",
116 "uint32_t mask;",
117 ])
118 yield f"}};"
119
120 def c_value(self, prefix="", suffix=""):
121 yield f"{prefix}{{"
122 yield from indent([
123 f".value = UINT32_C(0x{self.value:08X}),",
124 f".mask = UINT32_C(0x{self.mask:08X}),",
125 ])
126 yield f"}}{suffix}"
127
128 @classmethod
129 def c_var(cls, name):
130 yield f"struct svp64_opcode {name}"
131
132
133 class IntegerOpcode(Opcode):
134 def __init__(self, integer):
135 value = int(integer, 0)
136 bits = max(1, value.bit_length())
137 mask = int(("1" * bits), 2)
138
139 return super().__init__(value=value, mask=mask, bits=bits)
140
141
142 class PatternOpcode(Opcode):
143 def __init__(self, pattern):
144 value = 0
145 mask = 0
146 bits = len(pattern)
147 for bit in pattern:
148 value |= (bit == "1")
149 mask |= (bit != "-")
150 value <<= 1
151 mask <<= 1
152 value >>= 1
153 mask >>= 1
154
155 return super().__init__(value=value, mask=mask, bits=bits)
156
157
158 class Name(CType, str):
159 def __repr__(self):
160 escaped = self.replace("\"", "\\\"")
161 return f"\"{escaped}\""
162
163 def c_value(self, prefix="", suffix=""):
164 yield f"{prefix}{self!r}{suffix}"
165
166 @classmethod
167 def c_var(cls, name):
168 yield f"const char *{name}"
169
170
171 @_dataclasses.dataclass(eq=True, frozen=True)
172 class Record(CType):
173 in1: In1Sel
174 in2: In2Sel
175 in3: In3Sel
176 out: OutSel
177 out2: OutSel
178 cr_in: CRInSel
179 cr_out: CROutSel
180 sv_ptype: SVPType
181 sv_etype: SVEType
182 sv_in1: SVEXTRA
183 sv_in2: SVEXTRA
184 sv_in3: SVEXTRA
185 sv_out: SVEXTRA
186 sv_out2: SVEXTRA
187 sv_cr_in: SVEXTRA
188 sv_cr_out: SVEXTRA
189
190 @classmethod
191 def c_decl(cls):
192 bits_all = 0
193 yield f"struct svp64_record {{"
194 for field in _dataclasses.fields(cls):
195 bits = len(field.type).bit_length()
196 yield from indent([f"uint64_t {field.name} : {bits};"])
197 bits_all += bits
198 bits_rsvd = (64 - (bits_all % 64))
199 if bits_rsvd:
200 yield from indent([f"uint64_t : {bits_rsvd};"])
201 yield f"}};"
202
203 def c_value(self, prefix="", suffix=""):
204 yield f"{prefix}{{"
205 for field in _dataclasses.fields(self):
206 name = field.name
207 attr = getattr(self, name)
208 yield from indent(attr.c_value(prefix=f".{name} = ", suffix=","))
209 yield f"}}{suffix}"
210
211 @classmethod
212 def c_var(cls, name):
213 yield f"struct svp64_record {name}"
214
215
216 @_dataclasses.dataclass(eq=True, frozen=True)
217 class Entry(CType):
218 name: Name
219 record: Record
220
221 def __lt__(self, other):
222 if not isinstance(other, self.__class__):
223 return NotImplemented
224
225 return self.name < other.name
226
227 @classmethod
228 def c_decl(cls):
229 yield f"struct svp64_entry {{"
230 for field in _dataclasses.fields(cls):
231 yield from indent(field.type.c_var(name=f"{field.name};"))
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_entry {name}"
245
246
247 class Codegen(_enum.Enum):
248 PPC_SVP64_H = _enum.auto()
249 PPC_SVP64_OPC_C = _enum.auto()
250
251 @classmethod
252 def _missing_(cls, value):
253 return {
254 "ppc-svp64.h": Codegen.PPC_SVP64_H,
255 "ppc-svp64-opc.c": Codegen.PPC_SVP64_OPC_C,
256 }.get(value)
257
258 def __str__(self):
259 return {
260 Codegen.PPC_SVP64_H: "ppc-svp64.h",
261 Codegen.PPC_SVP64_OPC_C: "ppc-svp64-opc.c",
262 }[self]
263
264 def generate(self, entries):
265 def ppc_svp64_h(entries):
266 yield from DISCLAIMER
267 yield ""
268
269 yield f"#ifndef {self.name}"
270 yield f"#define {self.name}"
271 yield ""
272
273 yield "#include <stdint.h>"
274 yield ""
275
276 yield "#ifdef __cplusplus"
277 yield "extern \"C\" {"
278 yield "#endif"
279 yield ""
280
281 enums = (
282 In1Sel, In2Sel, In3Sel, OutSel,
283 CRInSel, CROutSel,
284 SVPType, SVEType, SVEXTRA,
285 )
286 for enum in enums:
287 yield from enum.c_decl()
288 yield ""
289
290 yield from Record.c_decl()
291 yield ""
292
293 yield from Entry.c_decl()
294 yield ""
295
296 yield "extern const struct svp64_entry svp64_entries[];"
297 yield "extern const unsigned int svp64_num_entries;"
298 yield ""
299
300 yield f"#define SVP64_NAME_MAX {max(map(lambda entry: len(entry.name), entries))}"
301 yield ""
302
303 yield "#ifdef __cplusplus"
304 yield "}"
305 yield "#endif"
306 yield ""
307
308 yield f"#endif /* {self.name} */"
309 yield ""
310
311 def ppc_svp64_opc_c(entries):
312 yield from DISCLAIMER
313 yield ""
314
315 yield "#include \"opcode/ppc-svp64.h\""
316 yield ""
317
318 yield "const struct svp64_entry svp64_entries[] = {"
319 for (index, entry) in enumerate(entries):
320 yield from indent(entry.c_value(prefix=f"[{index}] = ", suffix=","))
321 yield f"}};"
322 yield ""
323
324 yield "const unsigned int svp64_num_entries = \\"
325 yield " sizeof (svp64_entries) / sizeof (svp64_entries[0]);"
326 yield ""
327
328 return {
329 Codegen.PPC_SVP64_H: ppc_svp64_h,
330 Codegen.PPC_SVP64_OPC_C: ppc_svp64_opc_c,
331 }[self](entries)
332
333
334 def regex_enum(enum):
335 assert issubclass(enum, _enum.Enum)
336 return "|".join(item.name for item in enum)
337
338
339 PATTERN_VHDL_BINARY = r"(?:2#[01]+#)"
340 PATTERN_DECIMAL = r"(?:[0-9]+)"
341 PATTERN_PARTIAL_BINARY = r"(?:[01-]+)"
342
343 # Examples of the entries to be caught by the pattern below:
344 # 2 => (P2, EXTRA3, RA_OR_ZERO, NONE, NONE, RT, NONE, NONE, NONE, Idx1, NONE, NONE, Idx0, NONE, NONE, NONE), -- lwz
345 # -----10110 => (P2, EXTRA3, NONE, FRB, NONE, FRT, NONE, NONE, CR1, NONE, Idx1, NONE, Idx0, NONE, NONE, Idx0), -- fsqrts
346 # 2#0000000000# => (P2, EXTRA3, NONE, NONE, NONE, NONE, NONE, BFA, BF, NONE, NONE, NONE, NONE, NONE, Idx1, Idx0), -- mcrf
347 PATTERN = "".join((
348 r"^\s*",
349 rf"(?P<opcode>{PATTERN_VHDL_BINARY}|{PATTERN_DECIMAL}|{PATTERN_PARTIAL_BINARY})",
350 r"\s?=>\s?",
351 r"\(",
352 r",\s".join((
353 rf"(?P<ptype>{regex_enum(_SVPtype)})",
354 rf"(?P<etype>{regex_enum(_SVEtype)})",
355 rf"(?P<in1>{regex_enum(_In1Sel)})",
356 rf"(?P<in2>{regex_enum(_In2Sel)})",
357 rf"(?P<in3>{regex_enum(_In3Sel)})",
358 rf"(?P<out>{regex_enum(_OutSel)})",
359 rf"(?P<out2>{regex_enum(_OutSel)})",
360 rf"(?P<cr_in>{regex_enum(_CRInSel)})",
361 rf"(?P<cr_out>{regex_enum(_CROutSel)})",
362 rf"(?P<sv_in1>{regex_enum(_SVEXTRA)})",
363 rf"(?P<sv_in2>{regex_enum(_SVEXTRA)})",
364 rf"(?P<sv_in3>{regex_enum(_SVEXTRA)})",
365 rf"(?P<sv_out>{regex_enum(_SVEXTRA)})",
366 rf"(?P<sv_out2>{regex_enum(_SVEXTRA)})",
367 rf"(?P<sv_cr_in>{regex_enum(_SVEXTRA)})",
368 rf"(?P<sv_cr_out>{regex_enum(_SVEXTRA)})",
369 )),
370 r"\)",
371 r",",
372 r"\s?--\s?",
373 r"(?P<name>[A-Za-z0-9_\./]+)",
374 r"\s*$",
375 ))
376 REGEX = _re.compile(PATTERN)
377
378
379 ISA = _SVP64RM()
380 FIELDS = {field.name:field for field in _dataclasses.fields(Record)}
381 FIELDS.update({field.name:field for field in _dataclasses.fields(Entry)})
382 def parse(path, opcode_cls):
383 visited = set()
384 for record in ISA.get_svp64_csv(path):
385 opcode = opcode_cls(record.pop("opcode"))
386 names = record.pop("comment").split("=")[-1]
387 for name in map(Name, names.split("/")):
388 if name.startswith("l") and name.endswith("br"):
389 continue
390 if name in {"mcrxr", "mcrxrx", "darn"}:
391 continue
392 if name in {"bctar", "bcctr"}:
393 continue
394 if "rfid" in name:
395 continue
396 if name in {"setvl"}:
397 continue
398
399 record = {key.lower().replace(" ", "_"):value for (key, value) in record.items()}
400 for (key, value) in tuple(record.items()):
401 key = key.lower().replace(" ", "_")
402 if key not in FIELDS:
403 record.pop(key)
404 continue
405
406 field = FIELDS[key]
407 if not isinstance(value, field.type):
408 if issubclass(field.type, _enum.Enum):
409 value = {item.name:item for item in field.type}[value]
410 else:
411 value = field.type(value)
412
413 record[key] = value
414
415 if name not in visited:
416 yield Entry(name=name, record=Record(**record))
417
418 visited.add(name)
419
420
421 def main(codegen):
422 entries = []
423 table = {
424 "minor_19.csv": IntegerOpcode,
425 "minor_30.csv": IntegerOpcode,
426 "minor_31.csv": IntegerOpcode,
427 "minor_58.csv": IntegerOpcode,
428 "minor_62.csv": IntegerOpcode,
429 "minor_22.csv": IntegerOpcode,
430 "minor_5.csv": PatternOpcode,
431 "minor_63.csv": PatternOpcode,
432 "minor_59.csv": PatternOpcode,
433 "major.csv": IntegerOpcode,
434 "extra.csv": PatternOpcode,
435 }
436 for (path, opcode_cls) in table.items():
437 entries.extend(parse(path, opcode_cls))
438 entries = sorted(frozenset(entries))
439
440 for line in codegen.generate(entries):
441 print(line)
442
443
444 if __name__ == "__main__":
445 parser = _argparse.ArgumentParser()
446 parser.add_argument("codegen", type=Codegen, choices=Codegen, help="code generator")
447
448 args = vars(parser.parse_args())
449 main(**args)