• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#encoding=utf-8
2
3# Copyright (C) 2016 Intel Corporation
4# Copyright (C) 2016 Broadcom
5# Copyright (C) 2020 Collabora, Ltd.
6#
7# Permission is hereby granted, free of charge, to any person obtaining a
8# copy of this software and associated documentation files (the "Software"),
9# to deal in the Software without restriction, including without limitation
10# the rights to use, copy, modify, merge, publish, distribute, sublicense,
11# and/or sell copies of the Software, and to permit persons to whom the
12# Software is furnished to do so, subject to the following conditions:
13#
14# The above copyright notice and this permission notice (including the next
15# paragraph) shall be included in all copies or substantial portions of the
16# Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24# IN THE SOFTWARE.
25
26import argparse
27import xml.parsers.expat
28import sys
29import operator
30from functools import reduce
31
32global_prefix = "mali"
33
34v6_format_printer = """
35
36#define mali_pixel_format_print(fp, format) \\
37    fprintf(fp, "%*sFormat (v6): %s%s%s %s%s%s%s\\n", indent, "", \\
38        mali_format_as_str((enum mali_format)((format >> 12) & 0xFF)), \\
39        (format & (1 << 20)) ? " sRGB" : "", \\
40        (format & (1 << 21)) ? " big-endian" : "", \\
41        mali_channel_as_str((enum mali_channel)((format >> 0) & 0x7)), \\
42        mali_channel_as_str((enum mali_channel)((format >> 3) & 0x7)), \\
43        mali_channel_as_str((enum mali_channel)((format >> 6) & 0x7)), \\
44        mali_channel_as_str((enum mali_channel)((format >> 9) & 0x7)));
45
46"""
47
48v7_format_printer = """
49
50#define mali_pixel_format_print(fp, format) \\
51    fprintf(fp, "%*sFormat (v7): %s%s %s%s\\n", indent, "", \\
52        mali_format_as_str((enum mali_format)((format >> 12) & 0xFF)), \\
53        (format & (1 << 20)) ? " sRGB" : "", \\
54        mali_rgb_component_order_as_str((enum mali_rgb_component_order)(format & ((1 << 12) - 1))), \\
55        (format & (1 << 21)) ? " XXX BAD BIT" : "");
56
57"""
58
59def to_alphanum(name):
60    substitutions = {
61        ' ': '_',
62        '/': '_',
63        '[': '',
64        ']': '',
65        '(': '',
66        ')': '',
67        '-': '_',
68        ':': '',
69        '.': '',
70        ',': '',
71        '=': '',
72        '>': '',
73        '#': '',
74        '&': '',
75        '%': '',
76        '*': '',
77        '"': '',
78        '+': '',
79        '\'': '',
80    }
81
82    for i, j in substitutions.items():
83        name = name.replace(i, j)
84
85    return name
86
87def safe_name(name):
88    name = to_alphanum(name)
89    if not name[0].isalpha():
90        name = '_' + name
91
92    return name
93
94def prefixed_upper_name(prefix, name):
95    if prefix:
96        name = prefix + "_" + name
97    return safe_name(name).upper()
98
99def enum_name(name):
100    return "{}_{}".format(global_prefix, safe_name(name)).lower()
101
102MODIFIERS = ["shr", "minus", "align", "log2"]
103
104def parse_modifier(modifier):
105    if modifier is None:
106        return None
107
108    for mod in MODIFIERS:
109        if modifier[0:len(mod)] == mod:
110            if mod == "log2":
111                assert(len(mod) == len(modifier))
112                return [mod]
113
114            if modifier[len(mod)] == '(' and modifier[-1] == ')':
115                ret = [mod, int(modifier[(len(mod) + 1):-1])]
116                if ret[0] == 'align':
117                    align = ret[1]
118                    # Make sure the alignment is a power of 2
119                    assert(align > 0 and not(align & (align - 1)));
120
121                return ret
122
123    print("Invalid modifier")
124    assert(False)
125
126class Aggregate(object):
127    def __init__(self, parser, name, attrs):
128        self.parser = parser
129        self.sections = []
130        self.name = name
131        self.explicit_size = int(attrs["size"]) if "size" in attrs else 0
132        self.size = 0
133        self.align = int(attrs["align"]) if "align" in attrs else None
134
135    class Section:
136        def __init__(self, name):
137            self.name = name
138
139    def get_size(self):
140        if self.size > 0:
141            return self.size
142
143        size = 0
144        for section in self.sections:
145            size = max(size, section.offset + section.type.get_length())
146
147        if self.explicit_size > 0:
148            assert(self.explicit_size >= size)
149            self.size = self.explicit_size
150        else:
151            self.size = size
152        return self.size
153
154    def add_section(self, type_name, attrs):
155        assert("name" in attrs)
156        section = self.Section(safe_name(attrs["name"]).lower())
157        section.human_name = attrs["name"]
158        section.offset = int(attrs["offset"])
159        assert(section.offset % 4 == 0)
160        section.type = self.parser.structs[attrs["type"]]
161        section.type_name = type_name
162        self.sections.append(section)
163
164class Field(object):
165    def __init__(self, parser, attrs):
166        self.parser = parser
167        if "name" in attrs:
168            self.name = safe_name(attrs["name"]).lower()
169            self.human_name = attrs["name"]
170
171        if ":" in str(attrs["start"]):
172            (word, bit) = attrs["start"].split(":")
173            self.start = (int(word) * 32) + int(bit)
174        else:
175            self.start = int(attrs["start"])
176
177        self.end = self.start + int(attrs["size"]) - 1
178        self.type = attrs["type"]
179
180        if self.type == 'bool' and self.start != self.end:
181            print("#error Field {} has bool type but more than one bit of size".format(self.name));
182
183        if "prefix" in attrs:
184            self.prefix = safe_name(attrs["prefix"]).upper()
185        else:
186            self.prefix = None
187
188        self.default = attrs.get("default")
189
190        # Map enum values
191        if self.type in self.parser.enums and self.default is not None:
192            self.default = safe_name('{}_{}_{}'.format(global_prefix, self.type, self.default)).upper()
193
194        self.modifier  = parse_modifier(attrs.get("modifier"))
195
196    def emit_template_struct(self, dim):
197        if self.type == 'address':
198            type = 'uint64_t'
199        elif self.type == 'bool':
200            type = 'bool'
201        elif self.type in ['float', 'ulod', 'slod']:
202            type = 'float'
203        elif self.type in ['uint', 'hex'] and self.end - self.start > 32:
204            type = 'uint64_t'
205        elif self.type == 'int':
206            type = 'int32_t'
207        elif self.type in ['uint', 'hex', 'uint/float', 'padded', 'Pixel Format', 'Component Swizzle']:
208            type = 'uint32_t'
209        elif self.type in self.parser.structs:
210            type = 'struct ' + self.parser.gen_prefix(safe_name(self.type.upper()))
211        elif self.type in self.parser.enums:
212            type = 'enum ' + enum_name(self.type)
213        else:
214            print("#error unhandled type: %s" % self.type)
215            type = "uint32_t"
216
217        print("   %-36s %s%s;" % (type, self.name, dim))
218
219        for value in self.values:
220            name = prefixed_upper_name(self.prefix, value.name)
221            print("#define %-40s %d" % (name, value.value))
222
223    def overlaps(self, field):
224        return self != field and max(self.start, field.start) <= min(self.end, field.end)
225
226class Group(object):
227    def __init__(self, parser, parent, start, count, label):
228        self.parser = parser
229        self.parent = parent
230        self.start = start
231        self.count = count
232        self.label = label
233        self.size = 0
234        self.length = 0
235        self.fields = []
236
237    def get_length(self):
238        # Determine number of bytes in this group.
239        calculated = max(field.end // 8 for field in self.fields) + 1 if len(self.fields) > 0 else 0
240        if self.length > 0:
241            assert(self.length >= calculated)
242        else:
243            self.length = calculated
244        return self.length
245
246
247    def emit_template_struct(self, dim):
248        if self.count == 0:
249            print("   /* variable length fields follow */")
250        else:
251            if self.count > 1:
252                dim = "%s[%d]" % (dim, self.count)
253
254            if len(self.fields) == 0:
255                print("   int dummy;")
256
257            for field in self.fields:
258                field.emit_template_struct(dim)
259
260    class Word:
261        def __init__(self):
262            self.size = 32
263            self.contributors = []
264
265    class FieldRef:
266        def __init__(self, field, path, start, end):
267            self.field = field
268            self.path = path
269            self.start = start
270            self.end = end
271
272    def collect_fields(self, fields, offset, path, all_fields):
273        for field in fields:
274            field_path = '{}{}'.format(path, field.name)
275            field_offset = offset + field.start
276
277            if field.type in self.parser.structs:
278                sub_struct = self.parser.structs[field.type]
279                self.collect_fields(sub_struct.fields, field_offset, field_path + '.', all_fields)
280                continue
281
282            start = field_offset
283            end = offset + field.end
284            all_fields.append(self.FieldRef(field, field_path, start, end))
285
286    def collect_words(self, fields, offset, path, words):
287        for field in fields:
288            field_path = '{}{}'.format(path, field.name)
289            start = offset + field.start
290
291            if field.type in self.parser.structs:
292                sub_fields = self.parser.structs[field.type].fields
293                self.collect_words(sub_fields, start, field_path + '.', words)
294                continue
295
296            end = offset + field.end
297            contributor = self.FieldRef(field, field_path, start, end)
298            first_word = contributor.start // 32
299            last_word = contributor.end // 32
300            for b in range(first_word, last_word + 1):
301                if not b in words:
302                    words[b] = self.Word()
303                words[b].contributors.append(contributor)
304
305    def emit_pack_function(self):
306        self.get_length()
307
308        words = {}
309        self.collect_words(self.fields, 0, '', words)
310
311        # Validate the modifier is lossless
312        for field in self.fields:
313            if field.modifier is None:
314                continue
315
316            if field.modifier[0] == "shr":
317                shift = field.modifier[1]
318                mask = hex((1 << shift) - 1)
319                print("   assert(((__unpacked)->{} & {}) == 0); \\".format(field.name, mask))
320            elif field.modifier[0] == "minus":
321                print("   assert((__unpacked)->{} >= {}); \\".format(field.name, field.modifier[1]))
322            elif field.modifier[0] == "log2":
323                print("   assert(IS_POT_NONZERO((__unpacked)->{})); \\".format(field.name))
324
325        for index in range(self.length // 4):
326            # Handle MBZ words
327            if not index in words:
328                print("   __tmp_packed.opaque[%2d] = 0; \\" % index)
329                continue
330
331            word = words[index]
332
333            word_start = index * 32
334
335            v = None
336            prefix = "   __tmp_packed.opaque[%2d] =" % index
337
338            for contributor in word.contributors:
339                field = contributor.field
340                name = field.name
341                start = contributor.start
342                end = contributor.end
343                contrib_word_start = (start // 32) * 32
344                start -= contrib_word_start
345                end -= contrib_word_start
346
347                value = "(__unpacked)->{}".format(contributor.path)
348                if field.modifier is not None:
349                    if field.modifier[0] == "shr":
350                        value = "{} >> {}".format(value, field.modifier[1])
351                    elif field.modifier[0] == "minus":
352                        value = "{} - {}".format(value, field.modifier[1])
353                    elif field.modifier[0] == "align":
354                        value = "ALIGN_POT({}, {})".format(value, field.modifier[1])
355                    elif field.modifier[0] == "log2":
356                        value = "util_logbase2({})".format(value)
357
358                if field.type in ["uint", "hex", "uint/float", "address", "Pixel Format", "Component Swizzle"]:
359                    s = "util_bitpack_uint(%s, %d, %d)" % \
360                        (value, start, end)
361                elif field.type == "padded":
362                    s = "__gen_padded(%s, %d, %d)" % \
363                        (value, start, end)
364                elif field.type in self.parser.enums:
365                    s = "util_bitpack_uint(%s, %d, %d)" % \
366                        (value, start, end)
367                elif field.type == "int":
368                    s = "util_bitpack_sint(%s, %d, %d)" % \
369                        (value, start, end)
370                elif field.type == "bool":
371                    s = "util_bitpack_uint(%s, %d, %d)" % \
372                        (value, start, end)
373                elif field.type == "float":
374                    assert(start == 0 and end == 31)
375                    s = "util_bitpack_float({})".format(value)
376                elif field.type == "ulod":
377                    s = "util_bitpack_ufixed_clamp({}, {}, {}, 8)".format(value,
378                                                                          start,
379                                                                          end)
380                elif field.type == "slod":
381                    s = "util_bitpack_sfixed_clamp({}, {}, {}, 8)".format(value,
382                                                                          start,
383                                                                          end)
384                else:
385                    s = "#error unhandled field {}, type {}".format(contributor.path, field.type)
386
387                if not s == None:
388                    shift = word_start - contrib_word_start
389                    if shift:
390                        s = "%s >> %d" % (s, shift)
391
392                    if contributor == word.contributors[-1]:
393                        print("%s %s; \\" % (prefix, s))
394                    else:
395                        print("%s %s | \\" % (prefix, s))
396                    prefix = "           "
397
398            continue
399
400    # Given a field (start, end) contained in word `index`, generate the 32-bit
401    # mask of present bits relative to the word
402    def mask_for_word(self, index, start, end):
403        field_word_start = index * 32
404        start -= field_word_start
405        end -= field_word_start
406        # Cap multiword at one word
407        start = max(start, 0)
408        end = min(end, 32 - 1)
409        count = (end - start + 1)
410        return (((1 << count) - 1) << start)
411
412    def emit_unpack_function(self):
413        # First, verify there is no garbage in unused bits
414        words = {}
415        self.collect_words(self.fields, 0, '', words)
416
417        for index in range(self.length // 4):
418            base = index * 32
419            word = words.get(index, self.Word())
420            masks = [self.mask_for_word(index, c.start, c.end) for c in word.contributors]
421            mask = reduce(lambda x,y: x | y, masks, 0)
422
423            ALL_ONES = 0xffffffff
424
425            if mask != ALL_ONES:
426                TMPL = '   if (__tmp_packed.opaque[{}] & {}) fprintf(stderr, "XXX: Invalid field of {} unpacked at word {}\\n"); \\'
427                print(TMPL.format(index, hex(mask ^ ALL_ONES), self.label, index))
428
429        fieldrefs = []
430        self.collect_fields(self.fields, 0, '', fieldrefs)
431        for fieldref in fieldrefs:
432            field = fieldref.field
433            convert = None
434
435            args = []
436            args.append('(__unpacked)->{}'.format(fieldref.path))
437            args.append('&__tmp_packed.opaque[0]')
438            args.append(str(fieldref.start))
439            args.append(str(fieldref.end))
440
441            if field.type in set(["uint", "hex", "uint/float", "address", "Pixel Format", "Component Swizzle"]):
442                convert = "__gen_unpack_uint"
443            elif field.type in self.parser.enums:
444                convert = "__gen_unpack_uint"
445            elif field.type == "int":
446                convert = "__gen_unpack_sint"
447            elif field.type == "padded":
448                convert = "__gen_unpack_padded"
449            elif field.type == "bool":
450                convert = "__gen_unpack_uint"
451            elif field.type == "float":
452                convert = "__gen_unpack_float"
453            elif field.type == "ulod":
454                convert = "__gen_unpack_ulod"
455            elif field.type == "slod":
456                convert = "__gen_unpack_slod"
457            else:
458                s = "/* unhandled field %s, type %s */\n" % (field.name, field.type)
459
460            suffix = ""
461            prefix = ""
462            if field.modifier:
463                if field.modifier[0] == "minus":
464                    suffix = " + {}".format(field.modifier[1])
465                elif field.modifier[0] == "shr":
466                    suffix = " << {}".format(field.modifier[1])
467                if field.modifier[0] == "log2":
468                    prefix = "1U << "
469
470            print('   {}({}); \\'.format(convert, ', '.join(args)))
471
472            if len(prefix) != 0 or len(suffix) != 0:
473                print('   (__unpacked)->{} = {}(__unpacked)->{}{}; \\'.format(fieldref.path, prefix, fieldref.path, suffix))
474
475
476            if field.modifier and field.modifier[0] == "align":
477                mask = hex(field.modifier[1] - 1)
478                print('   assert(!((__unpacked)->{} & {})); \\'.format(fieldref.path, mask))
479
480    def emit_print_function(self):
481        for field in self.fields:
482            convert = None
483            name, val = field.human_name, 'values->{}'.format(field.name)
484
485            if field.type in self.parser.structs:
486                pack_name = self.parser.gen_prefix(safe_name(field.type)).upper()
487                print('   fprintf(fp, "%*s{}:\\n", indent, "");'.format(field.human_name))
488                print("   {}_print(fp, &values->{}, indent + 2);".format(pack_name, field.name))
489            elif field.type == "address":
490                # TODO resolve to name
491                print('   fprintf(fp, "%*s{}: 0x%" PRIx64 "\\n", indent, "", {});'.format(name, val))
492            elif field.type in self.parser.enums:
493                print('   fprintf(fp, "%*s{}: %s\\n", indent, "", {}_as_str({}));'.format(name, enum_name(field.type), val))
494            elif field.type == "int":
495                print('   fprintf(fp, "%*s{}: %d\\n", indent, "", {});'.format(name, val))
496            elif field.type == "bool":
497                print('   fprintf(fp, "%*s{}: %s\\n", indent, "", {} ? "true" : "false");'.format(name, val))
498            elif field.type in ["float", "ulod", "slod"]:
499                print('   fprintf(fp, "%*s{}: %f\\n", indent, "", {});'.format(name, val))
500            elif field.type in ["uint", "hex"] and (field.end - field.start) >= 32:
501                print('   fprintf(fp, "%*s{}: 0x%" PRIx64 "\\n", indent, "", {});'.format(name, val))
502            elif field.type == "hex":
503                print('   fprintf(fp, "%*s{}: 0x%x\\n", indent, "", {});'.format(name, val))
504            elif field.type == "uint/float":
505                print('   fprintf(fp, "%*s{}: 0x%X (%f)\\n", indent, "", {}, uif({}));'.format(name, val, val))
506            elif field.type == "Pixel Format":
507                print('   mali_pixel_format_print(fp, {});'.format(val))
508            elif field.type == "Component Swizzle":
509                print('   fprintf(fp, "%*s{}: %u (%s)\\n", indent, "", {}, mali_component_swizzle({}));'.format(name, val, val))
510            else:
511                print('   fprintf(fp, "%*s{}: %u\\n", indent, "", {});'.format(name, val))
512
513class Value(object):
514    def __init__(self, attrs):
515        self.name = attrs["name"]
516        self.value = int(attrs["value"], 0)
517
518pack_header = """/* Autogenerated file, do not edit */
519/*
520 * Copyright 2024 Collabora Ltd.
521 * SPDX-License-Identifier: MIT
522 */
523
524#ifndef PAN_PACK_H
525#define PAN_PACK_H
526
527#include "genxml/pan_pack_helpers.h"
528"""
529
530class Parser(object):
531    def __init__(self):
532        self.parser = xml.parsers.expat.ParserCreate()
533        self.parser.StartElementHandler = self.start_element
534        self.parser.EndElementHandler = self.end_element
535
536        self.struct = None
537        self.structs = {}
538        # Set of enum names we've seen.
539        self.enums = set()
540        self.aggregate = None
541        self.aggregates = {}
542
543    def gen_prefix(self, name):
544        return '{}_{}'.format(global_prefix.upper(), name)
545
546    def start_element(self, name, attrs):
547        if name == "panxml":
548            print(pack_header)
549            if "arch" in attrs:
550                arch = int(attrs["arch"])
551                if arch <= 6:
552                    print(v6_format_printer)
553                else:
554                    print(v7_format_printer)
555        elif name == "struct":
556            name = attrs["name"]
557            self.no_direct_packing = attrs.get("no-direct-packing", False)
558            object_name = self.gen_prefix(safe_name(name.upper()))
559            self.struct = object_name
560
561            self.group = Group(self, None, 0, 1, name)
562            if "size" in attrs:
563                self.group.length = int(attrs["size"]) * 4
564            self.group.align = int(attrs["align"]) if "align" in attrs else None
565            self.structs[attrs["name"]] = self.group
566        elif name == "field":
567            self.group.fields.append(Field(self, attrs))
568            self.values = []
569        elif name == "enum":
570            self.values = []
571            self.enum = safe_name(attrs["name"])
572            self.enums.add(attrs["name"])
573            if "prefix" in attrs:
574                self.prefix = attrs["prefix"]
575            else:
576                self.prefix= None
577        elif name == "value":
578            self.values.append(Value(attrs))
579        elif name == "aggregate":
580            aggregate_name = self.gen_prefix(safe_name(attrs["name"].upper()))
581            self.aggregate = Aggregate(self, aggregate_name, attrs)
582            self.aggregates[attrs['name']] = self.aggregate
583        elif name == "section":
584            type_name = self.gen_prefix(safe_name(attrs["type"].upper()))
585            self.aggregate.add_section(type_name, attrs)
586
587    def end_element(self, name):
588        if name == "struct":
589            self.emit_struct()
590            self.struct = None
591            self.group = None
592        elif name  == "field":
593            self.group.fields[-1].values = self.values
594        elif name  == "enum":
595            self.emit_enum()
596            self.enum = None
597        elif name == "aggregate":
598            self.emit_aggregate()
599            self.aggregate = None
600        elif name == "panxml":
601            # Include at the end so it can depend on us but not the converse
602            print('#endif')
603
604    def emit_header(self, name):
605        default_fields = []
606        for field in self.group.fields:
607            if not type(field) is Field:
608                continue
609            if field.default is not None:
610                default_fields.append("   .{} = {}".format(field.name, field.default))
611            elif field.type in self.structs:
612                default_fields.append("   .{} = {{ {}_header }}".format(field.name, self.gen_prefix(safe_name(field.type.upper()))))
613
614        print('#define %-40s\\' % (name + '_header'))
615        if default_fields:
616            print(",  \\\n".join(default_fields))
617        else:
618            print('   0')
619        print('')
620
621    def emit_template_struct(self, name, group):
622        print("struct %s {" % name)
623        group.emit_template_struct("")
624        print("};\n")
625
626    def emit_aggregate(self):
627        aggregate = self.aggregate
628        print("struct %s_packed {" % aggregate.name.lower())
629        print("   uint32_t opaque[{}];".format(aggregate.get_size() // 4))
630        print("};\n")
631        print('#define {}_PACKED_T struct {}_packed'.format(aggregate.name.upper(), aggregate.name.lower()))
632        print('#define {}_LENGTH {}'.format(aggregate.name.upper(), aggregate.size))
633        if aggregate.align != None:
634            print('#define {}_ALIGN {}'.format(aggregate.name.upper(), aggregate.align))
635        for section in aggregate.sections:
636            print('#define {}_SECTION_{}_TYPE struct {}'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
637            print('#define {}_SECTION_{}_PACKED_TYPE {}_PACKED_T'.format(aggregate.name.upper(), section.name.upper(), section.type_name.upper()))
638            print('#define {}_SECTION_{}_header {}_header'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
639            print('#define {}_SECTION_{}_pack {}_pack'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
640            print('#define {}_SECTION_{}_unpack {}_unpack'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
641            print('#define {}_SECTION_{}_print {}_print'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
642            print('#define {}_SECTION_{}_OFFSET {}'.format(aggregate.name.upper(), section.name.upper(), section.offset))
643        print("")
644
645    def emit_struct_detail(self, name, group):
646        group.get_length()
647
648        # Should be a whole number of words
649        assert((self.group.length % 4) == 0)
650
651        print('#define {} {}'.format (name + "_LENGTH", self.group.length))
652        if self.group.align != None:
653            print('#define {} {}'.format (name + "_ALIGN", self.group.align))
654        print('struct {}_packed {{ uint32_t opaque[{}]; }};'.format(name.lower(), self.group.length // 4))
655        print('#define {}_PACKED_T struct {}_packed'.format(name.upper(), name.lower()))
656
657    def emit_pack_function(self, name, group):
658        print("#define {}_pack(__packed, __unpacked) \\".format(name))
659        print("do { \\")
660        print("   {}_PACKED_T __tmp_packed; \\".format(name.upper()))
661        group.emit_pack_function()
662        print('   *(__packed) = __tmp_packed; \\')
663        print("} while (0);\n")
664
665    def emit_unpack_function(self, name, group):
666        print("#define {}_unpack(__packed, __unpacked) \\".format(name))
667        print("do { \\")
668        print("   {}_PACKED_T __tmp_packed = *(__packed); \\".format(name))
669        group.emit_unpack_function()
670        print("} while (0);\n")
671
672    def emit_print_function(self, name, group):
673        print("static inline void")
674        print("{}_print(FILE *fp, const struct {} * values, unsigned indent)\n{{".format(name.upper(), name))
675
676        group.emit_print_function()
677
678        print("}\n")
679
680    def emit_struct(self):
681        name = self.struct
682
683        self.emit_template_struct(self.struct, self.group)
684        self.emit_header(name)
685        if self.no_direct_packing == False:
686            self.emit_struct_detail(self.struct, self.group)
687            self.emit_pack_function(self.struct, self.group)
688            self.emit_unpack_function(self.struct, self.group)
689        self.emit_print_function(self.struct, self.group)
690
691    def enum_prefix(self, name):
692        return
693
694    def emit_enum(self):
695        e_name = enum_name(self.enum)
696        prefix = e_name if self.enum != 'Format' else global_prefix
697        print('enum {} {{'.format(e_name))
698
699        for value in self.values:
700            name = '{}_{}'.format(prefix, value.name)
701            name = safe_name(name).upper()
702            print('        % -36s = %6d,' % (name, value.value))
703        print('};\n')
704
705        print("static inline const char *")
706        print("{}_as_str(enum {} imm)\n{{".format(e_name.lower(), e_name))
707        print("    switch (imm) {")
708        for value in self.values:
709            name = '{}_{}'.format(prefix, value.name)
710            name = safe_name(name).upper()
711            print('    case {}: return "{}";'.format(name, value.name))
712        print('    default: return "XXX: INVALID";')
713        print("    }")
714        print("}\n")
715
716    def parse(self, filename):
717        file = open(filename, "rb")
718        self.parser.ParseFile(file)
719        file.close()
720
721
722parser = argparse.ArgumentParser()
723parser.add_argument('input_file')
724args = parser.parse_args()
725
726p = Parser()
727p.parse(args.input_file)
728