xref: /openbmc/qemu/scripts/decodetree.py (revision f7160f32)
1#!/usr/bin/env python3
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
23import os
24import re
25import sys
26import getopt
27
28insnwidth = 32
29insnmask = 0xffffffff
30variablewidth = False
31fields = {}
32arguments = {}
33formats = {}
34allpatterns = []
35anyextern = False
36
37translate_prefix = 'trans'
38translate_scope = 'static '
39input_file = ''
40output_file = None
41output_fd = None
42insntype = 'uint32_t'
43decode_function = 'decode'
44
45re_ident = '[a-zA-Z][a-zA-Z0-9_]*'
46
47
48def 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    prefix = ''
54    if file:
55        prefix += '{0}:'.format(file)
56    if lineno:
57        prefix += '{0}:'.format(lineno)
58    if prefix:
59        prefix += ' '
60    print(prefix, end='error: ', file=sys.stderr)
61    print(*args, file=sys.stderr)
62
63    if output_file and output_fd:
64        output_fd.close()
65        os.remove(output_file)
66    exit(1)
67# end error_with_file
68
69
70def error(lineno, *args):
71    error_with_file(input_file, lineno, *args)
72# end error
73
74
75def output(*args):
76    global output_fd
77    for a in args:
78        output_fd.write(a)
79
80
81def output_autogen():
82    output('/* This file is autogenerated by scripts/decodetree.py.  */\n\n')
83
84
85def str_indent(c):
86    """Return a string with C spaces"""
87    return ' ' * c
88
89
90def str_fields(fields):
91    """Return a string uniquely identifing FIELDS"""
92    r = ''
93    for n in sorted(fields.keys()):
94        r += '_' + n
95    return r[1:]
96
97
98def str_match_bits(bits, mask):
99    """Return a string pretty-printing BITS/MASK"""
100    global insnwidth
101
102    i = 1 << (insnwidth - 1)
103    space = 0x01010100
104    r = ''
105    while i != 0:
106        if i & mask:
107            if i & bits:
108                r += '1'
109            else:
110                r += '0'
111        else:
112            r += '.'
113        if i & space:
114            r += ' '
115        i >>= 1
116    return r
117
118
119def is_pow2(x):
120    """Return true iff X is equal to a power of 2."""
121    return (x & (x - 1)) == 0
122
123
124def ctz(x):
125    """Return the number of times 2 factors into X."""
126    assert x != 0
127    r = 0
128    while ((x >> r) & 1) == 0:
129        r += 1
130    return r
131
132
133def is_contiguous(bits):
134    if bits == 0:
135        return -1
136    shift = ctz(bits)
137    if is_pow2((bits >> shift) + 1):
138        return shift
139    else:
140        return -1
141
142
143def 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
152def 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
164class 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.mask == other.mask
188
189    def __ne__(self, other):
190        return not self.__eq__(other)
191# end Field
192
193
194class 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
229class 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
247class FunctionField:
248    """Class representing a field passed through a function"""
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 + '(ctx, ' + 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
269class ParameterField:
270    """Class representing a pseudo-field read from a function"""
271    def __init__(self, func):
272        self.mask = 0
273        self.sign = 0
274        self.func = func
275
276    def __str__(self):
277        return self.func
278
279    def str_extract(self):
280        return self.func + '(ctx)'
281
282    def __eq__(self, other):
283        return self.func == other.func
284
285    def __ne__(self, other):
286        return not self.__eq__(other)
287# end ParameterField
288
289
290class Arguments:
291    """Class representing the extracted fields of a format"""
292    def __init__(self, nm, flds, extern):
293        self.name = nm
294        self.extern = extern
295        self.fields = sorted(flds)
296
297    def __str__(self):
298        return self.name + ' ' + str(self.fields)
299
300    def struct_name(self):
301        return 'arg_' + self.name
302
303    def output_def(self):
304        if not self.extern:
305            output('typedef struct {\n')
306            for n in self.fields:
307                output('    int ', n, ';\n')
308            output('} ', self.struct_name(), ';\n\n')
309# end Arguments
310
311
312class General:
313    """Common code between instruction formats and instruction patterns"""
314    def __init__(self, name, lineno, base, fixb, fixm, udfm, fldm, flds, w):
315        self.name = name
316        self.file = input_file
317        self.lineno = lineno
318        self.base = base
319        self.fixedbits = fixb
320        self.fixedmask = fixm
321        self.undefmask = udfm
322        self.fieldmask = fldm
323        self.fields = flds
324        self.width = w
325
326    def __str__(self):
327        return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
328
329    def str1(self, i):
330        return str_indent(i) + self.__str__()
331# end General
332
333
334class Format(General):
335    """Class representing an instruction format"""
336
337    def extract_name(self):
338        global decode_function
339        return decode_function + '_extract_' + self.name
340
341    def output_extract(self):
342        output('static void ', self.extract_name(), '(DisasContext *ctx, ',
343               self.base.struct_name(), ' *a, ', insntype, ' insn)\n{\n')
344        for n, f in self.fields.items():
345            output('    a->', n, ' = ', f.str_extract(), ';\n')
346        output('}\n\n')
347# end Format
348
349
350class Pattern(General):
351    """Class representing an instruction pattern"""
352
353    def output_decl(self):
354        global translate_scope
355        global translate_prefix
356        output('typedef ', self.base.base.struct_name(),
357               ' arg_', self.name, ';\n')
358        output(translate_scope, 'bool ', translate_prefix, '_', self.name,
359               '(DisasContext *ctx, arg_', self.name, ' *a);\n')
360
361    def output_code(self, i, extracted, outerbits, outermask):
362        global translate_prefix
363        ind = str_indent(i)
364        arg = self.base.base.name
365        output(ind, '/* ', self.file, ':', str(self.lineno), ' */\n')
366        if not extracted:
367            output(ind, self.base.extract_name(),
368                   '(ctx, &u.f_', arg, ', insn);\n')
369        for n, f in self.fields.items():
370            output(ind, 'u.f_', arg, '.', n, ' = ', f.str_extract(), ';\n')
371        output(ind, 'if (', translate_prefix, '_', self.name,
372               '(ctx, &u.f_', arg, ')) return true;\n')
373
374    # Normal patterns do not have children.
375    def build_tree(self):
376        return
377    def prop_masks(self):
378        return
379    def prop_format(self):
380        return
381    def prop_width(self):
382        return
383
384# end Pattern
385
386
387class MultiPattern(General):
388    """Class representing a set of instruction patterns"""
389
390    def __init__(self, lineno):
391        self.file = input_file
392        self.lineno = lineno
393        self.pats = []
394        self.base = None
395        self.fixedbits = 0
396        self.fixedmask = 0
397        self.undefmask = 0
398        self.width = None
399
400    def __str__(self):
401        r = 'group'
402        if self.fixedbits is not None:
403            r += ' ' + str_match_bits(self.fixedbits, self.fixedmask)
404        return r
405
406    def output_decl(self):
407        for p in self.pats:
408            p.output_decl()
409
410    def prop_masks(self):
411        global insnmask
412
413        fixedmask = insnmask
414        undefmask = insnmask
415
416        # Collect fixedmask/undefmask for all of the children.
417        for p in self.pats:
418            p.prop_masks()
419            fixedmask &= p.fixedmask
420            undefmask &= p.undefmask
421
422        # Widen fixedmask until all fixedbits match
423        repeat = True
424        fixedbits = 0
425        while repeat and fixedmask != 0:
426            fixedbits = None
427            for p in self.pats:
428                thisbits = p.fixedbits & fixedmask
429                if fixedbits is None:
430                    fixedbits = thisbits
431                elif fixedbits != thisbits:
432                    fixedmask &= ~(fixedbits ^ thisbits)
433                    break
434            else:
435                repeat = False
436
437        self.fixedbits = fixedbits
438        self.fixedmask = fixedmask
439        self.undefmask = undefmask
440
441    def build_tree(self):
442        for p in self.pats:
443            p.build_tree()
444
445    def prop_format(self):
446        for p in self.pats:
447            p.build_tree()
448
449    def prop_width(self):
450        width = None
451        for p in self.pats:
452            p.prop_width()
453            if width is None:
454                width = p.width
455            elif width != p.width:
456                error_with_file(self.file, self.lineno,
457                                'width mismatch in patterns within braces')
458        self.width = width
459
460# end MultiPattern
461
462
463class IncMultiPattern(MultiPattern):
464    """Class representing an overlapping set of instruction patterns"""
465
466    def output_code(self, i, extracted, outerbits, outermask):
467        global translate_prefix
468        ind = str_indent(i)
469        for p in self.pats:
470            if outermask != p.fixedmask:
471                innermask = p.fixedmask & ~outermask
472                innerbits = p.fixedbits & ~outermask
473                output(ind, 'if ((insn & ',
474                       '0x{0:08x}) == 0x{1:08x}'.format(innermask, innerbits),
475                       ') {\n')
476                output(ind, '    /* ',
477                       str_match_bits(p.fixedbits, p.fixedmask), ' */\n')
478                p.output_code(i + 4, extracted, p.fixedbits, p.fixedmask)
479                output(ind, '}\n')
480            else:
481                p.output_code(i, extracted, p.fixedbits, p.fixedmask)
482#end IncMultiPattern
483
484
485class Tree:
486    """Class representing a node in a decode tree"""
487
488    def __init__(self, fm, tm):
489        self.fixedmask = fm
490        self.thismask = tm
491        self.subs = []
492        self.base = None
493
494    def str1(self, i):
495        ind = str_indent(i)
496        r = '{0}{1:08x}'.format(ind, self.fixedmask)
497        if self.format:
498            r += ' ' + self.format.name
499        r += ' [\n'
500        for (b, s) in self.subs:
501            r += '{0}  {1:08x}:\n'.format(ind, b)
502            r += s.str1(i + 4) + '\n'
503        r += ind + ']'
504        return r
505
506    def __str__(self):
507        return self.str1(0)
508
509    def output_code(self, i, extracted, outerbits, outermask):
510        ind = str_indent(i)
511
512        # If we identified all nodes below have the same format,
513        # extract the fields now.
514        if not extracted and self.base:
515            output(ind, self.base.extract_name(),
516                   '(ctx, &u.f_', self.base.base.name, ', insn);\n')
517            extracted = True
518
519        # Attempt to aid the compiler in producing compact switch statements.
520        # If the bits in the mask are contiguous, extract them.
521        sh = is_contiguous(self.thismask)
522        if sh > 0:
523            # Propagate SH down into the local functions.
524            def str_switch(b, sh=sh):
525                return '(insn >> {0}) & 0x{1:x}'.format(sh, b >> sh)
526
527            def str_case(b, sh=sh):
528                return '0x{0:x}'.format(b >> sh)
529        else:
530            def str_switch(b):
531                return 'insn & 0x{0:08x}'.format(b)
532
533            def str_case(b):
534                return '0x{0:08x}'.format(b)
535
536        output(ind, 'switch (', str_switch(self.thismask), ') {\n')
537        for b, s in sorted(self.subs):
538            assert (self.thismask & ~s.fixedmask) == 0
539            innermask = outermask | self.thismask
540            innerbits = outerbits | b
541            output(ind, 'case ', str_case(b), ':\n')
542            output(ind, '    /* ',
543                   str_match_bits(innerbits, innermask), ' */\n')
544            s.output_code(i + 4, extracted, innerbits, innermask)
545            output(ind, '    return false;\n')
546        output(ind, '}\n')
547# end Tree
548
549
550class ExcMultiPattern(MultiPattern):
551    """Class representing a non-overlapping set of instruction patterns"""
552
553    def output_code(self, i, extracted, outerbits, outermask):
554        # Defer everything to our decomposed Tree node
555        self.tree.output_code(i, extracted, outerbits, outermask)
556
557    @staticmethod
558    def __build_tree(pats, outerbits, outermask):
559        # Find the intersection of all remaining fixedmask.
560        innermask = ~outermask & insnmask
561        for i in pats:
562            innermask &= i.fixedmask
563
564        if innermask == 0:
565            # Edge condition: One pattern covers the entire insnmask
566            if len(pats) == 1:
567                t = Tree(outermask, innermask)
568                t.subs.append((0, pats[0]))
569                return t
570
571            text = 'overlapping patterns:'
572            for p in pats:
573                text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
574            error_with_file(pats[0].file, pats[0].lineno, text)
575
576        fullmask = outermask | innermask
577
578        # Sort each element of pats into the bin selected by the mask.
579        bins = {}
580        for i in pats:
581            fb = i.fixedbits & innermask
582            if fb in bins:
583                bins[fb].append(i)
584            else:
585                bins[fb] = [i]
586
587        # We must recurse if any bin has more than one element or if
588        # the single element in the bin has not been fully matched.
589        t = Tree(fullmask, innermask)
590
591        for b, l in bins.items():
592            s = l[0]
593            if len(l) > 1 or s.fixedmask & ~fullmask != 0:
594                s = ExcMultiPattern.__build_tree(l, b | outerbits, fullmask)
595            t.subs.append((b, s))
596
597        return t
598
599    def build_tree(self):
600        super().prop_format()
601        self.tree = self.__build_tree(self.pats, self.fixedbits,
602                                      self.fixedmask)
603
604    @staticmethod
605    def __prop_format(tree):
606        """Propagate Format objects into the decode tree"""
607
608        # Depth first search.
609        for (b, s) in tree.subs:
610            if isinstance(s, Tree):
611                ExcMultiPattern.__prop_format(s)
612
613        # If all entries in SUBS have the same format, then
614        # propagate that into the tree.
615        f = None
616        for (b, s) in tree.subs:
617            if f is None:
618                f = s.base
619                if f is None:
620                    return
621            if f is not s.base:
622                return
623        tree.base = f
624
625    def prop_format(self):
626        super().prop_format()
627        self.__prop_format(self.tree)
628
629# end ExcMultiPattern
630
631
632def parse_field(lineno, name, toks):
633    """Parse one instruction field from TOKS at LINENO"""
634    global fields
635    global re_ident
636    global insnwidth
637
638    # A "simple" field will have only one entry;
639    # a "multifield" will have several.
640    subs = []
641    width = 0
642    func = None
643    for t in toks:
644        if re.fullmatch('!function=' + re_ident, t):
645            if func:
646                error(lineno, 'duplicate function')
647            func = t.split('=')
648            func = func[1]
649            continue
650
651        if re.fullmatch('[0-9]+:s[0-9]+', t):
652            # Signed field extract
653            subtoks = t.split(':s')
654            sign = True
655        elif re.fullmatch('[0-9]+:[0-9]+', t):
656            # Unsigned field extract
657            subtoks = t.split(':')
658            sign = False
659        else:
660            error(lineno, 'invalid field token "{0}"'.format(t))
661        po = int(subtoks[0])
662        le = int(subtoks[1])
663        if po + le > insnwidth:
664            error(lineno, 'field {0} too large'.format(t))
665        f = Field(sign, po, le)
666        subs.append(f)
667        width += le
668
669    if width > insnwidth:
670        error(lineno, 'field too large')
671    if len(subs) == 0:
672        if func:
673            f = ParameterField(func)
674        else:
675            error(lineno, 'field with no value')
676    else:
677        if len(subs) == 1:
678            f = subs[0]
679        else:
680            mask = 0
681            for s in subs:
682                if mask & s.mask:
683                    error(lineno, 'field components overlap')
684                mask |= s.mask
685            f = MultiField(subs, mask)
686        if func:
687            f = FunctionField(func, f)
688
689    if name in fields:
690        error(lineno, 'duplicate field', name)
691    fields[name] = f
692# end parse_field
693
694
695def parse_arguments(lineno, name, toks):
696    """Parse one argument set from TOKS at LINENO"""
697    global arguments
698    global re_ident
699    global anyextern
700
701    flds = []
702    extern = False
703    for t in toks:
704        if re.fullmatch('!extern', t):
705            extern = True
706            anyextern = True
707            continue
708        if not re.fullmatch(re_ident, t):
709            error(lineno, 'invalid argument set token "{0}"'.format(t))
710        if t in flds:
711            error(lineno, 'duplicate argument "{0}"'.format(t))
712        flds.append(t)
713
714    if name in arguments:
715        error(lineno, 'duplicate argument set', name)
716    arguments[name] = Arguments(name, flds, extern)
717# end parse_arguments
718
719
720def lookup_field(lineno, name):
721    global fields
722    if name in fields:
723        return fields[name]
724    error(lineno, 'undefined field', name)
725
726
727def add_field(lineno, flds, new_name, f):
728    if new_name in flds:
729        error(lineno, 'duplicate field', new_name)
730    flds[new_name] = f
731    return flds
732
733
734def add_field_byname(lineno, flds, new_name, old_name):
735    return add_field(lineno, flds, new_name, lookup_field(lineno, old_name))
736
737
738def infer_argument_set(flds):
739    global arguments
740    global decode_function
741
742    for arg in arguments.values():
743        if eq_fields_for_args(flds, arg.fields):
744            return arg
745
746    name = decode_function + str(len(arguments))
747    arg = Arguments(name, flds.keys(), False)
748    arguments[name] = arg
749    return arg
750
751
752def infer_format(arg, fieldmask, flds, width):
753    global arguments
754    global formats
755    global decode_function
756
757    const_flds = {}
758    var_flds = {}
759    for n, c in flds.items():
760        if c is ConstField:
761            const_flds[n] = c
762        else:
763            var_flds[n] = c
764
765    # Look for an existing format with the same argument set and fields
766    for fmt in formats.values():
767        if arg and fmt.base != arg:
768            continue
769        if fieldmask != fmt.fieldmask:
770            continue
771        if width != fmt.width:
772            continue
773        if not eq_fields_for_fmts(flds, fmt.fields):
774            continue
775        return (fmt, const_flds)
776
777    name = decode_function + '_Fmt_' + str(len(formats))
778    if not arg:
779        arg = infer_argument_set(flds)
780
781    fmt = Format(name, 0, arg, 0, 0, 0, fieldmask, var_flds, width)
782    formats[name] = fmt
783
784    return (fmt, const_flds)
785# end infer_format
786
787
788def parse_generic(lineno, parent_pat, name, toks):
789    """Parse one instruction format from TOKS at LINENO"""
790    global fields
791    global arguments
792    global formats
793    global allpatterns
794    global re_ident
795    global insnwidth
796    global insnmask
797    global variablewidth
798
799    is_format = parent_pat is None
800
801    fixedmask = 0
802    fixedbits = 0
803    undefmask = 0
804    width = 0
805    flds = {}
806    arg = None
807    fmt = None
808    for t in toks:
809        # '&Foo' gives a format an explcit argument set.
810        if t[0] == '&':
811            tt = t[1:]
812            if arg:
813                error(lineno, 'multiple argument sets')
814            if tt in arguments:
815                arg = arguments[tt]
816            else:
817                error(lineno, 'undefined argument set', t)
818            continue
819
820        # '@Foo' gives a pattern an explicit format.
821        if t[0] == '@':
822            tt = t[1:]
823            if fmt:
824                error(lineno, 'multiple formats')
825            if tt in formats:
826                fmt = formats[tt]
827            else:
828                error(lineno, 'undefined format', t)
829            continue
830
831        # '%Foo' imports a field.
832        if t[0] == '%':
833            tt = t[1:]
834            flds = add_field_byname(lineno, flds, tt, tt)
835            continue
836
837        # 'Foo=%Bar' imports a field with a different name.
838        if re.fullmatch(re_ident + '=%' + re_ident, t):
839            (fname, iname) = t.split('=%')
840            flds = add_field_byname(lineno, flds, fname, iname)
841            continue
842
843        # 'Foo=number' sets an argument field to a constant value
844        if re.fullmatch(re_ident + '=[+-]?[0-9]+', t):
845            (fname, value) = t.split('=')
846            value = int(value)
847            flds = add_field(lineno, flds, fname, ConstField(value))
848            continue
849
850        # Pattern of 0s, 1s, dots and dashes indicate required zeros,
851        # required ones, or dont-cares.
852        if re.fullmatch('[01.-]+', t):
853            shift = len(t)
854            fms = t.replace('0', '1')
855            fms = fms.replace('.', '0')
856            fms = fms.replace('-', '0')
857            fbs = t.replace('.', '0')
858            fbs = fbs.replace('-', '0')
859            ubm = t.replace('1', '0')
860            ubm = ubm.replace('.', '0')
861            ubm = ubm.replace('-', '1')
862            fms = int(fms, 2)
863            fbs = int(fbs, 2)
864            ubm = int(ubm, 2)
865            fixedbits = (fixedbits << shift) | fbs
866            fixedmask = (fixedmask << shift) | fms
867            undefmask = (undefmask << shift) | ubm
868        # Otherwise, fieldname:fieldwidth
869        elif re.fullmatch(re_ident + ':s?[0-9]+', t):
870            (fname, flen) = t.split(':')
871            sign = False
872            if flen[0] == 's':
873                sign = True
874                flen = flen[1:]
875            shift = int(flen, 10)
876            if shift + width > insnwidth:
877                error(lineno, 'field {0} exceeds insnwidth'.format(fname))
878            f = Field(sign, insnwidth - width - shift, shift)
879            flds = add_field(lineno, flds, fname, f)
880            fixedbits <<= shift
881            fixedmask <<= shift
882            undefmask <<= shift
883        else:
884            error(lineno, 'invalid token "{0}"'.format(t))
885        width += shift
886
887    if variablewidth and width < insnwidth and width % 8 == 0:
888        shift = insnwidth - width
889        fixedbits <<= shift
890        fixedmask <<= shift
891        undefmask <<= shift
892        undefmask |= (1 << shift) - 1
893
894    # We should have filled in all of the bits of the instruction.
895    elif not (is_format and width == 0) and width != insnwidth:
896        error(lineno, 'definition has {0} bits'.format(width))
897
898    # Do not check for fields overlaping fields; one valid usage
899    # is to be able to duplicate fields via import.
900    fieldmask = 0
901    for f in flds.values():
902        fieldmask |= f.mask
903
904    # Fix up what we've parsed to match either a format or a pattern.
905    if is_format:
906        # Formats cannot reference formats.
907        if fmt:
908            error(lineno, 'format referencing format')
909        # If an argument set is given, then there should be no fields
910        # without a place to store it.
911        if arg:
912            for f in flds.keys():
913                if f not in arg.fields:
914                    error(lineno, 'field {0} not in argument set {1}'
915                                  .format(f, arg.name))
916        else:
917            arg = infer_argument_set(flds)
918        if name in formats:
919            error(lineno, 'duplicate format name', name)
920        fmt = Format(name, lineno, arg, fixedbits, fixedmask,
921                     undefmask, fieldmask, flds, width)
922        formats[name] = fmt
923    else:
924        # Patterns can reference a format ...
925        if fmt:
926            # ... but not an argument simultaneously
927            if arg:
928                error(lineno, 'pattern specifies both format and argument set')
929            if fixedmask & fmt.fixedmask:
930                error(lineno, 'pattern fixed bits overlap format fixed bits')
931            if width != fmt.width:
932                error(lineno, 'pattern uses format of different width')
933            fieldmask |= fmt.fieldmask
934            fixedbits |= fmt.fixedbits
935            fixedmask |= fmt.fixedmask
936            undefmask |= fmt.undefmask
937        else:
938            (fmt, flds) = infer_format(arg, fieldmask, flds, width)
939        arg = fmt.base
940        for f in flds.keys():
941            if f not in arg.fields:
942                error(lineno, 'field {0} not in argument set {1}'
943                              .format(f, arg.name))
944            if f in fmt.fields.keys():
945                error(lineno, 'field {0} set by format and pattern'.format(f))
946        for f in arg.fields:
947            if f not in flds.keys() and f not in fmt.fields.keys():
948                error(lineno, 'field {0} not initialized'.format(f))
949        pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
950                      undefmask, fieldmask, flds, width)
951        parent_pat.pats.append(pat)
952        allpatterns.append(pat)
953
954    # Validate the masks that we have assembled.
955    if fieldmask & fixedmask:
956        error(lineno, 'fieldmask overlaps fixedmask (0x{0:08x} & 0x{1:08x})'
957                      .format(fieldmask, fixedmask))
958    if fieldmask & undefmask:
959        error(lineno, 'fieldmask overlaps undefmask (0x{0:08x} & 0x{1:08x})'
960                      .format(fieldmask, undefmask))
961    if fixedmask & undefmask:
962        error(lineno, 'fixedmask overlaps undefmask (0x{0:08x} & 0x{1:08x})'
963                      .format(fixedmask, undefmask))
964    if not is_format:
965        allbits = fieldmask | fixedmask | undefmask
966        if allbits != insnmask:
967            error(lineno, 'bits left unspecified (0x{0:08x})'
968                          .format(allbits ^ insnmask))
969# end parse_general
970
971
972def parse_file(f, parent_pat):
973    """Parse all of the patterns within a file"""
974
975    # Read all of the lines of the file.  Concatenate lines
976    # ending in backslash; discard empty lines and comments.
977    toks = []
978    lineno = 0
979    nesting = 0
980    nesting_pats = []
981
982    for line in f:
983        lineno += 1
984
985        # Expand and strip spaces, to find indent.
986        line = line.rstrip()
987        line = line.expandtabs()
988        len1 = len(line)
989        line = line.lstrip()
990        len2 = len(line)
991
992        # Discard comments
993        end = line.find('#')
994        if end >= 0:
995            line = line[:end]
996
997        t = line.split()
998        if len(toks) != 0:
999            # Next line after continuation
1000            toks.extend(t)
1001        else:
1002            # Allow completely blank lines.
1003            if len1 == 0:
1004                continue
1005            indent = len1 - len2
1006            # Empty line due to comment.
1007            if len(t) == 0:
1008                # Indentation must be correct, even for comment lines.
1009                if indent != nesting:
1010                    error(lineno, 'indentation ', indent, ' != ', nesting)
1011                continue
1012            start_lineno = lineno
1013            toks = t
1014
1015        # Continuation?
1016        if toks[-1] == '\\':
1017            toks.pop()
1018            continue
1019
1020        name = toks[0]
1021        del toks[0]
1022
1023        # End nesting?
1024        if name == '}' or name == ']':
1025            if len(toks) != 0:
1026                error(start_lineno, 'extra tokens after close brace')
1027
1028            # Make sure { } and [ ] nest properly.
1029            if (name == '}') != isinstance(parent_pat, IncMultiPattern):
1030                error(lineno, 'mismatched close brace')
1031
1032            try:
1033                parent_pat = nesting_pats.pop()
1034            except:
1035                error(lineno, 'extra close brace')
1036
1037            nesting -= 2
1038            if indent != nesting:
1039                error(lineno, 'indentation ', indent, ' != ', nesting)
1040
1041            toks = []
1042            continue
1043
1044        # Everything else should have current indentation.
1045        if indent != nesting:
1046            error(start_lineno, 'indentation ', indent, ' != ', nesting)
1047
1048        # Start nesting?
1049        if name == '{' or name == '[':
1050            if len(toks) != 0:
1051                error(start_lineno, 'extra tokens after open brace')
1052
1053            if name == '{':
1054                nested_pat = IncMultiPattern(start_lineno)
1055            else:
1056                nested_pat = ExcMultiPattern(start_lineno)
1057            parent_pat.pats.append(nested_pat)
1058            nesting_pats.append(parent_pat)
1059            parent_pat = nested_pat
1060
1061            nesting += 2
1062            toks = []
1063            continue
1064
1065        # Determine the type of object needing to be parsed.
1066        if name[0] == '%':
1067            parse_field(start_lineno, name[1:], toks)
1068        elif name[0] == '&':
1069            parse_arguments(start_lineno, name[1:], toks)
1070        elif name[0] == '@':
1071            parse_generic(start_lineno, None, name[1:], toks)
1072        else:
1073            parse_generic(start_lineno, parent_pat, name, toks)
1074        toks = []
1075
1076    if nesting != 0:
1077        error(lineno, 'missing close brace')
1078# end parse_file
1079
1080
1081class SizeTree:
1082    """Class representing a node in a size decode tree"""
1083
1084    def __init__(self, m, w):
1085        self.mask = m
1086        self.subs = []
1087        self.base = None
1088        self.width = w
1089
1090    def str1(self, i):
1091        ind = str_indent(i)
1092        r = '{0}{1:08x}'.format(ind, self.mask)
1093        r += ' [\n'
1094        for (b, s) in self.subs:
1095            r += '{0}  {1:08x}:\n'.format(ind, b)
1096            r += s.str1(i + 4) + '\n'
1097        r += ind + ']'
1098        return r
1099
1100    def __str__(self):
1101        return self.str1(0)
1102
1103    def output_code(self, i, extracted, outerbits, outermask):
1104        ind = str_indent(i)
1105
1106        # If we need to load more bytes to test, do so now.
1107        if extracted < self.width:
1108            output(ind, 'insn = ', decode_function,
1109                   '_load_bytes(ctx, insn, {0}, {1});\n'
1110                   .format(extracted // 8, self.width // 8));
1111            extracted = self.width
1112
1113        # Attempt to aid the compiler in producing compact switch statements.
1114        # If the bits in the mask are contiguous, extract them.
1115        sh = is_contiguous(self.mask)
1116        if sh > 0:
1117            # Propagate SH down into the local functions.
1118            def str_switch(b, sh=sh):
1119                return '(insn >> {0}) & 0x{1:x}'.format(sh, b >> sh)
1120
1121            def str_case(b, sh=sh):
1122                return '0x{0:x}'.format(b >> sh)
1123        else:
1124            def str_switch(b):
1125                return 'insn & 0x{0:08x}'.format(b)
1126
1127            def str_case(b):
1128                return '0x{0:08x}'.format(b)
1129
1130        output(ind, 'switch (', str_switch(self.mask), ') {\n')
1131        for b, s in sorted(self.subs):
1132            innermask = outermask | self.mask
1133            innerbits = outerbits | b
1134            output(ind, 'case ', str_case(b), ':\n')
1135            output(ind, '    /* ',
1136                   str_match_bits(innerbits, innermask), ' */\n')
1137            s.output_code(i + 4, extracted, innerbits, innermask)
1138        output(ind, '}\n')
1139        output(ind, 'return insn;\n')
1140# end SizeTree
1141
1142class SizeLeaf:
1143    """Class representing a leaf node in a size decode tree"""
1144
1145    def __init__(self, m, w):
1146        self.mask = m
1147        self.width = w
1148
1149    def str1(self, i):
1150        ind = str_indent(i)
1151        return '{0}{1:08x}'.format(ind, self.mask)
1152
1153    def __str__(self):
1154        return self.str1(0)
1155
1156    def output_code(self, i, extracted, outerbits, outermask):
1157        global decode_function
1158        ind = str_indent(i)
1159
1160        # If we need to load more bytes, do so now.
1161        if extracted < self.width:
1162            output(ind, 'insn = ', decode_function,
1163                   '_load_bytes(ctx, insn, {0}, {1});\n'
1164                   .format(extracted // 8, self.width // 8));
1165            extracted = self.width
1166        output(ind, 'return insn;\n')
1167# end SizeLeaf
1168
1169
1170def build_size_tree(pats, width, outerbits, outermask):
1171    global insnwidth
1172
1173    # Collect the mask of bits that are fixed in this width
1174    innermask = 0xff << (insnwidth - width)
1175    innermask &= ~outermask
1176    minwidth = None
1177    onewidth = True
1178    for i in pats:
1179        innermask &= i.fixedmask
1180        if minwidth is None:
1181            minwidth = i.width
1182        elif minwidth != i.width:
1183            onewidth = False;
1184            if minwidth < i.width:
1185                minwidth = i.width
1186
1187    if onewidth:
1188        return SizeLeaf(innermask, minwidth)
1189
1190    if innermask == 0:
1191        if width < minwidth:
1192            return build_size_tree(pats, width + 8, outerbits, outermask)
1193
1194        pnames = []
1195        for p in pats:
1196            pnames.append(p.name + ':' + p.file + ':' + str(p.lineno))
1197        error_with_file(pats[0].file, pats[0].lineno,
1198                        'overlapping patterns size {0}:'.format(width), pnames)
1199
1200    bins = {}
1201    for i in pats:
1202        fb = i.fixedbits & innermask
1203        if fb in bins:
1204            bins[fb].append(i)
1205        else:
1206            bins[fb] = [i]
1207
1208    fullmask = outermask | innermask
1209    lens = sorted(bins.keys())
1210    if len(lens) == 1:
1211        b = lens[0]
1212        return build_size_tree(bins[b], width + 8, b | outerbits, fullmask)
1213
1214    r = SizeTree(innermask, width)
1215    for b, l in bins.items():
1216        s = build_size_tree(l, width, b | outerbits, fullmask)
1217        r.subs.append((b, s))
1218    return r
1219# end build_size_tree
1220
1221
1222def prop_size(tree):
1223    """Propagate minimum widths up the decode size tree"""
1224
1225    if isinstance(tree, SizeTree):
1226        min = None
1227        for (b, s) in tree.subs:
1228            width = prop_size(s)
1229            if min is None or min > width:
1230                min = width
1231        assert min >= tree.width
1232        tree.width = min
1233    else:
1234        min = tree.width
1235    return min
1236# end prop_size
1237
1238
1239def main():
1240    global arguments
1241    global formats
1242    global allpatterns
1243    global translate_scope
1244    global translate_prefix
1245    global output_fd
1246    global output_file
1247    global input_file
1248    global insnwidth
1249    global insntype
1250    global insnmask
1251    global decode_function
1252    global variablewidth
1253    global anyextern
1254
1255    decode_scope = 'static '
1256
1257    long_opts = ['decode=', 'translate=', 'output=', 'insnwidth=',
1258                 'static-decode=', 'varinsnwidth=']
1259    try:
1260        (opts, args) = getopt.getopt(sys.argv[1:], 'o:vw:', long_opts)
1261    except getopt.GetoptError as err:
1262        error(0, err)
1263    for o, a in opts:
1264        if o in ('-o', '--output'):
1265            output_file = a
1266        elif o == '--decode':
1267            decode_function = a
1268            decode_scope = ''
1269        elif o == '--static-decode':
1270            decode_function = a
1271        elif o == '--translate':
1272            translate_prefix = a
1273            translate_scope = ''
1274        elif o in ('-w', '--insnwidth', '--varinsnwidth'):
1275            if o == '--varinsnwidth':
1276                variablewidth = True
1277            insnwidth = int(a)
1278            if insnwidth == 16:
1279                insntype = 'uint16_t'
1280                insnmask = 0xffff
1281            elif insnwidth != 32:
1282                error(0, 'cannot handle insns of width', insnwidth)
1283        else:
1284            assert False, 'unhandled option'
1285
1286    if len(args) < 1:
1287        error(0, 'missing input file')
1288
1289    toppat = ExcMultiPattern(0)
1290
1291    for filename in args:
1292        input_file = filename
1293        f = open(filename, 'r')
1294        parse_file(f, toppat)
1295        f.close()
1296
1297    # We do not want to compute masks for toppat, because those masks
1298    # are used as a starting point for build_tree.  For toppat, we must
1299    # insist that decode begins from naught.
1300    for i in toppat.pats:
1301        i.prop_masks()
1302
1303    toppat.build_tree()
1304    toppat.prop_format()
1305
1306    if variablewidth:
1307        for i in toppat.pats:
1308            i.prop_width()
1309        stree = build_size_tree(toppat.pats, 8, 0, 0)
1310        prop_size(stree)
1311
1312    if output_file:
1313        output_fd = open(output_file, 'w')
1314    else:
1315        output_fd = sys.stdout
1316
1317    output_autogen()
1318    for n in sorted(arguments.keys()):
1319        f = arguments[n]
1320        f.output_def()
1321
1322    # A single translate function can be invoked for different patterns.
1323    # Make sure that the argument sets are the same, and declare the
1324    # function only once.
1325    #
1326    # If we're sharing formats, we're likely also sharing trans_* functions,
1327    # but we can't tell which ones.  Prevent issues from the compiler by
1328    # suppressing redundant declaration warnings.
1329    if anyextern:
1330        output("#pragma GCC diagnostic push\n",
1331               "#pragma GCC diagnostic ignored \"-Wredundant-decls\"\n",
1332               "#ifdef __clang__\n"
1333               "#  pragma GCC diagnostic ignored \"-Wtypedef-redefinition\"\n",
1334               "#endif\n\n")
1335
1336    out_pats = {}
1337    for i in allpatterns:
1338        if i.name in out_pats:
1339            p = out_pats[i.name]
1340            if i.base.base != p.base.base:
1341                error(0, i.name, ' has conflicting argument sets')
1342        else:
1343            i.output_decl()
1344            out_pats[i.name] = i
1345    output('\n')
1346
1347    if anyextern:
1348        output("#pragma GCC diagnostic pop\n\n")
1349
1350    for n in sorted(formats.keys()):
1351        f = formats[n]
1352        f.output_extract()
1353
1354    output(decode_scope, 'bool ', decode_function,
1355           '(DisasContext *ctx, ', insntype, ' insn)\n{\n')
1356
1357    i4 = str_indent(4)
1358
1359    if len(allpatterns) != 0:
1360        output(i4, 'union {\n')
1361        for n in sorted(arguments.keys()):
1362            f = arguments[n]
1363            output(i4, i4, f.struct_name(), ' f_', f.name, ';\n')
1364        output(i4, '} u;\n\n')
1365        toppat.output_code(4, False, 0, 0)
1366
1367    output(i4, 'return false;\n')
1368    output('}\n')
1369
1370    if variablewidth:
1371        output('\n', decode_scope, insntype, ' ', decode_function,
1372               '_load(DisasContext *ctx)\n{\n',
1373               '    ', insntype, ' insn = 0;\n\n')
1374        stree.output_code(4, 0, 0, 0)
1375        output('}\n')
1376
1377    if output_file:
1378        output_fd.close()
1379# end main
1380
1381
1382if __name__ == '__main__':
1383    main()
1384