add code to iterate through list of svp64 instructions
[simplev-cpp.git] / generate_headers.py
1 #!/usr/bin/env python3
2 # SPDX-License-Identifier: LGPL-2.1-or-later
3 # See Notices.txt for copyright information
4
5 import sys
6 from pprint import pprint
7 from io import StringIO
8 from typing import List
9 from soc.decoder.pseudo.pagereader import ISA
10 from soc.decoder.power_svp64 import SVP64RM
11 from soc.decoder.power_fields import DecodeFields
12 from soc.decoder.power_decoder import create_pdecode
13
14
15 class InclusiveRange:
16 __slots__ = "start", "stop"
17
18 def __init__(self, start, stop=None):
19 if stop is None:
20 stop = start
21 self.start = start
22 self.stop = stop
23
24 def __len__(self) -> int:
25 return self.width
26
27 @property
28 def width(self) -> int:
29 return self.stop - self.start + 1
30
31 def __repr__(self):
32 if self.start == self.stop:
33 return f"InclusiveRange({self.start})"
34 return f"InclusiveRange({self.start}, {self.stop})"
35
36 def __str__(self):
37 if self.start == self.stop:
38 return f"{self.start}"
39 return f"{self.start}:{self.stop}"
40
41 def append(self, v):
42 if v == self.stop + 1:
43 self.stop = v
44 else:
45 raise ValueError()
46
47 def endian_reversed(self, word_length) -> "InclusiveRange":
48 # note reversed stop/start
49 return InclusiveRange(word_length - 1 - self.stop,
50 word_length - 1 - self.start)
51
52
53 class RangesField:
54 __slots__ = "ranges",
55 ranges: List[InclusiveRange]
56
57 def __init__(self, ranges=None):
58 if ranges is None:
59 ranges = []
60 if isinstance(ranges, InclusiveRange):
61 ranges = [ranges]
62 self.ranges = ranges
63
64 def __len__(self):
65 retval = 0
66 for i in self.ranges:
67 retval += len(i)
68 return retval
69
70 def __repr__(self):
71 if len(self.ranges) == 0:
72 return "RangesField()"
73 if len(self.ranges) == 1:
74 return f"RangesField({self.ranges[0]})"
75 return f"RangesField({self.ranges})"
76
77 def __str__(self):
78 if len(self.ranges) == 0:
79 return "none"
80 return ",".join(map(str, self.ranges))
81
82 def __setitem__(self, key, value):
83 assert isinstance(key, int)
84 assert isinstance(value, int)
85 assert key == len(self)
86 try:
87 self.ranges[-1].append(value)
88 return
89 except IndexError:
90 pass
91 except ValueError:
92 pass
93 self.ranges.append(InclusiveRange(value))
94
95 def endian_reversed(self, word_length) -> "RangesField":
96 return RangesField([i.endian_reversed(word_length)
97 for i in reversed(self.ranges)])
98
99 @property
100 def contiguous(self) -> bool:
101 return len(self.ranges) == 1
102
103 @property
104 def start(self) -> int:
105 assert self.contiguous
106 return self.ranges[0].start
107
108 @property
109 def stop(self) -> int:
110 assert self.contiguous
111 return self.ranges[0].stop
112
113 @property
114 def width(self) -> int:
115 assert self.contiguous
116 return self.ranges[0].width
117
118
119 try:
120 # shut-up excessive printing
121 old_stdout = sys.stdout
122 new_stdout = StringIO()
123 sys.stdout = new_stdout
124 isa = ISA()
125 svp64rm = SVP64RM()
126 decode_fields = DecodeFields(bitkls=RangesField)
127 decode_fields.create_specs()
128 decoder = create_pdecode()
129 sys.stdout = old_stdout
130 except:
131 sys.stdout = old_stdout
132 print(new_stdout.getvalue())
133 raise
134
135
136 def flatten(v):
137 if isinstance(v, list):
138 for i in v:
139 yield from flatten(i)
140 else:
141 yield v
142
143
144 def subdecoders():
145 def visit_subdecoders(subdecoders):
146 for subdecoder in flatten(subdecoders):
147 yield subdecoder
148 yield from visit_subdecoders(subdecoder.subdecoders)
149 yield from visit_subdecoders(decoder.dec)
150
151
152 def make_opcodes_dict():
153 retval = {}
154 for subdecoder in subdecoders():
155 for opcode in subdecoder.opcodes:
156 opcode = dict(opcode)
157 opcode['subdecoder'] = subdecoder
158 comment = opcode['comment']
159 if comment not in retval:
160 retval[comment] = opcode
161 return retval
162
163
164 OPCODES_DICT = make_opcodes_dict()
165
166
167 def find_opcode(comment):
168 opcode = OPCODES_DICT[comment]
169 return opcode['subdecoder'].pattern, int(opcode['opcode'], base=0)
170
171
172 SETVL_PO, SETVL_XO = find_opcode("setvl")
173 PO_FIELD: RangesField = decode_fields.PO
174 RT_FIELD: RangesField = decode_fields.RT
175 RA_FIELD: RangesField = decode_fields.RA
176 SVL_SVi_FIELD: RangesField = decode_fields.FormSVL.SVi
177 SVL_vs_FIELD: RangesField = decode_fields.FormSVL.vs
178 SVL_ms_FIELD: RangesField = decode_fields.FormSVL.ms
179 SVL_XO_FIELD: RangesField = decode_fields.FormSVL.XO
180 SVL_Rc_FIELD: RangesField = decode_fields.FormSVL.Rc
181 print(f"SETVL_PO={SETVL_PO}")
182 print(f"SETVL_XO={SETVL_XO}")
183 print(f"PO_FIELD={PO_FIELD}")
184 print(f"RT_FIELD={RT_FIELD}")
185 print(f"RA_FIELD={RA_FIELD}")
186 print(f"SVL_SVi_FIELD={SVL_SVi_FIELD}")
187 print(f"SVL_vs_FIELD={SVL_vs_FIELD}")
188 print(f"SVL_ms_FIELD={SVL_ms_FIELD}")
189 print(f"SVL_XO_FIELD={SVL_XO_FIELD}")
190 print(f"SVL_Rc_FIELD={SVL_Rc_FIELD}")
191
192 WORD_LENGTH = 32
193 PO_SHIFT = PO_FIELD.endian_reversed(WORD_LENGTH).start
194 RT_SHIFT = RT_FIELD.endian_reversed(WORD_LENGTH).start
195 RA_SHIFT = RA_FIELD.endian_reversed(WORD_LENGTH).start
196 SVL_SVi_SHIFT = SVL_SVi_FIELD.endian_reversed(WORD_LENGTH).start
197 SVL_vs_SHIFT = SVL_vs_FIELD.endian_reversed(WORD_LENGTH).start
198 SVL_ms_SHIFT = SVL_ms_FIELD.endian_reversed(WORD_LENGTH).start
199 SVL_XO_SHIFT = SVL_XO_FIELD.endian_reversed(WORD_LENGTH).start
200 SVL_Rc_SHIFT = SVL_Rc_FIELD.endian_reversed(WORD_LENGTH).start
201
202 print(f"RT_SHIFT={RT_SHIFT}")
203 print(f"RA_SHIFT={RA_SHIFT}")
204 print(f"PO_SHIFT={PO_SHIFT}")
205 print(f"SVL_SVi_SHIFT={SVL_SVi_SHIFT}")
206 print(f"SVL_vs_SHIFT={SVL_vs_SHIFT}")
207 print(f"SVL_ms_SHIFT={SVL_ms_SHIFT}")
208 print(f"SVL_XO_SHIFT={SVL_XO_SHIFT}")
209 print(f"SVL_Rc_SHIFT={SVL_Rc_SHIFT}")
210
211
212 def is_power_of_2(i):
213 assert isinstance(i, int)
214 return (i & (i - 1)) == 0 and i != 0
215
216
217 with open("include/simplev_cpp_generated.h", mode="w", encoding="utf-8") as o:
218 o.write("""// SPDX-License-Identifier: LGPL-2.1-or-later
219 // See Notices.txt for copyright information
220 // This file is automatically generated by generate_headers.py,
221 // do not edit by hand
222 #pragma once
223 #include <cstddef>
224 #include <cstdint>
225 #include <type_traits>
226
227 #ifdef __clang__
228 #define SIMPLEV_USE_NONPOT_VECTORS
229 #endif
230
231 // #undef SIMPLEV_USE_BIGGER_THAN_8_BYTE_VECTORS
232
233 namespace sv
234 {
235 template <typename ElementType, std::size_t SUB_VL, std::size_t MAX_VL, typename = void>
236 struct VecTypeStruct;
237
238 template <typename ElementType, std::size_t SUB_VL, std::size_t MAX_VL>
239 using VecType = typename VecTypeStruct<ElementType, SUB_VL, MAX_VL>::Type;
240
241 #define SIMPLEV_MAKE_VEC_TYPE(size, underlying_size) \\
242 template <typename ElementType, std::size_t SUB_VL, std::size_t MAX_VL> \\
243 struct VecTypeStruct<ElementType, \\
244 SUB_VL, \\
245 MAX_VL, \\
246 std::enable_if_t<sizeof(ElementType) * SUB_VL * MAX_VL == (size)>> \\
247 final \\
248 { \\
249 typedef ElementType Type __attribute__((vector_size(underlying_size))); \\
250 };
251
252 template <typename ElementType, std::size_t SUB_VL, std::size_t MAX_VL>
253 struct Vec final
254 {
255 static_assert(MAX_VL > 0 && MAX_VL <= 64);
256 static_assert(SUB_VL >= 1 && SUB_VL <= 4);
257 using Type = VecType<ElementType, SUB_VL, MAX_VL>;
258 Type value;
259 };
260
261 // power-of-2
262 #define SIMPLEV_MAKE_VEC_TYPE_POT(size) SIMPLEV_MAKE_VEC_TYPE(size, size)
263
264 // non-power-of-2
265 #ifdef SIMPLEV_USE_NONPOT_VECTORS
266 #define SIMPLEV_MAKE_VEC_TYPE_NONPOT(size, rounded_up_size) SIMPLEV_MAKE_VEC_TYPE(size)
267 #else
268 #define SIMPLEV_MAKE_VEC_TYPE_NONPOT(size, rounded_up_size) \\
269 SIMPLEV_MAKE_VEC_TYPE(size, rounded_up_size)
270 #endif
271
272 """)
273 for i in range(64 * 4):
274 i += 1
275 if is_power_of_2(i):
276 o.write(f"SIMPLEV_MAKE_VEC_TYPE_POT({i})\n")
277 else:
278 rounded_up_size = 1 << i.bit_length()
279 o.write(f"SIMPLEV_MAKE_VEC_TYPE_NONPOT({i}, {rounded_up_size})\n")
280 if i == 8:
281 o.write("#ifdef SIMPLEV_USE_BIGGER_THAN_8_BYTE_VECTORS\n")
282 o.write(f"""#endif // SIMPLEV_USE_BIGGER_THAN_8_BYTE_VECTORS
283
284 template <std::size_t MAX_VL>
285 struct VL final
286 {{
287 static_assert(MAX_VL > 0 && MAX_VL <= 64);
288 std::size_t value;
289 }};
290
291 template <std::size_t MAX_VL>
292 inline __attribute__((always_inline)) VL<MAX_VL> setvl(std::size_t vl)
293 {{
294 VL<MAX_VL> retval;
295 asm volatile(
296 "# setvl %[retval], %[vl], MVL=%[max_vl]\\n\\t"
297 ".long %[instr] | (%[retval] << %[rt_shift]) | (%[vl] << %[ra_shift])"
298 : [retval] "=b"(retval.value)
299 : [vl] "b"(vl),
300 [max_vl] "n"(MAX_VL),
301 [instr] "n"(((MAX_VL - 1) << {SVL_SVi_SHIFT}) | {hex(
302 (1 << SVL_vs_SHIFT)
303 | (1 << SVL_ms_SHIFT)
304 | (SETVL_XO << SVL_XO_SHIFT)
305 | (SETVL_PO << PO_SHIFT))}),
306 [rt_shift] "n"({RT_SHIFT}),
307 [ra_shift] "n"({RA_SHIFT})
308 : "memory");
309 return retval;
310 }}
311 """)
312 for opcode in {i: None for i in svp64rm.instrs}:
313 try:
314 instr = OPCODES_DICT[opcode]
315 except KeyError as e:
316 print(repr(e), file=sys.stderr)
317 o.write(f"\n// skipped invalid opcode: {opcode!r}\n")
318 continue
319 o.write(f"\n/// {opcode}\n")
320 function_name = "sv_" + opcode.split('/')[0].replace('.', '_')
321 SV_Ptype = instr['SV_Ptype']
322 if SV_Ptype == 'P2':
323 pass
324 # TODO
325 else:
326 assert SV_Ptype == 'P1'
327 # TODO
328 o.write(f"""/// (not yet implemented)
329 template <typename... Args>
330 void {function_name}(Args &&...) = delete;
331 """)
332 o.write(f"""}} // namespace sv
333
334 #undef SIMPLEV_MAKE_VEC_TYPE
335 #undef SIMPLEV_MAKE_VEC_TYPE_NONPOT
336 #undef SIMPLEV_MAKE_VEC_TYPE_POT
337 #undef SIMPLEV_USE_NONPOT_VECTORS
338 #undef SIMPLEV_USE_BIGGER_THAN_8_BYTE_VECTORS
339 """)