xref: /openbmc/qemu/scripts/decodetree.py (revision 78cc9034)
13d004a37SPhilippe Mathieu-Daudé#!/usr/bin/env python3
2568ae7efSRichard Henderson# Copyright (c) 2018 Linaro Limited
3568ae7efSRichard Henderson#
4568ae7efSRichard Henderson# This library is free software; you can redistribute it and/or
5568ae7efSRichard Henderson# modify it under the terms of the GNU Lesser General Public
6568ae7efSRichard Henderson# License as published by the Free Software Foundation; either
7d6ea4236SChetan Pant# version 2.1 of the License, or (at your option) any later version.
8568ae7efSRichard Henderson#
9568ae7efSRichard Henderson# This library is distributed in the hope that it will be useful,
10568ae7efSRichard Henderson# but WITHOUT ANY WARRANTY; without even the implied warranty of
11568ae7efSRichard Henderson# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12568ae7efSRichard Henderson# Lesser General Public License for more details.
13568ae7efSRichard Henderson#
14568ae7efSRichard Henderson# You should have received a copy of the GNU Lesser General Public
15568ae7efSRichard Henderson# License along with this library; if not, see <http://www.gnu.org/licenses/>.
16568ae7efSRichard Henderson#
17568ae7efSRichard Henderson
18568ae7efSRichard Henderson#
19568ae7efSRichard Henderson# Generate a decoding tree from a specification file.
203fdbf5d6SRichard Henderson# See the syntax and semantics in docs/devel/decodetree.rst.
21568ae7efSRichard Henderson#
22568ae7efSRichard Henderson
234cacecaaSPhilippe Mathieu-Daudéimport io
24568ae7efSRichard Hendersonimport os
25568ae7efSRichard Hendersonimport re
26568ae7efSRichard Hendersonimport sys
27568ae7efSRichard Hendersonimport getopt
28568ae7efSRichard Henderson
29568ae7efSRichard Hendersoninsnwidth = 32
3060c425f3SLuis Fernando Fujita Piresbitop_width = 32
31568ae7efSRichard Hendersoninsnmask = 0xffffffff
3217560e93SRichard Hendersonvariablewidth = False
33568ae7efSRichard Hendersonfields = {}
34568ae7efSRichard Hendersonarguments = {}
35568ae7efSRichard Hendersonformats = {}
360eff2df4SRichard Hendersonallpatterns = []
37c6920795SRichard Hendersonanyextern = False
389b5acc56SRichard Hendersontestforerror = False
39568ae7efSRichard Henderson
40568ae7efSRichard Hendersontranslate_prefix = 'trans'
41568ae7efSRichard Hendersontranslate_scope = 'static '
42568ae7efSRichard Hendersoninput_file = ''
43568ae7efSRichard Hendersonoutput_file = None
44568ae7efSRichard Hendersonoutput_fd = None
45c6a5fc2aSRichard Hendersonoutput_null = False
46568ae7efSRichard Hendersoninsntype = 'uint32_t'
47abd04f92SRichard Hendersondecode_function = 'decode'
48568ae7efSRichard Henderson
49acfdd239SRichard Henderson# An identifier for C.
50acfdd239SRichard Hendersonre_C_ident = '[a-zA-Z][a-zA-Z0-9_]*'
51568ae7efSRichard Henderson
52acfdd239SRichard Henderson# Identifiers for Arguments, Fields, Formats and Patterns.
53acfdd239SRichard Hendersonre_arg_ident = '&[a-zA-Z0-9_]*'
54acfdd239SRichard Hendersonre_fld_ident = '%[a-zA-Z0-9_]*'
55acfdd239SRichard Hendersonre_fmt_ident = '@[a-zA-Z0-9_]*'
56acfdd239SRichard Hendersonre_pat_ident = '[a-zA-Z0-9_]*'
57568ae7efSRichard Henderson
5836d61244SPeter Maydell# Local implementation of a topological sort. We use the same API that
5936d61244SPeter Maydell# the Python graphlib does, so that when QEMU moves forward to a
6036d61244SPeter Maydell# baseline of Python 3.9 or newer this code can all be dropped and
6136d61244SPeter Maydell# replaced with:
6236d61244SPeter Maydell#    from graphlib import TopologicalSorter, CycleError
6336d61244SPeter Maydell#
6436d61244SPeter Maydell# https://docs.python.org/3.9/library/graphlib.html#graphlib.TopologicalSorter
6536d61244SPeter Maydell#
6636d61244SPeter Maydell# We only implement the parts of TopologicalSorter we care about:
6736d61244SPeter Maydell#  ts = TopologicalSorter(graph=None)
6836d61244SPeter Maydell#    create the sorter. graph is a dictionary whose keys are
6936d61244SPeter Maydell#    nodes and whose values are lists of the predecessors of that node.
7036d61244SPeter Maydell#    (That is, if graph contains "A" -> ["B", "C"] then we must output
7136d61244SPeter Maydell#    B and C before A.)
7236d61244SPeter Maydell#  ts.static_order()
7336d61244SPeter Maydell#    returns a list of all the nodes in sorted order, or raises CycleError
7436d61244SPeter Maydell#  CycleError
7536d61244SPeter Maydell#    exception raised if there are cycles in the graph. The second
7636d61244SPeter Maydell#    element in the args attribute is a list of nodes which form a
7736d61244SPeter Maydell#    cycle; the first and last element are the same, eg [a, b, c, a]
7836d61244SPeter Maydell#    (Our implementation doesn't give the order correctly.)
7936d61244SPeter Maydell#
8036d61244SPeter Maydell# For our purposes we can assume that the data set is always small
8136d61244SPeter Maydell# (typically 10 nodes or less, actual links in the graph very rare),
8236d61244SPeter Maydell# so we don't need to worry about efficiency of implementation.
8336d61244SPeter Maydell#
8436d61244SPeter Maydell# The core of this implementation is from
8536d61244SPeter Maydell# https://code.activestate.com/recipes/578272-topological-sort/
8636d61244SPeter Maydell# (but updated to Python 3), and is under the MIT license.
8736d61244SPeter Maydell
8836d61244SPeter Maydellclass CycleError(ValueError):
8936d61244SPeter Maydell    """Subclass of ValueError raised if cycles exist in the graph"""
9036d61244SPeter Maydell    pass
9136d61244SPeter Maydell
9236d61244SPeter Maydellclass TopologicalSorter:
9336d61244SPeter Maydell    """Topologically sort a graph"""
9436d61244SPeter Maydell    def __init__(self, graph=None):
9536d61244SPeter Maydell        self.graph = graph
9636d61244SPeter Maydell
9736d61244SPeter Maydell    def static_order(self):
9836d61244SPeter Maydell        # We do the sort right here, unlike the stdlib version
9936d61244SPeter Maydell        from functools import reduce
10036d61244SPeter Maydell        data = {}
10136d61244SPeter Maydell        r = []
10236d61244SPeter Maydell
10336d61244SPeter Maydell        if not self.graph:
10436d61244SPeter Maydell            return []
10536d61244SPeter Maydell
10636d61244SPeter Maydell        # This code wants the values in the dict to be specifically sets
10736d61244SPeter Maydell        for k, v in self.graph.items():
10836d61244SPeter Maydell            data[k] = set(v)
10936d61244SPeter Maydell
11036d61244SPeter Maydell        # Find all items that don't depend on anything.
11136d61244SPeter Maydell        extra_items_in_deps = (reduce(set.union, data.values())
11236d61244SPeter Maydell                               - set(data.keys()))
11336d61244SPeter Maydell        # Add empty dependencies where needed
11436d61244SPeter Maydell        data.update({item:{} for item in extra_items_in_deps})
11536d61244SPeter Maydell        while True:
11636d61244SPeter Maydell            ordered = set(item for item, dep in data.items() if not dep)
11736d61244SPeter Maydell            if not ordered:
11836d61244SPeter Maydell                break
11936d61244SPeter Maydell            r.extend(ordered)
12036d61244SPeter Maydell            data = {item: (dep - ordered)
12136d61244SPeter Maydell                    for item, dep in data.items()
12236d61244SPeter Maydell                        if item not in ordered}
12336d61244SPeter Maydell        if data:
12436d61244SPeter Maydell            # This doesn't give as nice results as the stdlib, which
12536d61244SPeter Maydell            # gives you the cycle by listing the nodes in order. Here
12636d61244SPeter Maydell            # we only know the nodes in the cycle but not their order.
12736d61244SPeter Maydell            raise CycleError(f'nodes are in a cycle', list(data.keys()))
12836d61244SPeter Maydell
12936d61244SPeter Maydell        return r
13036d61244SPeter Maydell# end TopologicalSorter
13136d61244SPeter Maydell
1326699ae6aSRichard Hendersondef error_with_file(file, lineno, *args):
133568ae7efSRichard Henderson    """Print an error message from file:line and args and exit."""
134568ae7efSRichard Henderson    global output_file
135568ae7efSRichard Henderson    global output_fd
136568ae7efSRichard Henderson
137*78cc9034SPeter Maydell    # For the test suite expected-errors case, don't print the
138*78cc9034SPeter Maydell    # string "error: ", so they don't turn up as false positives
139*78cc9034SPeter Maydell    # if you grep the meson logs for strings like that.
140*78cc9034SPeter Maydell    end = 'error: ' if not testforerror else 'detected: '
1412fd51b19SRichard Henderson    prefix = ''
1422fd51b19SRichard Henderson    if file:
1439f6e2b4dSRichard Henderson        prefix += f'{file}:'
144568ae7efSRichard Henderson    if lineno:
1459f6e2b4dSRichard Henderson        prefix += f'{lineno}:'
1462fd51b19SRichard Henderson    if prefix:
1472fd51b19SRichard Henderson        prefix += ' '
148*78cc9034SPeter Maydell    print(prefix, end=end, file=sys.stderr)
1492fd51b19SRichard Henderson    print(*args, file=sys.stderr)
1502fd51b19SRichard Henderson
151568ae7efSRichard Henderson    if output_file and output_fd:
152568ae7efSRichard Henderson        output_fd.close()
153568ae7efSRichard Henderson        os.remove(output_file)
1549b5acc56SRichard Henderson    exit(0 if testforerror else 1)
1552fd51b19SRichard Henderson# end error_with_file
1562fd51b19SRichard Henderson
157568ae7efSRichard Henderson
1586699ae6aSRichard Hendersondef error(lineno, *args):
1592fd51b19SRichard Henderson    error_with_file(input_file, lineno, *args)
1602fd51b19SRichard Henderson# end error
1612fd51b19SRichard Henderson
162568ae7efSRichard Henderson
163568ae7efSRichard Hendersondef output(*args):
164568ae7efSRichard Henderson    global output_fd
165568ae7efSRichard Henderson    for a in args:
166568ae7efSRichard Henderson        output_fd.write(a)
167568ae7efSRichard Henderson
168568ae7efSRichard Henderson
169568ae7efSRichard Hendersondef output_autogen():
170568ae7efSRichard Henderson    output('/* This file is autogenerated by scripts/decodetree.py.  */\n\n')
171568ae7efSRichard Henderson
172568ae7efSRichard Henderson
173568ae7efSRichard Hendersondef str_indent(c):
174568ae7efSRichard Henderson    """Return a string with C spaces"""
175568ae7efSRichard Henderson    return ' ' * c
176568ae7efSRichard Henderson
177568ae7efSRichard Henderson
178568ae7efSRichard Hendersondef str_fields(fields):
17965fdb3ccSzhaolichang    """Return a string uniquely identifying FIELDS"""
180568ae7efSRichard Henderson    r = ''
181568ae7efSRichard Henderson    for n in sorted(fields.keys()):
182568ae7efSRichard Henderson        r += '_' + n
183568ae7efSRichard Henderson    return r[1:]
184568ae7efSRichard Henderson
185568ae7efSRichard Henderson
186c7cefe6cSRichard Hendersondef whex(val):
187c7cefe6cSRichard Henderson    """Return a hex string for val padded for insnwidth"""
188c7cefe6cSRichard Henderson    global insnwidth
189c7cefe6cSRichard Henderson    return f'0x{val:0{insnwidth // 4}x}'
190c7cefe6cSRichard Henderson
191c7cefe6cSRichard Henderson
192c7cefe6cSRichard Hendersondef whexC(val):
193c7cefe6cSRichard Henderson    """Return a hex string for val padded for insnwidth,
194c7cefe6cSRichard Henderson       and with the proper suffix for a C constant."""
195c7cefe6cSRichard Henderson    suffix = ''
19660c425f3SLuis Fernando Fujita Pires    if val >= 0x100000000:
19760c425f3SLuis Fernando Fujita Pires        suffix = 'ull'
19860c425f3SLuis Fernando Fujita Pires    elif val >= 0x80000000:
199c7cefe6cSRichard Henderson        suffix = 'u'
200c7cefe6cSRichard Henderson    return whex(val) + suffix
201c7cefe6cSRichard Henderson
202c7cefe6cSRichard Henderson
203568ae7efSRichard Hendersondef str_match_bits(bits, mask):
204568ae7efSRichard Henderson    """Return a string pretty-printing BITS/MASK"""
205568ae7efSRichard Henderson    global insnwidth
206568ae7efSRichard Henderson
207568ae7efSRichard Henderson    i = 1 << (insnwidth - 1)
208568ae7efSRichard Henderson    space = 0x01010100
209568ae7efSRichard Henderson    r = ''
210568ae7efSRichard Henderson    while i != 0:
211568ae7efSRichard Henderson        if i & mask:
212568ae7efSRichard Henderson            if i & bits:
213568ae7efSRichard Henderson                r += '1'
214568ae7efSRichard Henderson            else:
215568ae7efSRichard Henderson                r += '0'
216568ae7efSRichard Henderson        else:
217568ae7efSRichard Henderson            r += '.'
218568ae7efSRichard Henderson        if i & space:
219568ae7efSRichard Henderson            r += ' '
220568ae7efSRichard Henderson        i >>= 1
221568ae7efSRichard Henderson    return r
222568ae7efSRichard Henderson
223568ae7efSRichard Henderson
224568ae7efSRichard Hendersondef is_pow2(x):
225568ae7efSRichard Henderson    """Return true iff X is equal to a power of 2."""
226568ae7efSRichard Henderson    return (x & (x - 1)) == 0
227568ae7efSRichard Henderson
228568ae7efSRichard Henderson
229568ae7efSRichard Hendersondef ctz(x):
230568ae7efSRichard Henderson    """Return the number of times 2 factors into X."""
231b44b3449SRichard Henderson    assert x != 0
232568ae7efSRichard Henderson    r = 0
233568ae7efSRichard Henderson    while ((x >> r) & 1) == 0:
234568ae7efSRichard Henderson        r += 1
235568ae7efSRichard Henderson    return r
236568ae7efSRichard Henderson
237568ae7efSRichard Henderson
238568ae7efSRichard Hendersondef is_contiguous(bits):
239b44b3449SRichard Henderson    if bits == 0:
240b44b3449SRichard Henderson        return -1
241568ae7efSRichard Henderson    shift = ctz(bits)
242568ae7efSRichard Henderson    if is_pow2((bits >> shift) + 1):
243568ae7efSRichard Henderson        return shift
244568ae7efSRichard Henderson    else:
245568ae7efSRichard Henderson        return -1
246568ae7efSRichard Henderson
247568ae7efSRichard Henderson
248af93ccacSRichard Hendersondef eq_fields_for_args(flds_a, arg):
249af93ccacSRichard Henderson    if len(flds_a) != len(arg.fields):
250af93ccacSRichard Henderson        return False
251af93ccacSRichard Henderson    # Only allow inference on default types
252af93ccacSRichard Henderson    for t in arg.types:
253af93ccacSRichard Henderson        if t != 'int':
254568ae7efSRichard Henderson            return False
255568ae7efSRichard Henderson    for k, a in flds_a.items():
256af93ccacSRichard Henderson        if k not in arg.fields:
257568ae7efSRichard Henderson            return False
258568ae7efSRichard Henderson    return True
259568ae7efSRichard Henderson
260568ae7efSRichard Henderson
261568ae7efSRichard Hendersondef eq_fields_for_fmts(flds_a, flds_b):
262568ae7efSRichard Henderson    if len(flds_a) != len(flds_b):
263568ae7efSRichard Henderson        return False
264568ae7efSRichard Henderson    for k, a in flds_a.items():
265568ae7efSRichard Henderson        if k not in flds_b:
266568ae7efSRichard Henderson            return False
267568ae7efSRichard Henderson        b = flds_b[k]
268568ae7efSRichard Henderson        if a.__class__ != b.__class__ or a != b:
269568ae7efSRichard Henderson            return False
270568ae7efSRichard Henderson    return True
271568ae7efSRichard Henderson
272568ae7efSRichard Henderson
273568ae7efSRichard Hendersonclass Field:
274568ae7efSRichard Henderson    """Class representing a simple instruction field"""
275568ae7efSRichard Henderson    def __init__(self, sign, pos, len):
276568ae7efSRichard Henderson        self.sign = sign
277568ae7efSRichard Henderson        self.pos = pos
278568ae7efSRichard Henderson        self.len = len
279568ae7efSRichard Henderson        self.mask = ((1 << len) - 1) << pos
280568ae7efSRichard Henderson
281568ae7efSRichard Henderson    def __str__(self):
282568ae7efSRichard Henderson        if self.sign:
283568ae7efSRichard Henderson            s = 's'
284568ae7efSRichard Henderson        else:
285568ae7efSRichard Henderson            s = ''
286cbcdf1a9SCleber Rosa        return str(self.pos) + ':' + s + str(self.len)
287568ae7efSRichard Henderson
288aeac22baSPeter Maydell    def str_extract(self, lvalue_formatter):
28960c425f3SLuis Fernando Fujita Pires        global bitop_width
29060c425f3SLuis Fernando Fujita Pires        s = 's' if self.sign else ''
29160c425f3SLuis Fernando Fujita Pires        return f'{s}extract{bitop_width}(insn, {self.pos}, {self.len})'
292568ae7efSRichard Henderson
2937e6c28beSPeter Maydell    def referenced_fields(self):
2947e6c28beSPeter Maydell        return []
2957e6c28beSPeter Maydell
296568ae7efSRichard Henderson    def __eq__(self, other):
2972c7d4427SRichard Henderson        return self.sign == other.sign and self.mask == other.mask
298568ae7efSRichard Henderson
299568ae7efSRichard Henderson    def __ne__(self, other):
300568ae7efSRichard Henderson        return not self.__eq__(other)
301568ae7efSRichard Henderson# end Field
302568ae7efSRichard Henderson
303568ae7efSRichard Henderson
304568ae7efSRichard Hendersonclass MultiField:
305568ae7efSRichard Henderson    """Class representing a compound instruction field"""
306568ae7efSRichard Henderson    def __init__(self, subs, mask):
307568ae7efSRichard Henderson        self.subs = subs
308568ae7efSRichard Henderson        self.sign = subs[0].sign
309568ae7efSRichard Henderson        self.mask = mask
310568ae7efSRichard Henderson
311568ae7efSRichard Henderson    def __str__(self):
312568ae7efSRichard Henderson        return str(self.subs)
313568ae7efSRichard Henderson
314aeac22baSPeter Maydell    def str_extract(self, lvalue_formatter):
31560c425f3SLuis Fernando Fujita Pires        global bitop_width
316568ae7efSRichard Henderson        ret = '0'
317568ae7efSRichard Henderson        pos = 0
318568ae7efSRichard Henderson        for f in reversed(self.subs):
319aeac22baSPeter Maydell            ext = f.str_extract(lvalue_formatter)
320568ae7efSRichard Henderson            if pos == 0:
3219f6e2b4dSRichard Henderson                ret = ext
322568ae7efSRichard Henderson            else:
32360c425f3SLuis Fernando Fujita Pires                ret = f'deposit{bitop_width}({ret}, {pos}, {bitop_width - pos}, {ext})'
324568ae7efSRichard Henderson            pos += f.len
325568ae7efSRichard Henderson        return ret
326568ae7efSRichard Henderson
3277e6c28beSPeter Maydell    def referenced_fields(self):
3287e6c28beSPeter Maydell        l = []
3297e6c28beSPeter Maydell        for f in self.subs:
3307e6c28beSPeter Maydell            l.extend(f.referenced_fields())
3317e6c28beSPeter Maydell        return l
3327e6c28beSPeter Maydell
333568ae7efSRichard Henderson    def __ne__(self, other):
334568ae7efSRichard Henderson        if len(self.subs) != len(other.subs):
335568ae7efSRichard Henderson            return True
336568ae7efSRichard Henderson        for a, b in zip(self.subs, other.subs):
337568ae7efSRichard Henderson            if a.__class__ != b.__class__ or a != b:
338568ae7efSRichard Henderson                return True
339568ae7efSRichard Henderson        return False
340568ae7efSRichard Henderson
341568ae7efSRichard Henderson    def __eq__(self, other):
342568ae7efSRichard Henderson        return not self.__ne__(other)
343568ae7efSRichard Henderson# end MultiField
344568ae7efSRichard Henderson
345568ae7efSRichard Henderson
346568ae7efSRichard Hendersonclass ConstField:
347568ae7efSRichard Henderson    """Class representing an argument field with constant value"""
348568ae7efSRichard Henderson    def __init__(self, value):
349568ae7efSRichard Henderson        self.value = value
350568ae7efSRichard Henderson        self.mask = 0
351568ae7efSRichard Henderson        self.sign = value < 0
352568ae7efSRichard Henderson
353568ae7efSRichard Henderson    def __str__(self):
354568ae7efSRichard Henderson        return str(self.value)
355568ae7efSRichard Henderson
356aeac22baSPeter Maydell    def str_extract(self, lvalue_formatter):
357568ae7efSRichard Henderson        return str(self.value)
358568ae7efSRichard Henderson
3597e6c28beSPeter Maydell    def referenced_fields(self):
3607e6c28beSPeter Maydell        return []
3617e6c28beSPeter Maydell
362568ae7efSRichard Henderson    def __cmp__(self, other):
363568ae7efSRichard Henderson        return self.value - other.value
364568ae7efSRichard Henderson# end ConstField
365568ae7efSRichard Henderson
366568ae7efSRichard Henderson
367568ae7efSRichard Hendersonclass FunctionField:
36894597b61SRichard Henderson    """Class representing a field passed through a function"""
369568ae7efSRichard Henderson    def __init__(self, func, base):
370568ae7efSRichard Henderson        self.mask = base.mask
371568ae7efSRichard Henderson        self.sign = base.sign
372568ae7efSRichard Henderson        self.base = base
373568ae7efSRichard Henderson        self.func = func
374568ae7efSRichard Henderson
375568ae7efSRichard Henderson    def __str__(self):
376568ae7efSRichard Henderson        return self.func + '(' + str(self.base) + ')'
377568ae7efSRichard Henderson
378aeac22baSPeter Maydell    def str_extract(self, lvalue_formatter):
379aeac22baSPeter Maydell        return (self.func + '(ctx, '
380aeac22baSPeter Maydell                + self.base.str_extract(lvalue_formatter) + ')')
381568ae7efSRichard Henderson
3827e6c28beSPeter Maydell    def referenced_fields(self):
3837e6c28beSPeter Maydell        return self.base.referenced_fields()
3847e6c28beSPeter Maydell
385568ae7efSRichard Henderson    def __eq__(self, other):
386568ae7efSRichard Henderson        return self.func == other.func and self.base == other.base
387568ae7efSRichard Henderson
388568ae7efSRichard Henderson    def __ne__(self, other):
389568ae7efSRichard Henderson        return not self.__eq__(other)
390568ae7efSRichard Henderson# end FunctionField
391568ae7efSRichard Henderson
392568ae7efSRichard Henderson
39394597b61SRichard Hendersonclass ParameterField:
39494597b61SRichard Henderson    """Class representing a pseudo-field read from a function"""
39594597b61SRichard Henderson    def __init__(self, func):
39694597b61SRichard Henderson        self.mask = 0
39794597b61SRichard Henderson        self.sign = 0
39894597b61SRichard Henderson        self.func = func
39994597b61SRichard Henderson
40094597b61SRichard Henderson    def __str__(self):
40194597b61SRichard Henderson        return self.func
40294597b61SRichard Henderson
403aeac22baSPeter Maydell    def str_extract(self, lvalue_formatter):
40494597b61SRichard Henderson        return self.func + '(ctx)'
40594597b61SRichard Henderson
4067e6c28beSPeter Maydell    def referenced_fields(self):
4077e6c28beSPeter Maydell        return []
4087e6c28beSPeter Maydell
40994597b61SRichard Henderson    def __eq__(self, other):
41094597b61SRichard Henderson        return self.func == other.func
41194597b61SRichard Henderson
41294597b61SRichard Henderson    def __ne__(self, other):
41394597b61SRichard Henderson        return not self.__eq__(other)
41494597b61SRichard Henderson# end ParameterField
41594597b61SRichard Henderson
4167e6c28beSPeter Maydellclass NamedField:
4177e6c28beSPeter Maydell    """Class representing a field already named in the pattern"""
4187e6c28beSPeter Maydell    def __init__(self, name, sign, len):
4197e6c28beSPeter Maydell        self.mask = 0
4207e6c28beSPeter Maydell        self.sign = sign
4217e6c28beSPeter Maydell        self.len = len
4227e6c28beSPeter Maydell        self.name = name
4237e6c28beSPeter Maydell
4247e6c28beSPeter Maydell    def __str__(self):
4257e6c28beSPeter Maydell        return self.name
4267e6c28beSPeter Maydell
4277e6c28beSPeter Maydell    def str_extract(self, lvalue_formatter):
4287e6c28beSPeter Maydell        global bitop_width
4297e6c28beSPeter Maydell        s = 's' if self.sign else ''
4307e6c28beSPeter Maydell        lvalue = lvalue_formatter(self.name)
4317e6c28beSPeter Maydell        return f'{s}extract{bitop_width}({lvalue}, 0, {self.len})'
4327e6c28beSPeter Maydell
4337e6c28beSPeter Maydell    def referenced_fields(self):
4347e6c28beSPeter Maydell        return [self.name]
4357e6c28beSPeter Maydell
4367e6c28beSPeter Maydell    def __eq__(self, other):
4377e6c28beSPeter Maydell        return self.name == other.name
4387e6c28beSPeter Maydell
4397e6c28beSPeter Maydell    def __ne__(self, other):
4407e6c28beSPeter Maydell        return not self.__eq__(other)
4417e6c28beSPeter Maydell# end NamedField
44294597b61SRichard Henderson
443568ae7efSRichard Hendersonclass Arguments:
444568ae7efSRichard Henderson    """Class representing the extracted fields of a format"""
445af93ccacSRichard Henderson    def __init__(self, nm, flds, types, extern):
446568ae7efSRichard Henderson        self.name = nm
447abd04f92SRichard Henderson        self.extern = extern
448af93ccacSRichard Henderson        self.fields = flds
449af93ccacSRichard Henderson        self.types = types
450568ae7efSRichard Henderson
451568ae7efSRichard Henderson    def __str__(self):
452568ae7efSRichard Henderson        return self.name + ' ' + str(self.fields)
453568ae7efSRichard Henderson
454568ae7efSRichard Henderson    def struct_name(self):
455568ae7efSRichard Henderson        return 'arg_' + self.name
456568ae7efSRichard Henderson
457568ae7efSRichard Henderson    def output_def(self):
458abd04f92SRichard Henderson        if not self.extern:
459568ae7efSRichard Henderson            output('typedef struct {\n')
460af93ccacSRichard Henderson            for (n, t) in zip(self.fields, self.types):
461af93ccacSRichard Henderson                output(f'    {t} {n};\n')
462568ae7efSRichard Henderson            output('} ', self.struct_name(), ';\n\n')
463568ae7efSRichard Henderson# end Arguments
464568ae7efSRichard Henderson
465568ae7efSRichard Hendersonclass General:
466568ae7efSRichard Henderson    """Common code between instruction formats and instruction patterns"""
46717560e93SRichard Henderson    def __init__(self, name, lineno, base, fixb, fixm, udfm, fldm, flds, w):
468568ae7efSRichard Henderson        self.name = name
4696699ae6aSRichard Henderson        self.file = input_file
470568ae7efSRichard Henderson        self.lineno = lineno
471568ae7efSRichard Henderson        self.base = base
472568ae7efSRichard Henderson        self.fixedbits = fixb
473568ae7efSRichard Henderson        self.fixedmask = fixm
474568ae7efSRichard Henderson        self.undefmask = udfm
475568ae7efSRichard Henderson        self.fieldmask = fldm
476568ae7efSRichard Henderson        self.fields = flds
47717560e93SRichard Henderson        self.width = w
4787e6c28beSPeter Maydell        self.dangling = None
479568ae7efSRichard Henderson
480568ae7efSRichard Henderson    def __str__(self):
4810eff2df4SRichard Henderson        return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
482568ae7efSRichard Henderson
483568ae7efSRichard Henderson    def str1(self, i):
484568ae7efSRichard Henderson        return str_indent(i) + self.__str__()
485aeac22baSPeter Maydell
4867e6c28beSPeter Maydell    def dangling_references(self):
4877e6c28beSPeter Maydell        # Return a list of all named references which aren't satisfied
4887e6c28beSPeter Maydell        # directly by this format/pattern. This will be either:
4897e6c28beSPeter Maydell        #  * a format referring to a field which is specified by the
4907e6c28beSPeter Maydell        #    pattern(s) using it
4917e6c28beSPeter Maydell        #  * a pattern referring to a field which is specified by the
4927e6c28beSPeter Maydell        #    format it uses
4937e6c28beSPeter Maydell        #  * a user error (referring to a field that doesn't exist at all)
4947e6c28beSPeter Maydell        if self.dangling is None:
4957e6c28beSPeter Maydell            # Compute this once and cache the answer
4967e6c28beSPeter Maydell            dangling = []
497aeac22baSPeter Maydell            for n, f in self.fields.items():
4987e6c28beSPeter Maydell                for r in f.referenced_fields():
4997e6c28beSPeter Maydell                    if r not in self.fields:
5007e6c28beSPeter Maydell                        dangling.append(r)
5017e6c28beSPeter Maydell            self.dangling = dangling
5027e6c28beSPeter Maydell        return self.dangling
5037e6c28beSPeter Maydell
5047e6c28beSPeter Maydell    def output_fields(self, indent, lvalue_formatter):
5057e6c28beSPeter Maydell        # We use a topological sort to ensure that any use of NamedField
5067e6c28beSPeter Maydell        # comes after the initialization of the field it is referencing.
5077e6c28beSPeter Maydell        graph = {}
5087e6c28beSPeter Maydell        for n, f in self.fields.items():
5097e6c28beSPeter Maydell            refs = f.referenced_fields()
5107e6c28beSPeter Maydell            graph[n] = refs
5117e6c28beSPeter Maydell
5127e6c28beSPeter Maydell        try:
5137e6c28beSPeter Maydell            ts = TopologicalSorter(graph)
5147e6c28beSPeter Maydell            for n in ts.static_order():
5157e6c28beSPeter Maydell                # We only want to emit assignments for the keys
5167e6c28beSPeter Maydell                # in our fields list, not for anything that ends up
5177e6c28beSPeter Maydell                # in the tsort graph only because it was referenced as
5187e6c28beSPeter Maydell                # a NamedField.
5197e6c28beSPeter Maydell                try:
5207e6c28beSPeter Maydell                    f = self.fields[n]
521aeac22baSPeter Maydell                    output(indent, lvalue_formatter(n), ' = ',
522aeac22baSPeter Maydell                           f.str_extract(lvalue_formatter), ';\n')
5237e6c28beSPeter Maydell                except KeyError:
5247e6c28beSPeter Maydell                    pass
5257e6c28beSPeter Maydell        except CycleError as e:
5267e6c28beSPeter Maydell            # The second element of args is a list of nodes which form
5277e6c28beSPeter Maydell            # a cycle (there might be others too, but only one is reported).
5287e6c28beSPeter Maydell            # Pretty-print it to tell the user.
5297e6c28beSPeter Maydell            cycle = ' => '.join(e.args[1])
5307e6c28beSPeter Maydell            error(self.lineno, 'field definitions form a cycle: ' + cycle)
531568ae7efSRichard Henderson# end General
532568ae7efSRichard Henderson
533568ae7efSRichard Henderson
534568ae7efSRichard Hendersonclass Format(General):
535568ae7efSRichard Henderson    """Class representing an instruction format"""
536568ae7efSRichard Henderson
537568ae7efSRichard Henderson    def extract_name(self):
53871ecf79bSRichard Henderson        global decode_function
53971ecf79bSRichard Henderson        return decode_function + '_extract_' + self.name
540568ae7efSRichard Henderson
541568ae7efSRichard Henderson    def output_extract(self):
542451e4ffdSRichard Henderson        output('static void ', self.extract_name(), '(DisasContext *ctx, ',
543568ae7efSRichard Henderson               self.base.struct_name(), ' *a, ', insntype, ' insn)\n{\n')
544aeac22baSPeter Maydell        self.output_fields(str_indent(4), lambda n: 'a->' + n)
545568ae7efSRichard Henderson        output('}\n\n')
546568ae7efSRichard Henderson# end Format
547568ae7efSRichard Henderson
548568ae7efSRichard Henderson
549568ae7efSRichard Hendersonclass Pattern(General):
550568ae7efSRichard Henderson    """Class representing an instruction pattern"""
551568ae7efSRichard Henderson
552568ae7efSRichard Henderson    def output_decl(self):
553568ae7efSRichard Henderson        global translate_scope
554568ae7efSRichard Henderson        global translate_prefix
555568ae7efSRichard Henderson        output('typedef ', self.base.base.struct_name(),
556568ae7efSRichard Henderson               ' arg_', self.name, ';\n')
55776805598SRichard Henderson        output(translate_scope, 'bool ', translate_prefix, '_', self.name,
5583a7be554SRichard Henderson               '(DisasContext *ctx, arg_', self.name, ' *a);\n')
559568ae7efSRichard Henderson
560568ae7efSRichard Henderson    def output_code(self, i, extracted, outerbits, outermask):
561568ae7efSRichard Henderson        global translate_prefix
562568ae7efSRichard Henderson        ind = str_indent(i)
563568ae7efSRichard Henderson        arg = self.base.base.name
5646699ae6aSRichard Henderson        output(ind, '/* ', self.file, ':', str(self.lineno), ' */\n')
5657e6c28beSPeter Maydell        # We might have named references in the format that refer to fields
5667e6c28beSPeter Maydell        # in the pattern, or named references in the pattern that refer
5677e6c28beSPeter Maydell        # to fields in the format. This affects whether we extract the fields
5687e6c28beSPeter Maydell        # for the format before or after the ones for the pattern.
5697e6c28beSPeter Maydell        # For simplicity we don't allow cross references in both directions.
5707e6c28beSPeter Maydell        # This is also where we catch the syntax error of referring to
5717e6c28beSPeter Maydell        # a nonexistent field.
5727e6c28beSPeter Maydell        fmt_refs = self.base.dangling_references()
5737e6c28beSPeter Maydell        for r in fmt_refs:
5747e6c28beSPeter Maydell            if r not in self.fields:
5757e6c28beSPeter Maydell                error(self.lineno, f'format refers to undefined field {r}')
5767e6c28beSPeter Maydell        pat_refs = self.dangling_references()
5777e6c28beSPeter Maydell        for r in pat_refs:
5787e6c28beSPeter Maydell            if r not in self.base.fields:
5797e6c28beSPeter Maydell                error(self.lineno, f'pattern refers to undefined field {r}')
5807e6c28beSPeter Maydell        if pat_refs and fmt_refs:
5817e6c28beSPeter Maydell            error(self.lineno, ('pattern that uses fields defined in format '
5827e6c28beSPeter Maydell                                'cannot use format that uses fields defined '
5837e6c28beSPeter Maydell                                'in pattern'))
5847e6c28beSPeter Maydell        if fmt_refs:
5857e6c28beSPeter Maydell            # pattern fields first
5867e6c28beSPeter Maydell            self.output_fields(ind, lambda n: 'u.f_' + arg + '.' + n)
5877e6c28beSPeter Maydell            assert not extracted, "dangling fmt refs but it was already extracted"
588568ae7efSRichard Henderson        if not extracted:
589451e4ffdSRichard Henderson            output(ind, self.base.extract_name(),
590451e4ffdSRichard Henderson                   '(ctx, &u.f_', arg, ', insn);\n')
5917e6c28beSPeter Maydell        if not fmt_refs:
5927e6c28beSPeter Maydell            # pattern fields last
593aeac22baSPeter Maydell            self.output_fields(ind, lambda n: 'u.f_' + arg + '.' + n)
5947e6c28beSPeter Maydell
595eb6b87faSRichard Henderson        output(ind, 'if (', translate_prefix, '_', self.name,
596eb6b87faSRichard Henderson               '(ctx, &u.f_', arg, ')) return true;\n')
59708561fc1SRichard Henderson
59808561fc1SRichard Henderson    # Normal patterns do not have children.
59908561fc1SRichard Henderson    def build_tree(self):
60008561fc1SRichard Henderson        return
60108561fc1SRichard Henderson    def prop_masks(self):
60208561fc1SRichard Henderson        return
60308561fc1SRichard Henderson    def prop_format(self):
60408561fc1SRichard Henderson        return
60508561fc1SRichard Henderson    def prop_width(self):
60608561fc1SRichard Henderson        return
60708561fc1SRichard Henderson
608568ae7efSRichard Henderson# end Pattern
609568ae7efSRichard Henderson
610568ae7efSRichard Henderson
611df63044dSRichard Hendersonclass MultiPattern(General):
612df63044dSRichard Henderson    """Class representing a set of instruction patterns"""
613df63044dSRichard Henderson
61408561fc1SRichard Henderson    def __init__(self, lineno):
615df63044dSRichard Henderson        self.file = input_file
616df63044dSRichard Henderson        self.lineno = lineno
61708561fc1SRichard Henderson        self.pats = []
618df63044dSRichard Henderson        self.base = None
619df63044dSRichard Henderson        self.fixedbits = 0
620df63044dSRichard Henderson        self.fixedmask = 0
621df63044dSRichard Henderson        self.undefmask = 0
622df63044dSRichard Henderson        self.width = None
623df63044dSRichard Henderson
624df63044dSRichard Henderson    def __str__(self):
625df63044dSRichard Henderson        r = 'group'
626df63044dSRichard Henderson        if self.fixedbits is not None:
627df63044dSRichard Henderson            r += ' ' + str_match_bits(self.fixedbits, self.fixedmask)
628df63044dSRichard Henderson        return r
629df63044dSRichard Henderson
630df63044dSRichard Henderson    def output_decl(self):
631df63044dSRichard Henderson        for p in self.pats:
632df63044dSRichard Henderson            p.output_decl()
63308561fc1SRichard Henderson
63408561fc1SRichard Henderson    def prop_masks(self):
63508561fc1SRichard Henderson        global insnmask
63608561fc1SRichard Henderson
63708561fc1SRichard Henderson        fixedmask = insnmask
63808561fc1SRichard Henderson        undefmask = insnmask
63908561fc1SRichard Henderson
64008561fc1SRichard Henderson        # Collect fixedmask/undefmask for all of the children.
64108561fc1SRichard Henderson        for p in self.pats:
64208561fc1SRichard Henderson            p.prop_masks()
64308561fc1SRichard Henderson            fixedmask &= p.fixedmask
64408561fc1SRichard Henderson            undefmask &= p.undefmask
64508561fc1SRichard Henderson
64608561fc1SRichard Henderson        # Widen fixedmask until all fixedbits match
64708561fc1SRichard Henderson        repeat = True
64808561fc1SRichard Henderson        fixedbits = 0
64908561fc1SRichard Henderson        while repeat and fixedmask != 0:
65008561fc1SRichard Henderson            fixedbits = None
65108561fc1SRichard Henderson            for p in self.pats:
65208561fc1SRichard Henderson                thisbits = p.fixedbits & fixedmask
65308561fc1SRichard Henderson                if fixedbits is None:
65408561fc1SRichard Henderson                    fixedbits = thisbits
65508561fc1SRichard Henderson                elif fixedbits != thisbits:
65608561fc1SRichard Henderson                    fixedmask &= ~(fixedbits ^ thisbits)
65708561fc1SRichard Henderson                    break
65808561fc1SRichard Henderson            else:
65908561fc1SRichard Henderson                repeat = False
66008561fc1SRichard Henderson
66108561fc1SRichard Henderson        self.fixedbits = fixedbits
66208561fc1SRichard Henderson        self.fixedmask = fixedmask
66308561fc1SRichard Henderson        self.undefmask = undefmask
66408561fc1SRichard Henderson
66508561fc1SRichard Henderson    def build_tree(self):
66608561fc1SRichard Henderson        for p in self.pats:
66708561fc1SRichard Henderson            p.build_tree()
66808561fc1SRichard Henderson
66908561fc1SRichard Henderson    def prop_format(self):
67008561fc1SRichard Henderson        for p in self.pats:
6712fd2eb5aSRichard Henderson            p.prop_format()
67208561fc1SRichard Henderson
67308561fc1SRichard Henderson    def prop_width(self):
67408561fc1SRichard Henderson        width = None
67508561fc1SRichard Henderson        for p in self.pats:
67608561fc1SRichard Henderson            p.prop_width()
67708561fc1SRichard Henderson            if width is None:
67808561fc1SRichard Henderson                width = p.width
67908561fc1SRichard Henderson            elif width != p.width:
68008561fc1SRichard Henderson                error_with_file(self.file, self.lineno,
68108561fc1SRichard Henderson                                'width mismatch in patterns within braces')
68208561fc1SRichard Henderson        self.width = width
68308561fc1SRichard Henderson
684df63044dSRichard Henderson# end MultiPattern
685df63044dSRichard Henderson
686df63044dSRichard Henderson
687df63044dSRichard Hendersonclass IncMultiPattern(MultiPattern):
6880eff2df4SRichard Henderson    """Class representing an overlapping set of instruction patterns"""
6890eff2df4SRichard Henderson
6900eff2df4SRichard Henderson    def output_code(self, i, extracted, outerbits, outermask):
6910eff2df4SRichard Henderson        global translate_prefix
6920eff2df4SRichard Henderson        ind = str_indent(i)
6930eff2df4SRichard Henderson        for p in self.pats:
6940eff2df4SRichard Henderson            if outermask != p.fixedmask:
6950eff2df4SRichard Henderson                innermask = p.fixedmask & ~outermask
6960eff2df4SRichard Henderson                innerbits = p.fixedbits & ~outermask
697c7cefe6cSRichard Henderson                output(ind, f'if ((insn & {whexC(innermask)}) == {whexC(innerbits)}) {{\n')
698c7cefe6cSRichard Henderson                output(ind, f'    /* {str_match_bits(p.fixedbits, p.fixedmask)} */\n')
6990eff2df4SRichard Henderson                p.output_code(i + 4, extracted, p.fixedbits, p.fixedmask)
7000eff2df4SRichard Henderson                output(ind, '}\n')
7010eff2df4SRichard Henderson            else:
7020eff2df4SRichard Henderson                p.output_code(i, extracted, p.fixedbits, p.fixedmask)
703f2604471SRichard Henderson
704f2604471SRichard Henderson    def build_tree(self):
705f2604471SRichard Henderson        if not self.pats:
706f2604471SRichard Henderson            error_with_file(self.file, self.lineno, 'empty pattern group')
707f2604471SRichard Henderson        super().build_tree()
708f2604471SRichard Henderson
709040145c4SRichard Henderson#end IncMultiPattern
7100eff2df4SRichard Henderson
7110eff2df4SRichard Henderson
71208561fc1SRichard Hendersonclass Tree:
71308561fc1SRichard Henderson    """Class representing a node in a decode tree"""
71408561fc1SRichard Henderson
71508561fc1SRichard Henderson    def __init__(self, fm, tm):
71608561fc1SRichard Henderson        self.fixedmask = fm
71708561fc1SRichard Henderson        self.thismask = tm
71808561fc1SRichard Henderson        self.subs = []
71908561fc1SRichard Henderson        self.base = None
72008561fc1SRichard Henderson
72108561fc1SRichard Henderson    def str1(self, i):
72208561fc1SRichard Henderson        ind = str_indent(i)
723c7cefe6cSRichard Henderson        r = ind + whex(self.fixedmask)
72408561fc1SRichard Henderson        if self.format:
72508561fc1SRichard Henderson            r += ' ' + self.format.name
72608561fc1SRichard Henderson        r += ' [\n'
72708561fc1SRichard Henderson        for (b, s) in self.subs:
728c7cefe6cSRichard Henderson            r += ind + f'  {whex(b)}:\n'
72908561fc1SRichard Henderson            r += s.str1(i + 4) + '\n'
73008561fc1SRichard Henderson        r += ind + ']'
73108561fc1SRichard Henderson        return r
73208561fc1SRichard Henderson
73308561fc1SRichard Henderson    def __str__(self):
73408561fc1SRichard Henderson        return self.str1(0)
73508561fc1SRichard Henderson
73608561fc1SRichard Henderson    def output_code(self, i, extracted, outerbits, outermask):
73708561fc1SRichard Henderson        ind = str_indent(i)
73808561fc1SRichard Henderson
73908561fc1SRichard Henderson        # If we identified all nodes below have the same format,
7407e6c28beSPeter Maydell        # extract the fields now. But don't do it if the format relies
7417e6c28beSPeter Maydell        # on named fields from the insn pattern, as those won't have
7427e6c28beSPeter Maydell        # been initialised at this point.
7437e6c28beSPeter Maydell        if not extracted and self.base and not self.base.dangling_references():
74408561fc1SRichard Henderson            output(ind, self.base.extract_name(),
74508561fc1SRichard Henderson                   '(ctx, &u.f_', self.base.base.name, ', insn);\n')
74608561fc1SRichard Henderson            extracted = True
74708561fc1SRichard Henderson
74808561fc1SRichard Henderson        # Attempt to aid the compiler in producing compact switch statements.
74908561fc1SRichard Henderson        # If the bits in the mask are contiguous, extract them.
75008561fc1SRichard Henderson        sh = is_contiguous(self.thismask)
75108561fc1SRichard Henderson        if sh > 0:
75208561fc1SRichard Henderson            # Propagate SH down into the local functions.
75308561fc1SRichard Henderson            def str_switch(b, sh=sh):
754c7cefe6cSRichard Henderson                return f'(insn >> {sh}) & {b >> sh:#x}'
75508561fc1SRichard Henderson
75608561fc1SRichard Henderson            def str_case(b, sh=sh):
757c7cefe6cSRichard Henderson                return hex(b >> sh)
75808561fc1SRichard Henderson        else:
75908561fc1SRichard Henderson            def str_switch(b):
760c7cefe6cSRichard Henderson                return f'insn & {whexC(b)}'
76108561fc1SRichard Henderson
76208561fc1SRichard Henderson            def str_case(b):
763c7cefe6cSRichard Henderson                return whexC(b)
76408561fc1SRichard Henderson
76508561fc1SRichard Henderson        output(ind, 'switch (', str_switch(self.thismask), ') {\n')
76608561fc1SRichard Henderson        for b, s in sorted(self.subs):
76708561fc1SRichard Henderson            assert (self.thismask & ~s.fixedmask) == 0
76808561fc1SRichard Henderson            innermask = outermask | self.thismask
76908561fc1SRichard Henderson            innerbits = outerbits | b
77008561fc1SRichard Henderson            output(ind, 'case ', str_case(b), ':\n')
77108561fc1SRichard Henderson            output(ind, '    /* ',
77208561fc1SRichard Henderson                   str_match_bits(innerbits, innermask), ' */\n')
77308561fc1SRichard Henderson            s.output_code(i + 4, extracted, innerbits, innermask)
774514101c0SPeter Maydell            output(ind, '    break;\n')
77508561fc1SRichard Henderson        output(ind, '}\n')
77608561fc1SRichard Henderson# end Tree
77708561fc1SRichard Henderson
77808561fc1SRichard Henderson
77908561fc1SRichard Hendersonclass ExcMultiPattern(MultiPattern):
78008561fc1SRichard Henderson    """Class representing a non-overlapping set of instruction patterns"""
78108561fc1SRichard Henderson
78208561fc1SRichard Henderson    def output_code(self, i, extracted, outerbits, outermask):
78308561fc1SRichard Henderson        # Defer everything to our decomposed Tree node
78408561fc1SRichard Henderson        self.tree.output_code(i, extracted, outerbits, outermask)
78508561fc1SRichard Henderson
78608561fc1SRichard Henderson    @staticmethod
78708561fc1SRichard Henderson    def __build_tree(pats, outerbits, outermask):
78808561fc1SRichard Henderson        # Find the intersection of all remaining fixedmask.
78908561fc1SRichard Henderson        innermask = ~outermask & insnmask
79008561fc1SRichard Henderson        for i in pats:
79108561fc1SRichard Henderson            innermask &= i.fixedmask
79208561fc1SRichard Henderson
79308561fc1SRichard Henderson        if innermask == 0:
79408561fc1SRichard Henderson            # Edge condition: One pattern covers the entire insnmask
79508561fc1SRichard Henderson            if len(pats) == 1:
79608561fc1SRichard Henderson                t = Tree(outermask, innermask)
79708561fc1SRichard Henderson                t.subs.append((0, pats[0]))
79808561fc1SRichard Henderson                return t
79908561fc1SRichard Henderson
80008561fc1SRichard Henderson            text = 'overlapping patterns:'
80108561fc1SRichard Henderson            for p in pats:
80208561fc1SRichard Henderson                text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
80308561fc1SRichard Henderson            error_with_file(pats[0].file, pats[0].lineno, text)
80408561fc1SRichard Henderson
80508561fc1SRichard Henderson        fullmask = outermask | innermask
80608561fc1SRichard Henderson
80708561fc1SRichard Henderson        # Sort each element of pats into the bin selected by the mask.
80808561fc1SRichard Henderson        bins = {}
80908561fc1SRichard Henderson        for i in pats:
81008561fc1SRichard Henderson            fb = i.fixedbits & innermask
81108561fc1SRichard Henderson            if fb in bins:
81208561fc1SRichard Henderson                bins[fb].append(i)
81308561fc1SRichard Henderson            else:
81408561fc1SRichard Henderson                bins[fb] = [i]
81508561fc1SRichard Henderson
81608561fc1SRichard Henderson        # We must recurse if any bin has more than one element or if
81708561fc1SRichard Henderson        # the single element in the bin has not been fully matched.
81808561fc1SRichard Henderson        t = Tree(fullmask, innermask)
81908561fc1SRichard Henderson
82008561fc1SRichard Henderson        for b, l in bins.items():
82108561fc1SRichard Henderson            s = l[0]
82208561fc1SRichard Henderson            if len(l) > 1 or s.fixedmask & ~fullmask != 0:
82308561fc1SRichard Henderson                s = ExcMultiPattern.__build_tree(l, b | outerbits, fullmask)
82408561fc1SRichard Henderson            t.subs.append((b, s))
82508561fc1SRichard Henderson
82608561fc1SRichard Henderson        return t
82708561fc1SRichard Henderson
82808561fc1SRichard Henderson    def build_tree(self):
8292fd2eb5aSRichard Henderson        super().build_tree()
83008561fc1SRichard Henderson        self.tree = self.__build_tree(self.pats, self.fixedbits,
83108561fc1SRichard Henderson                                      self.fixedmask)
83208561fc1SRichard Henderson
83308561fc1SRichard Henderson    @staticmethod
83408561fc1SRichard Henderson    def __prop_format(tree):
83508561fc1SRichard Henderson        """Propagate Format objects into the decode tree"""
83608561fc1SRichard Henderson
83708561fc1SRichard Henderson        # Depth first search.
83808561fc1SRichard Henderson        for (b, s) in tree.subs:
83908561fc1SRichard Henderson            if isinstance(s, Tree):
84008561fc1SRichard Henderson                ExcMultiPattern.__prop_format(s)
84108561fc1SRichard Henderson
84208561fc1SRichard Henderson        # If all entries in SUBS have the same format, then
84308561fc1SRichard Henderson        # propagate that into the tree.
84408561fc1SRichard Henderson        f = None
84508561fc1SRichard Henderson        for (b, s) in tree.subs:
84608561fc1SRichard Henderson            if f is None:
84708561fc1SRichard Henderson                f = s.base
84808561fc1SRichard Henderson                if f is None:
84908561fc1SRichard Henderson                    return
85008561fc1SRichard Henderson            if f is not s.base:
85108561fc1SRichard Henderson                return
85208561fc1SRichard Henderson        tree.base = f
85308561fc1SRichard Henderson
85408561fc1SRichard Henderson    def prop_format(self):
85508561fc1SRichard Henderson        super().prop_format()
85608561fc1SRichard Henderson        self.__prop_format(self.tree)
85708561fc1SRichard Henderson
85808561fc1SRichard Henderson# end ExcMultiPattern
85908561fc1SRichard Henderson
86008561fc1SRichard Henderson
861568ae7efSRichard Hendersondef parse_field(lineno, name, toks):
862568ae7efSRichard Henderson    """Parse one instruction field from TOKS at LINENO"""
863568ae7efSRichard Henderson    global fields
864568ae7efSRichard Henderson    global insnwidth
8657e6c28beSPeter Maydell    global re_C_ident
866568ae7efSRichard Henderson
867568ae7efSRichard Henderson    # A "simple" field will have only one entry;
868568ae7efSRichard Henderson    # a "multifield" will have several.
869568ae7efSRichard Henderson    subs = []
870568ae7efSRichard Henderson    width = 0
871568ae7efSRichard Henderson    func = None
872568ae7efSRichard Henderson    for t in toks:
873acfdd239SRichard Henderson        if re.match('^!function=', t):
874568ae7efSRichard Henderson            if func:
875568ae7efSRichard Henderson                error(lineno, 'duplicate function')
876568ae7efSRichard Henderson            func = t.split('=')
877568ae7efSRichard Henderson            func = func[1]
878568ae7efSRichard Henderson            continue
879568ae7efSRichard Henderson
8807e6c28beSPeter Maydell        if re.fullmatch(re_C_ident + ':s[0-9]+', t):
8817e6c28beSPeter Maydell            # Signed named field
8827e6c28beSPeter Maydell            subtoks = t.split(':')
8837e6c28beSPeter Maydell            n = subtoks[0]
8847e6c28beSPeter Maydell            le = int(subtoks[1])
8857e6c28beSPeter Maydell            f = NamedField(n, True, le)
8867e6c28beSPeter Maydell            subs.append(f)
8877e6c28beSPeter Maydell            width += le
8887e6c28beSPeter Maydell            continue
8897e6c28beSPeter Maydell        if re.fullmatch(re_C_ident + ':[0-9]+', t):
8907e6c28beSPeter Maydell            # Unsigned named field
8917e6c28beSPeter Maydell            subtoks = t.split(':')
8927e6c28beSPeter Maydell            n = subtoks[0]
8937e6c28beSPeter Maydell            le = int(subtoks[1])
8947e6c28beSPeter Maydell            f = NamedField(n, False, le)
8957e6c28beSPeter Maydell            subs.append(f)
8967e6c28beSPeter Maydell            width += le
8977e6c28beSPeter Maydell            continue
8987e6c28beSPeter Maydell
8992d110c11SJohn Snow        if re.fullmatch('[0-9]+:s[0-9]+', t):
900568ae7efSRichard Henderson            # Signed field extract
901568ae7efSRichard Henderson            subtoks = t.split(':s')
902568ae7efSRichard Henderson            sign = True
9032d110c11SJohn Snow        elif re.fullmatch('[0-9]+:[0-9]+', t):
904568ae7efSRichard Henderson            # Unsigned field extract
905568ae7efSRichard Henderson            subtoks = t.split(':')
906568ae7efSRichard Henderson            sign = False
907568ae7efSRichard Henderson        else:
9089f6e2b4dSRichard Henderson            error(lineno, f'invalid field token "{t}"')
909568ae7efSRichard Henderson        po = int(subtoks[0])
910568ae7efSRichard Henderson        le = int(subtoks[1])
911568ae7efSRichard Henderson        if po + le > insnwidth:
9129f6e2b4dSRichard Henderson            error(lineno, f'field {t} too large')
913568ae7efSRichard Henderson        f = Field(sign, po, le)
914568ae7efSRichard Henderson        subs.append(f)
915568ae7efSRichard Henderson        width += le
916568ae7efSRichard Henderson
917568ae7efSRichard Henderson    if width > insnwidth:
918568ae7efSRichard Henderson        error(lineno, 'field too large')
91994597b61SRichard Henderson    if len(subs) == 0:
92094597b61SRichard Henderson        if func:
92194597b61SRichard Henderson            f = ParameterField(func)
92294597b61SRichard Henderson        else:
92394597b61SRichard Henderson            error(lineno, 'field with no value')
92494597b61SRichard Henderson    else:
925568ae7efSRichard Henderson        if len(subs) == 1:
926568ae7efSRichard Henderson            f = subs[0]
927568ae7efSRichard Henderson        else:
928568ae7efSRichard Henderson            mask = 0
929568ae7efSRichard Henderson            for s in subs:
930568ae7efSRichard Henderson                if mask & s.mask:
931568ae7efSRichard Henderson                    error(lineno, 'field components overlap')
932568ae7efSRichard Henderson                mask |= s.mask
933568ae7efSRichard Henderson            f = MultiField(subs, mask)
934568ae7efSRichard Henderson        if func:
935568ae7efSRichard Henderson            f = FunctionField(func, f)
936568ae7efSRichard Henderson
937568ae7efSRichard Henderson    if name in fields:
938568ae7efSRichard Henderson        error(lineno, 'duplicate field', name)
939568ae7efSRichard Henderson    fields[name] = f
940568ae7efSRichard Henderson# end parse_field
941568ae7efSRichard Henderson
942568ae7efSRichard Henderson
943568ae7efSRichard Hendersondef parse_arguments(lineno, name, toks):
944568ae7efSRichard Henderson    """Parse one argument set from TOKS at LINENO"""
945568ae7efSRichard Henderson    global arguments
946acfdd239SRichard Henderson    global re_C_ident
947c6920795SRichard Henderson    global anyextern
948568ae7efSRichard Henderson
949568ae7efSRichard Henderson    flds = []
950af93ccacSRichard Henderson    types = []
951abd04f92SRichard Henderson    extern = False
952af93ccacSRichard Henderson    for n in toks:
953af93ccacSRichard Henderson        if re.fullmatch('!extern', n):
954abd04f92SRichard Henderson            extern = True
955c6920795SRichard Henderson            anyextern = True
956abd04f92SRichard Henderson            continue
957af93ccacSRichard Henderson        if re.fullmatch(re_C_ident + ':' + re_C_ident, n):
958af93ccacSRichard Henderson            (n, t) = n.split(':')
959af93ccacSRichard Henderson        elif re.fullmatch(re_C_ident, n):
960af93ccacSRichard Henderson            t = 'int'
961af93ccacSRichard Henderson        else:
962af93ccacSRichard Henderson            error(lineno, f'invalid argument set token "{n}"')
963af93ccacSRichard Henderson        if n in flds:
964af93ccacSRichard Henderson            error(lineno, f'duplicate argument "{n}"')
965af93ccacSRichard Henderson        flds.append(n)
966af93ccacSRichard Henderson        types.append(t)
967568ae7efSRichard Henderson
968568ae7efSRichard Henderson    if name in arguments:
969568ae7efSRichard Henderson        error(lineno, 'duplicate argument set', name)
970af93ccacSRichard Henderson    arguments[name] = Arguments(name, flds, types, extern)
971568ae7efSRichard Henderson# end parse_arguments
972568ae7efSRichard Henderson
973568ae7efSRichard Henderson
974568ae7efSRichard Hendersondef lookup_field(lineno, name):
975568ae7efSRichard Henderson    global fields
976568ae7efSRichard Henderson    if name in fields:
977568ae7efSRichard Henderson        return fields[name]
978568ae7efSRichard Henderson    error(lineno, 'undefined field', name)
979568ae7efSRichard Henderson
980568ae7efSRichard Henderson
981568ae7efSRichard Hendersondef add_field(lineno, flds, new_name, f):
982568ae7efSRichard Henderson    if new_name in flds:
983568ae7efSRichard Henderson        error(lineno, 'duplicate field', new_name)
984568ae7efSRichard Henderson    flds[new_name] = f
985568ae7efSRichard Henderson    return flds
986568ae7efSRichard Henderson
987568ae7efSRichard Henderson
988568ae7efSRichard Hendersondef add_field_byname(lineno, flds, new_name, old_name):
989568ae7efSRichard Henderson    return add_field(lineno, flds, new_name, lookup_field(lineno, old_name))
990568ae7efSRichard Henderson
991568ae7efSRichard Henderson
992568ae7efSRichard Hendersondef infer_argument_set(flds):
993568ae7efSRichard Henderson    global arguments
994abd04f92SRichard Henderson    global decode_function
995568ae7efSRichard Henderson
996568ae7efSRichard Henderson    for arg in arguments.values():
997af93ccacSRichard Henderson        if eq_fields_for_args(flds, arg):
998568ae7efSRichard Henderson            return arg
999568ae7efSRichard Henderson
1000abd04f92SRichard Henderson    name = decode_function + str(len(arguments))
1001af93ccacSRichard Henderson    arg = Arguments(name, flds.keys(), ['int'] * len(flds), False)
1002568ae7efSRichard Henderson    arguments[name] = arg
1003568ae7efSRichard Henderson    return arg
1004568ae7efSRichard Henderson
1005568ae7efSRichard Henderson
100617560e93SRichard Hendersondef infer_format(arg, fieldmask, flds, width):
1007568ae7efSRichard Henderson    global arguments
1008568ae7efSRichard Henderson    global formats
1009abd04f92SRichard Henderson    global decode_function
1010568ae7efSRichard Henderson
1011568ae7efSRichard Henderson    const_flds = {}
1012568ae7efSRichard Henderson    var_flds = {}
1013568ae7efSRichard Henderson    for n, c in flds.items():
1014568ae7efSRichard Henderson        if c is ConstField:
1015568ae7efSRichard Henderson            const_flds[n] = c
1016568ae7efSRichard Henderson        else:
1017568ae7efSRichard Henderson            var_flds[n] = c
1018568ae7efSRichard Henderson
1019568ae7efSRichard Henderson    # Look for an existing format with the same argument set and fields
1020568ae7efSRichard Henderson    for fmt in formats.values():
1021568ae7efSRichard Henderson        if arg and fmt.base != arg:
1022568ae7efSRichard Henderson            continue
1023568ae7efSRichard Henderson        if fieldmask != fmt.fieldmask:
1024568ae7efSRichard Henderson            continue
102517560e93SRichard Henderson        if width != fmt.width:
102617560e93SRichard Henderson            continue
1027568ae7efSRichard Henderson        if not eq_fields_for_fmts(flds, fmt.fields):
1028568ae7efSRichard Henderson            continue
1029568ae7efSRichard Henderson        return (fmt, const_flds)
1030568ae7efSRichard Henderson
1031abd04f92SRichard Henderson    name = decode_function + '_Fmt_' + str(len(formats))
1032568ae7efSRichard Henderson    if not arg:
1033568ae7efSRichard Henderson        arg = infer_argument_set(flds)
1034568ae7efSRichard Henderson
103517560e93SRichard Henderson    fmt = Format(name, 0, arg, 0, 0, 0, fieldmask, var_flds, width)
1036568ae7efSRichard Henderson    formats[name] = fmt
1037568ae7efSRichard Henderson
1038568ae7efSRichard Henderson    return (fmt, const_flds)
1039568ae7efSRichard Henderson# end infer_format
1040568ae7efSRichard Henderson
1041568ae7efSRichard Henderson
104208561fc1SRichard Hendersondef parse_generic(lineno, parent_pat, name, toks):
1043568ae7efSRichard Henderson    """Parse one instruction format from TOKS at LINENO"""
1044568ae7efSRichard Henderson    global fields
1045568ae7efSRichard Henderson    global arguments
1046568ae7efSRichard Henderson    global formats
10470eff2df4SRichard Henderson    global allpatterns
1048acfdd239SRichard Henderson    global re_arg_ident
1049acfdd239SRichard Henderson    global re_fld_ident
1050acfdd239SRichard Henderson    global re_fmt_ident
1051acfdd239SRichard Henderson    global re_C_ident
1052568ae7efSRichard Henderson    global insnwidth
1053568ae7efSRichard Henderson    global insnmask
105417560e93SRichard Henderson    global variablewidth
1055568ae7efSRichard Henderson
105608561fc1SRichard Henderson    is_format = parent_pat is None
105708561fc1SRichard Henderson
1058568ae7efSRichard Henderson    fixedmask = 0
1059568ae7efSRichard Henderson    fixedbits = 0
1060568ae7efSRichard Henderson    undefmask = 0
1061568ae7efSRichard Henderson    width = 0
1062568ae7efSRichard Henderson    flds = {}
1063568ae7efSRichard Henderson    arg = None
1064568ae7efSRichard Henderson    fmt = None
1065568ae7efSRichard Henderson    for t in toks:
106665fdb3ccSzhaolichang        # '&Foo' gives a format an explicit argument set.
1067acfdd239SRichard Henderson        if re.fullmatch(re_arg_ident, t):
1068568ae7efSRichard Henderson            tt = t[1:]
1069568ae7efSRichard Henderson            if arg:
1070568ae7efSRichard Henderson                error(lineno, 'multiple argument sets')
1071568ae7efSRichard Henderson            if tt in arguments:
1072568ae7efSRichard Henderson                arg = arguments[tt]
1073568ae7efSRichard Henderson            else:
1074568ae7efSRichard Henderson                error(lineno, 'undefined argument set', t)
1075568ae7efSRichard Henderson            continue
1076568ae7efSRichard Henderson
1077568ae7efSRichard Henderson        # '@Foo' gives a pattern an explicit format.
1078acfdd239SRichard Henderson        if re.fullmatch(re_fmt_ident, t):
1079568ae7efSRichard Henderson            tt = t[1:]
1080568ae7efSRichard Henderson            if fmt:
1081568ae7efSRichard Henderson                error(lineno, 'multiple formats')
1082568ae7efSRichard Henderson            if tt in formats:
1083568ae7efSRichard Henderson                fmt = formats[tt]
1084568ae7efSRichard Henderson            else:
1085568ae7efSRichard Henderson                error(lineno, 'undefined format', t)
1086568ae7efSRichard Henderson            continue
1087568ae7efSRichard Henderson
1088568ae7efSRichard Henderson        # '%Foo' imports a field.
1089acfdd239SRichard Henderson        if re.fullmatch(re_fld_ident, t):
1090568ae7efSRichard Henderson            tt = t[1:]
1091568ae7efSRichard Henderson            flds = add_field_byname(lineno, flds, tt, tt)
1092568ae7efSRichard Henderson            continue
1093568ae7efSRichard Henderson
1094568ae7efSRichard Henderson        # 'Foo=%Bar' imports a field with a different name.
1095acfdd239SRichard Henderson        if re.fullmatch(re_C_ident + '=' + re_fld_ident, t):
1096568ae7efSRichard Henderson            (fname, iname) = t.split('=%')
1097568ae7efSRichard Henderson            flds = add_field_byname(lineno, flds, fname, iname)
1098568ae7efSRichard Henderson            continue
1099568ae7efSRichard Henderson
1100568ae7efSRichard Henderson        # 'Foo=number' sets an argument field to a constant value
1101acfdd239SRichard Henderson        if re.fullmatch(re_C_ident + '=[+-]?[0-9]+', t):
1102568ae7efSRichard Henderson            (fname, value) = t.split('=')
1103568ae7efSRichard Henderson            value = int(value)
1104568ae7efSRichard Henderson            flds = add_field(lineno, flds, fname, ConstField(value))
1105568ae7efSRichard Henderson            continue
1106568ae7efSRichard Henderson
1107568ae7efSRichard Henderson        # Pattern of 0s, 1s, dots and dashes indicate required zeros,
1108568ae7efSRichard Henderson        # required ones, or dont-cares.
11092d110c11SJohn Snow        if re.fullmatch('[01.-]+', t):
1110568ae7efSRichard Henderson            shift = len(t)
1111568ae7efSRichard Henderson            fms = t.replace('0', '1')
1112568ae7efSRichard Henderson            fms = fms.replace('.', '0')
1113568ae7efSRichard Henderson            fms = fms.replace('-', '0')
1114568ae7efSRichard Henderson            fbs = t.replace('.', '0')
1115568ae7efSRichard Henderson            fbs = fbs.replace('-', '0')
1116568ae7efSRichard Henderson            ubm = t.replace('1', '0')
1117568ae7efSRichard Henderson            ubm = ubm.replace('.', '0')
1118568ae7efSRichard Henderson            ubm = ubm.replace('-', '1')
1119568ae7efSRichard Henderson            fms = int(fms, 2)
1120568ae7efSRichard Henderson            fbs = int(fbs, 2)
1121568ae7efSRichard Henderson            ubm = int(ubm, 2)
1122568ae7efSRichard Henderson            fixedbits = (fixedbits << shift) | fbs
1123568ae7efSRichard Henderson            fixedmask = (fixedmask << shift) | fms
1124568ae7efSRichard Henderson            undefmask = (undefmask << shift) | ubm
1125568ae7efSRichard Henderson        # Otherwise, fieldname:fieldwidth
1126acfdd239SRichard Henderson        elif re.fullmatch(re_C_ident + ':s?[0-9]+', t):
1127568ae7efSRichard Henderson            (fname, flen) = t.split(':')
1128568ae7efSRichard Henderson            sign = False
1129568ae7efSRichard Henderson            if flen[0] == 's':
1130568ae7efSRichard Henderson                sign = True
1131568ae7efSRichard Henderson                flen = flen[1:]
1132568ae7efSRichard Henderson            shift = int(flen, 10)
11332decfc95SRichard Henderson            if shift + width > insnwidth:
11349f6e2b4dSRichard Henderson                error(lineno, f'field {fname} exceeds insnwidth')
1135568ae7efSRichard Henderson            f = Field(sign, insnwidth - width - shift, shift)
1136568ae7efSRichard Henderson            flds = add_field(lineno, flds, fname, f)
1137568ae7efSRichard Henderson            fixedbits <<= shift
1138568ae7efSRichard Henderson            fixedmask <<= shift
1139568ae7efSRichard Henderson            undefmask <<= shift
1140568ae7efSRichard Henderson        else:
11419f6e2b4dSRichard Henderson            error(lineno, f'invalid token "{t}"')
1142568ae7efSRichard Henderson        width += shift
1143568ae7efSRichard Henderson
114417560e93SRichard Henderson    if variablewidth and width < insnwidth and width % 8 == 0:
114517560e93SRichard Henderson        shift = insnwidth - width
114617560e93SRichard Henderson        fixedbits <<= shift
114717560e93SRichard Henderson        fixedmask <<= shift
114817560e93SRichard Henderson        undefmask <<= shift
114917560e93SRichard Henderson        undefmask |= (1 << shift) - 1
115017560e93SRichard Henderson
1151568ae7efSRichard Henderson    # We should have filled in all of the bits of the instruction.
115217560e93SRichard Henderson    elif not (is_format and width == 0) and width != insnwidth:
11539f6e2b4dSRichard Henderson        error(lineno, f'definition has {width} bits')
1154568ae7efSRichard Henderson
115565fdb3ccSzhaolichang    # Do not check for fields overlapping fields; one valid usage
1156568ae7efSRichard Henderson    # is to be able to duplicate fields via import.
1157568ae7efSRichard Henderson    fieldmask = 0
1158568ae7efSRichard Henderson    for f in flds.values():
1159568ae7efSRichard Henderson        fieldmask |= f.mask
1160568ae7efSRichard Henderson
1161568ae7efSRichard Henderson    # Fix up what we've parsed to match either a format or a pattern.
1162568ae7efSRichard Henderson    if is_format:
1163568ae7efSRichard Henderson        # Formats cannot reference formats.
1164568ae7efSRichard Henderson        if fmt:
1165568ae7efSRichard Henderson            error(lineno, 'format referencing format')
1166568ae7efSRichard Henderson        # If an argument set is given, then there should be no fields
1167568ae7efSRichard Henderson        # without a place to store it.
1168568ae7efSRichard Henderson        if arg:
1169568ae7efSRichard Henderson            for f in flds.keys():
1170568ae7efSRichard Henderson                if f not in arg.fields:
11719f6e2b4dSRichard Henderson                    error(lineno, f'field {f} not in argument set {arg.name}')
1172568ae7efSRichard Henderson        else:
1173568ae7efSRichard Henderson            arg = infer_argument_set(flds)
1174568ae7efSRichard Henderson        if name in formats:
1175568ae7efSRichard Henderson            error(lineno, 'duplicate format name', name)
1176568ae7efSRichard Henderson        fmt = Format(name, lineno, arg, fixedbits, fixedmask,
117717560e93SRichard Henderson                     undefmask, fieldmask, flds, width)
1178568ae7efSRichard Henderson        formats[name] = fmt
1179568ae7efSRichard Henderson    else:
1180568ae7efSRichard Henderson        # Patterns can reference a format ...
1181568ae7efSRichard Henderson        if fmt:
1182568ae7efSRichard Henderson            # ... but not an argument simultaneously
1183568ae7efSRichard Henderson            if arg:
1184568ae7efSRichard Henderson                error(lineno, 'pattern specifies both format and argument set')
1185568ae7efSRichard Henderson            if fixedmask & fmt.fixedmask:
1186568ae7efSRichard Henderson                error(lineno, 'pattern fixed bits overlap format fixed bits')
118717560e93SRichard Henderson            if width != fmt.width:
118817560e93SRichard Henderson                error(lineno, 'pattern uses format of different width')
1189568ae7efSRichard Henderson            fieldmask |= fmt.fieldmask
1190568ae7efSRichard Henderson            fixedbits |= fmt.fixedbits
1191568ae7efSRichard Henderson            fixedmask |= fmt.fixedmask
1192568ae7efSRichard Henderson            undefmask |= fmt.undefmask
1193568ae7efSRichard Henderson        else:
119417560e93SRichard Henderson            (fmt, flds) = infer_format(arg, fieldmask, flds, width)
1195568ae7efSRichard Henderson        arg = fmt.base
1196568ae7efSRichard Henderson        for f in flds.keys():
1197568ae7efSRichard Henderson            if f not in arg.fields:
11989f6e2b4dSRichard Henderson                error(lineno, f'field {f} not in argument set {arg.name}')
1199568ae7efSRichard Henderson            if f in fmt.fields.keys():
12009f6e2b4dSRichard Henderson                error(lineno, f'field {f} set by format and pattern')
1201568ae7efSRichard Henderson        for f in arg.fields:
1202568ae7efSRichard Henderson            if f not in flds.keys() and f not in fmt.fields.keys():
12039f6e2b4dSRichard Henderson                error(lineno, f'field {f} not initialized')
1204568ae7efSRichard Henderson        pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
120517560e93SRichard Henderson                      undefmask, fieldmask, flds, width)
120608561fc1SRichard Henderson        parent_pat.pats.append(pat)
12070eff2df4SRichard Henderson        allpatterns.append(pat)
1208568ae7efSRichard Henderson
1209568ae7efSRichard Henderson    # Validate the masks that we have assembled.
1210568ae7efSRichard Henderson    if fieldmask & fixedmask:
1211c7cefe6cSRichard Henderson        error(lineno, 'fieldmask overlaps fixedmask ',
1212c7cefe6cSRichard Henderson              f'({whex(fieldmask)} & {whex(fixedmask)})')
1213568ae7efSRichard Henderson    if fieldmask & undefmask:
1214c7cefe6cSRichard Henderson        error(lineno, 'fieldmask overlaps undefmask ',
1215c7cefe6cSRichard Henderson              f'({whex(fieldmask)} & {whex(undefmask)})')
1216568ae7efSRichard Henderson    if fixedmask & undefmask:
1217c7cefe6cSRichard Henderson        error(lineno, 'fixedmask overlaps undefmask ',
1218c7cefe6cSRichard Henderson              f'({whex(fixedmask)} & {whex(undefmask)})')
1219568ae7efSRichard Henderson    if not is_format:
1220568ae7efSRichard Henderson        allbits = fieldmask | fixedmask | undefmask
1221568ae7efSRichard Henderson        if allbits != insnmask:
1222c7cefe6cSRichard Henderson            error(lineno, 'bits left unspecified ',
1223c7cefe6cSRichard Henderson                  f'({whex(allbits ^ insnmask)})')
1224568ae7efSRichard Henderson# end parse_general
1225568ae7efSRichard Henderson
12260eff2df4SRichard Henderson
122708561fc1SRichard Hendersondef parse_file(f, parent_pat):
1228568ae7efSRichard Henderson    """Parse all of the patterns within a file"""
1229acfdd239SRichard Henderson    global re_arg_ident
1230acfdd239SRichard Henderson    global re_fld_ident
1231acfdd239SRichard Henderson    global re_fmt_ident
1232acfdd239SRichard Henderson    global re_pat_ident
1233568ae7efSRichard Henderson
1234568ae7efSRichard Henderson    # Read all of the lines of the file.  Concatenate lines
1235568ae7efSRichard Henderson    # ending in backslash; discard empty lines and comments.
1236568ae7efSRichard Henderson    toks = []
1237568ae7efSRichard Henderson    lineno = 0
12380eff2df4SRichard Henderson    nesting = 0
123908561fc1SRichard Henderson    nesting_pats = []
12400eff2df4SRichard Henderson
1241568ae7efSRichard Henderson    for line in f:
1242568ae7efSRichard Henderson        lineno += 1
1243568ae7efSRichard Henderson
12440eff2df4SRichard Henderson        # Expand and strip spaces, to find indent.
12450eff2df4SRichard Henderson        line = line.rstrip()
12460eff2df4SRichard Henderson        line = line.expandtabs()
12470eff2df4SRichard Henderson        len1 = len(line)
12480eff2df4SRichard Henderson        line = line.lstrip()
12490eff2df4SRichard Henderson        len2 = len(line)
12500eff2df4SRichard Henderson
1251568ae7efSRichard Henderson        # Discard comments
1252568ae7efSRichard Henderson        end = line.find('#')
1253568ae7efSRichard Henderson        if end >= 0:
1254568ae7efSRichard Henderson            line = line[:end]
1255568ae7efSRichard Henderson
1256568ae7efSRichard Henderson        t = line.split()
1257568ae7efSRichard Henderson        if len(toks) != 0:
1258568ae7efSRichard Henderson            # Next line after continuation
1259568ae7efSRichard Henderson            toks.extend(t)
1260568ae7efSRichard Henderson        else:
12610eff2df4SRichard Henderson            # Allow completely blank lines.
12620eff2df4SRichard Henderson            if len1 == 0:
12630eff2df4SRichard Henderson                continue
12640eff2df4SRichard Henderson            indent = len1 - len2
12650eff2df4SRichard Henderson            # Empty line due to comment.
12660eff2df4SRichard Henderson            if len(t) == 0:
12670eff2df4SRichard Henderson                # Indentation must be correct, even for comment lines.
12680eff2df4SRichard Henderson                if indent != nesting:
12690eff2df4SRichard Henderson                    error(lineno, 'indentation ', indent, ' != ', nesting)
12700eff2df4SRichard Henderson                continue
12710eff2df4SRichard Henderson            start_lineno = lineno
1272568ae7efSRichard Henderson            toks = t
1273568ae7efSRichard Henderson
1274568ae7efSRichard Henderson        # Continuation?
1275568ae7efSRichard Henderson        if toks[-1] == '\\':
1276568ae7efSRichard Henderson            toks.pop()
1277568ae7efSRichard Henderson            continue
1278568ae7efSRichard Henderson
1279568ae7efSRichard Henderson        name = toks[0]
1280568ae7efSRichard Henderson        del toks[0]
1281568ae7efSRichard Henderson
12820eff2df4SRichard Henderson        # End nesting?
1283067e8b0fSRichard Henderson        if name == '}' or name == ']':
12840eff2df4SRichard Henderson            if len(toks) != 0:
12850eff2df4SRichard Henderson                error(start_lineno, 'extra tokens after close brace')
128608561fc1SRichard Henderson
1287067e8b0fSRichard Henderson            # Make sure { } and [ ] nest properly.
1288067e8b0fSRichard Henderson            if (name == '}') != isinstance(parent_pat, IncMultiPattern):
1289067e8b0fSRichard Henderson                error(lineno, 'mismatched close brace')
1290067e8b0fSRichard Henderson
129108561fc1SRichard Henderson            try:
129208561fc1SRichard Henderson                parent_pat = nesting_pats.pop()
129308561fc1SRichard Henderson            except:
1294067e8b0fSRichard Henderson                error(lineno, 'extra close brace')
129508561fc1SRichard Henderson
12960eff2df4SRichard Henderson            nesting -= 2
12970eff2df4SRichard Henderson            if indent != nesting:
129808561fc1SRichard Henderson                error(lineno, 'indentation ', indent, ' != ', nesting)
129908561fc1SRichard Henderson
13000eff2df4SRichard Henderson            toks = []
13010eff2df4SRichard Henderson            continue
13020eff2df4SRichard Henderson
13030eff2df4SRichard Henderson        # Everything else should have current indentation.
13040eff2df4SRichard Henderson        if indent != nesting:
13050eff2df4SRichard Henderson            error(start_lineno, 'indentation ', indent, ' != ', nesting)
13060eff2df4SRichard Henderson
13070eff2df4SRichard Henderson        # Start nesting?
1308067e8b0fSRichard Henderson        if name == '{' or name == '[':
13090eff2df4SRichard Henderson            if len(toks) != 0:
13100eff2df4SRichard Henderson                error(start_lineno, 'extra tokens after open brace')
131108561fc1SRichard Henderson
1312067e8b0fSRichard Henderson            if name == '{':
131308561fc1SRichard Henderson                nested_pat = IncMultiPattern(start_lineno)
1314067e8b0fSRichard Henderson            else:
1315067e8b0fSRichard Henderson                nested_pat = ExcMultiPattern(start_lineno)
131608561fc1SRichard Henderson            parent_pat.pats.append(nested_pat)
131708561fc1SRichard Henderson            nesting_pats.append(parent_pat)
131808561fc1SRichard Henderson            parent_pat = nested_pat
131908561fc1SRichard Henderson
13200eff2df4SRichard Henderson            nesting += 2
13210eff2df4SRichard Henderson            toks = []
13220eff2df4SRichard Henderson            continue
13230eff2df4SRichard Henderson
1324568ae7efSRichard Henderson        # Determine the type of object needing to be parsed.
1325acfdd239SRichard Henderson        if re.fullmatch(re_fld_ident, name):
13260eff2df4SRichard Henderson            parse_field(start_lineno, name[1:], toks)
1327acfdd239SRichard Henderson        elif re.fullmatch(re_arg_ident, name):
13280eff2df4SRichard Henderson            parse_arguments(start_lineno, name[1:], toks)
1329acfdd239SRichard Henderson        elif re.fullmatch(re_fmt_ident, name):
133008561fc1SRichard Henderson            parse_generic(start_lineno, None, name[1:], toks)
1331acfdd239SRichard Henderson        elif re.fullmatch(re_pat_ident, name):
133208561fc1SRichard Henderson            parse_generic(start_lineno, parent_pat, name, toks)
1333acfdd239SRichard Henderson        else:
13349f6e2b4dSRichard Henderson            error(lineno, f'invalid token "{name}"')
1335568ae7efSRichard Henderson        toks = []
1336067e8b0fSRichard Henderson
1337067e8b0fSRichard Henderson    if nesting != 0:
1338067e8b0fSRichard Henderson        error(lineno, 'missing close brace')
1339568ae7efSRichard Henderson# end parse_file
1340568ae7efSRichard Henderson
1341568ae7efSRichard Henderson
134270e0711aSRichard Hendersonclass SizeTree:
134370e0711aSRichard Henderson    """Class representing a node in a size decode tree"""
134470e0711aSRichard Henderson
134570e0711aSRichard Henderson    def __init__(self, m, w):
134670e0711aSRichard Henderson        self.mask = m
134770e0711aSRichard Henderson        self.subs = []
134870e0711aSRichard Henderson        self.base = None
134970e0711aSRichard Henderson        self.width = w
135070e0711aSRichard Henderson
135170e0711aSRichard Henderson    def str1(self, i):
135270e0711aSRichard Henderson        ind = str_indent(i)
1353c7cefe6cSRichard Henderson        r = ind + whex(self.mask) + ' [\n'
135470e0711aSRichard Henderson        for (b, s) in self.subs:
1355c7cefe6cSRichard Henderson            r += ind + f'  {whex(b)}:\n'
135670e0711aSRichard Henderson            r += s.str1(i + 4) + '\n'
135770e0711aSRichard Henderson        r += ind + ']'
135870e0711aSRichard Henderson        return r
135970e0711aSRichard Henderson
136070e0711aSRichard Henderson    def __str__(self):
136170e0711aSRichard Henderson        return self.str1(0)
136270e0711aSRichard Henderson
136370e0711aSRichard Henderson    def output_code(self, i, extracted, outerbits, outermask):
136470e0711aSRichard Henderson        ind = str_indent(i)
136570e0711aSRichard Henderson
136670e0711aSRichard Henderson        # If we need to load more bytes to test, do so now.
136770e0711aSRichard Henderson        if extracted < self.width:
13689f6e2b4dSRichard Henderson            output(ind, f'insn = {decode_function}_load_bytes',
13699f6e2b4dSRichard Henderson                   f'(ctx, insn, {extracted // 8}, {self.width // 8});\n')
137070e0711aSRichard Henderson            extracted = self.width
137170e0711aSRichard Henderson
137270e0711aSRichard Henderson        # Attempt to aid the compiler in producing compact switch statements.
137370e0711aSRichard Henderson        # If the bits in the mask are contiguous, extract them.
137470e0711aSRichard Henderson        sh = is_contiguous(self.mask)
137570e0711aSRichard Henderson        if sh > 0:
137670e0711aSRichard Henderson            # Propagate SH down into the local functions.
137770e0711aSRichard Henderson            def str_switch(b, sh=sh):
1378c7cefe6cSRichard Henderson                return f'(insn >> {sh}) & {b >> sh:#x}'
137970e0711aSRichard Henderson
138070e0711aSRichard Henderson            def str_case(b, sh=sh):
1381c7cefe6cSRichard Henderson                return hex(b >> sh)
138270e0711aSRichard Henderson        else:
138370e0711aSRichard Henderson            def str_switch(b):
1384c7cefe6cSRichard Henderson                return f'insn & {whexC(b)}'
138570e0711aSRichard Henderson
138670e0711aSRichard Henderson            def str_case(b):
1387c7cefe6cSRichard Henderson                return whexC(b)
138870e0711aSRichard Henderson
138970e0711aSRichard Henderson        output(ind, 'switch (', str_switch(self.mask), ') {\n')
139070e0711aSRichard Henderson        for b, s in sorted(self.subs):
139170e0711aSRichard Henderson            innermask = outermask | self.mask
139270e0711aSRichard Henderson            innerbits = outerbits | b
139370e0711aSRichard Henderson            output(ind, 'case ', str_case(b), ':\n')
139470e0711aSRichard Henderson            output(ind, '    /* ',
139570e0711aSRichard Henderson                   str_match_bits(innerbits, innermask), ' */\n')
139670e0711aSRichard Henderson            s.output_code(i + 4, extracted, innerbits, innermask)
139770e0711aSRichard Henderson        output(ind, '}\n')
139870e0711aSRichard Henderson        output(ind, 'return insn;\n')
139970e0711aSRichard Henderson# end SizeTree
140070e0711aSRichard Henderson
140170e0711aSRichard Hendersonclass SizeLeaf:
140270e0711aSRichard Henderson    """Class representing a leaf node in a size decode tree"""
140370e0711aSRichard Henderson
140470e0711aSRichard Henderson    def __init__(self, m, w):
140570e0711aSRichard Henderson        self.mask = m
140670e0711aSRichard Henderson        self.width = w
140770e0711aSRichard Henderson
140870e0711aSRichard Henderson    def str1(self, i):
1409c7cefe6cSRichard Henderson        return str_indent(i) + whex(self.mask)
141070e0711aSRichard Henderson
141170e0711aSRichard Henderson    def __str__(self):
141270e0711aSRichard Henderson        return self.str1(0)
141370e0711aSRichard Henderson
141470e0711aSRichard Henderson    def output_code(self, i, extracted, outerbits, outermask):
141570e0711aSRichard Henderson        global decode_function
141670e0711aSRichard Henderson        ind = str_indent(i)
141770e0711aSRichard Henderson
141870e0711aSRichard Henderson        # If we need to load more bytes, do so now.
141970e0711aSRichard Henderson        if extracted < self.width:
14209f6e2b4dSRichard Henderson            output(ind, f'insn = {decode_function}_load_bytes',
14219f6e2b4dSRichard Henderson                   f'(ctx, insn, {extracted // 8}, {self.width // 8});\n')
142270e0711aSRichard Henderson            extracted = self.width
142370e0711aSRichard Henderson        output(ind, 'return insn;\n')
142470e0711aSRichard Henderson# end SizeLeaf
142570e0711aSRichard Henderson
142670e0711aSRichard Henderson
142770e0711aSRichard Hendersondef build_size_tree(pats, width, outerbits, outermask):
142870e0711aSRichard Henderson    global insnwidth
142970e0711aSRichard Henderson
143070e0711aSRichard Henderson    # Collect the mask of bits that are fixed in this width
143170e0711aSRichard Henderson    innermask = 0xff << (insnwidth - width)
143270e0711aSRichard Henderson    innermask &= ~outermask
143370e0711aSRichard Henderson    minwidth = None
143470e0711aSRichard Henderson    onewidth = True
143570e0711aSRichard Henderson    for i in pats:
143670e0711aSRichard Henderson        innermask &= i.fixedmask
143770e0711aSRichard Henderson        if minwidth is None:
143870e0711aSRichard Henderson            minwidth = i.width
143970e0711aSRichard Henderson        elif minwidth != i.width:
144070e0711aSRichard Henderson            onewidth = False;
144170e0711aSRichard Henderson            if minwidth < i.width:
144270e0711aSRichard Henderson                minwidth = i.width
144370e0711aSRichard Henderson
144470e0711aSRichard Henderson    if onewidth:
144570e0711aSRichard Henderson        return SizeLeaf(innermask, minwidth)
144670e0711aSRichard Henderson
144770e0711aSRichard Henderson    if innermask == 0:
144870e0711aSRichard Henderson        if width < minwidth:
144970e0711aSRichard Henderson            return build_size_tree(pats, width + 8, outerbits, outermask)
145070e0711aSRichard Henderson
145170e0711aSRichard Henderson        pnames = []
145270e0711aSRichard Henderson        for p in pats:
145370e0711aSRichard Henderson            pnames.append(p.name + ':' + p.file + ':' + str(p.lineno))
145470e0711aSRichard Henderson        error_with_file(pats[0].file, pats[0].lineno,
14559f6e2b4dSRichard Henderson                        f'overlapping patterns size {width}:', pnames)
145670e0711aSRichard Henderson
145770e0711aSRichard Henderson    bins = {}
145870e0711aSRichard Henderson    for i in pats:
145970e0711aSRichard Henderson        fb = i.fixedbits & innermask
146070e0711aSRichard Henderson        if fb in bins:
146170e0711aSRichard Henderson            bins[fb].append(i)
146270e0711aSRichard Henderson        else:
146370e0711aSRichard Henderson            bins[fb] = [i]
146470e0711aSRichard Henderson
146570e0711aSRichard Henderson    fullmask = outermask | innermask
146670e0711aSRichard Henderson    lens = sorted(bins.keys())
146770e0711aSRichard Henderson    if len(lens) == 1:
146870e0711aSRichard Henderson        b = lens[0]
146970e0711aSRichard Henderson        return build_size_tree(bins[b], width + 8, b | outerbits, fullmask)
147070e0711aSRichard Henderson
147170e0711aSRichard Henderson    r = SizeTree(innermask, width)
147270e0711aSRichard Henderson    for b, l in bins.items():
147370e0711aSRichard Henderson        s = build_size_tree(l, width, b | outerbits, fullmask)
147470e0711aSRichard Henderson        r.subs.append((b, s))
147570e0711aSRichard Henderson    return r
147670e0711aSRichard Henderson# end build_size_tree
147770e0711aSRichard Henderson
147870e0711aSRichard Henderson
147970e0711aSRichard Hendersondef prop_size(tree):
148070e0711aSRichard Henderson    """Propagate minimum widths up the decode size tree"""
148170e0711aSRichard Henderson
148270e0711aSRichard Henderson    if isinstance(tree, SizeTree):
148370e0711aSRichard Henderson        min = None
148470e0711aSRichard Henderson        for (b, s) in tree.subs:
148570e0711aSRichard Henderson            width = prop_size(s)
148670e0711aSRichard Henderson            if min is None or min > width:
148770e0711aSRichard Henderson                min = width
148870e0711aSRichard Henderson        assert min >= tree.width
148970e0711aSRichard Henderson        tree.width = min
149070e0711aSRichard Henderson    else:
149170e0711aSRichard Henderson        min = tree.width
149270e0711aSRichard Henderson    return min
149370e0711aSRichard Henderson# end prop_size
149470e0711aSRichard Henderson
149570e0711aSRichard Henderson
1496568ae7efSRichard Hendersondef main():
1497568ae7efSRichard Henderson    global arguments
1498568ae7efSRichard Henderson    global formats
14990eff2df4SRichard Henderson    global allpatterns
1500568ae7efSRichard Henderson    global translate_scope
1501568ae7efSRichard Henderson    global translate_prefix
1502568ae7efSRichard Henderson    global output_fd
1503568ae7efSRichard Henderson    global output_file
1504c6a5fc2aSRichard Henderson    global output_null
1505568ae7efSRichard Henderson    global input_file
1506568ae7efSRichard Henderson    global insnwidth
1507568ae7efSRichard Henderson    global insntype
150883d7c40cSBastian Koppelmann    global insnmask
1509abd04f92SRichard Henderson    global decode_function
151060c425f3SLuis Fernando Fujita Pires    global bitop_width
151117560e93SRichard Henderson    global variablewidth
1512c6920795SRichard Henderson    global anyextern
15139b5acc56SRichard Henderson    global testforerror
1514568ae7efSRichard Henderson
1515568ae7efSRichard Henderson    decode_scope = 'static '
1516568ae7efSRichard Henderson
1517cd3e7fc1SRichard Henderson    long_opts = ['decode=', 'translate=', 'output=', 'insnwidth=',
1518c6a5fc2aSRichard Henderson                 'static-decode=', 'varinsnwidth=', 'test-for-error',
1519c6a5fc2aSRichard Henderson                 'output-null']
1520568ae7efSRichard Henderson    try:
1521abff1abfSPaolo Bonzini        (opts, args) = getopt.gnu_getopt(sys.argv[1:], 'o:vw:', long_opts)
1522568ae7efSRichard Henderson    except getopt.GetoptError as err:
1523568ae7efSRichard Henderson        error(0, err)
1524568ae7efSRichard Henderson    for o, a in opts:
1525568ae7efSRichard Henderson        if o in ('-o', '--output'):
1526568ae7efSRichard Henderson            output_file = a
1527568ae7efSRichard Henderson        elif o == '--decode':
1528568ae7efSRichard Henderson            decode_function = a
1529568ae7efSRichard Henderson            decode_scope = ''
1530cd3e7fc1SRichard Henderson        elif o == '--static-decode':
1531cd3e7fc1SRichard Henderson            decode_function = a
1532568ae7efSRichard Henderson        elif o == '--translate':
1533568ae7efSRichard Henderson            translate_prefix = a
1534568ae7efSRichard Henderson            translate_scope = ''
153517560e93SRichard Henderson        elif o in ('-w', '--insnwidth', '--varinsnwidth'):
153617560e93SRichard Henderson            if o == '--varinsnwidth':
153717560e93SRichard Henderson                variablewidth = True
1538568ae7efSRichard Henderson            insnwidth = int(a)
1539568ae7efSRichard Henderson            if insnwidth == 16:
1540568ae7efSRichard Henderson                insntype = 'uint16_t'
1541568ae7efSRichard Henderson                insnmask = 0xffff
154260c425f3SLuis Fernando Fujita Pires            elif insnwidth == 64:
154360c425f3SLuis Fernando Fujita Pires                insntype = 'uint64_t'
154460c425f3SLuis Fernando Fujita Pires                insnmask = 0xffffffffffffffff
154560c425f3SLuis Fernando Fujita Pires                bitop_width = 64
1546568ae7efSRichard Henderson            elif insnwidth != 32:
1547568ae7efSRichard Henderson                error(0, 'cannot handle insns of width', insnwidth)
15489b5acc56SRichard Henderson        elif o == '--test-for-error':
15499b5acc56SRichard Henderson            testforerror = True
1550c6a5fc2aSRichard Henderson        elif o == '--output-null':
1551c6a5fc2aSRichard Henderson            output_null = True
1552568ae7efSRichard Henderson        else:
1553568ae7efSRichard Henderson            assert False, 'unhandled option'
1554568ae7efSRichard Henderson
1555568ae7efSRichard Henderson    if len(args) < 1:
1556568ae7efSRichard Henderson        error(0, 'missing input file')
155708561fc1SRichard Henderson
155808561fc1SRichard Henderson    toppat = ExcMultiPattern(0)
155908561fc1SRichard Henderson
15606699ae6aSRichard Henderson    for filename in args:
15616699ae6aSRichard Henderson        input_file = filename
15624cacecaaSPhilippe Mathieu-Daudé        f = open(filename, 'rt', encoding='utf-8')
156308561fc1SRichard Henderson        parse_file(f, toppat)
1564568ae7efSRichard Henderson        f.close()
1565568ae7efSRichard Henderson
156608561fc1SRichard Henderson    # We do not want to compute masks for toppat, because those masks
156708561fc1SRichard Henderson    # are used as a starting point for build_tree.  For toppat, we must
156808561fc1SRichard Henderson    # insist that decode begins from naught.
156908561fc1SRichard Henderson    for i in toppat.pats:
157008561fc1SRichard Henderson        i.prop_masks()
157170e0711aSRichard Henderson
157208561fc1SRichard Henderson    toppat.build_tree()
157308561fc1SRichard Henderson    toppat.prop_format()
157408561fc1SRichard Henderson
157508561fc1SRichard Henderson    if variablewidth:
157608561fc1SRichard Henderson        for i in toppat.pats:
157708561fc1SRichard Henderson            i.prop_width()
157808561fc1SRichard Henderson        stree = build_size_tree(toppat.pats, 8, 0, 0)
157908561fc1SRichard Henderson        prop_size(stree)
1580568ae7efSRichard Henderson
1581c6a5fc2aSRichard Henderson    if output_null:
1582c6a5fc2aSRichard Henderson        output_fd = open(os.devnull, 'wt', encoding='utf-8', errors="ignore")
1583c6a5fc2aSRichard Henderson    elif output_file:
15844cacecaaSPhilippe Mathieu-Daudé        output_fd = open(output_file, 'wt', encoding='utf-8')
1585568ae7efSRichard Henderson    else:
15864cacecaaSPhilippe Mathieu-Daudé        output_fd = io.TextIOWrapper(sys.stdout.buffer,
15874cacecaaSPhilippe Mathieu-Daudé                                     encoding=sys.stdout.encoding,
15884cacecaaSPhilippe Mathieu-Daudé                                     errors="ignore")
1589568ae7efSRichard Henderson
1590568ae7efSRichard Henderson    output_autogen()
1591568ae7efSRichard Henderson    for n in sorted(arguments.keys()):
1592568ae7efSRichard Henderson        f = arguments[n]
1593568ae7efSRichard Henderson        f.output_def()
1594568ae7efSRichard Henderson
1595568ae7efSRichard Henderson    # A single translate function can be invoked for different patterns.
1596568ae7efSRichard Henderson    # Make sure that the argument sets are the same, and declare the
1597568ae7efSRichard Henderson    # function only once.
1598c6920795SRichard Henderson    #
1599c6920795SRichard Henderson    # If we're sharing formats, we're likely also sharing trans_* functions,
1600c6920795SRichard Henderson    # but we can't tell which ones.  Prevent issues from the compiler by
1601c6920795SRichard Henderson    # suppressing redundant declaration warnings.
1602c6920795SRichard Henderson    if anyextern:
16037aa12aa2SThomas Huth        output("#pragma GCC diagnostic push\n",
1604c6920795SRichard Henderson               "#pragma GCC diagnostic ignored \"-Wredundant-decls\"\n",
1605c6920795SRichard Henderson               "#ifdef __clang__\n"
1606c6920795SRichard Henderson               "#  pragma GCC diagnostic ignored \"-Wtypedef-redefinition\"\n",
1607c6920795SRichard Henderson               "#endif\n\n")
1608c6920795SRichard Henderson
1609568ae7efSRichard Henderson    out_pats = {}
16100eff2df4SRichard Henderson    for i in allpatterns:
1611568ae7efSRichard Henderson        if i.name in out_pats:
1612568ae7efSRichard Henderson            p = out_pats[i.name]
1613568ae7efSRichard Henderson            if i.base.base != p.base.base:
1614568ae7efSRichard Henderson                error(0, i.name, ' has conflicting argument sets')
1615568ae7efSRichard Henderson        else:
1616568ae7efSRichard Henderson            i.output_decl()
1617568ae7efSRichard Henderson            out_pats[i.name] = i
1618568ae7efSRichard Henderson    output('\n')
1619568ae7efSRichard Henderson
1620c6920795SRichard Henderson    if anyextern:
16217aa12aa2SThomas Huth        output("#pragma GCC diagnostic pop\n\n")
1622c6920795SRichard Henderson
1623568ae7efSRichard Henderson    for n in sorted(formats.keys()):
1624568ae7efSRichard Henderson        f = formats[n]
1625568ae7efSRichard Henderson        f.output_extract()
1626568ae7efSRichard Henderson
1627568ae7efSRichard Henderson    output(decode_scope, 'bool ', decode_function,
1628568ae7efSRichard Henderson           '(DisasContext *ctx, ', insntype, ' insn)\n{\n')
1629568ae7efSRichard Henderson
1630568ae7efSRichard Henderson    i4 = str_indent(4)
163182bfac1cSRichard Henderson
163282bfac1cSRichard Henderson    if len(allpatterns) != 0:
1633568ae7efSRichard Henderson        output(i4, 'union {\n')
1634568ae7efSRichard Henderson        for n in sorted(arguments.keys()):
1635568ae7efSRichard Henderson            f = arguments[n]
1636568ae7efSRichard Henderson            output(i4, i4, f.struct_name(), ' f_', f.name, ';\n')
1637568ae7efSRichard Henderson        output(i4, '} u;\n\n')
163808561fc1SRichard Henderson        toppat.output_code(4, False, 0, 0)
1639568ae7efSRichard Henderson
164082bfac1cSRichard Henderson    output(i4, 'return false;\n')
1641568ae7efSRichard Henderson    output('}\n')
1642568ae7efSRichard Henderson
164370e0711aSRichard Henderson    if variablewidth:
164470e0711aSRichard Henderson        output('\n', decode_scope, insntype, ' ', decode_function,
164570e0711aSRichard Henderson               '_load(DisasContext *ctx)\n{\n',
164670e0711aSRichard Henderson               '    ', insntype, ' insn = 0;\n\n')
164770e0711aSRichard Henderson        stree.output_code(4, 0, 0, 0)
164870e0711aSRichard Henderson        output('}\n')
164970e0711aSRichard Henderson
1650568ae7efSRichard Henderson    if output_file:
1651568ae7efSRichard Henderson        output_fd.close()
16529b5acc56SRichard Henderson    exit(1 if testforerror else 0)
1653568ae7efSRichard Henderson# end main
1654568ae7efSRichard Henderson
1655568ae7efSRichard Henderson
1656568ae7efSRichard Hendersonif __name__ == '__main__':
1657568ae7efSRichard Henderson    main()
1658