sv_binutils: add missing include directives
[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 " * http://libre-soc.org/openpower/sv_binutiks.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 @classmethod
106 def c_decl(cls):
107 yield f"struct svp64_opcode {{"
108 yield from indent([
109 "uint32_t value;",
110 "uint32_t mask;",
111 ])
112 yield f"}};"
113
114 def c_value(self, prefix="", suffix=""):
115 yield f"{prefix}{{"
116 yield from indent([
117 f".value = UINT32_C(0x{self.value:08X}),",
118 f".mask = UINT32_C(0x{self.mask:08X}),",
119 ])
120 yield f"}}{suffix}"
121
122 @classmethod
123 def c_var(cls, name):
124 yield f"struct svp64_opcode {name}"
125
126
127 class IntegerOpcode(Opcode):
128 def __init__(self, integer):
129 value = int(integer, 0)
130 bits = max(1, value.bit_length())
131 mask = int(("1" * bits), 2)
132
133 return super().__init__(value=value, mask=mask, bits=bits)
134
135
136 class PatternOpcode(Opcode):
137 def __init__(self, pattern):
138 value = 0
139 mask = 0
140 bits = len(pattern)
141 for bit in pattern:
142 value |= (bit == "1")
143 mask |= (bit != "-")
144 value <<= 1
145 mask <<= 1
146 value >>= 1
147 mask >>= 1
148
149 return super().__init__(value=value, mask=mask, bits=bits)
150
151
152 class Name(CType, str):
153 def __repr__(self):
154 escaped = self.replace("\"", "\\\"")
155 return f"\"{escaped}\""
156
157 def c_value(self, prefix="", suffix=""):
158 yield f"{prefix}{self!r}{suffix}"
159
160 @classmethod
161 def c_var(cls, name):
162 yield f"const char *{name}"
163
164
165 @_dataclasses.dataclass(eq=True, frozen=True)
166 class Entry(CType):
167 name: Name
168 opcode: Opcode
169 in1: In1Sel
170 in2: In2Sel
171 in3: In3Sel
172 out: OutSel
173 out2: OutSel
174 cr_in: CRInSel
175 cr_out: CROutSel
176 sv_ptype: SVPType
177 sv_etype: SVEType
178 sv_in1: SVEXTRA
179 sv_in2: SVEXTRA
180 sv_in3: SVEXTRA
181 sv_out: SVEXTRA
182 sv_out2: SVEXTRA
183 sv_cr_in: SVEXTRA
184 sv_cr_out: SVEXTRA
185
186 def __lt__(self, other):
187 if not isinstance(other, self.__class__):
188 return NotImplemented
189 return self.name < other.name
190
191 @classmethod
192 def c_decl(cls):
193 bits_all = 0
194 yield f"struct svp64_entry {{"
195 for field in _dataclasses.fields(cls):
196 if issubclass(field.type, Enum):
197 bits = len(field.type).bit_length()
198 yield from indent([f"uint64_t {field.name} : {bits};"])
199 bits_all += bits
200 else:
201 yield from indent(field.type.c_var(name=f"{field.name};"))
202 bits_rsvd = (64 - (bits_all % 64))
203 if bits_rsvd:
204 yield from indent([f"uint64_t : {bits_rsvd};"])
205 yield f"}};"
206
207 def c_value(self, prefix="", suffix=""):
208 yield f"{prefix}{{"
209 for field in _dataclasses.fields(self):
210 name = field.name
211 attr = getattr(self, name)
212 yield from indent(attr.c_value(prefix=f".{name} = ", suffix=","))
213 yield f"}}{suffix}"
214
215 @classmethod
216 def c_var(cls, name):
217 yield f"struct svp64_entry {name}"
218
219
220 class Codegen(_enum.Enum):
221 PPC_OPC_SVP64_H = _enum.auto()
222 PPC_OPC_SVP64_C = _enum.auto()
223
224 @classmethod
225 def _missing_(cls, value):
226 return {
227 "ppc-opc-svp64.h": Codegen.PPC_OPC_SVP64_H,
228 "ppc-opc-svp64.c": Codegen.PPC_OPC_SVP64_C,
229 }[value]
230
231 def __str__(self):
232 return {
233 Codegen.PPC_OPC_SVP64_H: "ppc-opc-svp64.h",
234 Codegen.PPC_OPC_SVP64_C: "ppc-opc-svp64.c",
235 }[self]
236
237 def generate(self, entries):
238 def ppc_opc_svp64_h(entries):
239 yield from DISCLAIMER
240 yield ""
241
242 yield f"#ifndef {self.name}"
243 yield f"#define {self.name}"
244 yield ""
245
246 yield "#include <stdint.h>"
247 yield ""
248
249 yield from Opcode.c_decl()
250 yield ""
251
252 enums = (
253 In1Sel, In2Sel, In3Sel, OutSel,
254 CRInSel, CROutSel,
255 SVPType, SVEType, SVEXTRA,
256 )
257 for enum in enums:
258 yield from enum.c_decl()
259 yield ""
260
261 yield from Entry.c_decl()
262 yield ""
263
264 yield "extern const struct svp64_entry svp64_entries[];"
265 yield "extern const unsigned int svp64_num_entries;"
266 yield ""
267
268 yield f"#endif /* {self.name} */"
269 yield ""
270
271 def ppc_opc_svp64_c(entries):
272 yield from DISCLAIMER
273 yield ""
274
275 yield "#include \"ppc-opc-svp64.h\""
276 yield ""
277
278 yield "const struct svp64_entry svp64_entries[] = {{"
279 for (index, entry) in enumerate(entries):
280 yield from indent(entry.c_value(prefix=f"[{index}] = ", suffix=","))
281 yield f"}};"
282 yield f"const unsigned int svp64_num_entries = {len(entries)};"
283 yield ""
284
285 return {
286 Codegen.PPC_OPC_SVP64_H: ppc_opc_svp64_h,
287 Codegen.PPC_OPC_SVP64_C: ppc_opc_svp64_c,
288 }[self](entries)
289
290
291 def regex_enum(enum):
292 assert issubclass(enum, _enum.Enum)
293 return "|".join(item.name for item in enum)
294
295
296 PATTERN_VHDL_BINARY = r"(?:2#[01]+#)"
297 PATTERN_DECIMAL = r"(?:[0-9]+)"
298 PATTERN_PARTIAL_BINARY = r"(?:[01-]+)"
299
300 # Examples of the entries to be caught by the pattern below:
301 # 2 => (P2, EXTRA3, RA_OR_ZERO, NONE, NONE, RT, NONE, NONE, NONE, Idx1, NONE, NONE, Idx0, NONE, NONE, NONE), -- lwz
302 # -----10110 => (P2, EXTRA3, NONE, FRB, NONE, FRT, NONE, NONE, CR1, NONE, Idx1, NONE, Idx0, NONE, NONE, Idx0), -- fsqrts
303 # 2#0000000000# => (P2, EXTRA3, NONE, NONE, NONE, NONE, NONE, BFA, BF, NONE, NONE, NONE, NONE, NONE, Idx1, Idx0), -- mcrf
304 PATTERN = "".join((
305 r"^\s*",
306 rf"(?P<opcode>{PATTERN_VHDL_BINARY}|{PATTERN_DECIMAL}|{PATTERN_PARTIAL_BINARY})",
307 r"\s?=>\s?",
308 r"\(",
309 r",\s".join((
310 rf"(?P<ptype>{regex_enum(_SVPtype)})",
311 rf"(?P<etype>{regex_enum(_SVEtype)})",
312 rf"(?P<in1>{regex_enum(_In1Sel)})",
313 rf"(?P<in2>{regex_enum(_In2Sel)})",
314 rf"(?P<in3>{regex_enum(_In3Sel)})",
315 rf"(?P<out>{regex_enum(_OutSel)})",
316 rf"(?P<out2>{regex_enum(_OutSel)})",
317 rf"(?P<cr_in>{regex_enum(_CRInSel)})",
318 rf"(?P<cr_out>{regex_enum(_CROutSel)})",
319 rf"(?P<sv_in1>{regex_enum(_SVEXTRA)})",
320 rf"(?P<sv_in2>{regex_enum(_SVEXTRA)})",
321 rf"(?P<sv_in3>{regex_enum(_SVEXTRA)})",
322 rf"(?P<sv_out>{regex_enum(_SVEXTRA)})",
323 rf"(?P<sv_out2>{regex_enum(_SVEXTRA)})",
324 rf"(?P<sv_cr_in>{regex_enum(_SVEXTRA)})",
325 rf"(?P<sv_cr_out>{regex_enum(_SVEXTRA)})",
326 )),
327 r"\)",
328 r",",
329 r"\s?--\s?",
330 r"(?P<name>[A-Za-z0-9_\./]+)",
331 r"\s*$",
332 ))
333 REGEX = _re.compile(PATTERN)
334
335
336 ISA = _SVP64RM()
337 FIELDS = {field.name:field for field in _dataclasses.fields(Entry)}
338 def parse(path, opcode_cls):
339 for entry in ISA.get_svp64_csv(path):
340 # skip instructions that are not suitable
341 name = entry["name"] = entry.pop("comment").split("=")[-1]
342 if name.startswith("l") and name.endswith("br"):
343 continue
344 if name in {"mcrxr", "mcrxrx", "darn"}:
345 continue
346 if name in {"bctar", "bcctr"}:
347 continue
348 if "rfid" in name:
349 continue
350 if name in {"setvl"}:
351 continue
352
353 entry = {key.lower().replace(" ", "_"):value for (key, value) in entry.items()}
354 for (key, value) in tuple(entry.items()):
355 key = key.lower().replace(" ", "_")
356 if key not in FIELDS:
357 entry.pop(key)
358 else:
359 field = FIELDS[key]
360 if issubclass(field.type, _enum.Enum):
361 value = {item.name:item for item in field.type}[value]
362 elif issubclass(field.type, Opcode):
363 value = opcode_cls(value)
364 else:
365 value = field.type(value)
366 entry[key] = value
367
368 yield Entry(**entry)
369
370
371 def main(codegen):
372 entries = []
373 table = {
374 "minor_19.csv": IntegerOpcode,
375 "minor_30.csv": IntegerOpcode,
376 "minor_31.csv": IntegerOpcode,
377 "minor_58.csv": IntegerOpcode,
378 "minor_62.csv": IntegerOpcode,
379 "minor_22.csv": IntegerOpcode,
380 "minor_5.csv": PatternOpcode,
381 "minor_63.csv": PatternOpcode,
382 "minor_59.csv": PatternOpcode,
383 "major.csv": IntegerOpcode,
384 "extra.csv": PatternOpcode,
385 }
386 for (path, opcode_cls) in table.items():
387 entries.extend(parse(path, opcode_cls))
388 entries = sorted(frozenset(entries))
389
390 for line in codegen.generate(entries):
391 print(line)
392
393
394 if __name__ == "__main__":
395 parser = _argparse.ArgumentParser()
396 parser.add_argument("codegen", type=Codegen, choices=Codegen, help="code generator")
397
398 args = vars(parser.parse_args())
399 main(**args)