sv_binutils: support basic header generation
[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 dataclasses as _dataclasses
5 import enum as _enum
6 import pathlib as _pathlib
7 import re as _re
8 import sys as _sys
9
10 from openpower.decoder.power_enums import (
11 In1Sel as _In1Sel,
12 In2Sel as _In2Sel,
13 In3Sel as _In3Sel,
14 OutSel as _OutSel,
15 CRInSel as _CRInSel,
16 CROutSel as _CROutSel,
17 SVPtype as _SVPtype,
18 SVEtype as _SVEtype,
19 SVEXTRA as _SVEXTRA,
20 )
21
22
23 DISCLAIMER = (
24 "/*",
25 " * this file is auto-generated, do not edit",
26 " * http://libre-soc.org/openpower/sv_binutiks.py",
27 " * part of Libre-SOC, sponsored by NLnet",
28 " */",
29 )
30
31
32 def indent(strings):
33 return map(lambda string: (" " + string), strings)
34
35
36 class Field:
37 @classmethod
38 @_abc.abstractmethod
39 def c_decl(self, name):
40 pass
41
42 @_abc.abstractmethod
43 def c_value(self, prefix="", suffix=""):
44 pass
45
46 @classmethod
47 @_abc.abstractmethod
48 def c_var(self, name):
49 pass
50
51
52 class Enum(Field, _enum.Enum):
53 @classmethod
54 def c_decl(cls):
55 c_tag = f"svp64_{cls.__name__.lower()}"
56 yield f"enum {c_tag} {{"
57 for item in cls:
58 yield from indent(item.c_value(suffix=","))
59 yield f"}};"
60
61 def c_value(self, prefix="", suffix=""):
62 c_tag = f"svp64_{self.__class__.__name__.lower()}"
63 yield f"{prefix}{c_tag.upper()}_{self.name.upper()}{suffix}"
64
65 @classmethod
66 def c_var(cls, name):
67 c_tag = f"svp64_{cls.__name__.lower()}"
68 yield f"enum {c_tag} {name};"
69
70
71 # Python forbids inheriting from enum unless it's empty.
72 In1Sel = Enum("In1Sel", {item.name:item.value for item in _In1Sel})
73 In2Sel = Enum("In2Sel", {item.name:item.value for item in _In2Sel})
74 In3Sel = Enum("In3Sel", {item.name:item.value for item in _In3Sel})
75 OutSel = Enum("OutSel", {item.name:item.value for item in _OutSel})
76 CRInSel = Enum("CRInSel", {item.name:item.value for item in _CRInSel})
77 CROutSel = Enum("CROutSel", {item.name:item.value for item in _CROutSel})
78 SVPType = Enum("SVPType", {item.name:item.value for item in _SVPtype})
79 SVEType = Enum("SVEType", {item.name:item.value for item in _SVEtype})
80 SVEXTRA = Enum("SVEXTRA", {item.name:item.value for item in _SVEXTRA})
81
82
83 class Opcode(Field, str):
84 def c_value(self, prefix="", suffix=""):
85 yield f"{prefix}\"{self}\"{suffix}"
86
87 @classmethod
88 def c_var(cls, name):
89 yield f"const char *{name};"
90
91
92 class Name(Field, str):
93 def __repr__(self):
94 escaped = self.replace("\"", "\\\"")
95 return f"\"{escaped}\""
96
97 def c_value(self, prefix="", suffix=""):
98 yield f"{prefix}{self!r}{suffix}"
99
100 @classmethod
101 def c_var(cls, name):
102 yield f"const char *{name};"
103
104
105 @_dataclasses.dataclass(eq=True, frozen=True)
106 class Entry:
107 name: Name
108 opcode: Opcode
109 in1: In1Sel
110 in2: In2Sel
111 in3: In3Sel
112 out: OutSel
113 out2: OutSel
114 cr_in: CRInSel
115 cr_out: CROutSel
116 ptype: SVPType
117 etype: SVEType
118 sv_in1: SVEXTRA
119 sv_in2: SVEXTRA
120 sv_in3: SVEXTRA
121 sv_out: SVEXTRA
122 sv_out2: SVEXTRA
123 sv_cr_in: SVEXTRA
124 sv_cr_out: SVEXTRA
125
126 @classmethod
127 def c_decl(cls):
128 yield f"struct svp64_entry {{"
129 for field in _dataclasses.fields(cls):
130 if issubclass(field.type, Enum):
131 bits = len(field.type).bit_length()
132 yield from indent([f"uint64_t {field.name} : {bits};"])
133 else:
134 yield from indent(field.type.c_var(name=field.name))
135 yield f"}};"
136
137 def c_value(self, prefix="", suffix=""):
138 yield f"{prefix}{{"
139 for field in _dataclasses.fields(self):
140 name = field.name
141 attr = getattr(self, name)
142 yield from indent(attr.c_value(prefix=f".{name} = ", suffix=","))
143 yield f"}}{suffix}"
144
145 @classmethod
146 def c_var(cls, name):
147 yield f"struct svp64_entry {name};"
148
149
150 class Codegen(_enum.Enum):
151 PPC_OPC_SVP64_H = _enum.auto()
152 PPC_OPC_SVP64_C = _enum.auto()
153
154 @classmethod
155 def _missing_(cls, value):
156 return {
157 "ppc-opc-svp64.h": Codegen.PPC_OPC_SVP64_H,
158 "ppc-opc-svp64.c": Codegen.PPC_OPC_SVP64_C,
159 }[value]
160
161 def __str__(self):
162 return {
163 Codegen.PPC_OPC_SVP64_H: "ppc-opc-svp64.h",
164 Codegen.PPC_OPC_SVP64_C: "ppc-opc-svp64.c",
165 }[self]
166
167 def generate(self, entries):
168 def ppc_opc_svp64_h(entries):
169 yield from DISCLAIMER
170 yield ""
171
172 yield f"#ifndef {self.name}"
173 yield f"#define {self.name}"
174 yield ""
175
176 enums = (
177 PType, EType,
178 In1Sel, In2Sel, In3Sel, OutSel,
179 CRInSel, CROutSel,
180 SVEXTRA,
181 )
182 for enum in enums:
183 yield from enum.c_decl()
184 yield ""
185
186 yield from Entry.c_decl()
187 yield ""
188
189 yield f"#endif /* {self.name} */"
190 yield ""
191
192 def ppc_opc_svp64_c(entries):
193 yield from ()
194
195 return {
196 Codegen.PPC_OPC_SVP64_H: ppc_opc_svp64_h,
197 Codegen.PPC_OPC_SVP64_C: ppc_opc_svp64_c,
198 }[self](entries)
199
200
201 def regex_enum(enum):
202 assert issubclass(enum, _enum.Enum)
203 return "|".join(item.name for item in enum)
204
205
206 PATTERN_VHDL_BINARY = r"(?:2#[01]+#)"
207 PATTERN_DECIMAL = r"(?:[0-9]+)"
208 PATTERN_PARTIAL_BINARY = r"(?:[01-]+)"
209
210 # Examples of the entries to be caught by the pattern below:
211 # 2 => (P2, EXTRA3, RA_OR_ZERO, NONE, NONE, RT, NONE, NONE, NONE, Idx1, NONE, NONE, Idx0, NONE, NONE, NONE), -- lwz
212 # -----10110 => (P2, EXTRA3, NONE, FRB, NONE, FRT, NONE, NONE, CR1, NONE, Idx1, NONE, Idx0, NONE, NONE, Idx0), -- fsqrts
213 # 2#0000000000# => (P2, EXTRA3, NONE, NONE, NONE, NONE, NONE, BFA, BF, NONE, NONE, NONE, NONE, NONE, Idx1, Idx0), -- mcrf
214 PATTERN = "".join((
215 r"^\s*",
216 rf"(?P<opcode>{PATTERN_VHDL_BINARY}|{PATTERN_DECIMAL}|{PATTERN_PARTIAL_BINARY})",
217 r"\s?=>\s?",
218 r"\(",
219 r",\s".join((
220 rf"(?P<ptype>{regex_enum(_SVPtype)})",
221 rf"(?P<etype>{regex_enum(_SVEtype)})",
222 rf"(?P<in1>{regex_enum(_In1Sel)})",
223 rf"(?P<in2>{regex_enum(_In2Sel)})",
224 rf"(?P<in3>{regex_enum(_In3Sel)})",
225 rf"(?P<out>{regex_enum(_OutSel)})",
226 rf"(?P<out2>{regex_enum(_OutSel)})",
227 rf"(?P<cr_in>{regex_enum(_CRInSel)})",
228 rf"(?P<cr_out>{regex_enum(_CROutSel)})",
229 rf"(?P<sv_in1>{regex_enum(_SVEXTRA)})",
230 rf"(?P<sv_in2>{regex_enum(_SVEXTRA)})",
231 rf"(?P<sv_in3>{regex_enum(_SVEXTRA)})",
232 rf"(?P<sv_out>{regex_enum(_SVEXTRA)})",
233 rf"(?P<sv_out2>{regex_enum(_SVEXTRA)})",
234 rf"(?P<sv_cr_in>{regex_enum(_SVEXTRA)})",
235 rf"(?P<sv_cr_out>{regex_enum(_SVEXTRA)})",
236 )),
237 r"\)",
238 r",",
239 r"\s?--\s?",
240 r"(?P<name>[A-Za-z0-9_\./]+)",
241 r"\s*$",
242 ))
243 REGEX = _re.compile(PATTERN)
244
245
246 def parse(stream):
247 for line in stream:
248 match = REGEX.match(line)
249 if match is not None:
250 entry = match.groupdict()
251 for field in _dataclasses.fields(Entry):
252 key = field.name
253 value = entry[key]
254 if issubclass(field.type, _enum.Enum):
255 value = {item.name:item for item in field.type}[value]
256 else:
257 value = field.type(value)
258 entry[key] = value
259 yield Entry(**entry)
260
261
262 def main(codegen):
263 entries = tuple(parse(_sys.stdin))
264 for line in codegen.generate(entries):
265 print(line)
266
267
268 if __name__ == "__main__":
269 parser = _argparse.ArgumentParser()
270 parser.add_argument("codegen", type=Codegen, choices=Codegen, help="code generator")
271
272 args = vars(parser.parse_args())
273 main(**args)