| 
									
										
										
										
											2020-01-30 17:32:25 +01:00
										 |  |  | #!/usr/bin/env python3 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | # Copyright (c) 2018 Linaro Limited | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This library is free software; you can redistribute it and/or | 
					
						
							|  |  |  | # modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  | # License as published by the Free Software Foundation; either | 
					
						
							| 
									
										
										
										
											2020-10-23 12:33:53 +00:00
										 |  |  | # version 2.1 of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | # | 
					
						
							|  |  |  | # This library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  | # Lesser General Public License for more details. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # You should have received a copy of the GNU Lesser General Public | 
					
						
							|  |  |  | # License along with this library; if not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Generate a decoding tree from a specification file. | 
					
						
							| 
									
										
										
										
											2019-02-23 13:00:10 -08:00
										 |  |  | # See the syntax and semantics in docs/devel/decodetree.rst. | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												decodetree: Open files with encoding='utf-8'
When decodetree.py was added in commit 568ae7efae7, QEMU was
using Python 2 which happily reads UTF-8 files in text mode.
Python 3 requires either UTF-8 locale or an explicit encoding
passed to open(). Now that Python 3 is required, explicit
UTF-8 encoding for decodetree source files.
To avoid further problems with the user locale, also explicit
UTF-8 encoding for the generated C files.
Explicit both input/output are plain text by using the 't' mode.
This fixes:
  $ /usr/bin/python3 scripts/decodetree.py test.decode
  Traceback (most recent call last):
    File "scripts/decodetree.py", line 1397, in <module>
      main()
    File "scripts/decodetree.py", line 1308, in main
      parse_file(f, toppat)
    File "scripts/decodetree.py", line 994, in parse_file
      for line in f:
    File "/usr/lib/python3.6/encodings/ascii.py", line 26, in decode
      return codecs.ascii_decode(input, self.errors)[0]
  UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 80:
  ordinal not in range(128)
Reported-by: Peter Maydell <peter.maydell@linaro.org>
Suggested-by: Yonggang Luo <luoyonggang@gmail.com>
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Message-Id: <20210110000240.761122-1-f4bug@amsat.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
											
										 
											2021-01-10 01:02:40 +01:00
										 |  |  | import io | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | import os | 
					
						
							|  |  |  | import re | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import getopt | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | insnwidth = 32 | 
					
						
							| 
									
										
										
										
											2021-04-07 22:18:49 +00:00
										 |  |  | bitop_width = 32 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | insnmask = 0xffffffff | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  | variablewidth = False | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | fields = {} | 
					
						
							|  |  |  | arguments = {} | 
					
						
							|  |  |  | formats = {} | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  | allpatterns = [] | 
					
						
							| 
									
										
										
										
											2019-08-09 08:12:50 -07:00
										 |  |  | anyextern = False | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | translate_prefix = 'trans' | 
					
						
							|  |  |  | translate_scope = 'static ' | 
					
						
							|  |  |  | input_file = '' | 
					
						
							|  |  |  | output_file = None | 
					
						
							|  |  |  | output_fd = None | 
					
						
							|  |  |  | insntype = 'uint32_t' | 
					
						
							| 
									
										
										
										
											2018-10-23 10:26:25 +01:00
										 |  |  | decode_function = 'decode' | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  | # An identifier for C. | 
					
						
							|  |  |  | re_C_ident = '[a-zA-Z][a-zA-Z0-9_]*' | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  | # Identifiers for Arguments, Fields, Formats and Patterns. | 
					
						
							|  |  |  | re_arg_ident = '&[a-zA-Z0-9_]*' | 
					
						
							|  |  |  | re_fld_ident = '%[a-zA-Z0-9_]*' | 
					
						
							|  |  |  | re_fmt_ident = '@[a-zA-Z0-9_]*' | 
					
						
							|  |  |  | re_pat_ident = '[a-zA-Z0-9_]*' | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-26 14:59:43 +01:00
										 |  |  | def error_with_file(file, lineno, *args): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     """Print an error message from file:line and args and exit.""" | 
					
						
							|  |  |  |     global output_file | 
					
						
							|  |  |  |     global output_fd | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-15 14:48:54 -07:00
										 |  |  |     prefix = '' | 
					
						
							|  |  |  |     if file: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |         prefix += f'{file}:' | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     if lineno: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |         prefix += f'{lineno}:' | 
					
						
							| 
									
										
										
										
											2020-05-15 14:48:54 -07:00
										 |  |  |     if prefix: | 
					
						
							|  |  |  |         prefix += ' ' | 
					
						
							|  |  |  |     print(prefix, end='error: ', file=sys.stderr) | 
					
						
							|  |  |  |     print(*args, file=sys.stderr) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     if output_file and output_fd: | 
					
						
							|  |  |  |         output_fd.close() | 
					
						
							|  |  |  |         os.remove(output_file) | 
					
						
							|  |  |  |     exit(1) | 
					
						
							| 
									
										
										
										
											2020-05-15 14:48:54 -07:00
										 |  |  | # end error_with_file | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-26 14:59:43 +01:00
										 |  |  | def error(lineno, *args): | 
					
						
							| 
									
										
										
										
											2020-05-15 14:48:54 -07:00
										 |  |  |     error_with_file(input_file, lineno, *args) | 
					
						
							|  |  |  | # end error | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | def output(*args): | 
					
						
							|  |  |  |     global output_fd | 
					
						
							|  |  |  |     for a in args: | 
					
						
							|  |  |  |         output_fd.write(a) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def output_autogen(): | 
					
						
							|  |  |  |     output('/* This file is autogenerated by scripts/decodetree.py.  */\n\n') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def str_indent(c): | 
					
						
							|  |  |  |     """Return a string with C spaces""" | 
					
						
							|  |  |  |     return ' ' * c | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def str_fields(fields): | 
					
						
							| 
									
										
										
										
											2020-09-17 15:50:23 +08:00
										 |  |  |     """Return a string uniquely identifying FIELDS""" | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     r = '' | 
					
						
							|  |  |  |     for n in sorted(fields.keys()): | 
					
						
							|  |  |  |         r += '_' + n | 
					
						
							|  |  |  |     return r[1:] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  | def whex(val): | 
					
						
							|  |  |  |     """Return a hex string for val padded for insnwidth""" | 
					
						
							|  |  |  |     global insnwidth | 
					
						
							|  |  |  |     return f'0x{val:0{insnwidth // 4}x}' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def whexC(val): | 
					
						
							|  |  |  |     """Return a hex string for val padded for insnwidth,
 | 
					
						
							|  |  |  |        and with the proper suffix for a C constant."""
 | 
					
						
							|  |  |  |     suffix = '' | 
					
						
							| 
									
										
										
										
											2021-04-07 22:18:49 +00:00
										 |  |  |     if val >= 0x100000000: | 
					
						
							|  |  |  |         suffix = 'ull' | 
					
						
							|  |  |  |     elif val >= 0x80000000: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |         suffix = 'u' | 
					
						
							|  |  |  |     return whex(val) + suffix | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | def str_match_bits(bits, mask): | 
					
						
							|  |  |  |     """Return a string pretty-printing BITS/MASK""" | 
					
						
							|  |  |  |     global insnwidth | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     i = 1 << (insnwidth - 1) | 
					
						
							|  |  |  |     space = 0x01010100 | 
					
						
							|  |  |  |     r = '' | 
					
						
							|  |  |  |     while i != 0: | 
					
						
							|  |  |  |         if i & mask: | 
					
						
							|  |  |  |             if i & bits: | 
					
						
							|  |  |  |                 r += '1' | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 r += '0' | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             r += '.' | 
					
						
							|  |  |  |         if i & space: | 
					
						
							|  |  |  |             r += ' ' | 
					
						
							|  |  |  |         i >>= 1 | 
					
						
							|  |  |  |     return r | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def is_pow2(x): | 
					
						
							|  |  |  |     """Return true iff X is equal to a power of 2.""" | 
					
						
							|  |  |  |     return (x & (x - 1)) == 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def ctz(x): | 
					
						
							|  |  |  |     """Return the number of times 2 factors into X.""" | 
					
						
							| 
									
										
										
										
											2020-05-16 13:15:02 -07:00
										 |  |  |     assert x != 0 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     r = 0 | 
					
						
							|  |  |  |     while ((x >> r) & 1) == 0: | 
					
						
							|  |  |  |         r += 1 | 
					
						
							|  |  |  |     return r | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def is_contiguous(bits): | 
					
						
							| 
									
										
										
										
											2020-05-16 13:15:02 -07:00
										 |  |  |     if bits == 0: | 
					
						
							|  |  |  |         return -1 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     shift = ctz(bits) | 
					
						
							|  |  |  |     if is_pow2((bits >> shift) + 1): | 
					
						
							|  |  |  |         return shift | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         return -1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-29 10:03:59 -07:00
										 |  |  | def eq_fields_for_args(flds_a, arg): | 
					
						
							|  |  |  |     if len(flds_a) != len(arg.fields): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2021-04-29 10:03:59 -07:00
										 |  |  |     # Only allow inference on default types | 
					
						
							|  |  |  |     for t in arg.types: | 
					
						
							|  |  |  |         if t != 'int': | 
					
						
							|  |  |  |             return False | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     for k, a in flds_a.items(): | 
					
						
							| 
									
										
										
										
											2021-04-29 10:03:59 -07:00
										 |  |  |         if k not in arg.fields: | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             return False | 
					
						
							|  |  |  |     return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def eq_fields_for_fmts(flds_a, flds_b): | 
					
						
							|  |  |  |     if len(flds_a) != len(flds_b): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     for k, a in flds_a.items(): | 
					
						
							|  |  |  |         if k not in flds_b: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |         b = flds_b[k] | 
					
						
							|  |  |  |         if a.__class__ != b.__class__ or a != b: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |     return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Field: | 
					
						
							|  |  |  |     """Class representing a simple instruction field""" | 
					
						
							|  |  |  |     def __init__(self, sign, pos, len): | 
					
						
							|  |  |  |         self.sign = sign | 
					
						
							|  |  |  |         self.pos = pos | 
					
						
							|  |  |  |         self.len = len | 
					
						
							|  |  |  |         self.mask = ((1 << len) - 1) << pos | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         if self.sign: | 
					
						
							|  |  |  |             s = 's' | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             s = '' | 
					
						
							| 
									
										
										
										
											2018-10-04 12:18:50 -04:00
										 |  |  |         return str(self.pos) + ':' + s + str(self.len) | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def str_extract(self): | 
					
						
							| 
									
										
										
										
											2021-04-07 22:18:49 +00:00
										 |  |  |         global bitop_width | 
					
						
							|  |  |  |         s = 's' if self.sign else '' | 
					
						
							|  |  |  |         return f'{s}extract{bitop_width}(insn, {self.pos}, {self.len})' | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __eq__(self, other): | 
					
						
							| 
									
										
										
										
											2019-06-11 16:39:41 +01:00
										 |  |  |         return self.sign == other.sign and self.mask == other.mask | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __ne__(self, other): | 
					
						
							|  |  |  |         return not self.__eq__(other) | 
					
						
							|  |  |  | # end Field | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MultiField: | 
					
						
							|  |  |  |     """Class representing a compound instruction field""" | 
					
						
							|  |  |  |     def __init__(self, subs, mask): | 
					
						
							|  |  |  |         self.subs = subs | 
					
						
							|  |  |  |         self.sign = subs[0].sign | 
					
						
							|  |  |  |         self.mask = mask | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return str(self.subs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def str_extract(self): | 
					
						
							| 
									
										
										
										
											2021-04-07 22:18:49 +00:00
										 |  |  |         global bitop_width | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         ret = '0' | 
					
						
							|  |  |  |         pos = 0 | 
					
						
							|  |  |  |         for f in reversed(self.subs): | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |             ext = f.str_extract() | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             if pos == 0: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |                 ret = ext | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2021-04-07 22:18:49 +00:00
										 |  |  |                 ret = f'deposit{bitop_width}({ret}, {pos}, {bitop_width - pos}, {ext})' | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             pos += f.len | 
					
						
							|  |  |  |         return ret | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ne__(self, other): | 
					
						
							|  |  |  |         if len(self.subs) != len(other.subs): | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  |         for a, b in zip(self.subs, other.subs): | 
					
						
							|  |  |  |             if a.__class__ != b.__class__ or a != b: | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __eq__(self, other): | 
					
						
							|  |  |  |         return not self.__ne__(other) | 
					
						
							|  |  |  | # end MultiField | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ConstField: | 
					
						
							|  |  |  |     """Class representing an argument field with constant value""" | 
					
						
							|  |  |  |     def __init__(self, value): | 
					
						
							|  |  |  |         self.value = value | 
					
						
							|  |  |  |         self.mask = 0 | 
					
						
							|  |  |  |         self.sign = value < 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return str(self.value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def str_extract(self): | 
					
						
							|  |  |  |         return str(self.value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __cmp__(self, other): | 
					
						
							|  |  |  |         return self.value - other.value | 
					
						
							|  |  |  | # end ConstField | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FunctionField: | 
					
						
							| 
									
										
										
										
											2019-07-22 17:02:56 -07:00
										 |  |  |     """Class representing a field passed through a function""" | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     def __init__(self, func, base): | 
					
						
							|  |  |  |         self.mask = base.mask | 
					
						
							|  |  |  |         self.sign = base.sign | 
					
						
							|  |  |  |         self.base = base | 
					
						
							|  |  |  |         self.func = func | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.func + '(' + str(self.base) + ')' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def str_extract(self): | 
					
						
							| 
									
										
										
										
											2019-03-20 19:21:31 -07:00
										 |  |  |         return self.func + '(ctx, ' + self.base.str_extract() + ')' | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __eq__(self, other): | 
					
						
							|  |  |  |         return self.func == other.func and self.base == other.base | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ne__(self, other): | 
					
						
							|  |  |  |         return not self.__eq__(other) | 
					
						
							|  |  |  | # end FunctionField | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-22 17:02:56 -07:00
										 |  |  | class ParameterField: | 
					
						
							|  |  |  |     """Class representing a pseudo-field read from a function""" | 
					
						
							|  |  |  |     def __init__(self, func): | 
					
						
							|  |  |  |         self.mask = 0 | 
					
						
							|  |  |  |         self.sign = 0 | 
					
						
							|  |  |  |         self.func = func | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.func | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def str_extract(self): | 
					
						
							|  |  |  |         return self.func + '(ctx)' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __eq__(self, other): | 
					
						
							|  |  |  |         return self.func == other.func | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ne__(self, other): | 
					
						
							|  |  |  |         return not self.__eq__(other) | 
					
						
							|  |  |  | # end ParameterField | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | class Arguments: | 
					
						
							|  |  |  |     """Class representing the extracted fields of a format""" | 
					
						
							| 
									
										
										
										
											2021-04-29 10:03:59 -07:00
										 |  |  |     def __init__(self, nm, flds, types, extern): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         self.name = nm | 
					
						
							| 
									
										
										
										
											2018-10-23 10:26:25 +01:00
										 |  |  |         self.extern = extern | 
					
						
							| 
									
										
										
										
											2021-04-29 10:03:59 -07:00
										 |  |  |         self.fields = flds | 
					
						
							|  |  |  |         self.types = types | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.name + ' ' + str(self.fields) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def struct_name(self): | 
					
						
							|  |  |  |         return 'arg_' + self.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def output_def(self): | 
					
						
							| 
									
										
										
										
											2018-10-23 10:26:25 +01:00
										 |  |  |         if not self.extern: | 
					
						
							|  |  |  |             output('typedef struct {\n') | 
					
						
							| 
									
										
										
										
											2021-04-29 10:03:59 -07:00
										 |  |  |             for (n, t) in zip(self.fields, self.types): | 
					
						
							|  |  |  |                 output(f'    {t} {n};\n') | 
					
						
							| 
									
										
										
										
											2018-10-23 10:26:25 +01:00
										 |  |  |             output('} ', self.struct_name(), ';\n\n') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | # end Arguments | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class General: | 
					
						
							|  |  |  |     """Common code between instruction formats and instruction patterns""" | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  |     def __init__(self, name, lineno, base, fixb, fixm, udfm, fldm, flds, w): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         self.name = name | 
					
						
							| 
									
										
										
										
											2018-10-26 14:59:43 +01:00
										 |  |  |         self.file = input_file | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         self.lineno = lineno | 
					
						
							|  |  |  |         self.base = base | 
					
						
							|  |  |  |         self.fixedbits = fixb | 
					
						
							|  |  |  |         self.fixedmask = fixm | 
					
						
							|  |  |  |         self.undefmask = udfm | 
					
						
							|  |  |  |         self.fieldmask = fldm | 
					
						
							|  |  |  |         self.fields = flds | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  |         self.width = w | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |         return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask) | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def str1(self, i): | 
					
						
							|  |  |  |         return str_indent(i) + self.__str__() | 
					
						
							|  |  |  | # end General | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Format(General): | 
					
						
							|  |  |  |     """Class representing an instruction format""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def extract_name(self): | 
					
						
							| 
									
										
										
										
											2019-02-28 14:45:50 -08:00
										 |  |  |         global decode_function | 
					
						
							|  |  |  |         return decode_function + '_extract_' + self.name | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def output_extract(self): | 
					
						
							| 
									
										
										
										
											2019-03-20 19:21:31 -07:00
										 |  |  |         output('static void ', self.extract_name(), '(DisasContext *ctx, ', | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |                self.base.struct_name(), ' *a, ', insntype, ' insn)\n{\n') | 
					
						
							|  |  |  |         for n, f in self.fields.items(): | 
					
						
							|  |  |  |             output('    a->', n, ' = ', f.str_extract(), ';\n') | 
					
						
							|  |  |  |         output('}\n\n') | 
					
						
							|  |  |  | # end Format | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Pattern(General): | 
					
						
							|  |  |  |     """Class representing an instruction pattern""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def output_decl(self): | 
					
						
							|  |  |  |         global translate_scope | 
					
						
							|  |  |  |         global translate_prefix | 
					
						
							|  |  |  |         output('typedef ', self.base.base.struct_name(), | 
					
						
							|  |  |  |                ' arg_', self.name, ';\n') | 
					
						
							| 
									
										
										
										
											2018-03-02 10:45:35 +00:00
										 |  |  |         output(translate_scope, 'bool ', translate_prefix, '_', self.name, | 
					
						
							| 
									
										
										
										
											2018-10-23 11:05:27 +01:00
										 |  |  |                '(DisasContext *ctx, arg_', self.name, ' *a);\n') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def output_code(self, i, extracted, outerbits, outermask): | 
					
						
							|  |  |  |         global translate_prefix | 
					
						
							|  |  |  |         ind = str_indent(i) | 
					
						
							|  |  |  |         arg = self.base.base.name | 
					
						
							| 
									
										
										
										
											2018-10-26 14:59:43 +01:00
										 |  |  |         output(ind, '/* ', self.file, ':', str(self.lineno), ' */\n') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         if not extracted: | 
					
						
							| 
									
										
										
										
											2019-03-20 19:21:31 -07:00
										 |  |  |             output(ind, self.base.extract_name(), | 
					
						
							|  |  |  |                    '(ctx, &u.f_', arg, ', insn);\n') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         for n, f in self.fields.items(): | 
					
						
							|  |  |  |             output(ind, 'u.f_', arg, '.', n, ' = ', f.str_extract(), ';\n') | 
					
						
							| 
									
										
										
										
											2019-02-23 08:57:46 -08:00
										 |  |  |         output(ind, 'if (', translate_prefix, '_', self.name, | 
					
						
							|  |  |  |                '(ctx, &u.f_', arg, ')) return true;\n') | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Normal patterns do not have children. | 
					
						
							|  |  |  |     def build_tree(self): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     def prop_masks(self): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     def prop_format(self): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     def prop_width(self): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | # end Pattern | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-16 11:19:45 -07:00
										 |  |  | class MultiPattern(General): | 
					
						
							|  |  |  |     """Class representing a set of instruction patterns""" | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |     def __init__(self, lineno): | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |         self.file = input_file | 
					
						
							|  |  |  |         self.lineno = lineno | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |         self.pats = [] | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |         self.base = None | 
					
						
							| 
									
										
										
										
											2020-05-16 11:19:45 -07:00
										 |  |  |         self.fixedbits = 0 | 
					
						
							|  |  |  |         self.fixedmask = 0 | 
					
						
							|  |  |  |         self.undefmask = 0 | 
					
						
							|  |  |  |         self.width = None | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							| 
									
										
										
										
											2020-05-16 11:19:45 -07:00
										 |  |  |         r = 'group' | 
					
						
							|  |  |  |         if self.fixedbits is not None: | 
					
						
							|  |  |  |             r += ' ' + str_match_bits(self.fixedbits, self.fixedmask) | 
					
						
							|  |  |  |         return r | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def output_decl(self): | 
					
						
							|  |  |  |         for p in self.pats: | 
					
						
							|  |  |  |             p.output_decl() | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def prop_masks(self): | 
					
						
							|  |  |  |         global insnmask | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fixedmask = insnmask | 
					
						
							|  |  |  |         undefmask = insnmask | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Collect fixedmask/undefmask for all of the children. | 
					
						
							|  |  |  |         for p in self.pats: | 
					
						
							|  |  |  |             p.prop_masks() | 
					
						
							|  |  |  |             fixedmask &= p.fixedmask | 
					
						
							|  |  |  |             undefmask &= p.undefmask | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Widen fixedmask until all fixedbits match | 
					
						
							|  |  |  |         repeat = True | 
					
						
							|  |  |  |         fixedbits = 0 | 
					
						
							|  |  |  |         while repeat and fixedmask != 0: | 
					
						
							|  |  |  |             fixedbits = None | 
					
						
							|  |  |  |             for p in self.pats: | 
					
						
							|  |  |  |                 thisbits = p.fixedbits & fixedmask | 
					
						
							|  |  |  |                 if fixedbits is None: | 
					
						
							|  |  |  |                     fixedbits = thisbits | 
					
						
							|  |  |  |                 elif fixedbits != thisbits: | 
					
						
							|  |  |  |                     fixedmask &= ~(fixedbits ^ thisbits) | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 repeat = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.fixedbits = fixedbits | 
					
						
							|  |  |  |         self.fixedmask = fixedmask | 
					
						
							|  |  |  |         self.undefmask = undefmask | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def build_tree(self): | 
					
						
							|  |  |  |         for p in self.pats: | 
					
						
							|  |  |  |             p.build_tree() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def prop_format(self): | 
					
						
							|  |  |  |         for p in self.pats: | 
					
						
							|  |  |  |             p.build_tree() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def prop_width(self): | 
					
						
							|  |  |  |         width = None | 
					
						
							|  |  |  |         for p in self.pats: | 
					
						
							|  |  |  |             p.prop_width() | 
					
						
							|  |  |  |             if width is None: | 
					
						
							|  |  |  |                 width = p.width | 
					
						
							|  |  |  |             elif width != p.width: | 
					
						
							|  |  |  |                 error_with_file(self.file, self.lineno, | 
					
						
							|  |  |  |                                 'width mismatch in patterns within braces') | 
					
						
							|  |  |  |         self.width = width | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-16 11:19:45 -07:00
										 |  |  | # end MultiPattern | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class IncMultiPattern(MultiPattern): | 
					
						
							|  |  |  |     """Class representing an overlapping set of instruction patterns""" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |     def output_code(self, i, extracted, outerbits, outermask): | 
					
						
							|  |  |  |         global translate_prefix | 
					
						
							|  |  |  |         ind = str_indent(i) | 
					
						
							|  |  |  |         for p in self.pats: | 
					
						
							|  |  |  |             if outermask != p.fixedmask: | 
					
						
							|  |  |  |                 innermask = p.fixedmask & ~outermask | 
					
						
							|  |  |  |                 innerbits = p.fixedbits & ~outermask | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |                 output(ind, f'if ((insn & {whexC(innermask)}) == {whexC(innerbits)}) {{\n') | 
					
						
							|  |  |  |                 output(ind, f'    /* {str_match_bits(p.fixedbits, p.fixedmask)} */\n') | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |                 p.output_code(i + 4, extracted, p.fixedbits, p.fixedmask) | 
					
						
							|  |  |  |                 output(ind, '}\n') | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 p.output_code(i, extracted, p.fixedbits, p.fixedmask) | 
					
						
							| 
									
										
										
										
											2020-05-16 10:50:43 -07:00
										 |  |  | #end IncMultiPattern | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  | class Tree: | 
					
						
							|  |  |  |     """Class representing a node in a decode tree""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, fm, tm): | 
					
						
							|  |  |  |         self.fixedmask = fm | 
					
						
							|  |  |  |         self.thismask = tm | 
					
						
							|  |  |  |         self.subs = [] | 
					
						
							|  |  |  |         self.base = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def str1(self, i): | 
					
						
							|  |  |  |         ind = str_indent(i) | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |         r = ind + whex(self.fixedmask) | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |         if self.format: | 
					
						
							|  |  |  |             r += ' ' + self.format.name | 
					
						
							|  |  |  |         r += ' [\n' | 
					
						
							|  |  |  |         for (b, s) in self.subs: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |             r += ind + f'  {whex(b)}:\n' | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |             r += s.str1(i + 4) + '\n' | 
					
						
							|  |  |  |         r += ind + ']' | 
					
						
							|  |  |  |         return r | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.str1(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def output_code(self, i, extracted, outerbits, outermask): | 
					
						
							|  |  |  |         ind = str_indent(i) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # If we identified all nodes below have the same format, | 
					
						
							|  |  |  |         # extract the fields now. | 
					
						
							|  |  |  |         if not extracted and self.base: | 
					
						
							|  |  |  |             output(ind, self.base.extract_name(), | 
					
						
							|  |  |  |                    '(ctx, &u.f_', self.base.base.name, ', insn);\n') | 
					
						
							|  |  |  |             extracted = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Attempt to aid the compiler in producing compact switch statements. | 
					
						
							|  |  |  |         # If the bits in the mask are contiguous, extract them. | 
					
						
							|  |  |  |         sh = is_contiguous(self.thismask) | 
					
						
							|  |  |  |         if sh > 0: | 
					
						
							|  |  |  |             # Propagate SH down into the local functions. | 
					
						
							|  |  |  |             def str_switch(b, sh=sh): | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |                 return f'(insn >> {sh}) & {b >> sh:#x}' | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             def str_case(b, sh=sh): | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |                 return hex(b >> sh) | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |         else: | 
					
						
							|  |  |  |             def str_switch(b): | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |                 return f'insn & {whexC(b)}' | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             def str_case(b): | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |                 return whexC(b) | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         output(ind, 'switch (', str_switch(self.thismask), ') {\n') | 
					
						
							|  |  |  |         for b, s in sorted(self.subs): | 
					
						
							|  |  |  |             assert (self.thismask & ~s.fixedmask) == 0 | 
					
						
							|  |  |  |             innermask = outermask | self.thismask | 
					
						
							|  |  |  |             innerbits = outerbits | b | 
					
						
							|  |  |  |             output(ind, 'case ', str_case(b), ':\n') | 
					
						
							|  |  |  |             output(ind, '    /* ', | 
					
						
							|  |  |  |                    str_match_bits(innerbits, innermask), ' */\n') | 
					
						
							|  |  |  |             s.output_code(i + 4, extracted, innerbits, innermask) | 
					
						
							| 
									
										
										
										
											2020-10-19 16:12:52 +01:00
										 |  |  |             output(ind, '    break;\n') | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |         output(ind, '}\n') | 
					
						
							|  |  |  | # end Tree | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ExcMultiPattern(MultiPattern): | 
					
						
							|  |  |  |     """Class representing a non-overlapping set of instruction patterns""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def output_code(self, i, extracted, outerbits, outermask): | 
					
						
							|  |  |  |         # Defer everything to our decomposed Tree node | 
					
						
							|  |  |  |         self.tree.output_code(i, extracted, outerbits, outermask) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def __build_tree(pats, outerbits, outermask): | 
					
						
							|  |  |  |         # Find the intersection of all remaining fixedmask. | 
					
						
							|  |  |  |         innermask = ~outermask & insnmask | 
					
						
							|  |  |  |         for i in pats: | 
					
						
							|  |  |  |             innermask &= i.fixedmask | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if innermask == 0: | 
					
						
							|  |  |  |             # Edge condition: One pattern covers the entire insnmask | 
					
						
							|  |  |  |             if len(pats) == 1: | 
					
						
							|  |  |  |                 t = Tree(outermask, innermask) | 
					
						
							|  |  |  |                 t.subs.append((0, pats[0])) | 
					
						
							|  |  |  |                 return t | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             text = 'overlapping patterns:' | 
					
						
							|  |  |  |             for p in pats: | 
					
						
							|  |  |  |                 text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p) | 
					
						
							|  |  |  |             error_with_file(pats[0].file, pats[0].lineno, text) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fullmask = outermask | innermask | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Sort each element of pats into the bin selected by the mask. | 
					
						
							|  |  |  |         bins = {} | 
					
						
							|  |  |  |         for i in pats: | 
					
						
							|  |  |  |             fb = i.fixedbits & innermask | 
					
						
							|  |  |  |             if fb in bins: | 
					
						
							|  |  |  |                 bins[fb].append(i) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 bins[fb] = [i] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # We must recurse if any bin has more than one element or if | 
					
						
							|  |  |  |         # the single element in the bin has not been fully matched. | 
					
						
							|  |  |  |         t = Tree(fullmask, innermask) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for b, l in bins.items(): | 
					
						
							|  |  |  |             s = l[0] | 
					
						
							|  |  |  |             if len(l) > 1 or s.fixedmask & ~fullmask != 0: | 
					
						
							|  |  |  |                 s = ExcMultiPattern.__build_tree(l, b | outerbits, fullmask) | 
					
						
							|  |  |  |             t.subs.append((b, s)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return t | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def build_tree(self): | 
					
						
							|  |  |  |         super().prop_format() | 
					
						
							|  |  |  |         self.tree = self.__build_tree(self.pats, self.fixedbits, | 
					
						
							|  |  |  |                                       self.fixedmask) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def __prop_format(tree): | 
					
						
							|  |  |  |         """Propagate Format objects into the decode tree""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Depth first search. | 
					
						
							|  |  |  |         for (b, s) in tree.subs: | 
					
						
							|  |  |  |             if isinstance(s, Tree): | 
					
						
							|  |  |  |                 ExcMultiPattern.__prop_format(s) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # If all entries in SUBS have the same format, then | 
					
						
							|  |  |  |         # propagate that into the tree. | 
					
						
							|  |  |  |         f = None | 
					
						
							|  |  |  |         for (b, s) in tree.subs: | 
					
						
							|  |  |  |             if f is None: | 
					
						
							|  |  |  |                 f = s.base | 
					
						
							|  |  |  |                 if f is None: | 
					
						
							|  |  |  |                     return | 
					
						
							|  |  |  |             if f is not s.base: | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |         tree.base = f | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def prop_format(self): | 
					
						
							|  |  |  |         super().prop_format() | 
					
						
							|  |  |  |         self.__prop_format(self.tree) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # end ExcMultiPattern | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | def parse_field(lineno, name, toks): | 
					
						
							|  |  |  |     """Parse one instruction field from TOKS at LINENO""" | 
					
						
							|  |  |  |     global fields | 
					
						
							|  |  |  |     global insnwidth | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # A "simple" field will have only one entry; | 
					
						
							|  |  |  |     # a "multifield" will have several. | 
					
						
							|  |  |  |     subs = [] | 
					
						
							|  |  |  |     width = 0 | 
					
						
							|  |  |  |     func = None | 
					
						
							|  |  |  |     for t in toks: | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |         if re.match('^!function=', t): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             if func: | 
					
						
							|  |  |  |                 error(lineno, 'duplicate function') | 
					
						
							|  |  |  |             func = t.split('=') | 
					
						
							|  |  |  |             func = func[1] | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-13 23:52:30 -04:00
										 |  |  |         if re.fullmatch('[0-9]+:s[0-9]+', t): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             # Signed field extract | 
					
						
							|  |  |  |             subtoks = t.split(':s') | 
					
						
							|  |  |  |             sign = True | 
					
						
							| 
									
										
										
										
											2020-05-13 23:52:30 -04:00
										 |  |  |         elif re.fullmatch('[0-9]+:[0-9]+', t): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             # Unsigned field extract | 
					
						
							|  |  |  |             subtoks = t.split(':') | 
					
						
							|  |  |  |             sign = False | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |             error(lineno, f'invalid field token "{t}"') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         po = int(subtoks[0]) | 
					
						
							|  |  |  |         le = int(subtoks[1]) | 
					
						
							|  |  |  |         if po + le > insnwidth: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |             error(lineno, f'field {t} too large') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         f = Field(sign, po, le) | 
					
						
							|  |  |  |         subs.append(f) | 
					
						
							|  |  |  |         width += le | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if width > insnwidth: | 
					
						
							|  |  |  |         error(lineno, 'field too large') | 
					
						
							| 
									
										
										
										
											2019-07-22 17:02:56 -07:00
										 |  |  |     if len(subs) == 0: | 
					
						
							|  |  |  |         if func: | 
					
						
							|  |  |  |             f = ParameterField(func) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             error(lineno, 'field with no value') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2019-07-22 17:02:56 -07:00
										 |  |  |         if len(subs) == 1: | 
					
						
							|  |  |  |             f = subs[0] | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             mask = 0 | 
					
						
							|  |  |  |             for s in subs: | 
					
						
							|  |  |  |                 if mask & s.mask: | 
					
						
							|  |  |  |                     error(lineno, 'field components overlap') | 
					
						
							|  |  |  |                 mask |= s.mask | 
					
						
							|  |  |  |             f = MultiField(subs, mask) | 
					
						
							|  |  |  |         if func: | 
					
						
							|  |  |  |             f = FunctionField(func, f) | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if name in fields: | 
					
						
							|  |  |  |         error(lineno, 'duplicate field', name) | 
					
						
							|  |  |  |     fields[name] = f | 
					
						
							|  |  |  | # end parse_field | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def parse_arguments(lineno, name, toks): | 
					
						
							|  |  |  |     """Parse one argument set from TOKS at LINENO""" | 
					
						
							|  |  |  |     global arguments | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |     global re_C_ident | 
					
						
							| 
									
										
										
										
											2019-08-09 08:12:50 -07:00
										 |  |  |     global anyextern | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     flds = [] | 
					
						
							| 
									
										
										
										
											2021-04-29 10:03:59 -07:00
										 |  |  |     types = [] | 
					
						
							| 
									
										
										
										
											2018-10-23 10:26:25 +01:00
										 |  |  |     extern = False | 
					
						
							| 
									
										
										
										
											2021-04-29 10:03:59 -07:00
										 |  |  |     for n in toks: | 
					
						
							|  |  |  |         if re.fullmatch('!extern', n): | 
					
						
							| 
									
										
										
										
											2018-10-23 10:26:25 +01:00
										 |  |  |             extern = True | 
					
						
							| 
									
										
										
										
											2019-08-09 08:12:50 -07:00
										 |  |  |             anyextern = True | 
					
						
							| 
									
										
										
										
											2018-10-23 10:26:25 +01:00
										 |  |  |             continue | 
					
						
							| 
									
										
										
										
											2021-04-29 10:03:59 -07:00
										 |  |  |         if re.fullmatch(re_C_ident + ':' + re_C_ident, n): | 
					
						
							|  |  |  |             (n, t) = n.split(':') | 
					
						
							|  |  |  |         elif re.fullmatch(re_C_ident, n): | 
					
						
							|  |  |  |             t = 'int' | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             error(lineno, f'invalid argument set token "{n}"') | 
					
						
							|  |  |  |         if n in flds: | 
					
						
							|  |  |  |             error(lineno, f'duplicate argument "{n}"') | 
					
						
							|  |  |  |         flds.append(n) | 
					
						
							|  |  |  |         types.append(t) | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if name in arguments: | 
					
						
							|  |  |  |         error(lineno, 'duplicate argument set', name) | 
					
						
							| 
									
										
										
										
											2021-04-29 10:03:59 -07:00
										 |  |  |     arguments[name] = Arguments(name, flds, types, extern) | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | # end parse_arguments | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def lookup_field(lineno, name): | 
					
						
							|  |  |  |     global fields | 
					
						
							|  |  |  |     if name in fields: | 
					
						
							|  |  |  |         return fields[name] | 
					
						
							|  |  |  |     error(lineno, 'undefined field', name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def add_field(lineno, flds, new_name, f): | 
					
						
							|  |  |  |     if new_name in flds: | 
					
						
							|  |  |  |         error(lineno, 'duplicate field', new_name) | 
					
						
							|  |  |  |     flds[new_name] = f | 
					
						
							|  |  |  |     return flds | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def add_field_byname(lineno, flds, new_name, old_name): | 
					
						
							|  |  |  |     return add_field(lineno, flds, new_name, lookup_field(lineno, old_name)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def infer_argument_set(flds): | 
					
						
							|  |  |  |     global arguments | 
					
						
							| 
									
										
										
										
											2018-10-23 10:26:25 +01:00
										 |  |  |     global decode_function | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for arg in arguments.values(): | 
					
						
							| 
									
										
										
										
											2021-04-29 10:03:59 -07:00
										 |  |  |         if eq_fields_for_args(flds, arg): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             return arg | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-23 10:26:25 +01:00
										 |  |  |     name = decode_function + str(len(arguments)) | 
					
						
							| 
									
										
										
										
											2021-04-29 10:03:59 -07:00
										 |  |  |     arg = Arguments(name, flds.keys(), ['int'] * len(flds), False) | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     arguments[name] = arg | 
					
						
							|  |  |  |     return arg | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  | def infer_format(arg, fieldmask, flds, width): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     global arguments | 
					
						
							|  |  |  |     global formats | 
					
						
							| 
									
										
										
										
											2018-10-23 10:26:25 +01:00
										 |  |  |     global decode_function | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const_flds = {} | 
					
						
							|  |  |  |     var_flds = {} | 
					
						
							|  |  |  |     for n, c in flds.items(): | 
					
						
							|  |  |  |         if c is ConstField: | 
					
						
							|  |  |  |             const_flds[n] = c | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             var_flds[n] = c | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Look for an existing format with the same argument set and fields | 
					
						
							|  |  |  |     for fmt in formats.values(): | 
					
						
							|  |  |  |         if arg and fmt.base != arg: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if fieldmask != fmt.fieldmask: | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  |         if width != fmt.width: | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         if not eq_fields_for_fmts(flds, fmt.fields): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         return (fmt, const_flds) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-23 10:26:25 +01:00
										 |  |  |     name = decode_function + '_Fmt_' + str(len(formats)) | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     if not arg: | 
					
						
							|  |  |  |         arg = infer_argument_set(flds) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  |     fmt = Format(name, 0, arg, 0, 0, 0, fieldmask, var_flds, width) | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     formats[name] = fmt | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return (fmt, const_flds) | 
					
						
							|  |  |  | # end infer_format | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  | def parse_generic(lineno, parent_pat, name, toks): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     """Parse one instruction format from TOKS at LINENO""" | 
					
						
							|  |  |  |     global fields | 
					
						
							|  |  |  |     global arguments | 
					
						
							|  |  |  |     global formats | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |     global allpatterns | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |     global re_arg_ident | 
					
						
							|  |  |  |     global re_fld_ident | 
					
						
							|  |  |  |     global re_fmt_ident | 
					
						
							|  |  |  |     global re_C_ident | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     global insnwidth | 
					
						
							|  |  |  |     global insnmask | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  |     global variablewidth | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |     is_format = parent_pat is None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     fixedmask = 0 | 
					
						
							|  |  |  |     fixedbits = 0 | 
					
						
							|  |  |  |     undefmask = 0 | 
					
						
							|  |  |  |     width = 0 | 
					
						
							|  |  |  |     flds = {} | 
					
						
							|  |  |  |     arg = None | 
					
						
							|  |  |  |     fmt = None | 
					
						
							|  |  |  |     for t in toks: | 
					
						
							| 
									
										
										
										
											2020-09-17 15:50:23 +08:00
										 |  |  |         # '&Foo' gives a format an explicit argument set. | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |         if re.fullmatch(re_arg_ident, t): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             tt = t[1:] | 
					
						
							|  |  |  |             if arg: | 
					
						
							|  |  |  |                 error(lineno, 'multiple argument sets') | 
					
						
							|  |  |  |             if tt in arguments: | 
					
						
							|  |  |  |                 arg = arguments[tt] | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 error(lineno, 'undefined argument set', t) | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # '@Foo' gives a pattern an explicit format. | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |         if re.fullmatch(re_fmt_ident, t): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             tt = t[1:] | 
					
						
							|  |  |  |             if fmt: | 
					
						
							|  |  |  |                 error(lineno, 'multiple formats') | 
					
						
							|  |  |  |             if tt in formats: | 
					
						
							|  |  |  |                 fmt = formats[tt] | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 error(lineno, 'undefined format', t) | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # '%Foo' imports a field. | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |         if re.fullmatch(re_fld_ident, t): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             tt = t[1:] | 
					
						
							|  |  |  |             flds = add_field_byname(lineno, flds, tt, tt) | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # 'Foo=%Bar' imports a field with a different name. | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |         if re.fullmatch(re_C_ident + '=' + re_fld_ident, t): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             (fname, iname) = t.split('=%') | 
					
						
							|  |  |  |             flds = add_field_byname(lineno, flds, fname, iname) | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # 'Foo=number' sets an argument field to a constant value | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |         if re.fullmatch(re_C_ident + '=[+-]?[0-9]+', t): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             (fname, value) = t.split('=') | 
					
						
							|  |  |  |             value = int(value) | 
					
						
							|  |  |  |             flds = add_field(lineno, flds, fname, ConstField(value)) | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Pattern of 0s, 1s, dots and dashes indicate required zeros, | 
					
						
							|  |  |  |         # required ones, or dont-cares. | 
					
						
							| 
									
										
										
										
											2020-05-13 23:52:30 -04:00
										 |  |  |         if re.fullmatch('[01.-]+', t): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             shift = len(t) | 
					
						
							|  |  |  |             fms = t.replace('0', '1') | 
					
						
							|  |  |  |             fms = fms.replace('.', '0') | 
					
						
							|  |  |  |             fms = fms.replace('-', '0') | 
					
						
							|  |  |  |             fbs = t.replace('.', '0') | 
					
						
							|  |  |  |             fbs = fbs.replace('-', '0') | 
					
						
							|  |  |  |             ubm = t.replace('1', '0') | 
					
						
							|  |  |  |             ubm = ubm.replace('.', '0') | 
					
						
							|  |  |  |             ubm = ubm.replace('-', '1') | 
					
						
							|  |  |  |             fms = int(fms, 2) | 
					
						
							|  |  |  |             fbs = int(fbs, 2) | 
					
						
							|  |  |  |             ubm = int(ubm, 2) | 
					
						
							|  |  |  |             fixedbits = (fixedbits << shift) | fbs | 
					
						
							|  |  |  |             fixedmask = (fixedmask << shift) | fms | 
					
						
							|  |  |  |             undefmask = (undefmask << shift) | ubm | 
					
						
							|  |  |  |         # Otherwise, fieldname:fieldwidth | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |         elif re.fullmatch(re_C_ident + ':s?[0-9]+', t): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             (fname, flen) = t.split(':') | 
					
						
							|  |  |  |             sign = False | 
					
						
							|  |  |  |             if flen[0] == 's': | 
					
						
							|  |  |  |                 sign = True | 
					
						
							|  |  |  |                 flen = flen[1:] | 
					
						
							|  |  |  |             shift = int(flen, 10) | 
					
						
							| 
									
										
										
										
											2019-03-05 15:34:41 -08:00
										 |  |  |             if shift + width > insnwidth: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |                 error(lineno, f'field {fname} exceeds insnwidth') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             f = Field(sign, insnwidth - width - shift, shift) | 
					
						
							|  |  |  |             flds = add_field(lineno, flds, fname, f) | 
					
						
							|  |  |  |             fixedbits <<= shift | 
					
						
							|  |  |  |             fixedmask <<= shift | 
					
						
							|  |  |  |             undefmask <<= shift | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |             error(lineno, f'invalid token "{t}"') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         width += shift | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  |     if variablewidth and width < insnwidth and width % 8 == 0: | 
					
						
							|  |  |  |         shift = insnwidth - width | 
					
						
							|  |  |  |         fixedbits <<= shift | 
					
						
							|  |  |  |         fixedmask <<= shift | 
					
						
							|  |  |  |         undefmask <<= shift | 
					
						
							|  |  |  |         undefmask |= (1 << shift) - 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     # We should have filled in all of the bits of the instruction. | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  |     elif not (is_format and width == 0) and width != insnwidth: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |         error(lineno, f'definition has {width} bits') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-17 15:50:23 +08:00
										 |  |  |     # Do not check for fields overlapping fields; one valid usage | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     # is to be able to duplicate fields via import. | 
					
						
							|  |  |  |     fieldmask = 0 | 
					
						
							|  |  |  |     for f in flds.values(): | 
					
						
							|  |  |  |         fieldmask |= f.mask | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Fix up what we've parsed to match either a format or a pattern. | 
					
						
							|  |  |  |     if is_format: | 
					
						
							|  |  |  |         # Formats cannot reference formats. | 
					
						
							|  |  |  |         if fmt: | 
					
						
							|  |  |  |             error(lineno, 'format referencing format') | 
					
						
							|  |  |  |         # If an argument set is given, then there should be no fields | 
					
						
							|  |  |  |         # without a place to store it. | 
					
						
							|  |  |  |         if arg: | 
					
						
							|  |  |  |             for f in flds.keys(): | 
					
						
							|  |  |  |                 if f not in arg.fields: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |                     error(lineno, f'field {f} not in argument set {arg.name}') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         else: | 
					
						
							|  |  |  |             arg = infer_argument_set(flds) | 
					
						
							|  |  |  |         if name in formats: | 
					
						
							|  |  |  |             error(lineno, 'duplicate format name', name) | 
					
						
							|  |  |  |         fmt = Format(name, lineno, arg, fixedbits, fixedmask, | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  |                      undefmask, fieldmask, flds, width) | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         formats[name] = fmt | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         # Patterns can reference a format ... | 
					
						
							|  |  |  |         if fmt: | 
					
						
							|  |  |  |             # ... but not an argument simultaneously | 
					
						
							|  |  |  |             if arg: | 
					
						
							|  |  |  |                 error(lineno, 'pattern specifies both format and argument set') | 
					
						
							|  |  |  |             if fixedmask & fmt.fixedmask: | 
					
						
							|  |  |  |                 error(lineno, 'pattern fixed bits overlap format fixed bits') | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  |             if width != fmt.width: | 
					
						
							|  |  |  |                 error(lineno, 'pattern uses format of different width') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             fieldmask |= fmt.fieldmask | 
					
						
							|  |  |  |             fixedbits |= fmt.fixedbits | 
					
						
							|  |  |  |             fixedmask |= fmt.fixedmask | 
					
						
							|  |  |  |             undefmask |= fmt.undefmask | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  |             (fmt, flds) = infer_format(arg, fieldmask, flds, width) | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         arg = fmt.base | 
					
						
							|  |  |  |         for f in flds.keys(): | 
					
						
							|  |  |  |             if f not in arg.fields: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |                 error(lineno, f'field {f} not in argument set {arg.name}') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             if f in fmt.fields.keys(): | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |                 error(lineno, f'field {f} set by format and pattern') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         for f in arg.fields: | 
					
						
							|  |  |  |             if f not in flds.keys() and f not in fmt.fields.keys(): | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |                 error(lineno, f'field {f} not initialized') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         pat = Pattern(name, lineno, fmt, fixedbits, fixedmask, | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  |                       undefmask, fieldmask, flds, width) | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |         parent_pat.pats.append(pat) | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |         allpatterns.append(pat) | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Validate the masks that we have assembled. | 
					
						
							|  |  |  |     if fieldmask & fixedmask: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |         error(lineno, 'fieldmask overlaps fixedmask ', | 
					
						
							|  |  |  |               f'({whex(fieldmask)} & {whex(fixedmask)})') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     if fieldmask & undefmask: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |         error(lineno, 'fieldmask overlaps undefmask ', | 
					
						
							|  |  |  |               f'({whex(fieldmask)} & {whex(undefmask)})') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     if fixedmask & undefmask: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |         error(lineno, 'fixedmask overlaps undefmask ', | 
					
						
							|  |  |  |               f'({whex(fixedmask)} & {whex(undefmask)})') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     if not is_format: | 
					
						
							|  |  |  |         allbits = fieldmask | fixedmask | undefmask | 
					
						
							|  |  |  |         if allbits != insnmask: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |             error(lineno, 'bits left unspecified ', | 
					
						
							|  |  |  |                   f'({whex(allbits ^ insnmask)})') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | # end parse_general | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  | def parse_file(f, parent_pat): | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     """Parse all of the patterns within a file""" | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |     global re_arg_ident | 
					
						
							|  |  |  |     global re_fld_ident | 
					
						
							|  |  |  |     global re_fmt_ident | 
					
						
							|  |  |  |     global re_pat_ident | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Read all of the lines of the file.  Concatenate lines | 
					
						
							|  |  |  |     # ending in backslash; discard empty lines and comments. | 
					
						
							|  |  |  |     toks = [] | 
					
						
							|  |  |  |     lineno = 0 | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |     nesting = 0 | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |     nesting_pats = [] | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     for line in f: | 
					
						
							|  |  |  |         lineno += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |         # Expand and strip spaces, to find indent. | 
					
						
							|  |  |  |         line = line.rstrip() | 
					
						
							|  |  |  |         line = line.expandtabs() | 
					
						
							|  |  |  |         len1 = len(line) | 
					
						
							|  |  |  |         line = line.lstrip() | 
					
						
							|  |  |  |         len2 = len(line) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         # Discard comments | 
					
						
							|  |  |  |         end = line.find('#') | 
					
						
							|  |  |  |         if end >= 0: | 
					
						
							|  |  |  |             line = line[:end] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         t = line.split() | 
					
						
							|  |  |  |         if len(toks) != 0: | 
					
						
							|  |  |  |             # Next line after continuation | 
					
						
							|  |  |  |             toks.extend(t) | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |             # Allow completely blank lines. | 
					
						
							|  |  |  |             if len1 == 0: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             indent = len1 - len2 | 
					
						
							|  |  |  |             # Empty line due to comment. | 
					
						
							|  |  |  |             if len(t) == 0: | 
					
						
							|  |  |  |                 # Indentation must be correct, even for comment lines. | 
					
						
							|  |  |  |                 if indent != nesting: | 
					
						
							|  |  |  |                     error(lineno, 'indentation ', indent, ' != ', nesting) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             start_lineno = lineno | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             toks = t | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Continuation? | 
					
						
							|  |  |  |         if toks[-1] == '\\': | 
					
						
							|  |  |  |             toks.pop() | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         name = toks[0] | 
					
						
							|  |  |  |         del toks[0] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |         # End nesting? | 
					
						
							| 
									
										
										
										
											2020-05-18 08:45:32 -07:00
										 |  |  |         if name == '}' or name == ']': | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |             if len(toks) != 0: | 
					
						
							|  |  |  |                 error(start_lineno, 'extra tokens after close brace') | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-18 08:45:32 -07:00
										 |  |  |             # Make sure { } and [ ] nest properly. | 
					
						
							|  |  |  |             if (name == '}') != isinstance(parent_pat, IncMultiPattern): | 
					
						
							|  |  |  |                 error(lineno, 'mismatched close brace') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 parent_pat = nesting_pats.pop() | 
					
						
							|  |  |  |             except: | 
					
						
							| 
									
										
										
										
											2020-05-18 08:45:32 -07:00
										 |  |  |                 error(lineno, 'extra close brace') | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |             nesting -= 2 | 
					
						
							|  |  |  |             if indent != nesting: | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |                 error(lineno, 'indentation ', indent, ' != ', nesting) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |             toks = [] | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Everything else should have current indentation. | 
					
						
							|  |  |  |         if indent != nesting: | 
					
						
							|  |  |  |             error(start_lineno, 'indentation ', indent, ' != ', nesting) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Start nesting? | 
					
						
							| 
									
										
										
										
											2020-05-18 08:45:32 -07:00
										 |  |  |         if name == '{' or name == '[': | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |             if len(toks) != 0: | 
					
						
							|  |  |  |                 error(start_lineno, 'extra tokens after open brace') | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-18 08:45:32 -07:00
										 |  |  |             if name == '{': | 
					
						
							|  |  |  |                 nested_pat = IncMultiPattern(start_lineno) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 nested_pat = ExcMultiPattern(start_lineno) | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |             parent_pat.pats.append(nested_pat) | 
					
						
							|  |  |  |             nesting_pats.append(parent_pat) | 
					
						
							|  |  |  |             parent_pat = nested_pat | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |             nesting += 2 | 
					
						
							|  |  |  |             toks = [] | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         # Determine the type of object needing to be parsed. | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |         if re.fullmatch(re_fld_ident, name): | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |             parse_field(start_lineno, name[1:], toks) | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |         elif re.fullmatch(re_arg_ident, name): | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |             parse_arguments(start_lineno, name[1:], toks) | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |         elif re.fullmatch(re_fmt_ident, name): | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |             parse_generic(start_lineno, None, name[1:], toks) | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |         elif re.fullmatch(re_pat_ident, name): | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |             parse_generic(start_lineno, parent_pat, name, toks) | 
					
						
							| 
									
										
										
										
											2020-09-03 12:23:34 -07:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |             error(lineno, f'invalid token "{name}"') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         toks = [] | 
					
						
							| 
									
										
										
										
											2020-05-18 08:45:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if nesting != 0: | 
					
						
							|  |  |  |         error(lineno, 'missing close brace') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | # end parse_file | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 11:34:11 -08:00
										 |  |  | class SizeTree: | 
					
						
							|  |  |  |     """Class representing a node in a size decode tree""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, m, w): | 
					
						
							|  |  |  |         self.mask = m | 
					
						
							|  |  |  |         self.subs = [] | 
					
						
							|  |  |  |         self.base = None | 
					
						
							|  |  |  |         self.width = w | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def str1(self, i): | 
					
						
							|  |  |  |         ind = str_indent(i) | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |         r = ind + whex(self.mask) + ' [\n' | 
					
						
							| 
									
										
										
										
											2019-01-31 11:34:11 -08:00
										 |  |  |         for (b, s) in self.subs: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |             r += ind + f'  {whex(b)}:\n' | 
					
						
							| 
									
										
										
										
											2019-01-31 11:34:11 -08:00
										 |  |  |             r += s.str1(i + 4) + '\n' | 
					
						
							|  |  |  |         r += ind + ']' | 
					
						
							|  |  |  |         return r | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.str1(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def output_code(self, i, extracted, outerbits, outermask): | 
					
						
							|  |  |  |         ind = str_indent(i) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # If we need to load more bytes to test, do so now. | 
					
						
							|  |  |  |         if extracted < self.width: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |             output(ind, f'insn = {decode_function}_load_bytes', | 
					
						
							|  |  |  |                    f'(ctx, insn, {extracted // 8}, {self.width // 8});\n') | 
					
						
							| 
									
										
										
										
											2019-01-31 11:34:11 -08:00
										 |  |  |             extracted = self.width | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Attempt to aid the compiler in producing compact switch statements. | 
					
						
							|  |  |  |         # If the bits in the mask are contiguous, extract them. | 
					
						
							|  |  |  |         sh = is_contiguous(self.mask) | 
					
						
							|  |  |  |         if sh > 0: | 
					
						
							|  |  |  |             # Propagate SH down into the local functions. | 
					
						
							|  |  |  |             def str_switch(b, sh=sh): | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |                 return f'(insn >> {sh}) & {b >> sh:#x}' | 
					
						
							| 
									
										
										
										
											2019-01-31 11:34:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             def str_case(b, sh=sh): | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |                 return hex(b >> sh) | 
					
						
							| 
									
										
										
										
											2019-01-31 11:34:11 -08:00
										 |  |  |         else: | 
					
						
							|  |  |  |             def str_switch(b): | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |                 return f'insn & {whexC(b)}' | 
					
						
							| 
									
										
										
										
											2019-01-31 11:34:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             def str_case(b): | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |                 return whexC(b) | 
					
						
							| 
									
										
										
										
											2019-01-31 11:34:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         output(ind, 'switch (', str_switch(self.mask), ') {\n') | 
					
						
							|  |  |  |         for b, s in sorted(self.subs): | 
					
						
							|  |  |  |             innermask = outermask | self.mask | 
					
						
							|  |  |  |             innerbits = outerbits | b | 
					
						
							|  |  |  |             output(ind, 'case ', str_case(b), ':\n') | 
					
						
							|  |  |  |             output(ind, '    /* ', | 
					
						
							|  |  |  |                    str_match_bits(innerbits, innermask), ' */\n') | 
					
						
							|  |  |  |             s.output_code(i + 4, extracted, innerbits, innermask) | 
					
						
							|  |  |  |         output(ind, '}\n') | 
					
						
							|  |  |  |         output(ind, 'return insn;\n') | 
					
						
							|  |  |  | # end SizeTree | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SizeLeaf: | 
					
						
							|  |  |  |     """Class representing a leaf node in a size decode tree""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, m, w): | 
					
						
							|  |  |  |         self.mask = m | 
					
						
							|  |  |  |         self.width = w | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def str1(self, i): | 
					
						
							| 
									
										
										
										
											2021-04-28 16:27:56 -07:00
										 |  |  |         return str_indent(i) + whex(self.mask) | 
					
						
							| 
									
										
										
										
											2019-01-31 11:34:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.str1(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def output_code(self, i, extracted, outerbits, outermask): | 
					
						
							|  |  |  |         global decode_function | 
					
						
							|  |  |  |         ind = str_indent(i) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # If we need to load more bytes, do so now. | 
					
						
							|  |  |  |         if extracted < self.width: | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |             output(ind, f'insn = {decode_function}_load_bytes', | 
					
						
							|  |  |  |                    f'(ctx, insn, {extracted // 8}, {self.width // 8});\n') | 
					
						
							| 
									
										
										
										
											2019-01-31 11:34:11 -08:00
										 |  |  |             extracted = self.width | 
					
						
							|  |  |  |         output(ind, 'return insn;\n') | 
					
						
							|  |  |  | # end SizeLeaf | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def build_size_tree(pats, width, outerbits, outermask): | 
					
						
							|  |  |  |     global insnwidth | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Collect the mask of bits that are fixed in this width | 
					
						
							|  |  |  |     innermask = 0xff << (insnwidth - width) | 
					
						
							|  |  |  |     innermask &= ~outermask | 
					
						
							|  |  |  |     minwidth = None | 
					
						
							|  |  |  |     onewidth = True | 
					
						
							|  |  |  |     for i in pats: | 
					
						
							|  |  |  |         innermask &= i.fixedmask | 
					
						
							|  |  |  |         if minwidth is None: | 
					
						
							|  |  |  |             minwidth = i.width | 
					
						
							|  |  |  |         elif minwidth != i.width: | 
					
						
							|  |  |  |             onewidth = False; | 
					
						
							|  |  |  |             if minwidth < i.width: | 
					
						
							|  |  |  |                 minwidth = i.width | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if onewidth: | 
					
						
							|  |  |  |         return SizeLeaf(innermask, minwidth) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if innermask == 0: | 
					
						
							|  |  |  |         if width < minwidth: | 
					
						
							|  |  |  |             return build_size_tree(pats, width + 8, outerbits, outermask) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         pnames = [] | 
					
						
							|  |  |  |         for p in pats: | 
					
						
							|  |  |  |             pnames.append(p.name + ':' + p.file + ':' + str(p.lineno)) | 
					
						
							|  |  |  |         error_with_file(pats[0].file, pats[0].lineno, | 
					
						
							| 
									
										
										
										
											2021-04-28 16:37:02 -07:00
										 |  |  |                         f'overlapping patterns size {width}:', pnames) | 
					
						
							| 
									
										
										
										
											2019-01-31 11:34:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     bins = {} | 
					
						
							|  |  |  |     for i in pats: | 
					
						
							|  |  |  |         fb = i.fixedbits & innermask | 
					
						
							|  |  |  |         if fb in bins: | 
					
						
							|  |  |  |             bins[fb].append(i) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             bins[fb] = [i] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fullmask = outermask | innermask | 
					
						
							|  |  |  |     lens = sorted(bins.keys()) | 
					
						
							|  |  |  |     if len(lens) == 1: | 
					
						
							|  |  |  |         b = lens[0] | 
					
						
							|  |  |  |         return build_size_tree(bins[b], width + 8, b | outerbits, fullmask) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     r = SizeTree(innermask, width) | 
					
						
							|  |  |  |     for b, l in bins.items(): | 
					
						
							|  |  |  |         s = build_size_tree(l, width, b | outerbits, fullmask) | 
					
						
							|  |  |  |         r.subs.append((b, s)) | 
					
						
							|  |  |  |     return r | 
					
						
							|  |  |  | # end build_size_tree | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def prop_size(tree): | 
					
						
							|  |  |  |     """Propagate minimum widths up the decode size tree""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if isinstance(tree, SizeTree): | 
					
						
							|  |  |  |         min = None | 
					
						
							|  |  |  |         for (b, s) in tree.subs: | 
					
						
							|  |  |  |             width = prop_size(s) | 
					
						
							|  |  |  |             if min is None or min > width: | 
					
						
							|  |  |  |                 min = width | 
					
						
							|  |  |  |         assert min >= tree.width | 
					
						
							|  |  |  |         tree.width = min | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         min = tree.width | 
					
						
							|  |  |  |     return min | 
					
						
							|  |  |  | # end prop_size | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | def main(): | 
					
						
							|  |  |  |     global arguments | 
					
						
							|  |  |  |     global formats | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |     global allpatterns | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     global translate_scope | 
					
						
							|  |  |  |     global translate_prefix | 
					
						
							|  |  |  |     global output_fd | 
					
						
							|  |  |  |     global output_file | 
					
						
							|  |  |  |     global input_file | 
					
						
							|  |  |  |     global insnwidth | 
					
						
							|  |  |  |     global insntype | 
					
						
							| 
									
										
										
										
											2018-03-19 12:58:46 +01:00
										 |  |  |     global insnmask | 
					
						
							| 
									
										
										
										
											2018-10-23 10:26:25 +01:00
										 |  |  |     global decode_function | 
					
						
							| 
									
										
										
										
											2021-04-07 22:18:49 +00:00
										 |  |  |     global bitop_width | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  |     global variablewidth | 
					
						
							| 
									
										
										
										
											2019-08-09 08:12:50 -07:00
										 |  |  |     global anyextern | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     decode_scope = 'static ' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-23 17:44:31 -08:00
										 |  |  |     long_opts = ['decode=', 'translate=', 'output=', 'insnwidth=', | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  |                  'static-decode=', 'varinsnwidth='] | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     try: | 
					
						
							| 
									
										
										
										
											2020-08-07 12:10:23 +02:00
										 |  |  |         (opts, args) = getopt.gnu_getopt(sys.argv[1:], 'o:vw:', long_opts) | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     except getopt.GetoptError as err: | 
					
						
							|  |  |  |         error(0, err) | 
					
						
							|  |  |  |     for o, a in opts: | 
					
						
							|  |  |  |         if o in ('-o', '--output'): | 
					
						
							|  |  |  |             output_file = a | 
					
						
							|  |  |  |         elif o == '--decode': | 
					
						
							|  |  |  |             decode_function = a | 
					
						
							|  |  |  |             decode_scope = '' | 
					
						
							| 
									
										
										
										
											2019-02-23 17:44:31 -08:00
										 |  |  |         elif o == '--static-decode': | 
					
						
							|  |  |  |             decode_function = a | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         elif o == '--translate': | 
					
						
							|  |  |  |             translate_prefix = a | 
					
						
							|  |  |  |             translate_scope = '' | 
					
						
							| 
									
										
										
										
											2019-01-30 18:01:29 -08:00
										 |  |  |         elif o in ('-w', '--insnwidth', '--varinsnwidth'): | 
					
						
							|  |  |  |             if o == '--varinsnwidth': | 
					
						
							|  |  |  |                 variablewidth = True | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             insnwidth = int(a) | 
					
						
							|  |  |  |             if insnwidth == 16: | 
					
						
							|  |  |  |                 insntype = 'uint16_t' | 
					
						
							|  |  |  |                 insnmask = 0xffff | 
					
						
							| 
									
										
										
										
											2021-04-07 22:18:49 +00:00
										 |  |  |             elif insnwidth == 64: | 
					
						
							|  |  |  |                 insntype = 'uint64_t' | 
					
						
							|  |  |  |                 insnmask = 0xffffffffffffffff | 
					
						
							|  |  |  |                 bitop_width = 64 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |             elif insnwidth != 32: | 
					
						
							|  |  |  |                 error(0, 'cannot handle insns of width', insnwidth) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             assert False, 'unhandled option' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if len(args) < 1: | 
					
						
							|  |  |  |         error(0, 'missing input file') | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     toppat = ExcMultiPattern(0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-26 14:59:43 +01:00
										 |  |  |     for filename in args: | 
					
						
							|  |  |  |         input_file = filename | 
					
						
							| 
									
										
											  
											
												decodetree: Open files with encoding='utf-8'
When decodetree.py was added in commit 568ae7efae7, QEMU was
using Python 2 which happily reads UTF-8 files in text mode.
Python 3 requires either UTF-8 locale or an explicit encoding
passed to open(). Now that Python 3 is required, explicit
UTF-8 encoding for decodetree source files.
To avoid further problems with the user locale, also explicit
UTF-8 encoding for the generated C files.
Explicit both input/output are plain text by using the 't' mode.
This fixes:
  $ /usr/bin/python3 scripts/decodetree.py test.decode
  Traceback (most recent call last):
    File "scripts/decodetree.py", line 1397, in <module>
      main()
    File "scripts/decodetree.py", line 1308, in main
      parse_file(f, toppat)
    File "scripts/decodetree.py", line 994, in parse_file
      for line in f:
    File "/usr/lib/python3.6/encodings/ascii.py", line 26, in decode
      return codecs.ascii_decode(input, self.errors)[0]
  UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 80:
  ordinal not in range(128)
Reported-by: Peter Maydell <peter.maydell@linaro.org>
Suggested-by: Yonggang Luo <luoyonggang@gmail.com>
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Message-Id: <20210110000240.761122-1-f4bug@amsat.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
											
										 
											2021-01-10 01:02:40 +01:00
										 |  |  |         f = open(filename, 'rt', encoding='utf-8') | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |         parse_file(f, toppat) | 
					
						
							| 
									
										
										
										
											2018-10-26 14:59:43 +01:00
										 |  |  |         f.close() | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |     # We do not want to compute masks for toppat, because those masks | 
					
						
							|  |  |  |     # are used as a starting point for build_tree.  For toppat, we must | 
					
						
							|  |  |  |     # insist that decode begins from naught. | 
					
						
							|  |  |  |     for i in toppat.pats: | 
					
						
							|  |  |  |         i.prop_masks() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     toppat.build_tree() | 
					
						
							|  |  |  |     toppat.prop_format() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 11:34:11 -08:00
										 |  |  |     if variablewidth: | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |         for i in toppat.pats: | 
					
						
							|  |  |  |             i.prop_width() | 
					
						
							|  |  |  |         stree = build_size_tree(toppat.pats, 8, 0, 0) | 
					
						
							| 
									
										
										
										
											2019-01-31 11:34:11 -08:00
										 |  |  |         prop_size(stree) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     if output_file: | 
					
						
							| 
									
										
											  
											
												decodetree: Open files with encoding='utf-8'
When decodetree.py was added in commit 568ae7efae7, QEMU was
using Python 2 which happily reads UTF-8 files in text mode.
Python 3 requires either UTF-8 locale or an explicit encoding
passed to open(). Now that Python 3 is required, explicit
UTF-8 encoding for decodetree source files.
To avoid further problems with the user locale, also explicit
UTF-8 encoding for the generated C files.
Explicit both input/output are plain text by using the 't' mode.
This fixes:
  $ /usr/bin/python3 scripts/decodetree.py test.decode
  Traceback (most recent call last):
    File "scripts/decodetree.py", line 1397, in <module>
      main()
    File "scripts/decodetree.py", line 1308, in main
      parse_file(f, toppat)
    File "scripts/decodetree.py", line 994, in parse_file
      for line in f:
    File "/usr/lib/python3.6/encodings/ascii.py", line 26, in decode
      return codecs.ascii_decode(input, self.errors)[0]
  UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 80:
  ordinal not in range(128)
Reported-by: Peter Maydell <peter.maydell@linaro.org>
Suggested-by: Yonggang Luo <luoyonggang@gmail.com>
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Message-Id: <20210110000240.761122-1-f4bug@amsat.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
											
										 
											2021-01-10 01:02:40 +01:00
										 |  |  |         output_fd = open(output_file, 'wt', encoding='utf-8') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     else: | 
					
						
							| 
									
										
											  
											
												decodetree: Open files with encoding='utf-8'
When decodetree.py was added in commit 568ae7efae7, QEMU was
using Python 2 which happily reads UTF-8 files in text mode.
Python 3 requires either UTF-8 locale or an explicit encoding
passed to open(). Now that Python 3 is required, explicit
UTF-8 encoding for decodetree source files.
To avoid further problems with the user locale, also explicit
UTF-8 encoding for the generated C files.
Explicit both input/output are plain text by using the 't' mode.
This fixes:
  $ /usr/bin/python3 scripts/decodetree.py test.decode
  Traceback (most recent call last):
    File "scripts/decodetree.py", line 1397, in <module>
      main()
    File "scripts/decodetree.py", line 1308, in main
      parse_file(f, toppat)
    File "scripts/decodetree.py", line 994, in parse_file
      for line in f:
    File "/usr/lib/python3.6/encodings/ascii.py", line 26, in decode
      return codecs.ascii_decode(input, self.errors)[0]
  UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 80:
  ordinal not in range(128)
Reported-by: Peter Maydell <peter.maydell@linaro.org>
Suggested-by: Yonggang Luo <luoyonggang@gmail.com>
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Message-Id: <20210110000240.761122-1-f4bug@amsat.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
											
										 
											2021-01-10 01:02:40 +01:00
										 |  |  |         output_fd = io.TextIOWrapper(sys.stdout.buffer, | 
					
						
							|  |  |  |                                      encoding=sys.stdout.encoding, | 
					
						
							|  |  |  |                                      errors="ignore") | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     output_autogen() | 
					
						
							|  |  |  |     for n in sorted(arguments.keys()): | 
					
						
							|  |  |  |         f = arguments[n] | 
					
						
							|  |  |  |         f.output_def() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # A single translate function can be invoked for different patterns. | 
					
						
							|  |  |  |     # Make sure that the argument sets are the same, and declare the | 
					
						
							|  |  |  |     # function only once. | 
					
						
							| 
									
										
										
										
											2019-08-09 08:12:50 -07:00
										 |  |  |     # | 
					
						
							|  |  |  |     # If we're sharing formats, we're likely also sharing trans_* functions, | 
					
						
							|  |  |  |     # but we can't tell which ones.  Prevent issues from the compiler by | 
					
						
							|  |  |  |     # suppressing redundant declaration warnings. | 
					
						
							|  |  |  |     if anyextern: | 
					
						
							| 
									
										
										
										
											2020-07-08 20:19:44 +02:00
										 |  |  |         output("#pragma GCC diagnostic push\n", | 
					
						
							|  |  |  |                "#pragma GCC diagnostic ignored \"-Wredundant-decls\"\n", | 
					
						
							|  |  |  |                "#ifdef __clang__\n" | 
					
						
							| 
									
										
										
										
											2019-08-09 08:12:50 -07:00
										 |  |  |                "#  pragma GCC diagnostic ignored \"-Wtypedef-redefinition\"\n", | 
					
						
							|  |  |  |                "#endif\n\n") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     out_pats = {} | 
					
						
							| 
									
										
										
										
											2019-02-23 11:35:36 -08:00
										 |  |  |     for i in allpatterns: | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |         if i.name in out_pats: | 
					
						
							|  |  |  |             p = out_pats[i.name] | 
					
						
							|  |  |  |             if i.base.base != p.base.base: | 
					
						
							|  |  |  |                 error(0, i.name, ' has conflicting argument sets') | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             i.output_decl() | 
					
						
							|  |  |  |             out_pats[i.name] = i | 
					
						
							|  |  |  |     output('\n') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-09 08:12:50 -07:00
										 |  |  |     if anyextern: | 
					
						
							| 
									
										
										
										
											2020-07-08 20:19:44 +02:00
										 |  |  |         output("#pragma GCC diagnostic pop\n\n") | 
					
						
							| 
									
										
										
										
											2019-08-09 08:12:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     for n in sorted(formats.keys()): | 
					
						
							|  |  |  |         f = formats[n] | 
					
						
							|  |  |  |         f.output_extract() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     output(decode_scope, 'bool ', decode_function, | 
					
						
							|  |  |  |            '(DisasContext *ctx, ', insntype, ' insn)\n{\n') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     i4 = str_indent(4) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-27 21:37:32 -08:00
										 |  |  |     if len(allpatterns) != 0: | 
					
						
							|  |  |  |         output(i4, 'union {\n') | 
					
						
							|  |  |  |         for n in sorted(arguments.keys()): | 
					
						
							|  |  |  |             f = arguments[n] | 
					
						
							|  |  |  |             output(i4, i4, f.struct_name(), ' f_', f.name, ';\n') | 
					
						
							|  |  |  |         output(i4, '} u;\n\n') | 
					
						
							| 
									
										
										
										
											2020-05-17 10:14:11 -07:00
										 |  |  |         toppat.output_code(4, False, 0, 0) | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-27 21:37:32 -08:00
										 |  |  |     output(i4, 'return false;\n') | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     output('}\n') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 11:34:11 -08:00
										 |  |  |     if variablewidth: | 
					
						
							|  |  |  |         output('\n', decode_scope, insntype, ' ', decode_function, | 
					
						
							|  |  |  |                '_load(DisasContext *ctx)\n{\n', | 
					
						
							|  |  |  |                '    ', insntype, ' insn = 0;\n\n') | 
					
						
							|  |  |  |         stree.output_code(4, 0, 0, 0) | 
					
						
							|  |  |  |         output('}\n') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 12:44:09 -08:00
										 |  |  |     if output_file: | 
					
						
							|  |  |  |         output_fd.close() | 
					
						
							|  |  |  | # end main | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     main() |