]> git.proxmox.com Git - mirror_qemu.git/blob - scripts/decodetree.py
decodetree: Initial support for variable-length ISAs
[mirror_qemu.git] / scripts / decodetree.py
1 #!/usr/bin/env python
2 # Copyright (c) 2018 Linaro Limited
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2 of the License, or (at your option) any later version.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 #
17
18 #
19 # Generate a decoding tree from a specification file.
20 # See the syntax and semantics in docs/devel/decodetree.rst.
21 #
22
23 import os
24 import re
25 import sys
26 import getopt
27
28 insnwidth = 32
29 insnmask = 0xffffffff
30 variablewidth = False
31 fields = {}
32 arguments = {}
33 formats = {}
34 patterns = []
35 allpatterns = []
36
37 translate_prefix = 'trans'
38 translate_scope = 'static '
39 input_file = ''
40 output_file = None
41 output_fd = None
42 insntype = 'uint32_t'
43 decode_function = 'decode'
44
45 re_ident = '[a-zA-Z][a-zA-Z0-9_]*'
46
47
48 def error_with_file(file, lineno, *args):
49 """Print an error message from file:line and args and exit."""
50 global output_file
51 global output_fd
52
53 if lineno:
54 r = '{0}:{1}: error:'.format(file, lineno)
55 elif input_file:
56 r = '{0}: error:'.format(file)
57 else:
58 r = 'error:'
59 for a in args:
60 r += ' ' + str(a)
61 r += '\n'
62 sys.stderr.write(r)
63 if output_file and output_fd:
64 output_fd.close()
65 os.remove(output_file)
66 exit(1)
67
68 def error(lineno, *args):
69 error_with_file(input_file, lineno, args)
70
71 def output(*args):
72 global output_fd
73 for a in args:
74 output_fd.write(a)
75
76
77 if sys.version_info >= (3, 4):
78 re_fullmatch = re.fullmatch
79 else:
80 def re_fullmatch(pat, str):
81 return re.match('^' + pat + '$', str)
82
83
84 def output_autogen():
85 output('/* This file is autogenerated by scripts/decodetree.py. */\n\n')
86
87
88 def str_indent(c):
89 """Return a string with C spaces"""
90 return ' ' * c
91
92
93 def str_fields(fields):
94 """Return a string uniquely identifing FIELDS"""
95 r = ''
96 for n in sorted(fields.keys()):
97 r += '_' + n
98 return r[1:]
99
100
101 def str_match_bits(bits, mask):
102 """Return a string pretty-printing BITS/MASK"""
103 global insnwidth
104
105 i = 1 << (insnwidth - 1)
106 space = 0x01010100
107 r = ''
108 while i != 0:
109 if i & mask:
110 if i & bits:
111 r += '1'
112 else:
113 r += '0'
114 else:
115 r += '.'
116 if i & space:
117 r += ' '
118 i >>= 1
119 return r
120
121
122 def is_pow2(x):
123 """Return true iff X is equal to a power of 2."""
124 return (x & (x - 1)) == 0
125
126
127 def ctz(x):
128 """Return the number of times 2 factors into X."""
129 r = 0
130 while ((x >> r) & 1) == 0:
131 r += 1
132 return r
133
134
135 def is_contiguous(bits):
136 shift = ctz(bits)
137 if is_pow2((bits >> shift) + 1):
138 return shift
139 else:
140 return -1
141
142
143 def eq_fields_for_args(flds_a, flds_b):
144 if len(flds_a) != len(flds_b):
145 return False
146 for k, a in flds_a.items():
147 if k not in flds_b:
148 return False
149 return True
150
151
152 def eq_fields_for_fmts(flds_a, flds_b):
153 if len(flds_a) != len(flds_b):
154 return False
155 for k, a in flds_a.items():
156 if k not in flds_b:
157 return False
158 b = flds_b[k]
159 if a.__class__ != b.__class__ or a != b:
160 return False
161 return True
162
163
164 class Field:
165 """Class representing a simple instruction field"""
166 def __init__(self, sign, pos, len):
167 self.sign = sign
168 self.pos = pos
169 self.len = len
170 self.mask = ((1 << len) - 1) << pos
171
172 def __str__(self):
173 if self.sign:
174 s = 's'
175 else:
176 s = ''
177 return str(self.pos) + ':' + s + str(self.len)
178
179 def str_extract(self):
180 if self.sign:
181 extr = 'sextract32'
182 else:
183 extr = 'extract32'
184 return '{0}(insn, {1}, {2})'.format(extr, self.pos, self.len)
185
186 def __eq__(self, other):
187 return self.sign == other.sign and self.sign == other.sign
188
189 def __ne__(self, other):
190 return not self.__eq__(other)
191 # end Field
192
193
194 class MultiField:
195 """Class representing a compound instruction field"""
196 def __init__(self, subs, mask):
197 self.subs = subs
198 self.sign = subs[0].sign
199 self.mask = mask
200
201 def __str__(self):
202 return str(self.subs)
203
204 def str_extract(self):
205 ret = '0'
206 pos = 0
207 for f in reversed(self.subs):
208 if pos == 0:
209 ret = f.str_extract()
210 else:
211 ret = 'deposit32({0}, {1}, {2}, {3})' \
212 .format(ret, pos, 32 - pos, f.str_extract())
213 pos += f.len
214 return ret
215
216 def __ne__(self, other):
217 if len(self.subs) != len(other.subs):
218 return True
219 for a, b in zip(self.subs, other.subs):
220 if a.__class__ != b.__class__ or a != b:
221 return True
222 return False
223
224 def __eq__(self, other):
225 return not self.__ne__(other)
226 # end MultiField
227
228
229 class ConstField:
230 """Class representing an argument field with constant value"""
231 def __init__(self, value):
232 self.value = value
233 self.mask = 0
234 self.sign = value < 0
235
236 def __str__(self):
237 return str(self.value)
238
239 def str_extract(self):
240 return str(self.value)
241
242 def __cmp__(self, other):
243 return self.value - other.value
244 # end ConstField
245
246
247 class FunctionField:
248 """Class representing a field passed through an expander"""
249 def __init__(self, func, base):
250 self.mask = base.mask
251 self.sign = base.sign
252 self.base = base
253 self.func = func
254
255 def __str__(self):
256 return self.func + '(' + str(self.base) + ')'
257
258 def str_extract(self):
259 return self.func + '(' + self.base.str_extract() + ')'
260
261 def __eq__(self, other):
262 return self.func == other.func and self.base == other.base
263
264 def __ne__(self, other):
265 return not self.__eq__(other)
266 # end FunctionField
267
268
269 class Arguments:
270 """Class representing the extracted fields of a format"""
271 def __init__(self, nm, flds, extern):
272 self.name = nm
273 self.extern = extern
274 self.fields = sorted(flds)
275
276 def __str__(self):
277 return self.name + ' ' + str(self.fields)
278
279 def struct_name(self):
280 return 'arg_' + self.name
281
282 def output_def(self):
283 if not self.extern:
284 output('typedef struct {\n')
285 for n in self.fields:
286 output(' int ', n, ';\n')
287 output('} ', self.struct_name(), ';\n\n')
288 # end Arguments
289
290
291 class General:
292 """Common code between instruction formats and instruction patterns"""
293 def __init__(self, name, lineno, base, fixb, fixm, udfm, fldm, flds, w):
294 self.name = name
295 self.file = input_file
296 self.lineno = lineno
297 self.base = base
298 self.fixedbits = fixb
299 self.fixedmask = fixm
300 self.undefmask = udfm
301 self.fieldmask = fldm
302 self.fields = flds
303 self.width = w
304
305 def __str__(self):
306 return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
307
308 def str1(self, i):
309 return str_indent(i) + self.__str__()
310 # end General
311
312
313 class Format(General):
314 """Class representing an instruction format"""
315
316 def extract_name(self):
317 global decode_function
318 return decode_function + '_extract_' + self.name
319
320 def output_extract(self):
321 output('static void ', self.extract_name(), '(',
322 self.base.struct_name(), ' *a, ', insntype, ' insn)\n{\n')
323 for n, f in self.fields.items():
324 output(' a->', n, ' = ', f.str_extract(), ';\n')
325 output('}\n\n')
326 # end Format
327
328
329 class Pattern(General):
330 """Class representing an instruction pattern"""
331
332 def output_decl(self):
333 global translate_scope
334 global translate_prefix
335 output('typedef ', self.base.base.struct_name(),
336 ' arg_', self.name, ';\n')
337 output(translate_scope, 'bool ', translate_prefix, '_', self.name,
338 '(DisasContext *ctx, arg_', self.name, ' *a);\n')
339
340 def output_code(self, i, extracted, outerbits, outermask):
341 global translate_prefix
342 ind = str_indent(i)
343 arg = self.base.base.name
344 output(ind, '/* ', self.file, ':', str(self.lineno), ' */\n')
345 if not extracted:
346 output(ind, self.base.extract_name(), '(&u.f_', arg, ', insn);\n')
347 for n, f in self.fields.items():
348 output(ind, 'u.f_', arg, '.', n, ' = ', f.str_extract(), ';\n')
349 output(ind, 'if (', translate_prefix, '_', self.name,
350 '(ctx, &u.f_', arg, ')) return true;\n')
351 # end Pattern
352
353
354 class MultiPattern(General):
355 """Class representing an overlapping set of instruction patterns"""
356
357 def __init__(self, lineno, pats, fixb, fixm, udfm, w):
358 self.file = input_file
359 self.lineno = lineno
360 self.pats = pats
361 self.base = None
362 self.fixedbits = fixb
363 self.fixedmask = fixm
364 self.undefmask = udfm
365 self.width = w
366
367 def __str__(self):
368 r = "{"
369 for p in self.pats:
370 r = r + ' ' + str(p)
371 return r + "}"
372
373 def output_decl(self):
374 for p in self.pats:
375 p.output_decl()
376
377 def output_code(self, i, extracted, outerbits, outermask):
378 global translate_prefix
379 ind = str_indent(i)
380 for p in self.pats:
381 if outermask != p.fixedmask:
382 innermask = p.fixedmask & ~outermask
383 innerbits = p.fixedbits & ~outermask
384 output(ind, 'if ((insn & ',
385 '0x{0:08x}) == 0x{1:08x}'.format(innermask, innerbits),
386 ') {\n')
387 output(ind, ' /* ',
388 str_match_bits(p.fixedbits, p.fixedmask), ' */\n')
389 p.output_code(i + 4, extracted, p.fixedbits, p.fixedmask)
390 output(ind, '}\n')
391 else:
392 p.output_code(i, extracted, p.fixedbits, p.fixedmask)
393 #end MultiPattern
394
395
396 def parse_field(lineno, name, toks):
397 """Parse one instruction field from TOKS at LINENO"""
398 global fields
399 global re_ident
400 global insnwidth
401
402 # A "simple" field will have only one entry;
403 # a "multifield" will have several.
404 subs = []
405 width = 0
406 func = None
407 for t in toks:
408 if re_fullmatch('!function=' + re_ident, t):
409 if func:
410 error(lineno, 'duplicate function')
411 func = t.split('=')
412 func = func[1]
413 continue
414
415 if re_fullmatch('[0-9]+:s[0-9]+', t):
416 # Signed field extract
417 subtoks = t.split(':s')
418 sign = True
419 elif re_fullmatch('[0-9]+:[0-9]+', t):
420 # Unsigned field extract
421 subtoks = t.split(':')
422 sign = False
423 else:
424 error(lineno, 'invalid field token "{0}"'.format(t))
425 po = int(subtoks[0])
426 le = int(subtoks[1])
427 if po + le > insnwidth:
428 error(lineno, 'field {0} too large'.format(t))
429 f = Field(sign, po, le)
430 subs.append(f)
431 width += le
432
433 if width > insnwidth:
434 error(lineno, 'field too large')
435 if len(subs) == 1:
436 f = subs[0]
437 else:
438 mask = 0
439 for s in subs:
440 if mask & s.mask:
441 error(lineno, 'field components overlap')
442 mask |= s.mask
443 f = MultiField(subs, mask)
444 if func:
445 f = FunctionField(func, f)
446
447 if name in fields:
448 error(lineno, 'duplicate field', name)
449 fields[name] = f
450 # end parse_field
451
452
453 def parse_arguments(lineno, name, toks):
454 """Parse one argument set from TOKS at LINENO"""
455 global arguments
456 global re_ident
457
458 flds = []
459 extern = False
460 for t in toks:
461 if re_fullmatch('!extern', t):
462 extern = True
463 continue
464 if not re_fullmatch(re_ident, t):
465 error(lineno, 'invalid argument set token "{0}"'.format(t))
466 if t in flds:
467 error(lineno, 'duplicate argument "{0}"'.format(t))
468 flds.append(t)
469
470 if name in arguments:
471 error(lineno, 'duplicate argument set', name)
472 arguments[name] = Arguments(name, flds, extern)
473 # end parse_arguments
474
475
476 def lookup_field(lineno, name):
477 global fields
478 if name in fields:
479 return fields[name]
480 error(lineno, 'undefined field', name)
481
482
483 def add_field(lineno, flds, new_name, f):
484 if new_name in flds:
485 error(lineno, 'duplicate field', new_name)
486 flds[new_name] = f
487 return flds
488
489
490 def add_field_byname(lineno, flds, new_name, old_name):
491 return add_field(lineno, flds, new_name, lookup_field(lineno, old_name))
492
493
494 def infer_argument_set(flds):
495 global arguments
496 global decode_function
497
498 for arg in arguments.values():
499 if eq_fields_for_args(flds, arg.fields):
500 return arg
501
502 name = decode_function + str(len(arguments))
503 arg = Arguments(name, flds.keys(), False)
504 arguments[name] = arg
505 return arg
506
507
508 def infer_format(arg, fieldmask, flds, width):
509 global arguments
510 global formats
511 global decode_function
512
513 const_flds = {}
514 var_flds = {}
515 for n, c in flds.items():
516 if c is ConstField:
517 const_flds[n] = c
518 else:
519 var_flds[n] = c
520
521 # Look for an existing format with the same argument set and fields
522 for fmt in formats.values():
523 if arg and fmt.base != arg:
524 continue
525 if fieldmask != fmt.fieldmask:
526 continue
527 if width != fmt.width:
528 continue
529 if not eq_fields_for_fmts(flds, fmt.fields):
530 continue
531 return (fmt, const_flds)
532
533 name = decode_function + '_Fmt_' + str(len(formats))
534 if not arg:
535 arg = infer_argument_set(flds)
536
537 fmt = Format(name, 0, arg, 0, 0, 0, fieldmask, var_flds, width)
538 formats[name] = fmt
539
540 return (fmt, const_flds)
541 # end infer_format
542
543
544 def parse_generic(lineno, is_format, name, toks):
545 """Parse one instruction format from TOKS at LINENO"""
546 global fields
547 global arguments
548 global formats
549 global patterns
550 global allpatterns
551 global re_ident
552 global insnwidth
553 global insnmask
554 global variablewidth
555
556 fixedmask = 0
557 fixedbits = 0
558 undefmask = 0
559 width = 0
560 flds = {}
561 arg = None
562 fmt = None
563 for t in toks:
564 # '&Foo' gives a format an explcit argument set.
565 if t[0] == '&':
566 tt = t[1:]
567 if arg:
568 error(lineno, 'multiple argument sets')
569 if tt in arguments:
570 arg = arguments[tt]
571 else:
572 error(lineno, 'undefined argument set', t)
573 continue
574
575 # '@Foo' gives a pattern an explicit format.
576 if t[0] == '@':
577 tt = t[1:]
578 if fmt:
579 error(lineno, 'multiple formats')
580 if tt in formats:
581 fmt = formats[tt]
582 else:
583 error(lineno, 'undefined format', t)
584 continue
585
586 # '%Foo' imports a field.
587 if t[0] == '%':
588 tt = t[1:]
589 flds = add_field_byname(lineno, flds, tt, tt)
590 continue
591
592 # 'Foo=%Bar' imports a field with a different name.
593 if re_fullmatch(re_ident + '=%' + re_ident, t):
594 (fname, iname) = t.split('=%')
595 flds = add_field_byname(lineno, flds, fname, iname)
596 continue
597
598 # 'Foo=number' sets an argument field to a constant value
599 if re_fullmatch(re_ident + '=[+-]?[0-9]+', t):
600 (fname, value) = t.split('=')
601 value = int(value)
602 flds = add_field(lineno, flds, fname, ConstField(value))
603 continue
604
605 # Pattern of 0s, 1s, dots and dashes indicate required zeros,
606 # required ones, or dont-cares.
607 if re_fullmatch('[01.-]+', t):
608 shift = len(t)
609 fms = t.replace('0', '1')
610 fms = fms.replace('.', '0')
611 fms = fms.replace('-', '0')
612 fbs = t.replace('.', '0')
613 fbs = fbs.replace('-', '0')
614 ubm = t.replace('1', '0')
615 ubm = ubm.replace('.', '0')
616 ubm = ubm.replace('-', '1')
617 fms = int(fms, 2)
618 fbs = int(fbs, 2)
619 ubm = int(ubm, 2)
620 fixedbits = (fixedbits << shift) | fbs
621 fixedmask = (fixedmask << shift) | fms
622 undefmask = (undefmask << shift) | ubm
623 # Otherwise, fieldname:fieldwidth
624 elif re_fullmatch(re_ident + ':s?[0-9]+', t):
625 (fname, flen) = t.split(':')
626 sign = False
627 if flen[0] == 's':
628 sign = True
629 flen = flen[1:]
630 shift = int(flen, 10)
631 if shift + width > insnwidth:
632 error(lineno, 'field {0} exceeds insnwidth'.format(fname))
633 f = Field(sign, insnwidth - width - shift, shift)
634 flds = add_field(lineno, flds, fname, f)
635 fixedbits <<= shift
636 fixedmask <<= shift
637 undefmask <<= shift
638 else:
639 error(lineno, 'invalid token "{0}"'.format(t))
640 width += shift
641
642 if variablewidth and width < insnwidth and width % 8 == 0:
643 shift = insnwidth - width
644 fixedbits <<= shift
645 fixedmask <<= shift
646 undefmask <<= shift
647 undefmask |= (1 << shift) - 1
648
649 # We should have filled in all of the bits of the instruction.
650 elif not (is_format and width == 0) and width != insnwidth:
651 error(lineno, 'definition has {0} bits'.format(width))
652
653 # Do not check for fields overlaping fields; one valid usage
654 # is to be able to duplicate fields via import.
655 fieldmask = 0
656 for f in flds.values():
657 fieldmask |= f.mask
658
659 # Fix up what we've parsed to match either a format or a pattern.
660 if is_format:
661 # Formats cannot reference formats.
662 if fmt:
663 error(lineno, 'format referencing format')
664 # If an argument set is given, then there should be no fields
665 # without a place to store it.
666 if arg:
667 for f in flds.keys():
668 if f not in arg.fields:
669 error(lineno, 'field {0} not in argument set {1}'
670 .format(f, arg.name))
671 else:
672 arg = infer_argument_set(flds)
673 if name in formats:
674 error(lineno, 'duplicate format name', name)
675 fmt = Format(name, lineno, arg, fixedbits, fixedmask,
676 undefmask, fieldmask, flds, width)
677 formats[name] = fmt
678 else:
679 # Patterns can reference a format ...
680 if fmt:
681 # ... but not an argument simultaneously
682 if arg:
683 error(lineno, 'pattern specifies both format and argument set')
684 if fixedmask & fmt.fixedmask:
685 error(lineno, 'pattern fixed bits overlap format fixed bits')
686 if width != fmt.width:
687 error(lineno, 'pattern uses format of different width')
688 fieldmask |= fmt.fieldmask
689 fixedbits |= fmt.fixedbits
690 fixedmask |= fmt.fixedmask
691 undefmask |= fmt.undefmask
692 else:
693 (fmt, flds) = infer_format(arg, fieldmask, flds, width)
694 arg = fmt.base
695 for f in flds.keys():
696 if f not in arg.fields:
697 error(lineno, 'field {0} not in argument set {1}'
698 .format(f, arg.name))
699 if f in fmt.fields.keys():
700 error(lineno, 'field {0} set by format and pattern'.format(f))
701 for f in arg.fields:
702 if f not in flds.keys() and f not in fmt.fields.keys():
703 error(lineno, 'field {0} not initialized'.format(f))
704 pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
705 undefmask, fieldmask, flds, width)
706 patterns.append(pat)
707 allpatterns.append(pat)
708
709 # Validate the masks that we have assembled.
710 if fieldmask & fixedmask:
711 error(lineno, 'fieldmask overlaps fixedmask (0x{0:08x} & 0x{1:08x})'
712 .format(fieldmask, fixedmask))
713 if fieldmask & undefmask:
714 error(lineno, 'fieldmask overlaps undefmask (0x{0:08x} & 0x{1:08x})'
715 .format(fieldmask, undefmask))
716 if fixedmask & undefmask:
717 error(lineno, 'fixedmask overlaps undefmask (0x{0:08x} & 0x{1:08x})'
718 .format(fixedmask, undefmask))
719 if not is_format:
720 allbits = fieldmask | fixedmask | undefmask
721 if allbits != insnmask:
722 error(lineno, 'bits left unspecified (0x{0:08x})'
723 .format(allbits ^ insnmask))
724 # end parse_general
725
726 def build_multi_pattern(lineno, pats):
727 """Validate the Patterns going into a MultiPattern."""
728 global patterns
729 global insnmask
730
731 if len(pats) < 2:
732 error(lineno, 'less than two patterns within braces')
733
734 fixedmask = insnmask
735 undefmask = insnmask
736
737 # Collect fixed/undefmask for all of the children.
738 # Move the defining lineno back to that of the first child.
739 for p in pats:
740 fixedmask &= p.fixedmask
741 undefmask &= p.undefmask
742 if p.lineno < lineno:
743 lineno = p.lineno
744
745 width = None
746 for p in pats:
747 if width is None:
748 width = p.width
749 elif width != p.width:
750 error(lineno, 'width mismatch in patterns within braces')
751
752 repeat = True
753 while repeat:
754 if fixedmask == 0:
755 error(lineno, 'no overlap in patterns within braces')
756 fixedbits = None
757 for p in pats:
758 thisbits = p.fixedbits & fixedmask
759 if fixedbits is None:
760 fixedbits = thisbits
761 elif fixedbits != thisbits:
762 fixedmask &= ~(fixedbits ^ thisbits)
763 break
764 else:
765 repeat = False
766
767 mp = MultiPattern(lineno, pats, fixedbits, fixedmask, undefmask, width)
768 patterns.append(mp)
769 # end build_multi_pattern
770
771 def parse_file(f):
772 """Parse all of the patterns within a file"""
773
774 global patterns
775
776 # Read all of the lines of the file. Concatenate lines
777 # ending in backslash; discard empty lines and comments.
778 toks = []
779 lineno = 0
780 nesting = 0
781 saved_pats = []
782
783 for line in f:
784 lineno += 1
785
786 # Expand and strip spaces, to find indent.
787 line = line.rstrip()
788 line = line.expandtabs()
789 len1 = len(line)
790 line = line.lstrip()
791 len2 = len(line)
792
793 # Discard comments
794 end = line.find('#')
795 if end >= 0:
796 line = line[:end]
797
798 t = line.split()
799 if len(toks) != 0:
800 # Next line after continuation
801 toks.extend(t)
802 else:
803 # Allow completely blank lines.
804 if len1 == 0:
805 continue
806 indent = len1 - len2
807 # Empty line due to comment.
808 if len(t) == 0:
809 # Indentation must be correct, even for comment lines.
810 if indent != nesting:
811 error(lineno, 'indentation ', indent, ' != ', nesting)
812 continue
813 start_lineno = lineno
814 toks = t
815
816 # Continuation?
817 if toks[-1] == '\\':
818 toks.pop()
819 continue
820
821 name = toks[0]
822 del toks[0]
823
824 # End nesting?
825 if name == '}':
826 if nesting == 0:
827 error(start_lineno, 'mismatched close brace')
828 if len(toks) != 0:
829 error(start_lineno, 'extra tokens after close brace')
830 nesting -= 2
831 if indent != nesting:
832 error(start_lineno, 'indentation ', indent, ' != ', nesting)
833 pats = patterns
834 patterns = saved_pats.pop()
835 build_multi_pattern(lineno, pats)
836 toks = []
837 continue
838
839 # Everything else should have current indentation.
840 if indent != nesting:
841 error(start_lineno, 'indentation ', indent, ' != ', nesting)
842
843 # Start nesting?
844 if name == '{':
845 if len(toks) != 0:
846 error(start_lineno, 'extra tokens after open brace')
847 saved_pats.append(patterns)
848 patterns = []
849 nesting += 2
850 toks = []
851 continue
852
853 # Determine the type of object needing to be parsed.
854 if name[0] == '%':
855 parse_field(start_lineno, name[1:], toks)
856 elif name[0] == '&':
857 parse_arguments(start_lineno, name[1:], toks)
858 elif name[0] == '@':
859 parse_generic(start_lineno, True, name[1:], toks)
860 else:
861 parse_generic(start_lineno, False, name, toks)
862 toks = []
863 # end parse_file
864
865
866 class Tree:
867 """Class representing a node in a decode tree"""
868
869 def __init__(self, fm, tm):
870 self.fixedmask = fm
871 self.thismask = tm
872 self.subs = []
873 self.base = None
874
875 def str1(self, i):
876 ind = str_indent(i)
877 r = '{0}{1:08x}'.format(ind, self.fixedmask)
878 if self.format:
879 r += ' ' + self.format.name
880 r += ' [\n'
881 for (b, s) in self.subs:
882 r += '{0} {1:08x}:\n'.format(ind, b)
883 r += s.str1(i + 4) + '\n'
884 r += ind + ']'
885 return r
886
887 def __str__(self):
888 return self.str1(0)
889
890 def output_code(self, i, extracted, outerbits, outermask):
891 ind = str_indent(i)
892
893 # If we identified all nodes below have the same format,
894 # extract the fields now.
895 if not extracted and self.base:
896 output(ind, self.base.extract_name(),
897 '(&u.f_', self.base.base.name, ', insn);\n')
898 extracted = True
899
900 # Attempt to aid the compiler in producing compact switch statements.
901 # If the bits in the mask are contiguous, extract them.
902 sh = is_contiguous(self.thismask)
903 if sh > 0:
904 # Propagate SH down into the local functions.
905 def str_switch(b, sh=sh):
906 return '(insn >> {0}) & 0x{1:x}'.format(sh, b >> sh)
907
908 def str_case(b, sh=sh):
909 return '0x{0:x}'.format(b >> sh)
910 else:
911 def str_switch(b):
912 return 'insn & 0x{0:08x}'.format(b)
913
914 def str_case(b):
915 return '0x{0:08x}'.format(b)
916
917 output(ind, 'switch (', str_switch(self.thismask), ') {\n')
918 for b, s in sorted(self.subs):
919 assert (self.thismask & ~s.fixedmask) == 0
920 innermask = outermask | self.thismask
921 innerbits = outerbits | b
922 output(ind, 'case ', str_case(b), ':\n')
923 output(ind, ' /* ',
924 str_match_bits(innerbits, innermask), ' */\n')
925 s.output_code(i + 4, extracted, innerbits, innermask)
926 output(ind, ' return false;\n')
927 output(ind, '}\n')
928 # end Tree
929
930
931 def build_tree(pats, outerbits, outermask):
932 # Find the intersection of all remaining fixedmask.
933 innermask = ~outermask & insnmask
934 for i in pats:
935 innermask &= i.fixedmask
936
937 if innermask == 0:
938 text = 'overlapping patterns:'
939 for p in pats:
940 text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
941 error_with_file(pats[0].file, pats[0].lineno, text)
942
943 fullmask = outermask | innermask
944
945 # Sort each element of pats into the bin selected by the mask.
946 bins = {}
947 for i in pats:
948 fb = i.fixedbits & innermask
949 if fb in bins:
950 bins[fb].append(i)
951 else:
952 bins[fb] = [i]
953
954 # We must recurse if any bin has more than one element or if
955 # the single element in the bin has not been fully matched.
956 t = Tree(fullmask, innermask)
957
958 for b, l in bins.items():
959 s = l[0]
960 if len(l) > 1 or s.fixedmask & ~fullmask != 0:
961 s = build_tree(l, b | outerbits, fullmask)
962 t.subs.append((b, s))
963
964 return t
965 # end build_tree
966
967
968 def prop_format(tree):
969 """Propagate Format objects into the decode tree"""
970
971 # Depth first search.
972 for (b, s) in tree.subs:
973 if isinstance(s, Tree):
974 prop_format(s)
975
976 # If all entries in SUBS have the same format, then
977 # propagate that into the tree.
978 f = None
979 for (b, s) in tree.subs:
980 if f is None:
981 f = s.base
982 if f is None:
983 return
984 if f is not s.base:
985 return
986 tree.base = f
987 # end prop_format
988
989
990 def main():
991 global arguments
992 global formats
993 global patterns
994 global allpatterns
995 global translate_scope
996 global translate_prefix
997 global output_fd
998 global output_file
999 global input_file
1000 global insnwidth
1001 global insntype
1002 global insnmask
1003 global decode_function
1004 global variablewidth
1005
1006 decode_scope = 'static '
1007
1008 long_opts = ['decode=', 'translate=', 'output=', 'insnwidth=',
1009 'static-decode=', 'varinsnwidth=']
1010 try:
1011 (opts, args) = getopt.getopt(sys.argv[1:], 'o:vw:', long_opts)
1012 except getopt.GetoptError as err:
1013 error(0, err)
1014 for o, a in opts:
1015 if o in ('-o', '--output'):
1016 output_file = a
1017 elif o == '--decode':
1018 decode_function = a
1019 decode_scope = ''
1020 elif o == '--static-decode':
1021 decode_function = a
1022 elif o == '--translate':
1023 translate_prefix = a
1024 translate_scope = ''
1025 elif o in ('-w', '--insnwidth', '--varinsnwidth'):
1026 if o == '--varinsnwidth':
1027 variablewidth = True
1028 insnwidth = int(a)
1029 if insnwidth == 16:
1030 insntype = 'uint16_t'
1031 insnmask = 0xffff
1032 elif insnwidth != 32:
1033 error(0, 'cannot handle insns of width', insnwidth)
1034 else:
1035 assert False, 'unhandled option'
1036
1037 if len(args) < 1:
1038 error(0, 'missing input file')
1039 for filename in args:
1040 input_file = filename
1041 f = open(filename, 'r')
1042 parse_file(f)
1043 f.close()
1044
1045 t = build_tree(patterns, 0, 0)
1046 prop_format(t)
1047
1048 if output_file:
1049 output_fd = open(output_file, 'w')
1050 else:
1051 output_fd = sys.stdout
1052
1053 output_autogen()
1054 for n in sorted(arguments.keys()):
1055 f = arguments[n]
1056 f.output_def()
1057
1058 # A single translate function can be invoked for different patterns.
1059 # Make sure that the argument sets are the same, and declare the
1060 # function only once.
1061 out_pats = {}
1062 for i in allpatterns:
1063 if i.name in out_pats:
1064 p = out_pats[i.name]
1065 if i.base.base != p.base.base:
1066 error(0, i.name, ' has conflicting argument sets')
1067 else:
1068 i.output_decl()
1069 out_pats[i.name] = i
1070 output('\n')
1071
1072 for n in sorted(formats.keys()):
1073 f = formats[n]
1074 f.output_extract()
1075
1076 output(decode_scope, 'bool ', decode_function,
1077 '(DisasContext *ctx, ', insntype, ' insn)\n{\n')
1078
1079 i4 = str_indent(4)
1080
1081 if len(allpatterns) != 0:
1082 output(i4, 'union {\n')
1083 for n in sorted(arguments.keys()):
1084 f = arguments[n]
1085 output(i4, i4, f.struct_name(), ' f_', f.name, ';\n')
1086 output(i4, '} u;\n\n')
1087 t.output_code(4, False, 0, 0)
1088
1089 output(i4, 'return false;\n')
1090 output('}\n')
1091
1092 if output_file:
1093 output_fd.close()
1094 # end main
1095
1096
1097 if __name__ == '__main__':
1098 main()