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