2 # SPDX-License-Identifier: LGPL-2.1-or-later
3 # See Notices.txt for copyright information
6 from io
import StringIO
7 from typing
import Any
, Dict
, List
8 from soc
.decoder
.pseudo
.pagereader
import ISA
9 from soc
.decoder
.power_svp64
import SVP64RM
10 from soc
.decoder
.power_fields
import DecodeFields
11 from soc
.decoder
.power_decoder
import create_pdecode
14 # generated text should wrap at 80 columns
18 def wcwidth(text
: str) -> int:
19 """ return the number of columns that `text` takes up if printed to a terminal.
20 returns -1 if any characters are not printable.
22 # TODO: replace with wcwidth from wcwidth
23 # package when we add pip packaging files
24 if text
.isprintable():
30 def __init__(self
, key
: str, value
: Any
):
32 self
.key_lines
= self
.key
.splitlines()
33 for i
in range(len(self
.key_lines
)):
34 self
.key_lines
[i
] = self
.key_lines
[i
].rstrip()
35 self
.value
= repr(value
)
36 self
.value_lines
= self
.value
.splitlines()
37 for i
in range(len(self
.value_lines
)):
38 self
.value_lines
[i
] = self
.value_lines
[i
].rstrip()
39 self
.width
= max(max(map(wcwidth
, self
.key_lines
)),
40 max(map(wcwidth
, self
.value_lines
)))
43 def format_dict_as_tables(d
: Dict
[str, Any
], column_width
: int) -> List
[str]:
44 entries
= [TableEntry(k
, v
) for k
, v
in d
.items()]
45 entries
.sort(key
=lambda entry
: entry
.key
)
48 col_sep_start_top_line
= '+-'
49 col_sep_start_mid_line
= '+='
50 col_sep_start_bottom_line
= '+-'
51 col_sep_start_width
= wcwidth(col_sep_start
)
53 col_sep_mid_top_line
= '-+-'
54 col_sep_mid_mid_line
= '=+='
55 col_sep_mid_bottom_line
= '-+-'
56 col_sep_mid_width
= wcwidth(col_sep_mid
)
58 col_sep_end_top_line
= '-+'
59 col_sep_end_mid_line
= '=+'
60 col_sep_end_bottom_line
= '-+'
61 col_sep_end_width
= wcwidth(col_sep_end
)
62 col_top_line_char
= '-'
63 col_mid_line_char
= '='
64 col_bottom_line_char
= '-'
65 retval
: List
[str] = []
66 while len(entries
) != 0:
67 total_width
= col_sep_start_width
- col_sep_mid_width
68 column_entries
: List
[TableEntry
] = []
71 while len(entries
) != 0:
73 next_total_width
= total_width
+ col_sep_mid_width
74 next_total_width
+= entry
.width
75 if len(column_entries
) != 0 and \
76 next_total_width
+ col_sep_end_width
>= column_width
:
79 total_width
= next_total_width
80 column_entries
.append(entry
)
81 key_line_count
= max(key_line_count
, len(entry
.key_lines
))
82 value_line_count
= max(value_line_count
, len(entry
.value_lines
))
83 top_line
= col_sep_start_top_line
84 mid_line
= col_sep_start_mid_line
85 bottom_line
= col_sep_start_bottom_line
86 key_lines
= [col_sep_start
] * key_line_count
87 value_lines
= [col_sep_start
] * value_line_count
88 for i
in range(len(column_entries
)):
89 last
= (i
== len(column_entries
) - 1)
90 entry
= column_entries
[i
]
92 def extend_line(line
, entry_text
, fill_char
,
93 col_sep_mid
, col_sep_end
):
95 line
+= fill_char
* (entry
.width
- wcwidth(entry_text
))
96 line
+= col_sep_end
if last
else col_sep_mid
99 top_line
= extend_line(line
=top_line
, entry_text
='',
100 fill_char
=col_top_line_char
,
101 col_sep_mid
=col_sep_mid_top_line
,
102 col_sep_end
=col_sep_end_top_line
)
103 mid_line
= extend_line(line
=mid_line
, entry_text
='',
104 fill_char
=col_mid_line_char
,
105 col_sep_mid
=col_sep_mid_mid_line
,
106 col_sep_end
=col_sep_end_mid_line
)
107 bottom_line
= extend_line(line
=bottom_line
, entry_text
='',
108 fill_char
=col_bottom_line_char
,
109 col_sep_mid
=col_sep_mid_bottom_line
,
110 col_sep_end
=col_sep_end_bottom_line
)
112 def extend_lines(lines
, entry_lines
):
113 for j
in range(len(lines
)):
115 if j
< len(entry_lines
):
116 entry_text
= entry_lines
[j
]
117 lines
[j
] = extend_line(line
=lines
[j
],
118 entry_text
=entry_text
,
120 col_sep_mid
=col_sep_mid
,
121 col_sep_end
=col_sep_end
)
123 extend_lines(key_lines
, entry
.key_lines
)
124 extend_lines(value_lines
, entry
.value_lines
)
125 retval
.append(top_line
)
126 retval
.extend(key_lines
)
127 retval
.append(mid_line
)
128 retval
.extend(value_lines
)
129 retval
.append(bottom_line
)
133 class InclusiveRange
:
134 __slots__
= "start", "stop"
136 def __init__(self
, start
, stop
=None):
142 def __len__(self
) -> int:
146 def width(self
) -> int:
147 return self
.stop
- self
.start
+ 1
150 if self
.start
== self
.stop
:
151 return f
"InclusiveRange({self.start})"
152 return f
"InclusiveRange({self.start}, {self.stop})"
155 if self
.start
== self
.stop
:
156 return f
"{self.start}"
157 return f
"{self.start}:{self.stop}"
160 if v
== self
.stop
+ 1:
165 def endian_reversed(self
, word_length
) -> "InclusiveRange":
166 # note reversed stop/start
167 return InclusiveRange(word_length
- 1 - self
.stop
,
168 word_length
- 1 - self
.start
)
172 __slots__
= "ranges",
173 ranges
: List
[InclusiveRange
]
175 def __init__(self
, ranges
=None):
178 if isinstance(ranges
, InclusiveRange
):
184 for i
in self
.ranges
:
189 if len(self
.ranges
) == 0:
190 return "RangesField()"
191 if len(self
.ranges
) == 1:
192 return f
"RangesField({self.ranges[0]})"
193 return f
"RangesField({self.ranges})"
196 if len(self
.ranges
) == 0:
198 return ",".join(map(str, self
.ranges
))
200 def __setitem__(self
, key
, value
):
201 assert isinstance(key
, int)
202 assert isinstance(value
, int)
203 assert key
== len(self
)
205 self
.ranges
[-1].append(value
)
211 self
.ranges
.append(InclusiveRange(value
))
213 def endian_reversed(self
, word_length
) -> "RangesField":
214 return RangesField([i
.endian_reversed(word_length
)
215 for i
in reversed(self
.ranges
)])
218 def contiguous(self
) -> bool:
219 return len(self
.ranges
) == 1
222 def start(self
) -> int:
223 assert self
.contiguous
224 return self
.ranges
[0].start
227 def stop(self
) -> int:
228 assert self
.contiguous
229 return self
.ranges
[0].stop
232 def width(self
) -> int:
233 assert self
.contiguous
234 return self
.ranges
[0].width
238 # shut-up excessive printing
239 old_stdout
= sys
.stdout
240 new_stdout
= StringIO()
241 sys
.stdout
= new_stdout
244 decode_fields
= DecodeFields(bitkls
=RangesField
)
245 decode_fields
.create_specs()
246 decoder
= create_pdecode()
247 sys
.stdout
= old_stdout
249 sys
.stdout
= old_stdout
250 print(new_stdout
.getvalue())
255 if isinstance(v
, list):
257 yield from flatten(i
)
263 def visit_subdecoders(subdecoders
):
264 for subdecoder
in flatten(subdecoders
):
266 yield from visit_subdecoders(subdecoder
.subdecoders
)
267 yield from visit_subdecoders(decoder
.dec
)
270 def make_opcodes_dict() -> Dict
[str, Dict
[str, Any
]]:
272 for subdecoder
in subdecoders():
273 for opcode
in subdecoder
.opcodes
:
274 opcode
= dict(opcode
)
275 opcode
['subdecoder'] = subdecoder
276 comment
= opcode
['comment']
277 if comment
not in retval
:
278 retval
[comment
] = opcode
280 print(f
"duplicate comment field: {comment!r}"
281 f
" subdecoder.pattern={subdecoder.pattern}")
285 OPCODES_DICT
= make_opcodes_dict()
288 def find_opcode(comment
):
289 opcode
= OPCODES_DICT
[comment
]
290 return opcode
['subdecoder'].pattern
, int(opcode
['opcode'], base
=0)
293 SETVL_PO
, SETVL_XO
= find_opcode("setvl")
294 PO_FIELD
: RangesField
= decode_fields
.PO
295 RT_FIELD
: RangesField
= decode_fields
.RT
296 RA_FIELD
: RangesField
= decode_fields
.RA
297 SVL_SVi_FIELD
: RangesField
= decode_fields
.FormSVL
.SVi
298 SVL_vs_FIELD
: RangesField
= decode_fields
.FormSVL
.vs
299 SVL_ms_FIELD
: RangesField
= decode_fields
.FormSVL
.ms
300 SVL_XO_FIELD
: RangesField
= decode_fields
.FormSVL
.XO
301 SVL_Rc_FIELD
: RangesField
= decode_fields
.FormSVL
.Rc
302 print(f
"SETVL_PO={SETVL_PO}")
303 print(f
"SETVL_XO={SETVL_XO}")
304 print(f
"PO_FIELD={PO_FIELD}")
305 print(f
"RT_FIELD={RT_FIELD}")
306 print(f
"RA_FIELD={RA_FIELD}")
307 print(f
"SVL_SVi_FIELD={SVL_SVi_FIELD}")
308 print(f
"SVL_vs_FIELD={SVL_vs_FIELD}")
309 print(f
"SVL_ms_FIELD={SVL_ms_FIELD}")
310 print(f
"SVL_XO_FIELD={SVL_XO_FIELD}")
311 print(f
"SVL_Rc_FIELD={SVL_Rc_FIELD}")
314 PO_SHIFT
= PO_FIELD
.endian_reversed(WORD_LENGTH
).start
315 RT_SHIFT
= RT_FIELD
.endian_reversed(WORD_LENGTH
).start
316 RA_SHIFT
= RA_FIELD
.endian_reversed(WORD_LENGTH
).start
317 SVL_SVi_SHIFT
= SVL_SVi_FIELD
.endian_reversed(WORD_LENGTH
).start
318 SVL_vs_SHIFT
= SVL_vs_FIELD
.endian_reversed(WORD_LENGTH
).start
319 SVL_ms_SHIFT
= SVL_ms_FIELD
.endian_reversed(WORD_LENGTH
).start
320 SVL_XO_SHIFT
= SVL_XO_FIELD
.endian_reversed(WORD_LENGTH
).start
321 SVL_Rc_SHIFT
= SVL_Rc_FIELD
.endian_reversed(WORD_LENGTH
).start
323 print(f
"RT_SHIFT={RT_SHIFT}")
324 print(f
"RA_SHIFT={RA_SHIFT}")
325 print(f
"PO_SHIFT={PO_SHIFT}")
326 print(f
"SVL_SVi_SHIFT={SVL_SVi_SHIFT}")
327 print(f
"SVL_vs_SHIFT={SVL_vs_SHIFT}")
328 print(f
"SVL_ms_SHIFT={SVL_ms_SHIFT}")
329 print(f
"SVL_XO_SHIFT={SVL_XO_SHIFT}")
330 print(f
"SVL_Rc_SHIFT={SVL_Rc_SHIFT}")
333 def is_power_of_2(i
):
334 assert isinstance(i
, int)
335 return (i
& (i
- 1)) == 0 and i
!= 0
338 with
open("include/simplev_cpp_generated.h", mode
="w", encoding
="utf-8") as o
:
339 o
.write("""// SPDX-License-Identifier: LGPL-2.1-or-later
340 // See Notices.txt for copyright information
341 // This file is automatically generated by generate_headers.py,
342 // do not edit by hand
346 #include <type_traits>
349 #define SIMPLEV_USE_NONPOT_VECTORS
352 // #undef SIMPLEV_USE_BIGGER_THAN_8_BYTE_VECTORS
356 template <typename ElementType, std::size_t SUB_VL, std::size_t MAX_VL, typename = void>
357 struct VecTypeStruct;
359 template <typename ElementType, std::size_t SUB_VL, std::size_t MAX_VL>
360 using VecType = typename VecTypeStruct<ElementType, SUB_VL, MAX_VL>::Type;
362 #define SIMPLEV_MAKE_VEC_TYPE(size, underlying_size) \\
363 template <typename ElementType, std::size_t SUB_VL, std::size_t MAX_VL> \\
364 struct VecTypeStruct<ElementType, \\
367 std::enable_if_t<sizeof(ElementType) * SUB_VL * MAX_VL == (size)>> \\
370 typedef ElementType Type __attribute__((vector_size(underlying_size))); \\
373 template <typename ElementType, std::size_t SUB_VL, std::size_t MAX_VL>
376 static_assert(MAX_VL > 0 && MAX_VL <= 64);
377 static_assert(SUB_VL >= 1 && SUB_VL <= 4);
378 using Type = VecType<ElementType, SUB_VL, MAX_VL>;
383 #define SIMPLEV_MAKE_VEC_TYPE_POT(size) SIMPLEV_MAKE_VEC_TYPE(size, size)
386 #ifdef SIMPLEV_USE_NONPOT_VECTORS
387 #define SIMPLEV_MAKE_VEC_TYPE_NONPOT(size, rounded_up_size) SIMPLEV_MAKE_VEC_TYPE(size)
389 #define SIMPLEV_MAKE_VEC_TYPE_NONPOT(size, rounded_up_size) \\
390 SIMPLEV_MAKE_VEC_TYPE(size, rounded_up_size)
394 for i
in range(64 * 4):
397 o
.write(f
"SIMPLEV_MAKE_VEC_TYPE_POT({i})\n")
399 rounded_up_size
= 1 << i
.bit_length()
400 o
.write(f
"SIMPLEV_MAKE_VEC_TYPE_NONPOT({i}, {rounded_up_size})\n")
402 o
.write("#ifdef SIMPLEV_USE_BIGGER_THAN_8_BYTE_VECTORS\n")
403 o
.write(f
"""#endif // SIMPLEV_USE_BIGGER_THAN_8_BYTE_VECTORS
405 template <std::size_t MAX_VL>
408 static_assert(MAX_VL > 0 && MAX_VL <= 64);
412 template <std::size_t MAX_VL>
413 inline __attribute__((always_inline)) VL<MAX_VL> setvl(std::size_t vl)
417 "# setvl %[retval], %[vl], MVL=%[max_vl]\\n\\t"
418 ".long %[instr] | (%[retval] << %[rt_shift]) | (%[vl] << %[ra_shift])"
419 : [retval] "=b"(retval.value)
421 [max_vl] "n"(MAX_VL),
422 [instr] "n"(((MAX_VL - 1) << {SVL_SVi_SHIFT}) | {hex(
424 | (1 << SVL_ms_SHIFT)
425 | (SETVL_XO << SVL_XO_SHIFT)
426 | (SETVL_PO << PO_SHIFT))}),
427 [rt_shift] "n"({RT_SHIFT}),
428 [ra_shift] "n"({RA_SHIFT})
433 for opcode
in {i
: None for i
in svp64rm
.instrs
}:
435 instr
= OPCODES_DICT
[opcode
]
436 except KeyError as e
:
437 print(repr(e
), file=sys
.stderr
)
438 o
.write(f
"\n// skipped invalid opcode: {opcode!r}\n")
440 o
.write(f
"\n/// {opcode}\n")
441 function_name
= "sv_" + opcode
.split('/')[0].replace('.', '_')
442 SV_Ptype
= instr
['SV_Ptype']
447 assert SV_Ptype
== 'P1'
449 o
.write("/// (not yet implemented)\n")
450 instr_without_subdecoder
= instr
.copy()
451 del instr_without_subdecoder
['subdecoder']
453 for line
in format_dict_as_tables(instr_without_subdecoder
,
454 OUTPUT_WIDTH
- wcwidth(comment
)):
455 o
.write((comment
+ line
).rstrip() + '\n')
456 o
.write(f
"""template <typename... Args>
457 void {function_name}(Args &&...) = delete;
459 o
.write(f
"""}} // namespace sv
461 #undef SIMPLEV_MAKE_VEC_TYPE
462 #undef SIMPLEV_MAKE_VEC_TYPE_NONPOT
463 #undef SIMPLEV_MAKE_VEC_TYPE_POT
464 #undef SIMPLEV_USE_NONPOT_VECTORS
465 #undef SIMPLEV_USE_BIGGER_THAN_8_BYTE_VECTORS