sv_binutils: sort entries by name
[openpower-isa.git] / src / openpower / sv / sv_binutils.py
1 import abc as _abc
2 import argparse as _argparse
3 import codecs as _codecs
4 import csv as _csv
5 import dataclasses as _dataclasses
6 import enum as _enum
7 import pathlib as _pathlib
8 import re as _re
9 import sys as _sys
10
11 from openpower.decoder.power_enums import (
12 In1Sel as _In1Sel,
13 In2Sel as _In2Sel,
14 In3Sel as _In3Sel,
15 OutSel as _OutSel,
16 CRInSel as _CRInSel,
17 CROutSel as _CROutSel,
18 SVPtype as _SVPtype,
19 SVEtype as _SVEtype,
20 SVEXTRA as _SVEXTRA,
21 )
22 from openpower.decoder.power_svp64 import SVP64RM as _SVP64RM
23
24
25 DISCLAIMER = (
26 "/*",
27 " * this file is auto-generated, do not edit",
28 " * http://libre-soc.org/openpower/sv_binutiks.py",
29 " * part of Libre-SOC, sponsored by NLnet",
30 " */",
31 )
32
33
34 def indent(strings):
35 return map(lambda string: (" " + string), strings)
36
37
38 class Field:
39 @classmethod
40 @_abc.abstractmethod
41 def c_decl(self, name):
42 pass
43
44 @_abc.abstractmethod
45 def c_value(self, prefix="", suffix=""):
46 pass
47
48 @classmethod
49 @_abc.abstractmethod
50 def c_var(self, name):
51 pass
52
53
54 class Enum(Field, _enum.Enum):
55 @classmethod
56 def c_decl(cls):
57 c_tag = f"svp64_{cls.__name__.lower()}"
58 yield f"enum {c_tag} {{"
59 for item in cls:
60 yield from indent(item.c_value(suffix=","))
61 yield f"}};"
62
63 def c_value(self, prefix="", suffix=""):
64 c_tag = f"svp64_{self.__class__.__name__.lower()}"
65 yield f"{prefix}{c_tag.upper()}_{self.name.upper()}{suffix}"
66
67 @classmethod
68 def c_var(cls, name):
69 c_tag = f"svp64_{cls.__name__.lower()}"
70 yield f"enum {c_tag} {name};"
71
72
73 # Python forbids inheriting from enum unless it's empty.
74 In1Sel = Enum("In1Sel", {item.name:item.value for item in _In1Sel})
75 In2Sel = Enum("In2Sel", {item.name:item.value for item in _In2Sel})
76 In3Sel = Enum("In3Sel", {item.name:item.value for item in _In3Sel})
77 OutSel = Enum("OutSel", {item.name:item.value for item in _OutSel})
78 CRInSel = Enum("CRInSel", {item.name:item.value for item in _CRInSel})
79 CROutSel = Enum("CROutSel", {item.name:item.value for item in _CROutSel})
80 SVPType = Enum("SVPType", {item.name:item.value for item in _SVPtype})
81 SVEType = Enum("SVEType", {item.name:item.value for item in _SVEtype})
82 SVEXTRA = Enum("SVEXTRA", {item.name:item.value for item in _SVEXTRA})
83
84
85 class Opcode(Field):
86 def __init__(self, value, mask, bits):
87 self.__value = value
88 self.__mask = mask
89 self.__bits = bits
90
91 return super().__init__()
92
93 @property
94 def value(self):
95 return self.__value
96
97 @property
98 def mask(self):
99 return self.__mask
100
101 @property
102 def bits(self):
103 return self.__bits
104
105 def __repr__(self):
106 fmt = f"{{value:0{self.bits}b}}:{{mask:0{self.bits}b}}"
107 return fmt.format(value=self.value, mask=self.mask)
108
109 @classmethod
110 def c_decl(cls):
111 yield f"struct svp64_opcode {{"
112 yield from indent([
113 "uint32_t value;",
114 "uint32_t mask;",
115 ])
116 yield f"}};"
117
118 def c_value(self, prefix="", suffix=""):
119 yield f"{prefix}{{"
120 yield from indent([
121 f".value = UINT32_C(0x{self.value:08X}),",
122 f".mask = UINT32_C(0x{self.mask:08X}),",
123 ])
124 yield f"}}{suffix}"
125
126 @classmethod
127 def c_var(cls, name):
128 yield f"struct svp64_opcode {name};"
129
130
131 class IntegerOpcode(Opcode):
132 def __init__(self, integer):
133 value = int(integer, 0)
134 bits = max(1, value.bit_length())
135 mask = int(("1" * bits), 2)
136
137 return super().__init__(value=value, mask=mask, bits=bits)
138
139
140 class PatternOpcode(Opcode):
141 def __init__(self, pattern):
142 value = 0
143 mask = 0
144 bits = len(pattern)
145 for bit in pattern:
146 value |= (bit == "1")
147 mask |= (bit != "-")
148 value <<= 1
149 mask <<= 1
150 value >>= 1
151 mask >>= 1
152
153 return super().__init__(value=value, mask=mask, bits=bits)
154
155
156 class Name(Field, str):
157 def __repr__(self):
158 escaped = self.replace("\"", "\\\"")
159 return f"\"{escaped}\""
160
161 def c_value(self, prefix="", suffix=""):
162 yield f"{prefix}{self!r}{suffix}"
163
164 @classmethod
165 def c_var(cls, name):
166 yield f"const char *{name};"
167
168
169 @_dataclasses.dataclass(eq=True, frozen=True)
170 class Entry:
171 name: Name
172 opcode: Opcode
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 def __lt__(self, other):
191 if not isinstance(other, self.__class__):
192 return NotImplemented
193 return self.name < other.name
194
195 @classmethod
196 def c_decl(cls):
197 bits_all = 0
198 yield f"struct svp64_entry {{"
199 for field in _dataclasses.fields(cls):
200 if issubclass(field.type, Enum):
201 bits = len(field.type).bit_length()
202 yield from indent([f"uint64_t {field.name} : {bits};"])
203 bits_all += bits
204 else:
205 yield from indent(field.type.c_var(name=field.name))
206 bits_rsvd = (64 - (bits_all % 64))
207 if bits_rsvd:
208 yield from indent([f"uint64_t : {bits_rsvd};"])
209 yield f"}};"
210
211 def c_value(self, prefix="", suffix=""):
212 yield f"{prefix}{{"
213 for field in _dataclasses.fields(self):
214 name = field.name
215 attr = getattr(self, name)
216 yield from indent(attr.c_value(prefix=f".{name} = ", suffix=","))
217 yield f"}}{suffix}"
218
219 @classmethod
220 def c_var(cls, name):
221 yield f"struct svp64_entry {name};"
222
223
224 class Codegen(_enum.Enum):
225 PPC_OPC_SVP64_H = _enum.auto()
226 PPC_OPC_SVP64_C = _enum.auto()
227
228 @classmethod
229 def _missing_(cls, value):
230 return {
231 "ppc-opc-svp64.h": Codegen.PPC_OPC_SVP64_H,
232 "ppc-opc-svp64.c": Codegen.PPC_OPC_SVP64_C,
233 }[value]
234
235 def __str__(self):
236 return {
237 Codegen.PPC_OPC_SVP64_H: "ppc-opc-svp64.h",
238 Codegen.PPC_OPC_SVP64_C: "ppc-opc-svp64.c",
239 }[self]
240
241 def generate(self, entries):
242 def ppc_opc_svp64_h(entries):
243 yield from DISCLAIMER
244 yield ""
245
246 yield f"#ifndef {self.name}"
247 yield f"#define {self.name}"
248 yield ""
249
250 yield from Opcode.c_decl()
251 yield ""
252
253 enums = (
254 In1Sel, In2Sel, In3Sel, OutSel,
255 CRInSel, CROutSel,
256 SVPType, SVEType, SVEXTRA,
257 )
258 for enum in enums:
259 yield from enum.c_decl()
260 yield ""
261
262 yield from Entry.c_decl()
263 yield ""
264
265 yield f"#endif /* {self.name} */"
266 yield ""
267
268 def ppc_opc_svp64_c(entries):
269 yield from ()
270
271 return {
272 Codegen.PPC_OPC_SVP64_H: ppc_opc_svp64_h,
273 Codegen.PPC_OPC_SVP64_C: ppc_opc_svp64_c,
274 }[self](entries)
275
276
277 def regex_enum(enum):
278 assert issubclass(enum, _enum.Enum)
279 return "|".join(item.name for item in enum)
280
281
282 PATTERN_VHDL_BINARY = r"(?:2#[01]+#)"
283 PATTERN_DECIMAL = r"(?:[0-9]+)"
284 PATTERN_PARTIAL_BINARY = r"(?:[01-]+)"
285
286 # Examples of the entries to be caught by the pattern below:
287 # 2 => (P2, EXTRA3, RA_OR_ZERO, NONE, NONE, RT, NONE, NONE, NONE, Idx1, NONE, NONE, Idx0, NONE, NONE, NONE), -- lwz
288 # -----10110 => (P2, EXTRA3, NONE, FRB, NONE, FRT, NONE, NONE, CR1, NONE, Idx1, NONE, Idx0, NONE, NONE, Idx0), -- fsqrts
289 # 2#0000000000# => (P2, EXTRA3, NONE, NONE, NONE, NONE, NONE, BFA, BF, NONE, NONE, NONE, NONE, NONE, Idx1, Idx0), -- mcrf
290 PATTERN = "".join((
291 r"^\s*",
292 rf"(?P<opcode>{PATTERN_VHDL_BINARY}|{PATTERN_DECIMAL}|{PATTERN_PARTIAL_BINARY})",
293 r"\s?=>\s?",
294 r"\(",
295 r",\s".join((
296 rf"(?P<ptype>{regex_enum(_SVPtype)})",
297 rf"(?P<etype>{regex_enum(_SVEtype)})",
298 rf"(?P<in1>{regex_enum(_In1Sel)})",
299 rf"(?P<in2>{regex_enum(_In2Sel)})",
300 rf"(?P<in3>{regex_enum(_In3Sel)})",
301 rf"(?P<out>{regex_enum(_OutSel)})",
302 rf"(?P<out2>{regex_enum(_OutSel)})",
303 rf"(?P<cr_in>{regex_enum(_CRInSel)})",
304 rf"(?P<cr_out>{regex_enum(_CROutSel)})",
305 rf"(?P<sv_in1>{regex_enum(_SVEXTRA)})",
306 rf"(?P<sv_in2>{regex_enum(_SVEXTRA)})",
307 rf"(?P<sv_in3>{regex_enum(_SVEXTRA)})",
308 rf"(?P<sv_out>{regex_enum(_SVEXTRA)})",
309 rf"(?P<sv_out2>{regex_enum(_SVEXTRA)})",
310 rf"(?P<sv_cr_in>{regex_enum(_SVEXTRA)})",
311 rf"(?P<sv_cr_out>{regex_enum(_SVEXTRA)})",
312 )),
313 r"\)",
314 r",",
315 r"\s?--\s?",
316 r"(?P<name>[A-Za-z0-9_\./]+)",
317 r"\s*$",
318 ))
319 REGEX = _re.compile(PATTERN)
320
321
322 ISA = _SVP64RM()
323 FIELDS = {field.name:field for field in _dataclasses.fields(Entry)}
324 def parse(path, opcode_cls):
325 for entry in ISA.get_svp64_csv(path):
326 # skip instructions that are not suitable
327 name = entry["name"] = entry.pop("comment").split("=")[-1]
328 if name.startswith("l") and name.endswith("br"):
329 continue
330 if name in {"mcrxr", "mcrxrx", "darn"}:
331 continue
332 if name in {"bctar", "bcctr"}:
333 continue
334 if "rfid" in name:
335 continue
336 if name in {"setvl"}:
337 continue
338
339 entry = {key.lower().replace(" ", "_"):value for (key, value) in entry.items()}
340 for (key, value) in tuple(entry.items()):
341 key = key.lower().replace(" ", "_")
342 if key not in FIELDS:
343 entry.pop(key)
344 else:
345 field = FIELDS[key]
346 if issubclass(field.type, _enum.Enum):
347 value = {item.name:item for item in field.type}[value]
348 elif issubclass(field.type, Opcode):
349 value = opcode_cls(value)
350 else:
351 value = field.type(value)
352 entry[key] = value
353
354 yield Entry(**entry)
355
356
357 def main(codegen):
358 entries = []
359 table = {
360 "minor_19.csv": IntegerOpcode,
361 "minor_30.csv": IntegerOpcode,
362 "minor_31.csv": IntegerOpcode,
363 "minor_58.csv": IntegerOpcode,
364 "minor_62.csv": IntegerOpcode,
365 "minor_22.csv": IntegerOpcode,
366 "minor_5.csv": PatternOpcode,
367 "minor_63.csv": PatternOpcode,
368 "minor_59.csv": PatternOpcode,
369 "major.csv": IntegerOpcode,
370 "extra.csv": PatternOpcode,
371 }
372 for (path, opcode_cls) in table.items():
373 entries.extend(parse(path, opcode_cls))
374 entries = sorted(entries)
375
376 for line in codegen.generate(entries):
377 print(line)
378
379
380 if __name__ == "__main__":
381 parser = _argparse.ArgumentParser()
382 parser.add_argument("codegen", type=Codegen, choices=Codegen, help="code generator")
383
384 args = vars(parser.parse_args())
385 main(**args)