blob: 73d569c128c85bbbb4b04bc3b80ad4c8e8651851 [file] [log] [blame]
Philippe Mathieu-Daudé3d004a32020-01-30 17:32:25 +01001#!/usr/bin/env python3
Richard Henderson568ae7e2017-12-07 12:44:09 -08002# Copyright (c) 2018 Linaro Limited
3#
4# This library is free software; you can redistribute it and/or
5# modify it under the terms of the GNU Lesser General Public
6# License as published by the Free Software Foundation; either
Chetan Pantd6ea4232020-10-23 12:33:53 +00007# version 2.1 of the License, or (at your option) any later version.
Richard Henderson568ae7e2017-12-07 12:44:09 -08008#
9# This library is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12# Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public
15# License along with this library; if not, see <http://www.gnu.org/licenses/>.
16#
17
18#
19# Generate a decoding tree from a specification file.
Richard Henderson3fdbf5d2019-02-23 13:00:10 -080020# See the syntax and semantics in docs/devel/decodetree.rst.
Richard Henderson568ae7e2017-12-07 12:44:09 -080021#
22
Philippe Mathieu-Daudé4caceca2021-01-10 01:02:40 +010023import io
Richard Henderson568ae7e2017-12-07 12:44:09 -080024import os
25import re
26import sys
27import getopt
Richard Henderson568ae7e2017-12-07 12:44:09 -080028
29insnwidth = 32
Luis Fernando Fujita Pires60c425f2021-04-07 22:18:49 +000030bitop_width = 32
Richard Henderson568ae7e2017-12-07 12:44:09 -080031insnmask = 0xffffffff
Richard Henderson17560e92019-01-30 18:01:29 -080032variablewidth = False
Richard Henderson568ae7e2017-12-07 12:44:09 -080033fields = {}
34arguments = {}
35formats = {}
Richard Henderson0eff2df2019-02-23 11:35:36 -080036allpatterns = []
Richard Hendersonc6920792019-08-09 08:12:50 -070037anyextern = False
Richard Henderson9b5acc52023-05-25 18:04:05 -070038testforerror = False
Richard Henderson568ae7e2017-12-07 12:44:09 -080039
40translate_prefix = 'trans'
41translate_scope = 'static '
42input_file = ''
43output_file = None
44output_fd = None
45insntype = 'uint32_t'
Richard Hendersonabd04f92018-10-23 10:26:25 +010046decode_function = 'decode'
Richard Henderson568ae7e2017-12-07 12:44:09 -080047
Richard Hendersonacfdd232020-09-03 12:23:34 -070048# An identifier for C.
49re_C_ident = '[a-zA-Z][a-zA-Z0-9_]*'
Richard Henderson568ae7e2017-12-07 12:44:09 -080050
Richard Hendersonacfdd232020-09-03 12:23:34 -070051# Identifiers for Arguments, Fields, Formats and Patterns.
52re_arg_ident = '&[a-zA-Z0-9_]*'
53re_fld_ident = '%[a-zA-Z0-9_]*'
54re_fmt_ident = '@[a-zA-Z0-9_]*'
55re_pat_ident = '[a-zA-Z0-9_]*'
Richard Henderson568ae7e2017-12-07 12:44:09 -080056
Richard Henderson6699ae62018-10-26 14:59:43 +010057def error_with_file(file, lineno, *args):
Richard Henderson568ae7e2017-12-07 12:44:09 -080058 """Print an error message from file:line and args and exit."""
59 global output_file
60 global output_fd
61
Richard Henderson2fd51b12020-05-15 14:48:54 -070062 prefix = ''
63 if file:
Richard Henderson9f6e2b42021-04-28 16:37:02 -070064 prefix += f'{file}:'
Richard Henderson568ae7e2017-12-07 12:44:09 -080065 if lineno:
Richard Henderson9f6e2b42021-04-28 16:37:02 -070066 prefix += f'{lineno}:'
Richard Henderson2fd51b12020-05-15 14:48:54 -070067 if prefix:
68 prefix += ' '
69 print(prefix, end='error: ', file=sys.stderr)
70 print(*args, file=sys.stderr)
71
Richard Henderson568ae7e2017-12-07 12:44:09 -080072 if output_file and output_fd:
73 output_fd.close()
Richard Henderson036cc752023-05-26 10:22:51 -070074 # Do not try to remove e.g. -o /dev/null
75 if not output_file.startswith("/dev"):
76 try:
77 os.remove(output_file)
78 except PermissionError:
79 pass
Richard Henderson9b5acc52023-05-25 18:04:05 -070080 exit(0 if testforerror else 1)
Richard Henderson2fd51b12020-05-15 14:48:54 -070081# end error_with_file
82
Richard Henderson568ae7e2017-12-07 12:44:09 -080083
Richard Henderson6699ae62018-10-26 14:59:43 +010084def error(lineno, *args):
Richard Henderson2fd51b12020-05-15 14:48:54 -070085 error_with_file(input_file, lineno, *args)
86# end error
87
Richard Henderson568ae7e2017-12-07 12:44:09 -080088
89def output(*args):
90 global output_fd
91 for a in args:
92 output_fd.write(a)
93
94
Richard Henderson568ae7e2017-12-07 12:44:09 -080095def output_autogen():
96 output('/* This file is autogenerated by scripts/decodetree.py. */\n\n')
97
98
99def str_indent(c):
100 """Return a string with C spaces"""
101 return ' ' * c
102
103
104def str_fields(fields):
zhaolichang65fdb3c2020-09-17 15:50:23 +0800105 """Return a string uniquely identifying FIELDS"""
Richard Henderson568ae7e2017-12-07 12:44:09 -0800106 r = ''
107 for n in sorted(fields.keys()):
108 r += '_' + n
109 return r[1:]
110
111
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700112def whex(val):
113 """Return a hex string for val padded for insnwidth"""
114 global insnwidth
115 return f'0x{val:0{insnwidth // 4}x}'
116
117
118def whexC(val):
119 """Return a hex string for val padded for insnwidth,
120 and with the proper suffix for a C constant."""
121 suffix = ''
Luis Fernando Fujita Pires60c425f2021-04-07 22:18:49 +0000122 if val >= 0x100000000:
123 suffix = 'ull'
124 elif val >= 0x80000000:
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700125 suffix = 'u'
126 return whex(val) + suffix
127
128
Richard Henderson568ae7e2017-12-07 12:44:09 -0800129def str_match_bits(bits, mask):
130 """Return a string pretty-printing BITS/MASK"""
131 global insnwidth
132
133 i = 1 << (insnwidth - 1)
134 space = 0x01010100
135 r = ''
136 while i != 0:
137 if i & mask:
138 if i & bits:
139 r += '1'
140 else:
141 r += '0'
142 else:
143 r += '.'
144 if i & space:
145 r += ' '
146 i >>= 1
147 return r
148
149
150def is_pow2(x):
151 """Return true iff X is equal to a power of 2."""
152 return (x & (x - 1)) == 0
153
154
155def ctz(x):
156 """Return the number of times 2 factors into X."""
Richard Hendersonb44b3442020-05-16 13:15:02 -0700157 assert x != 0
Richard Henderson568ae7e2017-12-07 12:44:09 -0800158 r = 0
159 while ((x >> r) & 1) == 0:
160 r += 1
161 return r
162
163
164def is_contiguous(bits):
Richard Hendersonb44b3442020-05-16 13:15:02 -0700165 if bits == 0:
166 return -1
Richard Henderson568ae7e2017-12-07 12:44:09 -0800167 shift = ctz(bits)
168 if is_pow2((bits >> shift) + 1):
169 return shift
170 else:
171 return -1
172
173
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700174def eq_fields_for_args(flds_a, arg):
175 if len(flds_a) != len(arg.fields):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800176 return False
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700177 # Only allow inference on default types
178 for t in arg.types:
179 if t != 'int':
180 return False
Richard Henderson568ae7e2017-12-07 12:44:09 -0800181 for k, a in flds_a.items():
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700182 if k not in arg.fields:
Richard Henderson568ae7e2017-12-07 12:44:09 -0800183 return False
184 return True
185
186
187def eq_fields_for_fmts(flds_a, flds_b):
188 if len(flds_a) != len(flds_b):
189 return False
190 for k, a in flds_a.items():
191 if k not in flds_b:
192 return False
193 b = flds_b[k]
194 if a.__class__ != b.__class__ or a != b:
195 return False
196 return True
197
198
199class Field:
200 """Class representing a simple instruction field"""
201 def __init__(self, sign, pos, len):
202 self.sign = sign
203 self.pos = pos
204 self.len = len
205 self.mask = ((1 << len) - 1) << pos
206
207 def __str__(self):
208 if self.sign:
209 s = 's'
210 else:
211 s = ''
Cleber Rosacbcdf1a2018-10-04 12:18:50 -0400212 return str(self.pos) + ':' + s + str(self.len)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800213
Peter Maydellaeac22b2023-05-23 13:04:44 +0100214 def str_extract(self, lvalue_formatter):
Luis Fernando Fujita Pires60c425f2021-04-07 22:18:49 +0000215 global bitop_width
216 s = 's' if self.sign else ''
217 return f'{s}extract{bitop_width}(insn, {self.pos}, {self.len})'
Richard Henderson568ae7e2017-12-07 12:44:09 -0800218
219 def __eq__(self, other):
Richard Henderson2c7d4422019-06-11 16:39:41 +0100220 return self.sign == other.sign and self.mask == other.mask
Richard Henderson568ae7e2017-12-07 12:44:09 -0800221
222 def __ne__(self, other):
223 return not self.__eq__(other)
224# end Field
225
226
227class MultiField:
228 """Class representing a compound instruction field"""
229 def __init__(self, subs, mask):
230 self.subs = subs
231 self.sign = subs[0].sign
232 self.mask = mask
233
234 def __str__(self):
235 return str(self.subs)
236
Peter Maydellaeac22b2023-05-23 13:04:44 +0100237 def str_extract(self, lvalue_formatter):
Luis Fernando Fujita Pires60c425f2021-04-07 22:18:49 +0000238 global bitop_width
Richard Henderson568ae7e2017-12-07 12:44:09 -0800239 ret = '0'
240 pos = 0
241 for f in reversed(self.subs):
Peter Maydellaeac22b2023-05-23 13:04:44 +0100242 ext = f.str_extract(lvalue_formatter)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800243 if pos == 0:
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700244 ret = ext
Richard Henderson568ae7e2017-12-07 12:44:09 -0800245 else:
Luis Fernando Fujita Pires60c425f2021-04-07 22:18:49 +0000246 ret = f'deposit{bitop_width}({ret}, {pos}, {bitop_width - pos}, {ext})'
Richard Henderson568ae7e2017-12-07 12:44:09 -0800247 pos += f.len
248 return ret
249
250 def __ne__(self, other):
251 if len(self.subs) != len(other.subs):
252 return True
253 for a, b in zip(self.subs, other.subs):
254 if a.__class__ != b.__class__ or a != b:
255 return True
256 return False
257
258 def __eq__(self, other):
259 return not self.__ne__(other)
260# end MultiField
261
262
263class ConstField:
264 """Class representing an argument field with constant value"""
265 def __init__(self, value):
266 self.value = value
267 self.mask = 0
268 self.sign = value < 0
269
270 def __str__(self):
271 return str(self.value)
272
Peter Maydellaeac22b2023-05-23 13:04:44 +0100273 def str_extract(self, lvalue_formatter):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800274 return str(self.value)
275
276 def __cmp__(self, other):
277 return self.value - other.value
278# end ConstField
279
280
281class FunctionField:
Richard Henderson94597b62019-07-22 17:02:56 -0700282 """Class representing a field passed through a function"""
Richard Henderson568ae7e2017-12-07 12:44:09 -0800283 def __init__(self, func, base):
284 self.mask = base.mask
285 self.sign = base.sign
286 self.base = base
287 self.func = func
288
289 def __str__(self):
290 return self.func + '(' + str(self.base) + ')'
291
Peter Maydellaeac22b2023-05-23 13:04:44 +0100292 def str_extract(self, lvalue_formatter):
293 return (self.func + '(ctx, '
294 + self.base.str_extract(lvalue_formatter) + ')')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800295
296 def __eq__(self, other):
297 return self.func == other.func and self.base == other.base
298
299 def __ne__(self, other):
300 return not self.__eq__(other)
301# end FunctionField
302
303
Richard Henderson94597b62019-07-22 17:02:56 -0700304class ParameterField:
305 """Class representing a pseudo-field read from a function"""
306 def __init__(self, func):
307 self.mask = 0
308 self.sign = 0
309 self.func = func
310
311 def __str__(self):
312 return self.func
313
Peter Maydellaeac22b2023-05-23 13:04:44 +0100314 def str_extract(self, lvalue_formatter):
Richard Henderson94597b62019-07-22 17:02:56 -0700315 return self.func + '(ctx)'
316
317 def __eq__(self, other):
318 return self.func == other.func
319
320 def __ne__(self, other):
321 return not self.__eq__(other)
322# end ParameterField
323
324
Richard Henderson568ae7e2017-12-07 12:44:09 -0800325class Arguments:
326 """Class representing the extracted fields of a format"""
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700327 def __init__(self, nm, flds, types, extern):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800328 self.name = nm
Richard Hendersonabd04f92018-10-23 10:26:25 +0100329 self.extern = extern
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700330 self.fields = flds
331 self.types = types
Richard Henderson568ae7e2017-12-07 12:44:09 -0800332
333 def __str__(self):
334 return self.name + ' ' + str(self.fields)
335
336 def struct_name(self):
337 return 'arg_' + self.name
338
339 def output_def(self):
Richard Hendersonabd04f92018-10-23 10:26:25 +0100340 if not self.extern:
341 output('typedef struct {\n')
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700342 for (n, t) in zip(self.fields, self.types):
343 output(f' {t} {n};\n')
Richard Hendersonabd04f92018-10-23 10:26:25 +0100344 output('} ', self.struct_name(), ';\n\n')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800345# end Arguments
346
347
348class General:
349 """Common code between instruction formats and instruction patterns"""
Richard Henderson17560e92019-01-30 18:01:29 -0800350 def __init__(self, name, lineno, base, fixb, fixm, udfm, fldm, flds, w):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800351 self.name = name
Richard Henderson6699ae62018-10-26 14:59:43 +0100352 self.file = input_file
Richard Henderson568ae7e2017-12-07 12:44:09 -0800353 self.lineno = lineno
354 self.base = base
355 self.fixedbits = fixb
356 self.fixedmask = fixm
357 self.undefmask = udfm
358 self.fieldmask = fldm
359 self.fields = flds
Richard Henderson17560e92019-01-30 18:01:29 -0800360 self.width = w
Richard Henderson568ae7e2017-12-07 12:44:09 -0800361
362 def __str__(self):
Richard Henderson0eff2df2019-02-23 11:35:36 -0800363 return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800364
365 def str1(self, i):
366 return str_indent(i) + self.__str__()
Peter Maydellaeac22b2023-05-23 13:04:44 +0100367
368 def output_fields(self, indent, lvalue_formatter):
369 for n, f in self.fields.items():
370 output(indent, lvalue_formatter(n), ' = ',
371 f.str_extract(lvalue_formatter), ';\n')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800372# end General
373
374
375class Format(General):
376 """Class representing an instruction format"""
377
378 def extract_name(self):
Richard Henderson71ecf792019-02-28 14:45:50 -0800379 global decode_function
380 return decode_function + '_extract_' + self.name
Richard Henderson568ae7e2017-12-07 12:44:09 -0800381
382 def output_extract(self):
Richard Henderson451e4ff2019-03-20 19:21:31 -0700383 output('static void ', self.extract_name(), '(DisasContext *ctx, ',
Richard Henderson568ae7e2017-12-07 12:44:09 -0800384 self.base.struct_name(), ' *a, ', insntype, ' insn)\n{\n')
Peter Maydellaeac22b2023-05-23 13:04:44 +0100385 self.output_fields(str_indent(4), lambda n: 'a->' + n)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800386 output('}\n\n')
387# end Format
388
389
390class Pattern(General):
391 """Class representing an instruction pattern"""
392
393 def output_decl(self):
394 global translate_scope
395 global translate_prefix
396 output('typedef ', self.base.base.struct_name(),
397 ' arg_', self.name, ';\n')
Richard Henderson76805592018-03-02 10:45:35 +0000398 output(translate_scope, 'bool ', translate_prefix, '_', self.name,
Richard Henderson3a7be552018-10-23 11:05:27 +0100399 '(DisasContext *ctx, arg_', self.name, ' *a);\n')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800400
401 def output_code(self, i, extracted, outerbits, outermask):
402 global translate_prefix
403 ind = str_indent(i)
404 arg = self.base.base.name
Richard Henderson6699ae62018-10-26 14:59:43 +0100405 output(ind, '/* ', self.file, ':', str(self.lineno), ' */\n')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800406 if not extracted:
Richard Henderson451e4ff2019-03-20 19:21:31 -0700407 output(ind, self.base.extract_name(),
408 '(ctx, &u.f_', arg, ', insn);\n')
Peter Maydellaeac22b2023-05-23 13:04:44 +0100409 self.output_fields(ind, lambda n: 'u.f_' + arg + '.' + n)
Richard Hendersoneb6b87f2019-02-23 08:57:46 -0800410 output(ind, 'if (', translate_prefix, '_', self.name,
411 '(ctx, &u.f_', arg, ')) return true;\n')
Richard Henderson08561fc2020-05-17 10:14:11 -0700412
413 # Normal patterns do not have children.
414 def build_tree(self):
415 return
416 def prop_masks(self):
417 return
418 def prop_format(self):
419 return
420 def prop_width(self):
421 return
422
Richard Henderson568ae7e2017-12-07 12:44:09 -0800423# end Pattern
424
425
Richard Hendersondf630442020-05-16 11:19:45 -0700426class MultiPattern(General):
427 """Class representing a set of instruction patterns"""
428
Richard Henderson08561fc2020-05-17 10:14:11 -0700429 def __init__(self, lineno):
Richard Hendersondf630442020-05-16 11:19:45 -0700430 self.file = input_file
431 self.lineno = lineno
Richard Henderson08561fc2020-05-17 10:14:11 -0700432 self.pats = []
Richard Hendersondf630442020-05-16 11:19:45 -0700433 self.base = None
434 self.fixedbits = 0
435 self.fixedmask = 0
436 self.undefmask = 0
437 self.width = None
438
439 def __str__(self):
440 r = 'group'
441 if self.fixedbits is not None:
442 r += ' ' + str_match_bits(self.fixedbits, self.fixedmask)
443 return r
444
445 def output_decl(self):
446 for p in self.pats:
447 p.output_decl()
Richard Henderson08561fc2020-05-17 10:14:11 -0700448
449 def prop_masks(self):
450 global insnmask
451
452 fixedmask = insnmask
453 undefmask = insnmask
454
455 # Collect fixedmask/undefmask for all of the children.
456 for p in self.pats:
457 p.prop_masks()
458 fixedmask &= p.fixedmask
459 undefmask &= p.undefmask
460
461 # Widen fixedmask until all fixedbits match
462 repeat = True
463 fixedbits = 0
464 while repeat and fixedmask != 0:
465 fixedbits = None
466 for p in self.pats:
467 thisbits = p.fixedbits & fixedmask
468 if fixedbits is None:
469 fixedbits = thisbits
470 elif fixedbits != thisbits:
471 fixedmask &= ~(fixedbits ^ thisbits)
472 break
473 else:
474 repeat = False
475
476 self.fixedbits = fixedbits
477 self.fixedmask = fixedmask
478 self.undefmask = undefmask
479
480 def build_tree(self):
481 for p in self.pats:
482 p.build_tree()
483
484 def prop_format(self):
485 for p in self.pats:
Richard Henderson2fd2eb52023-05-25 18:45:43 -0700486 p.prop_format()
Richard Henderson08561fc2020-05-17 10:14:11 -0700487
488 def prop_width(self):
489 width = None
490 for p in self.pats:
491 p.prop_width()
492 if width is None:
493 width = p.width
494 elif width != p.width:
495 error_with_file(self.file, self.lineno,
496 'width mismatch in patterns within braces')
497 self.width = width
498
Richard Hendersondf630442020-05-16 11:19:45 -0700499# end MultiPattern
500
501
502class IncMultiPattern(MultiPattern):
Richard Henderson0eff2df2019-02-23 11:35:36 -0800503 """Class representing an overlapping set of instruction patterns"""
504
Richard Henderson0eff2df2019-02-23 11:35:36 -0800505 def output_code(self, i, extracted, outerbits, outermask):
506 global translate_prefix
507 ind = str_indent(i)
508 for p in self.pats:
509 if outermask != p.fixedmask:
510 innermask = p.fixedmask & ~outermask
511 innerbits = p.fixedbits & ~outermask
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700512 output(ind, f'if ((insn & {whexC(innermask)}) == {whexC(innerbits)}) {{\n')
513 output(ind, f' /* {str_match_bits(p.fixedbits, p.fixedmask)} */\n')
Richard Henderson0eff2df2019-02-23 11:35:36 -0800514 p.output_code(i + 4, extracted, p.fixedbits, p.fixedmask)
515 output(ind, '}\n')
516 else:
517 p.output_code(i, extracted, p.fixedbits, p.fixedmask)
Richard Hendersonf2604472023-05-25 18:50:58 -0700518
519 def build_tree(self):
520 if not self.pats:
521 error_with_file(self.file, self.lineno, 'empty pattern group')
522 super().build_tree()
523
Richard Henderson040145c2020-05-16 10:50:43 -0700524#end IncMultiPattern
Richard Henderson0eff2df2019-02-23 11:35:36 -0800525
526
Richard Henderson08561fc2020-05-17 10:14:11 -0700527class Tree:
528 """Class representing a node in a decode tree"""
529
530 def __init__(self, fm, tm):
531 self.fixedmask = fm
532 self.thismask = tm
533 self.subs = []
534 self.base = None
535
536 def str1(self, i):
537 ind = str_indent(i)
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700538 r = ind + whex(self.fixedmask)
Richard Henderson08561fc2020-05-17 10:14:11 -0700539 if self.format:
540 r += ' ' + self.format.name
541 r += ' [\n'
542 for (b, s) in self.subs:
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700543 r += ind + f' {whex(b)}:\n'
Richard Henderson08561fc2020-05-17 10:14:11 -0700544 r += s.str1(i + 4) + '\n'
545 r += ind + ']'
546 return r
547
548 def __str__(self):
549 return self.str1(0)
550
551 def output_code(self, i, extracted, outerbits, outermask):
552 ind = str_indent(i)
553
554 # If we identified all nodes below have the same format,
555 # extract the fields now.
556 if not extracted and self.base:
557 output(ind, self.base.extract_name(),
558 '(ctx, &u.f_', self.base.base.name, ', insn);\n')
559 extracted = True
560
561 # Attempt to aid the compiler in producing compact switch statements.
562 # If the bits in the mask are contiguous, extract them.
563 sh = is_contiguous(self.thismask)
564 if sh > 0:
565 # Propagate SH down into the local functions.
566 def str_switch(b, sh=sh):
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700567 return f'(insn >> {sh}) & {b >> sh:#x}'
Richard Henderson08561fc2020-05-17 10:14:11 -0700568
569 def str_case(b, sh=sh):
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700570 return hex(b >> sh)
Richard Henderson08561fc2020-05-17 10:14:11 -0700571 else:
572 def str_switch(b):
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700573 return f'insn & {whexC(b)}'
Richard Henderson08561fc2020-05-17 10:14:11 -0700574
575 def str_case(b):
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700576 return whexC(b)
Richard Henderson08561fc2020-05-17 10:14:11 -0700577
578 output(ind, 'switch (', str_switch(self.thismask), ') {\n')
579 for b, s in sorted(self.subs):
580 assert (self.thismask & ~s.fixedmask) == 0
581 innermask = outermask | self.thismask
582 innerbits = outerbits | b
583 output(ind, 'case ', str_case(b), ':\n')
584 output(ind, ' /* ',
585 str_match_bits(innerbits, innermask), ' */\n')
586 s.output_code(i + 4, extracted, innerbits, innermask)
Peter Maydell514101c2020-10-19 16:12:52 +0100587 output(ind, ' break;\n')
Richard Henderson08561fc2020-05-17 10:14:11 -0700588 output(ind, '}\n')
589# end Tree
590
591
592class ExcMultiPattern(MultiPattern):
593 """Class representing a non-overlapping set of instruction patterns"""
594
595 def output_code(self, i, extracted, outerbits, outermask):
596 # Defer everything to our decomposed Tree node
597 self.tree.output_code(i, extracted, outerbits, outermask)
598
599 @staticmethod
600 def __build_tree(pats, outerbits, outermask):
601 # Find the intersection of all remaining fixedmask.
602 innermask = ~outermask & insnmask
603 for i in pats:
604 innermask &= i.fixedmask
605
606 if innermask == 0:
607 # Edge condition: One pattern covers the entire insnmask
608 if len(pats) == 1:
609 t = Tree(outermask, innermask)
610 t.subs.append((0, pats[0]))
611 return t
612
613 text = 'overlapping patterns:'
614 for p in pats:
615 text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
616 error_with_file(pats[0].file, pats[0].lineno, text)
617
618 fullmask = outermask | innermask
619
620 # Sort each element of pats into the bin selected by the mask.
621 bins = {}
622 for i in pats:
623 fb = i.fixedbits & innermask
624 if fb in bins:
625 bins[fb].append(i)
626 else:
627 bins[fb] = [i]
628
629 # We must recurse if any bin has more than one element or if
630 # the single element in the bin has not been fully matched.
631 t = Tree(fullmask, innermask)
632
633 for b, l in bins.items():
634 s = l[0]
635 if len(l) > 1 or s.fixedmask & ~fullmask != 0:
636 s = ExcMultiPattern.__build_tree(l, b | outerbits, fullmask)
637 t.subs.append((b, s))
638
639 return t
640
641 def build_tree(self):
Richard Henderson2fd2eb52023-05-25 18:45:43 -0700642 super().build_tree()
Richard Henderson08561fc2020-05-17 10:14:11 -0700643 self.tree = self.__build_tree(self.pats, self.fixedbits,
644 self.fixedmask)
645
646 @staticmethod
647 def __prop_format(tree):
648 """Propagate Format objects into the decode tree"""
649
650 # Depth first search.
651 for (b, s) in tree.subs:
652 if isinstance(s, Tree):
653 ExcMultiPattern.__prop_format(s)
654
655 # If all entries in SUBS have the same format, then
656 # propagate that into the tree.
657 f = None
658 for (b, s) in tree.subs:
659 if f is None:
660 f = s.base
661 if f is None:
662 return
663 if f is not s.base:
664 return
665 tree.base = f
666
667 def prop_format(self):
668 super().prop_format()
669 self.__prop_format(self.tree)
670
671# end ExcMultiPattern
672
673
Richard Henderson568ae7e2017-12-07 12:44:09 -0800674def parse_field(lineno, name, toks):
675 """Parse one instruction field from TOKS at LINENO"""
676 global fields
Richard Henderson568ae7e2017-12-07 12:44:09 -0800677 global insnwidth
678
679 # A "simple" field will have only one entry;
680 # a "multifield" will have several.
681 subs = []
682 width = 0
683 func = None
684 for t in toks:
Richard Hendersonacfdd232020-09-03 12:23:34 -0700685 if re.match('^!function=', t):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800686 if func:
687 error(lineno, 'duplicate function')
688 func = t.split('=')
689 func = func[1]
690 continue
691
John Snow2d110c12020-05-13 23:52:30 -0400692 if re.fullmatch('[0-9]+:s[0-9]+', t):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800693 # Signed field extract
694 subtoks = t.split(':s')
695 sign = True
John Snow2d110c12020-05-13 23:52:30 -0400696 elif re.fullmatch('[0-9]+:[0-9]+', t):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800697 # Unsigned field extract
698 subtoks = t.split(':')
699 sign = False
700 else:
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700701 error(lineno, f'invalid field token "{t}"')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800702 po = int(subtoks[0])
703 le = int(subtoks[1])
704 if po + le > insnwidth:
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700705 error(lineno, f'field {t} too large')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800706 f = Field(sign, po, le)
707 subs.append(f)
708 width += le
709
710 if width > insnwidth:
711 error(lineno, 'field too large')
Richard Henderson94597b62019-07-22 17:02:56 -0700712 if len(subs) == 0:
713 if func:
714 f = ParameterField(func)
715 else:
716 error(lineno, 'field with no value')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800717 else:
Richard Henderson94597b62019-07-22 17:02:56 -0700718 if len(subs) == 1:
719 f = subs[0]
720 else:
721 mask = 0
722 for s in subs:
723 if mask & s.mask:
724 error(lineno, 'field components overlap')
725 mask |= s.mask
726 f = MultiField(subs, mask)
727 if func:
728 f = FunctionField(func, f)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800729
730 if name in fields:
731 error(lineno, 'duplicate field', name)
732 fields[name] = f
733# end parse_field
734
735
736def parse_arguments(lineno, name, toks):
737 """Parse one argument set from TOKS at LINENO"""
738 global arguments
Richard Hendersonacfdd232020-09-03 12:23:34 -0700739 global re_C_ident
Richard Hendersonc6920792019-08-09 08:12:50 -0700740 global anyextern
Richard Henderson568ae7e2017-12-07 12:44:09 -0800741
742 flds = []
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700743 types = []
Richard Hendersonabd04f92018-10-23 10:26:25 +0100744 extern = False
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700745 for n in toks:
746 if re.fullmatch('!extern', n):
Richard Hendersonabd04f92018-10-23 10:26:25 +0100747 extern = True
Richard Hendersonc6920792019-08-09 08:12:50 -0700748 anyextern = True
Richard Hendersonabd04f92018-10-23 10:26:25 +0100749 continue
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700750 if re.fullmatch(re_C_ident + ':' + re_C_ident, n):
751 (n, t) = n.split(':')
752 elif re.fullmatch(re_C_ident, n):
753 t = 'int'
754 else:
755 error(lineno, f'invalid argument set token "{n}"')
756 if n in flds:
757 error(lineno, f'duplicate argument "{n}"')
758 flds.append(n)
759 types.append(t)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800760
761 if name in arguments:
762 error(lineno, 'duplicate argument set', name)
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700763 arguments[name] = Arguments(name, flds, types, extern)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800764# end parse_arguments
765
766
767def lookup_field(lineno, name):
768 global fields
769 if name in fields:
770 return fields[name]
771 error(lineno, 'undefined field', name)
772
773
774def add_field(lineno, flds, new_name, f):
775 if new_name in flds:
776 error(lineno, 'duplicate field', new_name)
777 flds[new_name] = f
778 return flds
779
780
781def add_field_byname(lineno, flds, new_name, old_name):
782 return add_field(lineno, flds, new_name, lookup_field(lineno, old_name))
783
784
785def infer_argument_set(flds):
786 global arguments
Richard Hendersonabd04f92018-10-23 10:26:25 +0100787 global decode_function
Richard Henderson568ae7e2017-12-07 12:44:09 -0800788
789 for arg in arguments.values():
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700790 if eq_fields_for_args(flds, arg):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800791 return arg
792
Richard Hendersonabd04f92018-10-23 10:26:25 +0100793 name = decode_function + str(len(arguments))
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700794 arg = Arguments(name, flds.keys(), ['int'] * len(flds), False)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800795 arguments[name] = arg
796 return arg
797
798
Richard Henderson17560e92019-01-30 18:01:29 -0800799def infer_format(arg, fieldmask, flds, width):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800800 global arguments
801 global formats
Richard Hendersonabd04f92018-10-23 10:26:25 +0100802 global decode_function
Richard Henderson568ae7e2017-12-07 12:44:09 -0800803
804 const_flds = {}
805 var_flds = {}
806 for n, c in flds.items():
807 if c is ConstField:
808 const_flds[n] = c
809 else:
810 var_flds[n] = c
811
812 # Look for an existing format with the same argument set and fields
813 for fmt in formats.values():
814 if arg and fmt.base != arg:
815 continue
816 if fieldmask != fmt.fieldmask:
817 continue
Richard Henderson17560e92019-01-30 18:01:29 -0800818 if width != fmt.width:
819 continue
Richard Henderson568ae7e2017-12-07 12:44:09 -0800820 if not eq_fields_for_fmts(flds, fmt.fields):
821 continue
822 return (fmt, const_flds)
823
Richard Hendersonabd04f92018-10-23 10:26:25 +0100824 name = decode_function + '_Fmt_' + str(len(formats))
Richard Henderson568ae7e2017-12-07 12:44:09 -0800825 if not arg:
826 arg = infer_argument_set(flds)
827
Richard Henderson17560e92019-01-30 18:01:29 -0800828 fmt = Format(name, 0, arg, 0, 0, 0, fieldmask, var_flds, width)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800829 formats[name] = fmt
830
831 return (fmt, const_flds)
832# end infer_format
833
834
Richard Henderson08561fc2020-05-17 10:14:11 -0700835def parse_generic(lineno, parent_pat, name, toks):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800836 """Parse one instruction format from TOKS at LINENO"""
837 global fields
838 global arguments
839 global formats
Richard Henderson0eff2df2019-02-23 11:35:36 -0800840 global allpatterns
Richard Hendersonacfdd232020-09-03 12:23:34 -0700841 global re_arg_ident
842 global re_fld_ident
843 global re_fmt_ident
844 global re_C_ident
Richard Henderson568ae7e2017-12-07 12:44:09 -0800845 global insnwidth
846 global insnmask
Richard Henderson17560e92019-01-30 18:01:29 -0800847 global variablewidth
Richard Henderson568ae7e2017-12-07 12:44:09 -0800848
Richard Henderson08561fc2020-05-17 10:14:11 -0700849 is_format = parent_pat is None
850
Richard Henderson568ae7e2017-12-07 12:44:09 -0800851 fixedmask = 0
852 fixedbits = 0
853 undefmask = 0
854 width = 0
855 flds = {}
856 arg = None
857 fmt = None
858 for t in toks:
zhaolichang65fdb3c2020-09-17 15:50:23 +0800859 # '&Foo' gives a format an explicit argument set.
Richard Hendersonacfdd232020-09-03 12:23:34 -0700860 if re.fullmatch(re_arg_ident, t):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800861 tt = t[1:]
862 if arg:
863 error(lineno, 'multiple argument sets')
864 if tt in arguments:
865 arg = arguments[tt]
866 else:
867 error(lineno, 'undefined argument set', t)
868 continue
869
870 # '@Foo' gives a pattern an explicit format.
Richard Hendersonacfdd232020-09-03 12:23:34 -0700871 if re.fullmatch(re_fmt_ident, t):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800872 tt = t[1:]
873 if fmt:
874 error(lineno, 'multiple formats')
875 if tt in formats:
876 fmt = formats[tt]
877 else:
878 error(lineno, 'undefined format', t)
879 continue
880
881 # '%Foo' imports a field.
Richard Hendersonacfdd232020-09-03 12:23:34 -0700882 if re.fullmatch(re_fld_ident, t):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800883 tt = t[1:]
884 flds = add_field_byname(lineno, flds, tt, tt)
885 continue
886
887 # 'Foo=%Bar' imports a field with a different name.
Richard Hendersonacfdd232020-09-03 12:23:34 -0700888 if re.fullmatch(re_C_ident + '=' + re_fld_ident, t):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800889 (fname, iname) = t.split('=%')
890 flds = add_field_byname(lineno, flds, fname, iname)
891 continue
892
893 # 'Foo=number' sets an argument field to a constant value
Richard Hendersonacfdd232020-09-03 12:23:34 -0700894 if re.fullmatch(re_C_ident + '=[+-]?[0-9]+', t):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800895 (fname, value) = t.split('=')
896 value = int(value)
897 flds = add_field(lineno, flds, fname, ConstField(value))
898 continue
899
900 # Pattern of 0s, 1s, dots and dashes indicate required zeros,
901 # required ones, or dont-cares.
John Snow2d110c12020-05-13 23:52:30 -0400902 if re.fullmatch('[01.-]+', t):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800903 shift = len(t)
904 fms = t.replace('0', '1')
905 fms = fms.replace('.', '0')
906 fms = fms.replace('-', '0')
907 fbs = t.replace('.', '0')
908 fbs = fbs.replace('-', '0')
909 ubm = t.replace('1', '0')
910 ubm = ubm.replace('.', '0')
911 ubm = ubm.replace('-', '1')
912 fms = int(fms, 2)
913 fbs = int(fbs, 2)
914 ubm = int(ubm, 2)
915 fixedbits = (fixedbits << shift) | fbs
916 fixedmask = (fixedmask << shift) | fms
917 undefmask = (undefmask << shift) | ubm
918 # Otherwise, fieldname:fieldwidth
Richard Hendersonacfdd232020-09-03 12:23:34 -0700919 elif re.fullmatch(re_C_ident + ':s?[0-9]+', t):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800920 (fname, flen) = t.split(':')
921 sign = False
922 if flen[0] == 's':
923 sign = True
924 flen = flen[1:]
925 shift = int(flen, 10)
Richard Henderson2decfc92019-03-05 15:34:41 -0800926 if shift + width > insnwidth:
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700927 error(lineno, f'field {fname} exceeds insnwidth')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800928 f = Field(sign, insnwidth - width - shift, shift)
929 flds = add_field(lineno, flds, fname, f)
930 fixedbits <<= shift
931 fixedmask <<= shift
932 undefmask <<= shift
933 else:
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700934 error(lineno, f'invalid token "{t}"')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800935 width += shift
936
Richard Henderson17560e92019-01-30 18:01:29 -0800937 if variablewidth and width < insnwidth and width % 8 == 0:
938 shift = insnwidth - width
939 fixedbits <<= shift
940 fixedmask <<= shift
941 undefmask <<= shift
942 undefmask |= (1 << shift) - 1
943
Richard Henderson568ae7e2017-12-07 12:44:09 -0800944 # We should have filled in all of the bits of the instruction.
Richard Henderson17560e92019-01-30 18:01:29 -0800945 elif not (is_format and width == 0) and width != insnwidth:
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700946 error(lineno, f'definition has {width} bits')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800947
zhaolichang65fdb3c2020-09-17 15:50:23 +0800948 # Do not check for fields overlapping fields; one valid usage
Richard Henderson568ae7e2017-12-07 12:44:09 -0800949 # is to be able to duplicate fields via import.
950 fieldmask = 0
951 for f in flds.values():
952 fieldmask |= f.mask
953
954 # Fix up what we've parsed to match either a format or a pattern.
955 if is_format:
956 # Formats cannot reference formats.
957 if fmt:
958 error(lineno, 'format referencing format')
959 # If an argument set is given, then there should be no fields
960 # without a place to store it.
961 if arg:
962 for f in flds.keys():
963 if f not in arg.fields:
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700964 error(lineno, f'field {f} not in argument set {arg.name}')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800965 else:
966 arg = infer_argument_set(flds)
967 if name in formats:
968 error(lineno, 'duplicate format name', name)
969 fmt = Format(name, lineno, arg, fixedbits, fixedmask,
Richard Henderson17560e92019-01-30 18:01:29 -0800970 undefmask, fieldmask, flds, width)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800971 formats[name] = fmt
972 else:
973 # Patterns can reference a format ...
974 if fmt:
975 # ... but not an argument simultaneously
976 if arg:
977 error(lineno, 'pattern specifies both format and argument set')
978 if fixedmask & fmt.fixedmask:
979 error(lineno, 'pattern fixed bits overlap format fixed bits')
Richard Henderson17560e92019-01-30 18:01:29 -0800980 if width != fmt.width:
981 error(lineno, 'pattern uses format of different width')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800982 fieldmask |= fmt.fieldmask
983 fixedbits |= fmt.fixedbits
984 fixedmask |= fmt.fixedmask
985 undefmask |= fmt.undefmask
986 else:
Richard Henderson17560e92019-01-30 18:01:29 -0800987 (fmt, flds) = infer_format(arg, fieldmask, flds, width)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800988 arg = fmt.base
989 for f in flds.keys():
990 if f not in arg.fields:
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700991 error(lineno, f'field {f} not in argument set {arg.name}')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800992 if f in fmt.fields.keys():
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700993 error(lineno, f'field {f} set by format and pattern')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800994 for f in arg.fields:
995 if f not in flds.keys() and f not in fmt.fields.keys():
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700996 error(lineno, f'field {f} not initialized')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800997 pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
Richard Henderson17560e92019-01-30 18:01:29 -0800998 undefmask, fieldmask, flds, width)
Richard Henderson08561fc2020-05-17 10:14:11 -0700999 parent_pat.pats.append(pat)
Richard Henderson0eff2df2019-02-23 11:35:36 -08001000 allpatterns.append(pat)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001001
1002 # Validate the masks that we have assembled.
1003 if fieldmask & fixedmask:
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001004 error(lineno, 'fieldmask overlaps fixedmask ',
1005 f'({whex(fieldmask)} & {whex(fixedmask)})')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001006 if fieldmask & undefmask:
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001007 error(lineno, 'fieldmask overlaps undefmask ',
1008 f'({whex(fieldmask)} & {whex(undefmask)})')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001009 if fixedmask & undefmask:
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001010 error(lineno, 'fixedmask overlaps undefmask ',
1011 f'({whex(fixedmask)} & {whex(undefmask)})')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001012 if not is_format:
1013 allbits = fieldmask | fixedmask | undefmask
1014 if allbits != insnmask:
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001015 error(lineno, 'bits left unspecified ',
1016 f'({whex(allbits ^ insnmask)})')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001017# end parse_general
1018
Richard Henderson0eff2df2019-02-23 11:35:36 -08001019
Richard Henderson08561fc2020-05-17 10:14:11 -07001020def parse_file(f, parent_pat):
Richard Henderson568ae7e2017-12-07 12:44:09 -08001021 """Parse all of the patterns within a file"""
Richard Hendersonacfdd232020-09-03 12:23:34 -07001022 global re_arg_ident
1023 global re_fld_ident
1024 global re_fmt_ident
1025 global re_pat_ident
Richard Henderson568ae7e2017-12-07 12:44:09 -08001026
1027 # Read all of the lines of the file. Concatenate lines
1028 # ending in backslash; discard empty lines and comments.
1029 toks = []
1030 lineno = 0
Richard Henderson0eff2df2019-02-23 11:35:36 -08001031 nesting = 0
Richard Henderson08561fc2020-05-17 10:14:11 -07001032 nesting_pats = []
Richard Henderson0eff2df2019-02-23 11:35:36 -08001033
Richard Henderson568ae7e2017-12-07 12:44:09 -08001034 for line in f:
1035 lineno += 1
1036
Richard Henderson0eff2df2019-02-23 11:35:36 -08001037 # Expand and strip spaces, to find indent.
1038 line = line.rstrip()
1039 line = line.expandtabs()
1040 len1 = len(line)
1041 line = line.lstrip()
1042 len2 = len(line)
1043
Richard Henderson568ae7e2017-12-07 12:44:09 -08001044 # Discard comments
1045 end = line.find('#')
1046 if end >= 0:
1047 line = line[:end]
1048
1049 t = line.split()
1050 if len(toks) != 0:
1051 # Next line after continuation
1052 toks.extend(t)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001053 else:
Richard Henderson0eff2df2019-02-23 11:35:36 -08001054 # Allow completely blank lines.
1055 if len1 == 0:
1056 continue
1057 indent = len1 - len2
1058 # Empty line due to comment.
1059 if len(t) == 0:
1060 # Indentation must be correct, even for comment lines.
1061 if indent != nesting:
1062 error(lineno, 'indentation ', indent, ' != ', nesting)
1063 continue
1064 start_lineno = lineno
Richard Henderson568ae7e2017-12-07 12:44:09 -08001065 toks = t
1066
1067 # Continuation?
1068 if toks[-1] == '\\':
1069 toks.pop()
1070 continue
1071
Richard Henderson568ae7e2017-12-07 12:44:09 -08001072 name = toks[0]
1073 del toks[0]
1074
Richard Henderson0eff2df2019-02-23 11:35:36 -08001075 # End nesting?
Richard Henderson067e8b02020-05-18 08:45:32 -07001076 if name == '}' or name == ']':
Richard Henderson0eff2df2019-02-23 11:35:36 -08001077 if len(toks) != 0:
1078 error(start_lineno, 'extra tokens after close brace')
Richard Henderson08561fc2020-05-17 10:14:11 -07001079
Richard Henderson067e8b02020-05-18 08:45:32 -07001080 # Make sure { } and [ ] nest properly.
1081 if (name == '}') != isinstance(parent_pat, IncMultiPattern):
1082 error(lineno, 'mismatched close brace')
1083
Richard Henderson08561fc2020-05-17 10:14:11 -07001084 try:
1085 parent_pat = nesting_pats.pop()
1086 except:
Richard Henderson067e8b02020-05-18 08:45:32 -07001087 error(lineno, 'extra close brace')
Richard Henderson08561fc2020-05-17 10:14:11 -07001088
Richard Henderson0eff2df2019-02-23 11:35:36 -08001089 nesting -= 2
1090 if indent != nesting:
Richard Henderson08561fc2020-05-17 10:14:11 -07001091 error(lineno, 'indentation ', indent, ' != ', nesting)
1092
Richard Henderson0eff2df2019-02-23 11:35:36 -08001093 toks = []
1094 continue
1095
1096 # Everything else should have current indentation.
1097 if indent != nesting:
1098 error(start_lineno, 'indentation ', indent, ' != ', nesting)
1099
1100 # Start nesting?
Richard Henderson067e8b02020-05-18 08:45:32 -07001101 if name == '{' or name == '[':
Richard Henderson0eff2df2019-02-23 11:35:36 -08001102 if len(toks) != 0:
1103 error(start_lineno, 'extra tokens after open brace')
Richard Henderson08561fc2020-05-17 10:14:11 -07001104
Richard Henderson067e8b02020-05-18 08:45:32 -07001105 if name == '{':
1106 nested_pat = IncMultiPattern(start_lineno)
1107 else:
1108 nested_pat = ExcMultiPattern(start_lineno)
Richard Henderson08561fc2020-05-17 10:14:11 -07001109 parent_pat.pats.append(nested_pat)
1110 nesting_pats.append(parent_pat)
1111 parent_pat = nested_pat
1112
Richard Henderson0eff2df2019-02-23 11:35:36 -08001113 nesting += 2
1114 toks = []
1115 continue
1116
Richard Henderson568ae7e2017-12-07 12:44:09 -08001117 # Determine the type of object needing to be parsed.
Richard Hendersonacfdd232020-09-03 12:23:34 -07001118 if re.fullmatch(re_fld_ident, name):
Richard Henderson0eff2df2019-02-23 11:35:36 -08001119 parse_field(start_lineno, name[1:], toks)
Richard Hendersonacfdd232020-09-03 12:23:34 -07001120 elif re.fullmatch(re_arg_ident, name):
Richard Henderson0eff2df2019-02-23 11:35:36 -08001121 parse_arguments(start_lineno, name[1:], toks)
Richard Hendersonacfdd232020-09-03 12:23:34 -07001122 elif re.fullmatch(re_fmt_ident, name):
Richard Henderson08561fc2020-05-17 10:14:11 -07001123 parse_generic(start_lineno, None, name[1:], toks)
Richard Hendersonacfdd232020-09-03 12:23:34 -07001124 elif re.fullmatch(re_pat_ident, name):
Richard Henderson08561fc2020-05-17 10:14:11 -07001125 parse_generic(start_lineno, parent_pat, name, toks)
Richard Hendersonacfdd232020-09-03 12:23:34 -07001126 else:
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001127 error(lineno, f'invalid token "{name}"')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001128 toks = []
Richard Henderson067e8b02020-05-18 08:45:32 -07001129
1130 if nesting != 0:
1131 error(lineno, 'missing close brace')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001132# end parse_file
1133
1134
Richard Henderson70e07112019-01-31 11:34:11 -08001135class SizeTree:
1136 """Class representing a node in a size decode tree"""
1137
1138 def __init__(self, m, w):
1139 self.mask = m
1140 self.subs = []
1141 self.base = None
1142 self.width = w
1143
1144 def str1(self, i):
1145 ind = str_indent(i)
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001146 r = ind + whex(self.mask) + ' [\n'
Richard Henderson70e07112019-01-31 11:34:11 -08001147 for (b, s) in self.subs:
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001148 r += ind + f' {whex(b)}:\n'
Richard Henderson70e07112019-01-31 11:34:11 -08001149 r += s.str1(i + 4) + '\n'
1150 r += ind + ']'
1151 return r
1152
1153 def __str__(self):
1154 return self.str1(0)
1155
1156 def output_code(self, i, extracted, outerbits, outermask):
1157 ind = str_indent(i)
1158
1159 # If we need to load more bytes to test, do so now.
1160 if extracted < self.width:
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001161 output(ind, f'insn = {decode_function}_load_bytes',
1162 f'(ctx, insn, {extracted // 8}, {self.width // 8});\n')
Richard Henderson70e07112019-01-31 11:34:11 -08001163 extracted = self.width
1164
1165 # Attempt to aid the compiler in producing compact switch statements.
1166 # If the bits in the mask are contiguous, extract them.
1167 sh = is_contiguous(self.mask)
1168 if sh > 0:
1169 # Propagate SH down into the local functions.
1170 def str_switch(b, sh=sh):
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001171 return f'(insn >> {sh}) & {b >> sh:#x}'
Richard Henderson70e07112019-01-31 11:34:11 -08001172
1173 def str_case(b, sh=sh):
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001174 return hex(b >> sh)
Richard Henderson70e07112019-01-31 11:34:11 -08001175 else:
1176 def str_switch(b):
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001177 return f'insn & {whexC(b)}'
Richard Henderson70e07112019-01-31 11:34:11 -08001178
1179 def str_case(b):
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001180 return whexC(b)
Richard Henderson70e07112019-01-31 11:34:11 -08001181
1182 output(ind, 'switch (', str_switch(self.mask), ') {\n')
1183 for b, s in sorted(self.subs):
1184 innermask = outermask | self.mask
1185 innerbits = outerbits | b
1186 output(ind, 'case ', str_case(b), ':\n')
1187 output(ind, ' /* ',
1188 str_match_bits(innerbits, innermask), ' */\n')
1189 s.output_code(i + 4, extracted, innerbits, innermask)
1190 output(ind, '}\n')
1191 output(ind, 'return insn;\n')
1192# end SizeTree
1193
1194class SizeLeaf:
1195 """Class representing a leaf node in a size decode tree"""
1196
1197 def __init__(self, m, w):
1198 self.mask = m
1199 self.width = w
1200
1201 def str1(self, i):
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001202 return str_indent(i) + whex(self.mask)
Richard Henderson70e07112019-01-31 11:34:11 -08001203
1204 def __str__(self):
1205 return self.str1(0)
1206
1207 def output_code(self, i, extracted, outerbits, outermask):
1208 global decode_function
1209 ind = str_indent(i)
1210
1211 # If we need to load more bytes, do so now.
1212 if extracted < self.width:
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001213 output(ind, f'insn = {decode_function}_load_bytes',
1214 f'(ctx, insn, {extracted // 8}, {self.width // 8});\n')
Richard Henderson70e07112019-01-31 11:34:11 -08001215 extracted = self.width
1216 output(ind, 'return insn;\n')
1217# end SizeLeaf
1218
1219
1220def build_size_tree(pats, width, outerbits, outermask):
1221 global insnwidth
1222
1223 # Collect the mask of bits that are fixed in this width
1224 innermask = 0xff << (insnwidth - width)
1225 innermask &= ~outermask
1226 minwidth = None
1227 onewidth = True
1228 for i in pats:
1229 innermask &= i.fixedmask
1230 if minwidth is None:
1231 minwidth = i.width
1232 elif minwidth != i.width:
1233 onewidth = False;
1234 if minwidth < i.width:
1235 minwidth = i.width
1236
1237 if onewidth:
1238 return SizeLeaf(innermask, minwidth)
1239
1240 if innermask == 0:
1241 if width < minwidth:
1242 return build_size_tree(pats, width + 8, outerbits, outermask)
1243
1244 pnames = []
1245 for p in pats:
1246 pnames.append(p.name + ':' + p.file + ':' + str(p.lineno))
1247 error_with_file(pats[0].file, pats[0].lineno,
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001248 f'overlapping patterns size {width}:', pnames)
Richard Henderson70e07112019-01-31 11:34:11 -08001249
1250 bins = {}
1251 for i in pats:
1252 fb = i.fixedbits & innermask
1253 if fb in bins:
1254 bins[fb].append(i)
1255 else:
1256 bins[fb] = [i]
1257
1258 fullmask = outermask | innermask
1259 lens = sorted(bins.keys())
1260 if len(lens) == 1:
1261 b = lens[0]
1262 return build_size_tree(bins[b], width + 8, b | outerbits, fullmask)
1263
1264 r = SizeTree(innermask, width)
1265 for b, l in bins.items():
1266 s = build_size_tree(l, width, b | outerbits, fullmask)
1267 r.subs.append((b, s))
1268 return r
1269# end build_size_tree
1270
1271
Richard Henderson70e07112019-01-31 11:34:11 -08001272def prop_size(tree):
1273 """Propagate minimum widths up the decode size tree"""
1274
1275 if isinstance(tree, SizeTree):
1276 min = None
1277 for (b, s) in tree.subs:
1278 width = prop_size(s)
1279 if min is None or min > width:
1280 min = width
1281 assert min >= tree.width
1282 tree.width = min
1283 else:
1284 min = tree.width
1285 return min
1286# end prop_size
1287
1288
Richard Henderson568ae7e2017-12-07 12:44:09 -08001289def main():
1290 global arguments
1291 global formats
Richard Henderson0eff2df2019-02-23 11:35:36 -08001292 global allpatterns
Richard Henderson568ae7e2017-12-07 12:44:09 -08001293 global translate_scope
1294 global translate_prefix
1295 global output_fd
1296 global output_file
1297 global input_file
1298 global insnwidth
1299 global insntype
Bastian Koppelmann83d7c402018-03-19 12:58:46 +01001300 global insnmask
Richard Hendersonabd04f92018-10-23 10:26:25 +01001301 global decode_function
Luis Fernando Fujita Pires60c425f2021-04-07 22:18:49 +00001302 global bitop_width
Richard Henderson17560e92019-01-30 18:01:29 -08001303 global variablewidth
Richard Hendersonc6920792019-08-09 08:12:50 -07001304 global anyextern
Richard Henderson9b5acc52023-05-25 18:04:05 -07001305 global testforerror
Richard Henderson568ae7e2017-12-07 12:44:09 -08001306
Richard Henderson568ae7e2017-12-07 12:44:09 -08001307 decode_scope = 'static '
1308
Richard Hendersoncd3e7fc2019-02-23 17:44:31 -08001309 long_opts = ['decode=', 'translate=', 'output=', 'insnwidth=',
Richard Henderson9b5acc52023-05-25 18:04:05 -07001310 'static-decode=', 'varinsnwidth=', 'test-for-error']
Richard Henderson568ae7e2017-12-07 12:44:09 -08001311 try:
Paolo Bonziniabff1ab2020-08-07 12:10:23 +02001312 (opts, args) = getopt.gnu_getopt(sys.argv[1:], 'o:vw:', long_opts)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001313 except getopt.GetoptError as err:
1314 error(0, err)
1315 for o, a in opts:
1316 if o in ('-o', '--output'):
1317 output_file = a
1318 elif o == '--decode':
1319 decode_function = a
1320 decode_scope = ''
Richard Hendersoncd3e7fc2019-02-23 17:44:31 -08001321 elif o == '--static-decode':
1322 decode_function = a
Richard Henderson568ae7e2017-12-07 12:44:09 -08001323 elif o == '--translate':
1324 translate_prefix = a
1325 translate_scope = ''
Richard Henderson17560e92019-01-30 18:01:29 -08001326 elif o in ('-w', '--insnwidth', '--varinsnwidth'):
1327 if o == '--varinsnwidth':
1328 variablewidth = True
Richard Henderson568ae7e2017-12-07 12:44:09 -08001329 insnwidth = int(a)
1330 if insnwidth == 16:
1331 insntype = 'uint16_t'
1332 insnmask = 0xffff
Luis Fernando Fujita Pires60c425f2021-04-07 22:18:49 +00001333 elif insnwidth == 64:
1334 insntype = 'uint64_t'
1335 insnmask = 0xffffffffffffffff
1336 bitop_width = 64
Richard Henderson568ae7e2017-12-07 12:44:09 -08001337 elif insnwidth != 32:
1338 error(0, 'cannot handle insns of width', insnwidth)
Richard Henderson9b5acc52023-05-25 18:04:05 -07001339 elif o == '--test-for-error':
1340 testforerror = True
Richard Henderson568ae7e2017-12-07 12:44:09 -08001341 else:
1342 assert False, 'unhandled option'
1343
1344 if len(args) < 1:
1345 error(0, 'missing input file')
Richard Henderson08561fc2020-05-17 10:14:11 -07001346
1347 toppat = ExcMultiPattern(0)
1348
Richard Henderson6699ae62018-10-26 14:59:43 +01001349 for filename in args:
1350 input_file = filename
Philippe Mathieu-Daudé4caceca2021-01-10 01:02:40 +01001351 f = open(filename, 'rt', encoding='utf-8')
Richard Henderson08561fc2020-05-17 10:14:11 -07001352 parse_file(f, toppat)
Richard Henderson6699ae62018-10-26 14:59:43 +01001353 f.close()
Richard Henderson568ae7e2017-12-07 12:44:09 -08001354
Richard Henderson08561fc2020-05-17 10:14:11 -07001355 # We do not want to compute masks for toppat, because those masks
1356 # are used as a starting point for build_tree. For toppat, we must
1357 # insist that decode begins from naught.
1358 for i in toppat.pats:
1359 i.prop_masks()
Richard Henderson70e07112019-01-31 11:34:11 -08001360
Richard Henderson08561fc2020-05-17 10:14:11 -07001361 toppat.build_tree()
1362 toppat.prop_format()
1363
1364 if variablewidth:
1365 for i in toppat.pats:
1366 i.prop_width()
1367 stree = build_size_tree(toppat.pats, 8, 0, 0)
1368 prop_size(stree)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001369
1370 if output_file:
Philippe Mathieu-Daudé4caceca2021-01-10 01:02:40 +01001371 output_fd = open(output_file, 'wt', encoding='utf-8')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001372 else:
Philippe Mathieu-Daudé4caceca2021-01-10 01:02:40 +01001373 output_fd = io.TextIOWrapper(sys.stdout.buffer,
1374 encoding=sys.stdout.encoding,
1375 errors="ignore")
Richard Henderson568ae7e2017-12-07 12:44:09 -08001376
1377 output_autogen()
1378 for n in sorted(arguments.keys()):
1379 f = arguments[n]
1380 f.output_def()
1381
1382 # A single translate function can be invoked for different patterns.
1383 # Make sure that the argument sets are the same, and declare the
1384 # function only once.
Richard Hendersonc6920792019-08-09 08:12:50 -07001385 #
1386 # If we're sharing formats, we're likely also sharing trans_* functions,
1387 # but we can't tell which ones. Prevent issues from the compiler by
1388 # suppressing redundant declaration warnings.
1389 if anyextern:
Thomas Huth7aa12aa2020-07-08 20:19:44 +02001390 output("#pragma GCC diagnostic push\n",
1391 "#pragma GCC diagnostic ignored \"-Wredundant-decls\"\n",
1392 "#ifdef __clang__\n"
Richard Hendersonc6920792019-08-09 08:12:50 -07001393 "# pragma GCC diagnostic ignored \"-Wtypedef-redefinition\"\n",
Richard Hendersonc6920792019-08-09 08:12:50 -07001394 "#endif\n\n")
1395
Richard Henderson568ae7e2017-12-07 12:44:09 -08001396 out_pats = {}
Richard Henderson0eff2df2019-02-23 11:35:36 -08001397 for i in allpatterns:
Richard Henderson568ae7e2017-12-07 12:44:09 -08001398 if i.name in out_pats:
1399 p = out_pats[i.name]
1400 if i.base.base != p.base.base:
1401 error(0, i.name, ' has conflicting argument sets')
1402 else:
1403 i.output_decl()
1404 out_pats[i.name] = i
1405 output('\n')
1406
Richard Hendersonc6920792019-08-09 08:12:50 -07001407 if anyextern:
Thomas Huth7aa12aa2020-07-08 20:19:44 +02001408 output("#pragma GCC diagnostic pop\n\n")
Richard Hendersonc6920792019-08-09 08:12:50 -07001409
Richard Henderson568ae7e2017-12-07 12:44:09 -08001410 for n in sorted(formats.keys()):
1411 f = formats[n]
1412 f.output_extract()
1413
1414 output(decode_scope, 'bool ', decode_function,
1415 '(DisasContext *ctx, ', insntype, ' insn)\n{\n')
1416
1417 i4 = str_indent(4)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001418
Richard Henderson82bfac12019-02-27 21:37:32 -08001419 if len(allpatterns) != 0:
1420 output(i4, 'union {\n')
1421 for n in sorted(arguments.keys()):
1422 f = arguments[n]
1423 output(i4, i4, f.struct_name(), ' f_', f.name, ';\n')
1424 output(i4, '} u;\n\n')
Richard Henderson08561fc2020-05-17 10:14:11 -07001425 toppat.output_code(4, False, 0, 0)
Richard Henderson82bfac12019-02-27 21:37:32 -08001426
Richard Hendersoneb6b87f2019-02-23 08:57:46 -08001427 output(i4, 'return false;\n')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001428 output('}\n')
1429
Richard Henderson70e07112019-01-31 11:34:11 -08001430 if variablewidth:
1431 output('\n', decode_scope, insntype, ' ', decode_function,
1432 '_load(DisasContext *ctx)\n{\n',
1433 ' ', insntype, ' insn = 0;\n\n')
1434 stree.output_code(4, 0, 0, 0)
1435 output('}\n')
1436
Richard Henderson568ae7e2017-12-07 12:44:09 -08001437 if output_file:
1438 output_fd.close()
Richard Henderson9b5acc52023-05-25 18:04:05 -07001439 exit(1 if testforerror else 0)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001440# end main
1441
1442
1443if __name__ == '__main__':
1444 main()