blob: a8a6cb69cda4bcd320c7e184a1031af390cf469a [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
Richard Hendersonc6a5fc22023-05-31 16:25:10 -070045output_null = False
Richard Henderson568ae7e2017-12-07 12:44:09 -080046insntype = 'uint32_t'
Richard Hendersonabd04f92018-10-23 10:26:25 +010047decode_function = 'decode'
Richard Henderson568ae7e2017-12-07 12:44:09 -080048
Richard Hendersonacfdd232020-09-03 12:23:34 -070049# An identifier for C.
50re_C_ident = '[a-zA-Z][a-zA-Z0-9_]*'
Richard Henderson568ae7e2017-12-07 12:44:09 -080051
Richard Hendersonacfdd232020-09-03 12:23:34 -070052# Identifiers for Arguments, Fields, Formats and Patterns.
53re_arg_ident = '&[a-zA-Z0-9_]*'
54re_fld_ident = '%[a-zA-Z0-9_]*'
55re_fmt_ident = '@[a-zA-Z0-9_]*'
56re_pat_ident = '[a-zA-Z0-9_]*'
Richard Henderson568ae7e2017-12-07 12:44:09 -080057
Peter Maydell36d61242023-05-23 13:04:45 +010058# Local implementation of a topological sort. We use the same API that
59# the Python graphlib does, so that when QEMU moves forward to a
60# baseline of Python 3.9 or newer this code can all be dropped and
61# replaced with:
62# from graphlib import TopologicalSorter, CycleError
63#
64# https://docs.python.org/3.9/library/graphlib.html#graphlib.TopologicalSorter
65#
66# We only implement the parts of TopologicalSorter we care about:
67# ts = TopologicalSorter(graph=None)
68# create the sorter. graph is a dictionary whose keys are
69# nodes and whose values are lists of the predecessors of that node.
70# (That is, if graph contains "A" -> ["B", "C"] then we must output
71# B and C before A.)
72# ts.static_order()
73# returns a list of all the nodes in sorted order, or raises CycleError
74# CycleError
75# exception raised if there are cycles in the graph. The second
76# element in the args attribute is a list of nodes which form a
77# cycle; the first and last element are the same, eg [a, b, c, a]
78# (Our implementation doesn't give the order correctly.)
79#
80# For our purposes we can assume that the data set is always small
81# (typically 10 nodes or less, actual links in the graph very rare),
82# so we don't need to worry about efficiency of implementation.
83#
84# The core of this implementation is from
85# https://code.activestate.com/recipes/578272-topological-sort/
86# (but updated to Python 3), and is under the MIT license.
87
88class CycleError(ValueError):
89 """Subclass of ValueError raised if cycles exist in the graph"""
90 pass
91
92class TopologicalSorter:
93 """Topologically sort a graph"""
94 def __init__(self, graph=None):
95 self.graph = graph
96
97 def static_order(self):
98 # We do the sort right here, unlike the stdlib version
99 from functools import reduce
100 data = {}
101 r = []
102
103 if not self.graph:
104 return []
105
106 # This code wants the values in the dict to be specifically sets
107 for k, v in self.graph.items():
108 data[k] = set(v)
109
110 # Find all items that don't depend on anything.
111 extra_items_in_deps = (reduce(set.union, data.values())
112 - set(data.keys()))
113 # Add empty dependencies where needed
114 data.update({item:{} for item in extra_items_in_deps})
115 while True:
116 ordered = set(item for item, dep in data.items() if not dep)
117 if not ordered:
118 break
119 r.extend(ordered)
120 data = {item: (dep - ordered)
121 for item, dep in data.items()
122 if item not in ordered}
123 if data:
124 # This doesn't give as nice results as the stdlib, which
125 # gives you the cycle by listing the nodes in order. Here
126 # we only know the nodes in the cycle but not their order.
127 raise CycleError(f'nodes are in a cycle', list(data.keys()))
128
129 return r
130# end TopologicalSorter
131
Richard Henderson6699ae62018-10-26 14:59:43 +0100132def error_with_file(file, lineno, *args):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800133 """Print an error message from file:line and args and exit."""
134 global output_file
135 global output_fd
136
Richard Henderson2fd51b12020-05-15 14:48:54 -0700137 prefix = ''
138 if file:
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700139 prefix += f'{file}:'
Richard Henderson568ae7e2017-12-07 12:44:09 -0800140 if lineno:
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700141 prefix += f'{lineno}:'
Richard Henderson2fd51b12020-05-15 14:48:54 -0700142 if prefix:
143 prefix += ' '
144 print(prefix, end='error: ', file=sys.stderr)
145 print(*args, file=sys.stderr)
146
Richard Henderson568ae7e2017-12-07 12:44:09 -0800147 if output_file and output_fd:
148 output_fd.close()
Richard Hendersonc6a5fc22023-05-31 16:25:10 -0700149 os.remove(output_file)
Richard Henderson9b5acc52023-05-25 18:04:05 -0700150 exit(0 if testforerror else 1)
Richard Henderson2fd51b12020-05-15 14:48:54 -0700151# end error_with_file
152
Richard Henderson568ae7e2017-12-07 12:44:09 -0800153
Richard Henderson6699ae62018-10-26 14:59:43 +0100154def error(lineno, *args):
Richard Henderson2fd51b12020-05-15 14:48:54 -0700155 error_with_file(input_file, lineno, *args)
156# end error
157
Richard Henderson568ae7e2017-12-07 12:44:09 -0800158
159def output(*args):
160 global output_fd
161 for a in args:
162 output_fd.write(a)
163
164
Richard Henderson568ae7e2017-12-07 12:44:09 -0800165def output_autogen():
166 output('/* This file is autogenerated by scripts/decodetree.py. */\n\n')
167
168
169def str_indent(c):
170 """Return a string with C spaces"""
171 return ' ' * c
172
173
174def str_fields(fields):
zhaolichang65fdb3c2020-09-17 15:50:23 +0800175 """Return a string uniquely identifying FIELDS"""
Richard Henderson568ae7e2017-12-07 12:44:09 -0800176 r = ''
177 for n in sorted(fields.keys()):
178 r += '_' + n
179 return r[1:]
180
181
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700182def whex(val):
183 """Return a hex string for val padded for insnwidth"""
184 global insnwidth
185 return f'0x{val:0{insnwidth // 4}x}'
186
187
188def whexC(val):
189 """Return a hex string for val padded for insnwidth,
190 and with the proper suffix for a C constant."""
191 suffix = ''
Luis Fernando Fujita Pires60c425f2021-04-07 22:18:49 +0000192 if val >= 0x100000000:
193 suffix = 'ull'
194 elif val >= 0x80000000:
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700195 suffix = 'u'
196 return whex(val) + suffix
197
198
Richard Henderson568ae7e2017-12-07 12:44:09 -0800199def str_match_bits(bits, mask):
200 """Return a string pretty-printing BITS/MASK"""
201 global insnwidth
202
203 i = 1 << (insnwidth - 1)
204 space = 0x01010100
205 r = ''
206 while i != 0:
207 if i & mask:
208 if i & bits:
209 r += '1'
210 else:
211 r += '0'
212 else:
213 r += '.'
214 if i & space:
215 r += ' '
216 i >>= 1
217 return r
218
219
220def is_pow2(x):
221 """Return true iff X is equal to a power of 2."""
222 return (x & (x - 1)) == 0
223
224
225def ctz(x):
226 """Return the number of times 2 factors into X."""
Richard Hendersonb44b3442020-05-16 13:15:02 -0700227 assert x != 0
Richard Henderson568ae7e2017-12-07 12:44:09 -0800228 r = 0
229 while ((x >> r) & 1) == 0:
230 r += 1
231 return r
232
233
234def is_contiguous(bits):
Richard Hendersonb44b3442020-05-16 13:15:02 -0700235 if bits == 0:
236 return -1
Richard Henderson568ae7e2017-12-07 12:44:09 -0800237 shift = ctz(bits)
238 if is_pow2((bits >> shift) + 1):
239 return shift
240 else:
241 return -1
242
243
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700244def eq_fields_for_args(flds_a, arg):
245 if len(flds_a) != len(arg.fields):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800246 return False
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700247 # Only allow inference on default types
248 for t in arg.types:
249 if t != 'int':
250 return False
Richard Henderson568ae7e2017-12-07 12:44:09 -0800251 for k, a in flds_a.items():
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700252 if k not in arg.fields:
Richard Henderson568ae7e2017-12-07 12:44:09 -0800253 return False
254 return True
255
256
257def eq_fields_for_fmts(flds_a, flds_b):
258 if len(flds_a) != len(flds_b):
259 return False
260 for k, a in flds_a.items():
261 if k not in flds_b:
262 return False
263 b = flds_b[k]
264 if a.__class__ != b.__class__ or a != b:
265 return False
266 return True
267
268
269class Field:
270 """Class representing a simple instruction field"""
271 def __init__(self, sign, pos, len):
272 self.sign = sign
273 self.pos = pos
274 self.len = len
275 self.mask = ((1 << len) - 1) << pos
276
277 def __str__(self):
278 if self.sign:
279 s = 's'
280 else:
281 s = ''
Cleber Rosacbcdf1a2018-10-04 12:18:50 -0400282 return str(self.pos) + ':' + s + str(self.len)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800283
Peter Maydellaeac22b2023-05-23 13:04:44 +0100284 def str_extract(self, lvalue_formatter):
Luis Fernando Fujita Pires60c425f2021-04-07 22:18:49 +0000285 global bitop_width
286 s = 's' if self.sign else ''
287 return f'{s}extract{bitop_width}(insn, {self.pos}, {self.len})'
Richard Henderson568ae7e2017-12-07 12:44:09 -0800288
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100289 def referenced_fields(self):
290 return []
291
Richard Henderson568ae7e2017-12-07 12:44:09 -0800292 def __eq__(self, other):
Richard Henderson2c7d4422019-06-11 16:39:41 +0100293 return self.sign == other.sign and self.mask == other.mask
Richard Henderson568ae7e2017-12-07 12:44:09 -0800294
295 def __ne__(self, other):
296 return not self.__eq__(other)
297# end Field
298
299
300class MultiField:
301 """Class representing a compound instruction field"""
302 def __init__(self, subs, mask):
303 self.subs = subs
304 self.sign = subs[0].sign
305 self.mask = mask
306
307 def __str__(self):
308 return str(self.subs)
309
Peter Maydellaeac22b2023-05-23 13:04:44 +0100310 def str_extract(self, lvalue_formatter):
Luis Fernando Fujita Pires60c425f2021-04-07 22:18:49 +0000311 global bitop_width
Richard Henderson568ae7e2017-12-07 12:44:09 -0800312 ret = '0'
313 pos = 0
314 for f in reversed(self.subs):
Peter Maydellaeac22b2023-05-23 13:04:44 +0100315 ext = f.str_extract(lvalue_formatter)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800316 if pos == 0:
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700317 ret = ext
Richard Henderson568ae7e2017-12-07 12:44:09 -0800318 else:
Luis Fernando Fujita Pires60c425f2021-04-07 22:18:49 +0000319 ret = f'deposit{bitop_width}({ret}, {pos}, {bitop_width - pos}, {ext})'
Richard Henderson568ae7e2017-12-07 12:44:09 -0800320 pos += f.len
321 return ret
322
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100323 def referenced_fields(self):
324 l = []
325 for f in self.subs:
326 l.extend(f.referenced_fields())
327 return l
328
Richard Henderson568ae7e2017-12-07 12:44:09 -0800329 def __ne__(self, other):
330 if len(self.subs) != len(other.subs):
331 return True
332 for a, b in zip(self.subs, other.subs):
333 if a.__class__ != b.__class__ or a != b:
334 return True
335 return False
336
337 def __eq__(self, other):
338 return not self.__ne__(other)
339# end MultiField
340
341
342class ConstField:
343 """Class representing an argument field with constant value"""
344 def __init__(self, value):
345 self.value = value
346 self.mask = 0
347 self.sign = value < 0
348
349 def __str__(self):
350 return str(self.value)
351
Peter Maydellaeac22b2023-05-23 13:04:44 +0100352 def str_extract(self, lvalue_formatter):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800353 return str(self.value)
354
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100355 def referenced_fields(self):
356 return []
357
Richard Henderson568ae7e2017-12-07 12:44:09 -0800358 def __cmp__(self, other):
359 return self.value - other.value
360# end ConstField
361
362
363class FunctionField:
Richard Henderson94597b62019-07-22 17:02:56 -0700364 """Class representing a field passed through a function"""
Richard Henderson568ae7e2017-12-07 12:44:09 -0800365 def __init__(self, func, base):
366 self.mask = base.mask
367 self.sign = base.sign
368 self.base = base
369 self.func = func
370
371 def __str__(self):
372 return self.func + '(' + str(self.base) + ')'
373
Peter Maydellaeac22b2023-05-23 13:04:44 +0100374 def str_extract(self, lvalue_formatter):
375 return (self.func + '(ctx, '
376 + self.base.str_extract(lvalue_formatter) + ')')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800377
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100378 def referenced_fields(self):
379 return self.base.referenced_fields()
380
Richard Henderson568ae7e2017-12-07 12:44:09 -0800381 def __eq__(self, other):
382 return self.func == other.func and self.base == other.base
383
384 def __ne__(self, other):
385 return not self.__eq__(other)
386# end FunctionField
387
388
Richard Henderson94597b62019-07-22 17:02:56 -0700389class ParameterField:
390 """Class representing a pseudo-field read from a function"""
391 def __init__(self, func):
392 self.mask = 0
393 self.sign = 0
394 self.func = func
395
396 def __str__(self):
397 return self.func
398
Peter Maydellaeac22b2023-05-23 13:04:44 +0100399 def str_extract(self, lvalue_formatter):
Richard Henderson94597b62019-07-22 17:02:56 -0700400 return self.func + '(ctx)'
401
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100402 def referenced_fields(self):
403 return []
404
Richard Henderson94597b62019-07-22 17:02:56 -0700405 def __eq__(self, other):
406 return self.func == other.func
407
408 def __ne__(self, other):
409 return not self.__eq__(other)
410# end ParameterField
411
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100412class NamedField:
413 """Class representing a field already named in the pattern"""
414 def __init__(self, name, sign, len):
415 self.mask = 0
416 self.sign = sign
417 self.len = len
418 self.name = name
419
420 def __str__(self):
421 return self.name
422
423 def str_extract(self, lvalue_formatter):
424 global bitop_width
425 s = 's' if self.sign else ''
426 lvalue = lvalue_formatter(self.name)
427 return f'{s}extract{bitop_width}({lvalue}, 0, {self.len})'
428
429 def referenced_fields(self):
430 return [self.name]
431
432 def __eq__(self, other):
433 return self.name == other.name
434
435 def __ne__(self, other):
436 return not self.__eq__(other)
437# end NamedField
Richard Henderson94597b62019-07-22 17:02:56 -0700438
Richard Henderson568ae7e2017-12-07 12:44:09 -0800439class Arguments:
440 """Class representing the extracted fields of a format"""
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700441 def __init__(self, nm, flds, types, extern):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800442 self.name = nm
Richard Hendersonabd04f92018-10-23 10:26:25 +0100443 self.extern = extern
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700444 self.fields = flds
445 self.types = types
Richard Henderson568ae7e2017-12-07 12:44:09 -0800446
447 def __str__(self):
448 return self.name + ' ' + str(self.fields)
449
450 def struct_name(self):
451 return 'arg_' + self.name
452
453 def output_def(self):
Richard Hendersonabd04f92018-10-23 10:26:25 +0100454 if not self.extern:
455 output('typedef struct {\n')
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700456 for (n, t) in zip(self.fields, self.types):
457 output(f' {t} {n};\n')
Richard Hendersonabd04f92018-10-23 10:26:25 +0100458 output('} ', self.struct_name(), ';\n\n')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800459# end Arguments
460
Richard Henderson568ae7e2017-12-07 12:44:09 -0800461class General:
462 """Common code between instruction formats and instruction patterns"""
Richard Henderson17560e92019-01-30 18:01:29 -0800463 def __init__(self, name, lineno, base, fixb, fixm, udfm, fldm, flds, w):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800464 self.name = name
Richard Henderson6699ae62018-10-26 14:59:43 +0100465 self.file = input_file
Richard Henderson568ae7e2017-12-07 12:44:09 -0800466 self.lineno = lineno
467 self.base = base
468 self.fixedbits = fixb
469 self.fixedmask = fixm
470 self.undefmask = udfm
471 self.fieldmask = fldm
472 self.fields = flds
Richard Henderson17560e92019-01-30 18:01:29 -0800473 self.width = w
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100474 self.dangling = None
Richard Henderson568ae7e2017-12-07 12:44:09 -0800475
476 def __str__(self):
Richard Henderson0eff2df2019-02-23 11:35:36 -0800477 return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800478
479 def str1(self, i):
480 return str_indent(i) + self.__str__()
Peter Maydellaeac22b2023-05-23 13:04:44 +0100481
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100482 def dangling_references(self):
483 # Return a list of all named references which aren't satisfied
484 # directly by this format/pattern. This will be either:
485 # * a format referring to a field which is specified by the
486 # pattern(s) using it
487 # * a pattern referring to a field which is specified by the
488 # format it uses
489 # * a user error (referring to a field that doesn't exist at all)
490 if self.dangling is None:
491 # Compute this once and cache the answer
492 dangling = []
493 for n, f in self.fields.items():
494 for r in f.referenced_fields():
495 if r not in self.fields:
496 dangling.append(r)
497 self.dangling = dangling
498 return self.dangling
499
Peter Maydellaeac22b2023-05-23 13:04:44 +0100500 def output_fields(self, indent, lvalue_formatter):
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100501 # We use a topological sort to ensure that any use of NamedField
502 # comes after the initialization of the field it is referencing.
503 graph = {}
Peter Maydellaeac22b2023-05-23 13:04:44 +0100504 for n, f in self.fields.items():
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100505 refs = f.referenced_fields()
506 graph[n] = refs
507
508 try:
509 ts = TopologicalSorter(graph)
510 for n in ts.static_order():
511 # We only want to emit assignments for the keys
512 # in our fields list, not for anything that ends up
513 # in the tsort graph only because it was referenced as
514 # a NamedField.
515 try:
516 f = self.fields[n]
517 output(indent, lvalue_formatter(n), ' = ',
518 f.str_extract(lvalue_formatter), ';\n')
519 except KeyError:
520 pass
521 except CycleError as e:
522 # The second element of args is a list of nodes which form
523 # a cycle (there might be others too, but only one is reported).
524 # Pretty-print it to tell the user.
525 cycle = ' => '.join(e.args[1])
526 error(self.lineno, 'field definitions form a cycle: ' + cycle)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800527# end General
528
529
530class Format(General):
531 """Class representing an instruction format"""
532
533 def extract_name(self):
Richard Henderson71ecf792019-02-28 14:45:50 -0800534 global decode_function
535 return decode_function + '_extract_' + self.name
Richard Henderson568ae7e2017-12-07 12:44:09 -0800536
537 def output_extract(self):
Richard Henderson451e4ff2019-03-20 19:21:31 -0700538 output('static void ', self.extract_name(), '(DisasContext *ctx, ',
Richard Henderson568ae7e2017-12-07 12:44:09 -0800539 self.base.struct_name(), ' *a, ', insntype, ' insn)\n{\n')
Peter Maydellaeac22b2023-05-23 13:04:44 +0100540 self.output_fields(str_indent(4), lambda n: 'a->' + n)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800541 output('}\n\n')
542# end Format
543
544
545class Pattern(General):
546 """Class representing an instruction pattern"""
547
548 def output_decl(self):
549 global translate_scope
550 global translate_prefix
551 output('typedef ', self.base.base.struct_name(),
552 ' arg_', self.name, ';\n')
Richard Henderson76805592018-03-02 10:45:35 +0000553 output(translate_scope, 'bool ', translate_prefix, '_', self.name,
Richard Henderson3a7be552018-10-23 11:05:27 +0100554 '(DisasContext *ctx, arg_', self.name, ' *a);\n')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800555
556 def output_code(self, i, extracted, outerbits, outermask):
557 global translate_prefix
558 ind = str_indent(i)
559 arg = self.base.base.name
Richard Henderson6699ae62018-10-26 14:59:43 +0100560 output(ind, '/* ', self.file, ':', str(self.lineno), ' */\n')
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100561 # We might have named references in the format that refer to fields
562 # in the pattern, or named references in the pattern that refer
563 # to fields in the format. This affects whether we extract the fields
564 # for the format before or after the ones for the pattern.
565 # For simplicity we don't allow cross references in both directions.
566 # This is also where we catch the syntax error of referring to
567 # a nonexistent field.
568 fmt_refs = self.base.dangling_references()
569 for r in fmt_refs:
570 if r not in self.fields:
571 error(self.lineno, f'format refers to undefined field {r}')
572 pat_refs = self.dangling_references()
573 for r in pat_refs:
574 if r not in self.base.fields:
575 error(self.lineno, f'pattern refers to undefined field {r}')
576 if pat_refs and fmt_refs:
577 error(self.lineno, ('pattern that uses fields defined in format '
578 'cannot use format that uses fields defined '
579 'in pattern'))
580 if fmt_refs:
581 # pattern fields first
582 self.output_fields(ind, lambda n: 'u.f_' + arg + '.' + n)
583 assert not extracted, "dangling fmt refs but it was already extracted"
Richard Henderson568ae7e2017-12-07 12:44:09 -0800584 if not extracted:
Richard Henderson451e4ff2019-03-20 19:21:31 -0700585 output(ind, self.base.extract_name(),
586 '(ctx, &u.f_', arg, ', insn);\n')
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100587 if not fmt_refs:
588 # pattern fields last
589 self.output_fields(ind, lambda n: 'u.f_' + arg + '.' + n)
590
Richard Hendersoneb6b87f2019-02-23 08:57:46 -0800591 output(ind, 'if (', translate_prefix, '_', self.name,
592 '(ctx, &u.f_', arg, ')) return true;\n')
Richard Henderson08561fc2020-05-17 10:14:11 -0700593
594 # Normal patterns do not have children.
595 def build_tree(self):
596 return
597 def prop_masks(self):
598 return
599 def prop_format(self):
600 return
601 def prop_width(self):
602 return
603
Richard Henderson568ae7e2017-12-07 12:44:09 -0800604# end Pattern
605
606
Richard Hendersondf630442020-05-16 11:19:45 -0700607class MultiPattern(General):
608 """Class representing a set of instruction patterns"""
609
Richard Henderson08561fc2020-05-17 10:14:11 -0700610 def __init__(self, lineno):
Richard Hendersondf630442020-05-16 11:19:45 -0700611 self.file = input_file
612 self.lineno = lineno
Richard Henderson08561fc2020-05-17 10:14:11 -0700613 self.pats = []
Richard Hendersondf630442020-05-16 11:19:45 -0700614 self.base = None
615 self.fixedbits = 0
616 self.fixedmask = 0
617 self.undefmask = 0
618 self.width = None
619
620 def __str__(self):
621 r = 'group'
622 if self.fixedbits is not None:
623 r += ' ' + str_match_bits(self.fixedbits, self.fixedmask)
624 return r
625
626 def output_decl(self):
627 for p in self.pats:
628 p.output_decl()
Richard Henderson08561fc2020-05-17 10:14:11 -0700629
630 def prop_masks(self):
631 global insnmask
632
633 fixedmask = insnmask
634 undefmask = insnmask
635
636 # Collect fixedmask/undefmask for all of the children.
637 for p in self.pats:
638 p.prop_masks()
639 fixedmask &= p.fixedmask
640 undefmask &= p.undefmask
641
642 # Widen fixedmask until all fixedbits match
643 repeat = True
644 fixedbits = 0
645 while repeat and fixedmask != 0:
646 fixedbits = None
647 for p in self.pats:
648 thisbits = p.fixedbits & fixedmask
649 if fixedbits is None:
650 fixedbits = thisbits
651 elif fixedbits != thisbits:
652 fixedmask &= ~(fixedbits ^ thisbits)
653 break
654 else:
655 repeat = False
656
657 self.fixedbits = fixedbits
658 self.fixedmask = fixedmask
659 self.undefmask = undefmask
660
661 def build_tree(self):
662 for p in self.pats:
663 p.build_tree()
664
665 def prop_format(self):
666 for p in self.pats:
Richard Henderson2fd2eb52023-05-25 18:45:43 -0700667 p.prop_format()
Richard Henderson08561fc2020-05-17 10:14:11 -0700668
669 def prop_width(self):
670 width = None
671 for p in self.pats:
672 p.prop_width()
673 if width is None:
674 width = p.width
675 elif width != p.width:
676 error_with_file(self.file, self.lineno,
677 'width mismatch in patterns within braces')
678 self.width = width
679
Richard Hendersondf630442020-05-16 11:19:45 -0700680# end MultiPattern
681
682
683class IncMultiPattern(MultiPattern):
Richard Henderson0eff2df2019-02-23 11:35:36 -0800684 """Class representing an overlapping set of instruction patterns"""
685
Richard Henderson0eff2df2019-02-23 11:35:36 -0800686 def output_code(self, i, extracted, outerbits, outermask):
687 global translate_prefix
688 ind = str_indent(i)
689 for p in self.pats:
690 if outermask != p.fixedmask:
691 innermask = p.fixedmask & ~outermask
692 innerbits = p.fixedbits & ~outermask
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700693 output(ind, f'if ((insn & {whexC(innermask)}) == {whexC(innerbits)}) {{\n')
694 output(ind, f' /* {str_match_bits(p.fixedbits, p.fixedmask)} */\n')
Richard Henderson0eff2df2019-02-23 11:35:36 -0800695 p.output_code(i + 4, extracted, p.fixedbits, p.fixedmask)
696 output(ind, '}\n')
697 else:
698 p.output_code(i, extracted, p.fixedbits, p.fixedmask)
Richard Hendersonf2604472023-05-25 18:50:58 -0700699
700 def build_tree(self):
701 if not self.pats:
702 error_with_file(self.file, self.lineno, 'empty pattern group')
703 super().build_tree()
704
Richard Henderson040145c2020-05-16 10:50:43 -0700705#end IncMultiPattern
Richard Henderson0eff2df2019-02-23 11:35:36 -0800706
707
Richard Henderson08561fc2020-05-17 10:14:11 -0700708class Tree:
709 """Class representing a node in a decode tree"""
710
711 def __init__(self, fm, tm):
712 self.fixedmask = fm
713 self.thismask = tm
714 self.subs = []
715 self.base = None
716
717 def str1(self, i):
718 ind = str_indent(i)
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700719 r = ind + whex(self.fixedmask)
Richard Henderson08561fc2020-05-17 10:14:11 -0700720 if self.format:
721 r += ' ' + self.format.name
722 r += ' [\n'
723 for (b, s) in self.subs:
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700724 r += ind + f' {whex(b)}:\n'
Richard Henderson08561fc2020-05-17 10:14:11 -0700725 r += s.str1(i + 4) + '\n'
726 r += ind + ']'
727 return r
728
729 def __str__(self):
730 return self.str1(0)
731
732 def output_code(self, i, extracted, outerbits, outermask):
733 ind = str_indent(i)
734
735 # If we identified all nodes below have the same format,
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100736 # extract the fields now. But don't do it if the format relies
737 # on named fields from the insn pattern, as those won't have
738 # been initialised at this point.
739 if not extracted and self.base and not self.base.dangling_references():
Richard Henderson08561fc2020-05-17 10:14:11 -0700740 output(ind, self.base.extract_name(),
741 '(ctx, &u.f_', self.base.base.name, ', insn);\n')
742 extracted = True
743
744 # Attempt to aid the compiler in producing compact switch statements.
745 # If the bits in the mask are contiguous, extract them.
746 sh = is_contiguous(self.thismask)
747 if sh > 0:
748 # Propagate SH down into the local functions.
749 def str_switch(b, sh=sh):
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700750 return f'(insn >> {sh}) & {b >> sh:#x}'
Richard Henderson08561fc2020-05-17 10:14:11 -0700751
752 def str_case(b, sh=sh):
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700753 return hex(b >> sh)
Richard Henderson08561fc2020-05-17 10:14:11 -0700754 else:
755 def str_switch(b):
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700756 return f'insn & {whexC(b)}'
Richard Henderson08561fc2020-05-17 10:14:11 -0700757
758 def str_case(b):
Richard Hendersonc7cefe62021-04-28 16:27:56 -0700759 return whexC(b)
Richard Henderson08561fc2020-05-17 10:14:11 -0700760
761 output(ind, 'switch (', str_switch(self.thismask), ') {\n')
762 for b, s in sorted(self.subs):
763 assert (self.thismask & ~s.fixedmask) == 0
764 innermask = outermask | self.thismask
765 innerbits = outerbits | b
766 output(ind, 'case ', str_case(b), ':\n')
767 output(ind, ' /* ',
768 str_match_bits(innerbits, innermask), ' */\n')
769 s.output_code(i + 4, extracted, innerbits, innermask)
Peter Maydell514101c2020-10-19 16:12:52 +0100770 output(ind, ' break;\n')
Richard Henderson08561fc2020-05-17 10:14:11 -0700771 output(ind, '}\n')
772# end Tree
773
774
775class ExcMultiPattern(MultiPattern):
776 """Class representing a non-overlapping set of instruction patterns"""
777
778 def output_code(self, i, extracted, outerbits, outermask):
779 # Defer everything to our decomposed Tree node
780 self.tree.output_code(i, extracted, outerbits, outermask)
781
782 @staticmethod
783 def __build_tree(pats, outerbits, outermask):
784 # Find the intersection of all remaining fixedmask.
785 innermask = ~outermask & insnmask
786 for i in pats:
787 innermask &= i.fixedmask
788
789 if innermask == 0:
790 # Edge condition: One pattern covers the entire insnmask
791 if len(pats) == 1:
792 t = Tree(outermask, innermask)
793 t.subs.append((0, pats[0]))
794 return t
795
796 text = 'overlapping patterns:'
797 for p in pats:
798 text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
799 error_with_file(pats[0].file, pats[0].lineno, text)
800
801 fullmask = outermask | innermask
802
803 # Sort each element of pats into the bin selected by the mask.
804 bins = {}
805 for i in pats:
806 fb = i.fixedbits & innermask
807 if fb in bins:
808 bins[fb].append(i)
809 else:
810 bins[fb] = [i]
811
812 # We must recurse if any bin has more than one element or if
813 # the single element in the bin has not been fully matched.
814 t = Tree(fullmask, innermask)
815
816 for b, l in bins.items():
817 s = l[0]
818 if len(l) > 1 or s.fixedmask & ~fullmask != 0:
819 s = ExcMultiPattern.__build_tree(l, b | outerbits, fullmask)
820 t.subs.append((b, s))
821
822 return t
823
824 def build_tree(self):
Richard Henderson2fd2eb52023-05-25 18:45:43 -0700825 super().build_tree()
Richard Henderson08561fc2020-05-17 10:14:11 -0700826 self.tree = self.__build_tree(self.pats, self.fixedbits,
827 self.fixedmask)
828
829 @staticmethod
830 def __prop_format(tree):
831 """Propagate Format objects into the decode tree"""
832
833 # Depth first search.
834 for (b, s) in tree.subs:
835 if isinstance(s, Tree):
836 ExcMultiPattern.__prop_format(s)
837
838 # If all entries in SUBS have the same format, then
839 # propagate that into the tree.
840 f = None
841 for (b, s) in tree.subs:
842 if f is None:
843 f = s.base
844 if f is None:
845 return
846 if f is not s.base:
847 return
848 tree.base = f
849
850 def prop_format(self):
851 super().prop_format()
852 self.__prop_format(self.tree)
853
854# end ExcMultiPattern
855
856
Richard Henderson568ae7e2017-12-07 12:44:09 -0800857def parse_field(lineno, name, toks):
858 """Parse one instruction field from TOKS at LINENO"""
859 global fields
Richard Henderson568ae7e2017-12-07 12:44:09 -0800860 global insnwidth
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100861 global re_C_ident
Richard Henderson568ae7e2017-12-07 12:44:09 -0800862
863 # A "simple" field will have only one entry;
864 # a "multifield" will have several.
865 subs = []
866 width = 0
867 func = None
868 for t in toks:
Richard Hendersonacfdd232020-09-03 12:23:34 -0700869 if re.match('^!function=', t):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800870 if func:
871 error(lineno, 'duplicate function')
872 func = t.split('=')
873 func = func[1]
874 continue
875
Peter Maydell7e6c28b2023-05-23 13:04:46 +0100876 if re.fullmatch(re_C_ident + ':s[0-9]+', t):
877 # Signed named field
878 subtoks = t.split(':')
879 n = subtoks[0]
880 le = int(subtoks[1])
881 f = NamedField(n, True, le)
882 subs.append(f)
883 width += le
884 continue
885 if re.fullmatch(re_C_ident + ':[0-9]+', t):
886 # Unsigned named field
887 subtoks = t.split(':')
888 n = subtoks[0]
889 le = int(subtoks[1])
890 f = NamedField(n, False, le)
891 subs.append(f)
892 width += le
893 continue
894
John Snow2d110c12020-05-13 23:52:30 -0400895 if re.fullmatch('[0-9]+:s[0-9]+', t):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800896 # Signed field extract
897 subtoks = t.split(':s')
898 sign = True
John Snow2d110c12020-05-13 23:52:30 -0400899 elif re.fullmatch('[0-9]+:[0-9]+', t):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800900 # Unsigned field extract
901 subtoks = t.split(':')
902 sign = False
903 else:
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700904 error(lineno, f'invalid field token "{t}"')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800905 po = int(subtoks[0])
906 le = int(subtoks[1])
907 if po + le > insnwidth:
Richard Henderson9f6e2b42021-04-28 16:37:02 -0700908 error(lineno, f'field {t} too large')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800909 f = Field(sign, po, le)
910 subs.append(f)
911 width += le
912
913 if width > insnwidth:
914 error(lineno, 'field too large')
Richard Henderson94597b62019-07-22 17:02:56 -0700915 if len(subs) == 0:
916 if func:
917 f = ParameterField(func)
918 else:
919 error(lineno, 'field with no value')
Richard Henderson568ae7e2017-12-07 12:44:09 -0800920 else:
Richard Henderson94597b62019-07-22 17:02:56 -0700921 if len(subs) == 1:
922 f = subs[0]
923 else:
924 mask = 0
925 for s in subs:
926 if mask & s.mask:
927 error(lineno, 'field components overlap')
928 mask |= s.mask
929 f = MultiField(subs, mask)
930 if func:
931 f = FunctionField(func, f)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800932
933 if name in fields:
934 error(lineno, 'duplicate field', name)
935 fields[name] = f
936# end parse_field
937
938
939def parse_arguments(lineno, name, toks):
940 """Parse one argument set from TOKS at LINENO"""
941 global arguments
Richard Hendersonacfdd232020-09-03 12:23:34 -0700942 global re_C_ident
Richard Hendersonc6920792019-08-09 08:12:50 -0700943 global anyextern
Richard Henderson568ae7e2017-12-07 12:44:09 -0800944
945 flds = []
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700946 types = []
Richard Hendersonabd04f92018-10-23 10:26:25 +0100947 extern = False
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700948 for n in toks:
949 if re.fullmatch('!extern', n):
Richard Hendersonabd04f92018-10-23 10:26:25 +0100950 extern = True
Richard Hendersonc6920792019-08-09 08:12:50 -0700951 anyextern = True
Richard Hendersonabd04f92018-10-23 10:26:25 +0100952 continue
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700953 if re.fullmatch(re_C_ident + ':' + re_C_ident, n):
954 (n, t) = n.split(':')
955 elif re.fullmatch(re_C_ident, n):
956 t = 'int'
957 else:
958 error(lineno, f'invalid argument set token "{n}"')
959 if n in flds:
960 error(lineno, f'duplicate argument "{n}"')
961 flds.append(n)
962 types.append(t)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800963
964 if name in arguments:
965 error(lineno, 'duplicate argument set', name)
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700966 arguments[name] = Arguments(name, flds, types, extern)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800967# end parse_arguments
968
969
970def lookup_field(lineno, name):
971 global fields
972 if name in fields:
973 return fields[name]
974 error(lineno, 'undefined field', name)
975
976
977def add_field(lineno, flds, new_name, f):
978 if new_name in flds:
979 error(lineno, 'duplicate field', new_name)
980 flds[new_name] = f
981 return flds
982
983
984def add_field_byname(lineno, flds, new_name, old_name):
985 return add_field(lineno, flds, new_name, lookup_field(lineno, old_name))
986
987
988def infer_argument_set(flds):
989 global arguments
Richard Hendersonabd04f92018-10-23 10:26:25 +0100990 global decode_function
Richard Henderson568ae7e2017-12-07 12:44:09 -0800991
992 for arg in arguments.values():
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700993 if eq_fields_for_args(flds, arg):
Richard Henderson568ae7e2017-12-07 12:44:09 -0800994 return arg
995
Richard Hendersonabd04f92018-10-23 10:26:25 +0100996 name = decode_function + str(len(arguments))
Richard Hendersonaf93cca2021-04-29 10:03:59 -0700997 arg = Arguments(name, flds.keys(), ['int'] * len(flds), False)
Richard Henderson568ae7e2017-12-07 12:44:09 -0800998 arguments[name] = arg
999 return arg
1000
1001
Richard Henderson17560e92019-01-30 18:01:29 -08001002def infer_format(arg, fieldmask, flds, width):
Richard Henderson568ae7e2017-12-07 12:44:09 -08001003 global arguments
1004 global formats
Richard Hendersonabd04f92018-10-23 10:26:25 +01001005 global decode_function
Richard Henderson568ae7e2017-12-07 12:44:09 -08001006
1007 const_flds = {}
1008 var_flds = {}
1009 for n, c in flds.items():
1010 if c is ConstField:
1011 const_flds[n] = c
1012 else:
1013 var_flds[n] = c
1014
1015 # Look for an existing format with the same argument set and fields
1016 for fmt in formats.values():
1017 if arg and fmt.base != arg:
1018 continue
1019 if fieldmask != fmt.fieldmask:
1020 continue
Richard Henderson17560e92019-01-30 18:01:29 -08001021 if width != fmt.width:
1022 continue
Richard Henderson568ae7e2017-12-07 12:44:09 -08001023 if not eq_fields_for_fmts(flds, fmt.fields):
1024 continue
1025 return (fmt, const_flds)
1026
Richard Hendersonabd04f92018-10-23 10:26:25 +01001027 name = decode_function + '_Fmt_' + str(len(formats))
Richard Henderson568ae7e2017-12-07 12:44:09 -08001028 if not arg:
1029 arg = infer_argument_set(flds)
1030
Richard Henderson17560e92019-01-30 18:01:29 -08001031 fmt = Format(name, 0, arg, 0, 0, 0, fieldmask, var_flds, width)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001032 formats[name] = fmt
1033
1034 return (fmt, const_flds)
1035# end infer_format
1036
1037
Richard Henderson08561fc2020-05-17 10:14:11 -07001038def parse_generic(lineno, parent_pat, name, toks):
Richard Henderson568ae7e2017-12-07 12:44:09 -08001039 """Parse one instruction format from TOKS at LINENO"""
1040 global fields
1041 global arguments
1042 global formats
Richard Henderson0eff2df2019-02-23 11:35:36 -08001043 global allpatterns
Richard Hendersonacfdd232020-09-03 12:23:34 -07001044 global re_arg_ident
1045 global re_fld_ident
1046 global re_fmt_ident
1047 global re_C_ident
Richard Henderson568ae7e2017-12-07 12:44:09 -08001048 global insnwidth
1049 global insnmask
Richard Henderson17560e92019-01-30 18:01:29 -08001050 global variablewidth
Richard Henderson568ae7e2017-12-07 12:44:09 -08001051
Richard Henderson08561fc2020-05-17 10:14:11 -07001052 is_format = parent_pat is None
1053
Richard Henderson568ae7e2017-12-07 12:44:09 -08001054 fixedmask = 0
1055 fixedbits = 0
1056 undefmask = 0
1057 width = 0
1058 flds = {}
1059 arg = None
1060 fmt = None
1061 for t in toks:
zhaolichang65fdb3c2020-09-17 15:50:23 +08001062 # '&Foo' gives a format an explicit argument set.
Richard Hendersonacfdd232020-09-03 12:23:34 -07001063 if re.fullmatch(re_arg_ident, t):
Richard Henderson568ae7e2017-12-07 12:44:09 -08001064 tt = t[1:]
1065 if arg:
1066 error(lineno, 'multiple argument sets')
1067 if tt in arguments:
1068 arg = arguments[tt]
1069 else:
1070 error(lineno, 'undefined argument set', t)
1071 continue
1072
1073 # '@Foo' gives a pattern an explicit format.
Richard Hendersonacfdd232020-09-03 12:23:34 -07001074 if re.fullmatch(re_fmt_ident, t):
Richard Henderson568ae7e2017-12-07 12:44:09 -08001075 tt = t[1:]
1076 if fmt:
1077 error(lineno, 'multiple formats')
1078 if tt in formats:
1079 fmt = formats[tt]
1080 else:
1081 error(lineno, 'undefined format', t)
1082 continue
1083
1084 # '%Foo' imports a field.
Richard Hendersonacfdd232020-09-03 12:23:34 -07001085 if re.fullmatch(re_fld_ident, t):
Richard Henderson568ae7e2017-12-07 12:44:09 -08001086 tt = t[1:]
1087 flds = add_field_byname(lineno, flds, tt, tt)
1088 continue
1089
1090 # 'Foo=%Bar' imports a field with a different name.
Richard Hendersonacfdd232020-09-03 12:23:34 -07001091 if re.fullmatch(re_C_ident + '=' + re_fld_ident, t):
Richard Henderson568ae7e2017-12-07 12:44:09 -08001092 (fname, iname) = t.split('=%')
1093 flds = add_field_byname(lineno, flds, fname, iname)
1094 continue
1095
1096 # 'Foo=number' sets an argument field to a constant value
Richard Hendersonacfdd232020-09-03 12:23:34 -07001097 if re.fullmatch(re_C_ident + '=[+-]?[0-9]+', t):
Richard Henderson568ae7e2017-12-07 12:44:09 -08001098 (fname, value) = t.split('=')
1099 value = int(value)
1100 flds = add_field(lineno, flds, fname, ConstField(value))
1101 continue
1102
1103 # Pattern of 0s, 1s, dots and dashes indicate required zeros,
1104 # required ones, or dont-cares.
John Snow2d110c12020-05-13 23:52:30 -04001105 if re.fullmatch('[01.-]+', t):
Richard Henderson568ae7e2017-12-07 12:44:09 -08001106 shift = len(t)
1107 fms = t.replace('0', '1')
1108 fms = fms.replace('.', '0')
1109 fms = fms.replace('-', '0')
1110 fbs = t.replace('.', '0')
1111 fbs = fbs.replace('-', '0')
1112 ubm = t.replace('1', '0')
1113 ubm = ubm.replace('.', '0')
1114 ubm = ubm.replace('-', '1')
1115 fms = int(fms, 2)
1116 fbs = int(fbs, 2)
1117 ubm = int(ubm, 2)
1118 fixedbits = (fixedbits << shift) | fbs
1119 fixedmask = (fixedmask << shift) | fms
1120 undefmask = (undefmask << shift) | ubm
1121 # Otherwise, fieldname:fieldwidth
Richard Hendersonacfdd232020-09-03 12:23:34 -07001122 elif re.fullmatch(re_C_ident + ':s?[0-9]+', t):
Richard Henderson568ae7e2017-12-07 12:44:09 -08001123 (fname, flen) = t.split(':')
1124 sign = False
1125 if flen[0] == 's':
1126 sign = True
1127 flen = flen[1:]
1128 shift = int(flen, 10)
Richard Henderson2decfc92019-03-05 15:34:41 -08001129 if shift + width > insnwidth:
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001130 error(lineno, f'field {fname} exceeds insnwidth')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001131 f = Field(sign, insnwidth - width - shift, shift)
1132 flds = add_field(lineno, flds, fname, f)
1133 fixedbits <<= shift
1134 fixedmask <<= shift
1135 undefmask <<= shift
1136 else:
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001137 error(lineno, f'invalid token "{t}"')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001138 width += shift
1139
Richard Henderson17560e92019-01-30 18:01:29 -08001140 if variablewidth and width < insnwidth and width % 8 == 0:
1141 shift = insnwidth - width
1142 fixedbits <<= shift
1143 fixedmask <<= shift
1144 undefmask <<= shift
1145 undefmask |= (1 << shift) - 1
1146
Richard Henderson568ae7e2017-12-07 12:44:09 -08001147 # We should have filled in all of the bits of the instruction.
Richard Henderson17560e92019-01-30 18:01:29 -08001148 elif not (is_format and width == 0) and width != insnwidth:
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001149 error(lineno, f'definition has {width} bits')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001150
zhaolichang65fdb3c2020-09-17 15:50:23 +08001151 # Do not check for fields overlapping fields; one valid usage
Richard Henderson568ae7e2017-12-07 12:44:09 -08001152 # is to be able to duplicate fields via import.
1153 fieldmask = 0
1154 for f in flds.values():
1155 fieldmask |= f.mask
1156
1157 # Fix up what we've parsed to match either a format or a pattern.
1158 if is_format:
1159 # Formats cannot reference formats.
1160 if fmt:
1161 error(lineno, 'format referencing format')
1162 # If an argument set is given, then there should be no fields
1163 # without a place to store it.
1164 if arg:
1165 for f in flds.keys():
1166 if f not in arg.fields:
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001167 error(lineno, f'field {f} not in argument set {arg.name}')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001168 else:
1169 arg = infer_argument_set(flds)
1170 if name in formats:
1171 error(lineno, 'duplicate format name', name)
1172 fmt = Format(name, lineno, arg, fixedbits, fixedmask,
Richard Henderson17560e92019-01-30 18:01:29 -08001173 undefmask, fieldmask, flds, width)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001174 formats[name] = fmt
1175 else:
1176 # Patterns can reference a format ...
1177 if fmt:
1178 # ... but not an argument simultaneously
1179 if arg:
1180 error(lineno, 'pattern specifies both format and argument set')
1181 if fixedmask & fmt.fixedmask:
1182 error(lineno, 'pattern fixed bits overlap format fixed bits')
Richard Henderson17560e92019-01-30 18:01:29 -08001183 if width != fmt.width:
1184 error(lineno, 'pattern uses format of different width')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001185 fieldmask |= fmt.fieldmask
1186 fixedbits |= fmt.fixedbits
1187 fixedmask |= fmt.fixedmask
1188 undefmask |= fmt.undefmask
1189 else:
Richard Henderson17560e92019-01-30 18:01:29 -08001190 (fmt, flds) = infer_format(arg, fieldmask, flds, width)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001191 arg = fmt.base
1192 for f in flds.keys():
1193 if f not in arg.fields:
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001194 error(lineno, f'field {f} not in argument set {arg.name}')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001195 if f in fmt.fields.keys():
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001196 error(lineno, f'field {f} set by format and pattern')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001197 for f in arg.fields:
1198 if f not in flds.keys() and f not in fmt.fields.keys():
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001199 error(lineno, f'field {f} not initialized')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001200 pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
Richard Henderson17560e92019-01-30 18:01:29 -08001201 undefmask, fieldmask, flds, width)
Richard Henderson08561fc2020-05-17 10:14:11 -07001202 parent_pat.pats.append(pat)
Richard Henderson0eff2df2019-02-23 11:35:36 -08001203 allpatterns.append(pat)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001204
1205 # Validate the masks that we have assembled.
1206 if fieldmask & fixedmask:
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001207 error(lineno, 'fieldmask overlaps fixedmask ',
1208 f'({whex(fieldmask)} & {whex(fixedmask)})')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001209 if fieldmask & undefmask:
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001210 error(lineno, 'fieldmask overlaps undefmask ',
1211 f'({whex(fieldmask)} & {whex(undefmask)})')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001212 if fixedmask & undefmask:
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001213 error(lineno, 'fixedmask overlaps undefmask ',
1214 f'({whex(fixedmask)} & {whex(undefmask)})')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001215 if not is_format:
1216 allbits = fieldmask | fixedmask | undefmask
1217 if allbits != insnmask:
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001218 error(lineno, 'bits left unspecified ',
1219 f'({whex(allbits ^ insnmask)})')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001220# end parse_general
1221
Richard Henderson0eff2df2019-02-23 11:35:36 -08001222
Richard Henderson08561fc2020-05-17 10:14:11 -07001223def parse_file(f, parent_pat):
Richard Henderson568ae7e2017-12-07 12:44:09 -08001224 """Parse all of the patterns within a file"""
Richard Hendersonacfdd232020-09-03 12:23:34 -07001225 global re_arg_ident
1226 global re_fld_ident
1227 global re_fmt_ident
1228 global re_pat_ident
Richard Henderson568ae7e2017-12-07 12:44:09 -08001229
1230 # Read all of the lines of the file. Concatenate lines
1231 # ending in backslash; discard empty lines and comments.
1232 toks = []
1233 lineno = 0
Richard Henderson0eff2df2019-02-23 11:35:36 -08001234 nesting = 0
Richard Henderson08561fc2020-05-17 10:14:11 -07001235 nesting_pats = []
Richard Henderson0eff2df2019-02-23 11:35:36 -08001236
Richard Henderson568ae7e2017-12-07 12:44:09 -08001237 for line in f:
1238 lineno += 1
1239
Richard Henderson0eff2df2019-02-23 11:35:36 -08001240 # Expand and strip spaces, to find indent.
1241 line = line.rstrip()
1242 line = line.expandtabs()
1243 len1 = len(line)
1244 line = line.lstrip()
1245 len2 = len(line)
1246
Richard Henderson568ae7e2017-12-07 12:44:09 -08001247 # Discard comments
1248 end = line.find('#')
1249 if end >= 0:
1250 line = line[:end]
1251
1252 t = line.split()
1253 if len(toks) != 0:
1254 # Next line after continuation
1255 toks.extend(t)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001256 else:
Richard Henderson0eff2df2019-02-23 11:35:36 -08001257 # Allow completely blank lines.
1258 if len1 == 0:
1259 continue
1260 indent = len1 - len2
1261 # Empty line due to comment.
1262 if len(t) == 0:
1263 # Indentation must be correct, even for comment lines.
1264 if indent != nesting:
1265 error(lineno, 'indentation ', indent, ' != ', nesting)
1266 continue
1267 start_lineno = lineno
Richard Henderson568ae7e2017-12-07 12:44:09 -08001268 toks = t
1269
1270 # Continuation?
1271 if toks[-1] == '\\':
1272 toks.pop()
1273 continue
1274
Richard Henderson568ae7e2017-12-07 12:44:09 -08001275 name = toks[0]
1276 del toks[0]
1277
Richard Henderson0eff2df2019-02-23 11:35:36 -08001278 # End nesting?
Richard Henderson067e8b02020-05-18 08:45:32 -07001279 if name == '}' or name == ']':
Richard Henderson0eff2df2019-02-23 11:35:36 -08001280 if len(toks) != 0:
1281 error(start_lineno, 'extra tokens after close brace')
Richard Henderson08561fc2020-05-17 10:14:11 -07001282
Richard Henderson067e8b02020-05-18 08:45:32 -07001283 # Make sure { } and [ ] nest properly.
1284 if (name == '}') != isinstance(parent_pat, IncMultiPattern):
1285 error(lineno, 'mismatched close brace')
1286
Richard Henderson08561fc2020-05-17 10:14:11 -07001287 try:
1288 parent_pat = nesting_pats.pop()
1289 except:
Richard Henderson067e8b02020-05-18 08:45:32 -07001290 error(lineno, 'extra close brace')
Richard Henderson08561fc2020-05-17 10:14:11 -07001291
Richard Henderson0eff2df2019-02-23 11:35:36 -08001292 nesting -= 2
1293 if indent != nesting:
Richard Henderson08561fc2020-05-17 10:14:11 -07001294 error(lineno, 'indentation ', indent, ' != ', nesting)
1295
Richard Henderson0eff2df2019-02-23 11:35:36 -08001296 toks = []
1297 continue
1298
1299 # Everything else should have current indentation.
1300 if indent != nesting:
1301 error(start_lineno, 'indentation ', indent, ' != ', nesting)
1302
1303 # Start nesting?
Richard Henderson067e8b02020-05-18 08:45:32 -07001304 if name == '{' or name == '[':
Richard Henderson0eff2df2019-02-23 11:35:36 -08001305 if len(toks) != 0:
1306 error(start_lineno, 'extra tokens after open brace')
Richard Henderson08561fc2020-05-17 10:14:11 -07001307
Richard Henderson067e8b02020-05-18 08:45:32 -07001308 if name == '{':
1309 nested_pat = IncMultiPattern(start_lineno)
1310 else:
1311 nested_pat = ExcMultiPattern(start_lineno)
Richard Henderson08561fc2020-05-17 10:14:11 -07001312 parent_pat.pats.append(nested_pat)
1313 nesting_pats.append(parent_pat)
1314 parent_pat = nested_pat
1315
Richard Henderson0eff2df2019-02-23 11:35:36 -08001316 nesting += 2
1317 toks = []
1318 continue
1319
Richard Henderson568ae7e2017-12-07 12:44:09 -08001320 # Determine the type of object needing to be parsed.
Richard Hendersonacfdd232020-09-03 12:23:34 -07001321 if re.fullmatch(re_fld_ident, name):
Richard Henderson0eff2df2019-02-23 11:35:36 -08001322 parse_field(start_lineno, name[1:], toks)
Richard Hendersonacfdd232020-09-03 12:23:34 -07001323 elif re.fullmatch(re_arg_ident, name):
Richard Henderson0eff2df2019-02-23 11:35:36 -08001324 parse_arguments(start_lineno, name[1:], toks)
Richard Hendersonacfdd232020-09-03 12:23:34 -07001325 elif re.fullmatch(re_fmt_ident, name):
Richard Henderson08561fc2020-05-17 10:14:11 -07001326 parse_generic(start_lineno, None, name[1:], toks)
Richard Hendersonacfdd232020-09-03 12:23:34 -07001327 elif re.fullmatch(re_pat_ident, name):
Richard Henderson08561fc2020-05-17 10:14:11 -07001328 parse_generic(start_lineno, parent_pat, name, toks)
Richard Hendersonacfdd232020-09-03 12:23:34 -07001329 else:
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001330 error(lineno, f'invalid token "{name}"')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001331 toks = []
Richard Henderson067e8b02020-05-18 08:45:32 -07001332
1333 if nesting != 0:
1334 error(lineno, 'missing close brace')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001335# end parse_file
1336
1337
Richard Henderson70e07112019-01-31 11:34:11 -08001338class SizeTree:
1339 """Class representing a node in a size decode tree"""
1340
1341 def __init__(self, m, w):
1342 self.mask = m
1343 self.subs = []
1344 self.base = None
1345 self.width = w
1346
1347 def str1(self, i):
1348 ind = str_indent(i)
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001349 r = ind + whex(self.mask) + ' [\n'
Richard Henderson70e07112019-01-31 11:34:11 -08001350 for (b, s) in self.subs:
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001351 r += ind + f' {whex(b)}:\n'
Richard Henderson70e07112019-01-31 11:34:11 -08001352 r += s.str1(i + 4) + '\n'
1353 r += ind + ']'
1354 return r
1355
1356 def __str__(self):
1357 return self.str1(0)
1358
1359 def output_code(self, i, extracted, outerbits, outermask):
1360 ind = str_indent(i)
1361
1362 # If we need to load more bytes to test, do so now.
1363 if extracted < self.width:
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001364 output(ind, f'insn = {decode_function}_load_bytes',
1365 f'(ctx, insn, {extracted // 8}, {self.width // 8});\n')
Richard Henderson70e07112019-01-31 11:34:11 -08001366 extracted = self.width
1367
1368 # Attempt to aid the compiler in producing compact switch statements.
1369 # If the bits in the mask are contiguous, extract them.
1370 sh = is_contiguous(self.mask)
1371 if sh > 0:
1372 # Propagate SH down into the local functions.
1373 def str_switch(b, sh=sh):
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001374 return f'(insn >> {sh}) & {b >> sh:#x}'
Richard Henderson70e07112019-01-31 11:34:11 -08001375
1376 def str_case(b, sh=sh):
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001377 return hex(b >> sh)
Richard Henderson70e07112019-01-31 11:34:11 -08001378 else:
1379 def str_switch(b):
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001380 return f'insn & {whexC(b)}'
Richard Henderson70e07112019-01-31 11:34:11 -08001381
1382 def str_case(b):
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001383 return whexC(b)
Richard Henderson70e07112019-01-31 11:34:11 -08001384
1385 output(ind, 'switch (', str_switch(self.mask), ') {\n')
1386 for b, s in sorted(self.subs):
1387 innermask = outermask | self.mask
1388 innerbits = outerbits | b
1389 output(ind, 'case ', str_case(b), ':\n')
1390 output(ind, ' /* ',
1391 str_match_bits(innerbits, innermask), ' */\n')
1392 s.output_code(i + 4, extracted, innerbits, innermask)
1393 output(ind, '}\n')
1394 output(ind, 'return insn;\n')
1395# end SizeTree
1396
1397class SizeLeaf:
1398 """Class representing a leaf node in a size decode tree"""
1399
1400 def __init__(self, m, w):
1401 self.mask = m
1402 self.width = w
1403
1404 def str1(self, i):
Richard Hendersonc7cefe62021-04-28 16:27:56 -07001405 return str_indent(i) + whex(self.mask)
Richard Henderson70e07112019-01-31 11:34:11 -08001406
1407 def __str__(self):
1408 return self.str1(0)
1409
1410 def output_code(self, i, extracted, outerbits, outermask):
1411 global decode_function
1412 ind = str_indent(i)
1413
1414 # If we need to load more bytes, do so now.
1415 if extracted < self.width:
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001416 output(ind, f'insn = {decode_function}_load_bytes',
1417 f'(ctx, insn, {extracted // 8}, {self.width // 8});\n')
Richard Henderson70e07112019-01-31 11:34:11 -08001418 extracted = self.width
1419 output(ind, 'return insn;\n')
1420# end SizeLeaf
1421
1422
1423def build_size_tree(pats, width, outerbits, outermask):
1424 global insnwidth
1425
1426 # Collect the mask of bits that are fixed in this width
1427 innermask = 0xff << (insnwidth - width)
1428 innermask &= ~outermask
1429 minwidth = None
1430 onewidth = True
1431 for i in pats:
1432 innermask &= i.fixedmask
1433 if minwidth is None:
1434 minwidth = i.width
1435 elif minwidth != i.width:
1436 onewidth = False;
1437 if minwidth < i.width:
1438 minwidth = i.width
1439
1440 if onewidth:
1441 return SizeLeaf(innermask, minwidth)
1442
1443 if innermask == 0:
1444 if width < minwidth:
1445 return build_size_tree(pats, width + 8, outerbits, outermask)
1446
1447 pnames = []
1448 for p in pats:
1449 pnames.append(p.name + ':' + p.file + ':' + str(p.lineno))
1450 error_with_file(pats[0].file, pats[0].lineno,
Richard Henderson9f6e2b42021-04-28 16:37:02 -07001451 f'overlapping patterns size {width}:', pnames)
Richard Henderson70e07112019-01-31 11:34:11 -08001452
1453 bins = {}
1454 for i in pats:
1455 fb = i.fixedbits & innermask
1456 if fb in bins:
1457 bins[fb].append(i)
1458 else:
1459 bins[fb] = [i]
1460
1461 fullmask = outermask | innermask
1462 lens = sorted(bins.keys())
1463 if len(lens) == 1:
1464 b = lens[0]
1465 return build_size_tree(bins[b], width + 8, b | outerbits, fullmask)
1466
1467 r = SizeTree(innermask, width)
1468 for b, l in bins.items():
1469 s = build_size_tree(l, width, b | outerbits, fullmask)
1470 r.subs.append((b, s))
1471 return r
1472# end build_size_tree
1473
1474
Richard Henderson70e07112019-01-31 11:34:11 -08001475def prop_size(tree):
1476 """Propagate minimum widths up the decode size tree"""
1477
1478 if isinstance(tree, SizeTree):
1479 min = None
1480 for (b, s) in tree.subs:
1481 width = prop_size(s)
1482 if min is None or min > width:
1483 min = width
1484 assert min >= tree.width
1485 tree.width = min
1486 else:
1487 min = tree.width
1488 return min
1489# end prop_size
1490
1491
Richard Henderson568ae7e2017-12-07 12:44:09 -08001492def main():
1493 global arguments
1494 global formats
Richard Henderson0eff2df2019-02-23 11:35:36 -08001495 global allpatterns
Richard Henderson568ae7e2017-12-07 12:44:09 -08001496 global translate_scope
1497 global translate_prefix
1498 global output_fd
1499 global output_file
Richard Hendersonc6a5fc22023-05-31 16:25:10 -07001500 global output_null
Richard Henderson568ae7e2017-12-07 12:44:09 -08001501 global input_file
1502 global insnwidth
1503 global insntype
Bastian Koppelmann83d7c402018-03-19 12:58:46 +01001504 global insnmask
Richard Hendersonabd04f92018-10-23 10:26:25 +01001505 global decode_function
Luis Fernando Fujita Pires60c425f2021-04-07 22:18:49 +00001506 global bitop_width
Richard Henderson17560e92019-01-30 18:01:29 -08001507 global variablewidth
Richard Hendersonc6920792019-08-09 08:12:50 -07001508 global anyextern
Richard Henderson9b5acc52023-05-25 18:04:05 -07001509 global testforerror
Richard Henderson568ae7e2017-12-07 12:44:09 -08001510
Richard Henderson568ae7e2017-12-07 12:44:09 -08001511 decode_scope = 'static '
1512
Richard Hendersoncd3e7fc2019-02-23 17:44:31 -08001513 long_opts = ['decode=', 'translate=', 'output=', 'insnwidth=',
Richard Hendersonc6a5fc22023-05-31 16:25:10 -07001514 'static-decode=', 'varinsnwidth=', 'test-for-error',
1515 'output-null']
Richard Henderson568ae7e2017-12-07 12:44:09 -08001516 try:
Paolo Bonziniabff1ab2020-08-07 12:10:23 +02001517 (opts, args) = getopt.gnu_getopt(sys.argv[1:], 'o:vw:', long_opts)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001518 except getopt.GetoptError as err:
1519 error(0, err)
1520 for o, a in opts:
1521 if o in ('-o', '--output'):
1522 output_file = a
1523 elif o == '--decode':
1524 decode_function = a
1525 decode_scope = ''
Richard Hendersoncd3e7fc2019-02-23 17:44:31 -08001526 elif o == '--static-decode':
1527 decode_function = a
Richard Henderson568ae7e2017-12-07 12:44:09 -08001528 elif o == '--translate':
1529 translate_prefix = a
1530 translate_scope = ''
Richard Henderson17560e92019-01-30 18:01:29 -08001531 elif o in ('-w', '--insnwidth', '--varinsnwidth'):
1532 if o == '--varinsnwidth':
1533 variablewidth = True
Richard Henderson568ae7e2017-12-07 12:44:09 -08001534 insnwidth = int(a)
1535 if insnwidth == 16:
1536 insntype = 'uint16_t'
1537 insnmask = 0xffff
Luis Fernando Fujita Pires60c425f2021-04-07 22:18:49 +00001538 elif insnwidth == 64:
1539 insntype = 'uint64_t'
1540 insnmask = 0xffffffffffffffff
1541 bitop_width = 64
Richard Henderson568ae7e2017-12-07 12:44:09 -08001542 elif insnwidth != 32:
1543 error(0, 'cannot handle insns of width', insnwidth)
Richard Henderson9b5acc52023-05-25 18:04:05 -07001544 elif o == '--test-for-error':
1545 testforerror = True
Richard Hendersonc6a5fc22023-05-31 16:25:10 -07001546 elif o == '--output-null':
1547 output_null = True
Richard Henderson568ae7e2017-12-07 12:44:09 -08001548 else:
1549 assert False, 'unhandled option'
1550
1551 if len(args) < 1:
1552 error(0, 'missing input file')
Richard Henderson08561fc2020-05-17 10:14:11 -07001553
1554 toppat = ExcMultiPattern(0)
1555
Richard Henderson6699ae62018-10-26 14:59:43 +01001556 for filename in args:
1557 input_file = filename
Philippe Mathieu-Daudé4caceca2021-01-10 01:02:40 +01001558 f = open(filename, 'rt', encoding='utf-8')
Richard Henderson08561fc2020-05-17 10:14:11 -07001559 parse_file(f, toppat)
Richard Henderson6699ae62018-10-26 14:59:43 +01001560 f.close()
Richard Henderson568ae7e2017-12-07 12:44:09 -08001561
Richard Henderson08561fc2020-05-17 10:14:11 -07001562 # We do not want to compute masks for toppat, because those masks
1563 # are used as a starting point for build_tree. For toppat, we must
1564 # insist that decode begins from naught.
1565 for i in toppat.pats:
1566 i.prop_masks()
Richard Henderson70e07112019-01-31 11:34:11 -08001567
Richard Henderson08561fc2020-05-17 10:14:11 -07001568 toppat.build_tree()
1569 toppat.prop_format()
1570
1571 if variablewidth:
1572 for i in toppat.pats:
1573 i.prop_width()
1574 stree = build_size_tree(toppat.pats, 8, 0, 0)
1575 prop_size(stree)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001576
Richard Hendersonc6a5fc22023-05-31 16:25:10 -07001577 if output_null:
1578 output_fd = open(os.devnull, 'wt', encoding='utf-8', errors="ignore")
1579 elif output_file:
Philippe Mathieu-Daudé4caceca2021-01-10 01:02:40 +01001580 output_fd = open(output_file, 'wt', encoding='utf-8')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001581 else:
Philippe Mathieu-Daudé4caceca2021-01-10 01:02:40 +01001582 output_fd = io.TextIOWrapper(sys.stdout.buffer,
1583 encoding=sys.stdout.encoding,
1584 errors="ignore")
Richard Henderson568ae7e2017-12-07 12:44:09 -08001585
1586 output_autogen()
1587 for n in sorted(arguments.keys()):
1588 f = arguments[n]
1589 f.output_def()
1590
1591 # A single translate function can be invoked for different patterns.
1592 # Make sure that the argument sets are the same, and declare the
1593 # function only once.
Richard Hendersonc6920792019-08-09 08:12:50 -07001594 #
1595 # If we're sharing formats, we're likely also sharing trans_* functions,
1596 # but we can't tell which ones. Prevent issues from the compiler by
1597 # suppressing redundant declaration warnings.
1598 if anyextern:
Thomas Huth7aa12aa2020-07-08 20:19:44 +02001599 output("#pragma GCC diagnostic push\n",
1600 "#pragma GCC diagnostic ignored \"-Wredundant-decls\"\n",
1601 "#ifdef __clang__\n"
Richard Hendersonc6920792019-08-09 08:12:50 -07001602 "# pragma GCC diagnostic ignored \"-Wtypedef-redefinition\"\n",
Richard Hendersonc6920792019-08-09 08:12:50 -07001603 "#endif\n\n")
1604
Richard Henderson568ae7e2017-12-07 12:44:09 -08001605 out_pats = {}
Richard Henderson0eff2df2019-02-23 11:35:36 -08001606 for i in allpatterns:
Richard Henderson568ae7e2017-12-07 12:44:09 -08001607 if i.name in out_pats:
1608 p = out_pats[i.name]
1609 if i.base.base != p.base.base:
1610 error(0, i.name, ' has conflicting argument sets')
1611 else:
1612 i.output_decl()
1613 out_pats[i.name] = i
1614 output('\n')
1615
Richard Hendersonc6920792019-08-09 08:12:50 -07001616 if anyextern:
Thomas Huth7aa12aa2020-07-08 20:19:44 +02001617 output("#pragma GCC diagnostic pop\n\n")
Richard Hendersonc6920792019-08-09 08:12:50 -07001618
Richard Henderson568ae7e2017-12-07 12:44:09 -08001619 for n in sorted(formats.keys()):
1620 f = formats[n]
1621 f.output_extract()
1622
1623 output(decode_scope, 'bool ', decode_function,
1624 '(DisasContext *ctx, ', insntype, ' insn)\n{\n')
1625
1626 i4 = str_indent(4)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001627
Richard Henderson82bfac12019-02-27 21:37:32 -08001628 if len(allpatterns) != 0:
1629 output(i4, 'union {\n')
1630 for n in sorted(arguments.keys()):
1631 f = arguments[n]
1632 output(i4, i4, f.struct_name(), ' f_', f.name, ';\n')
1633 output(i4, '} u;\n\n')
Richard Henderson08561fc2020-05-17 10:14:11 -07001634 toppat.output_code(4, False, 0, 0)
Richard Henderson82bfac12019-02-27 21:37:32 -08001635
Richard Hendersoneb6b87f2019-02-23 08:57:46 -08001636 output(i4, 'return false;\n')
Richard Henderson568ae7e2017-12-07 12:44:09 -08001637 output('}\n')
1638
Richard Henderson70e07112019-01-31 11:34:11 -08001639 if variablewidth:
1640 output('\n', decode_scope, insntype, ' ', decode_function,
1641 '_load(DisasContext *ctx)\n{\n',
1642 ' ', insntype, ' insn = 0;\n\n')
1643 stree.output_code(4, 0, 0, 0)
1644 output('}\n')
1645
Richard Henderson568ae7e2017-12-07 12:44:09 -08001646 if output_file:
1647 output_fd.close()
Richard Henderson9b5acc52023-05-25 18:04:05 -07001648 exit(1 if testforerror else 0)
Richard Henderson568ae7e2017-12-07 12:44:09 -08001649# end main
1650
1651
1652if __name__ == '__main__':
1653 main()