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 xml.parsers.expat
27import sys
28import operator
29from functools import reduce
30
31global_prefix = "mali"
32
33pack_header = """
34/* Generated code, see midgard.xml and gen_pack_header.py
35 *
36 * Packets, enums and structures for Panfrost.
37 *
38 * This file has been generated, do not hand edit.
39 */
40
41#ifndef PAN_PACK_H
42#define PAN_PACK_H
43
44#include <stdio.h>
45#include <stdint.h>
46#include <stdbool.h>
47#include <assert.h>
48#include <math.h>
49#include <inttypes.h>
50#include "util/macros.h"
51#include "util/u_math.h"
52
53#define __gen_unpack_float(x, y, z) uif(__gen_unpack_uint(x, y, z))
54
55static inline uint64_t
56__gen_uint(uint64_t v, uint32_t start, uint32_t end)
57{
58#ifndef NDEBUG
59   const int width = end - start + 1;
60   if (width < 64) {
61      const uint64_t max = (1ull << width) - 1;
62      assert(v <= max);
63   }
64#endif
65
66   return v << start;
67}
68
69static inline uint32_t
70__gen_sint(int32_t v, uint32_t start, uint32_t end)
71{
72#ifndef NDEBUG
73   const int width = end - start + 1;
74   if (width < 64) {
75      const int64_t max = (1ll << (width - 1)) - 1;
76      const int64_t min = -(1ll << (width - 1));
77      assert(min <= v && v <= max);
78   }
79#endif
80
81   return ((uint32_t) v) << start;
82}
83
84static inline uint32_t
85__gen_padded(uint32_t v, uint32_t start, uint32_t end)
86{
87    unsigned shift = __builtin_ctz(v);
88    unsigned odd = v >> (shift + 1);
89
90#ifndef NDEBUG
91    assert((v >> shift) & 1);
92    assert(shift <= 31);
93    assert(odd <= 7);
94    assert((end - start + 1) == 8);
95#endif
96
97    return __gen_uint(shift | (odd << 5), start, end);
98}
99
100
101static inline uint64_t
102__gen_unpack_uint(const uint8_t *restrict cl, uint32_t start, uint32_t end)
103{
104   uint64_t val = 0;
105   const int width = end - start + 1;
106   const uint64_t mask = (width == 64 ? ~0 : (1ull << width) - 1 );
107
108   for (int byte = start / 8; byte <= end / 8; byte++) {
109      val |= ((uint64_t) cl[byte]) << ((byte - start / 8) * 8);
110   }
111
112   return (val >> (start % 8)) & mask;
113}
114
115static inline uint64_t
116__gen_unpack_sint(const uint8_t *restrict cl, uint32_t start, uint32_t end)
117{
118   int size = end - start + 1;
119   int64_t val = __gen_unpack_uint(cl, start, end);
120
121   /* Get the sign bit extended. */
122   return (val << (64 - size)) >> (64 - size);
123}
124
125static inline uint64_t
126__gen_unpack_padded(const uint8_t *restrict cl, uint32_t start, uint32_t end)
127{
128   unsigned val = __gen_unpack_uint(cl, start, end);
129   unsigned shift = val & 0b11111;
130   unsigned odd = val >> 5;
131
132   return (2*odd + 1) << shift;
133}
134
135#define pan_prepare(dst, T)                                 \\
136   *(dst) = (struct MALI_ ## T){ MALI_ ## T ## _header }
137
138#define pan_pack(dst, T, name)                              \\
139   for (struct MALI_ ## T name = { MALI_ ## T ## _header }, \\
140        *_loop_terminate = (void *) (dst);                  \\
141        __builtin_expect(_loop_terminate != NULL, 1);       \\
142        ({ MALI_ ## T ## _pack((uint32_t *) (dst), &name);  \\
143           _loop_terminate = NULL; }))
144
145#define pan_unpack(src, T, name)                        \\
146        struct MALI_ ## T name;                         \\
147        MALI_ ## T ## _unpack((uint8_t *)(src), &name)
148
149#define pan_print(fp, T, var, indent)                   \\
150        MALI_ ## T ## _print(fp, &(var), indent)
151
152#define pan_section_ptr(base, A, S) \\
153        ((void *)((uint8_t *)(base) + MALI_ ## A ## _SECTION_ ## S ## _OFFSET))
154
155#define pan_section_pack(dst, A, S, name)                                                         \\
156   for (MALI_ ## A ## _SECTION_ ## S ## _TYPE name = { MALI_ ## A ## _SECTION_ ## S ## _header }, \\
157        *_loop_terminate = (void *) (dst);                                                        \\
158        __builtin_expect(_loop_terminate != NULL, 1);                                             \\
159        ({ MALI_ ## A ## _SECTION_ ## S ## _pack(pan_section_ptr(dst, A, S), &name);              \\
160           _loop_terminate = NULL; }))
161
162#define pan_section_unpack(src, A, S, name)                               \\
163        MALI_ ## A ## _SECTION_ ## S ## _TYPE name;                       \\
164        MALI_ ## A ## _SECTION_ ## S ## _unpack(pan_section_ptr(src, A, S), &name)
165
166#define pan_section_print(fp, A, S, var, indent)                          \\
167        MALI_ ## A ## _SECTION_ ## S ## _print(fp, &(var), indent)
168
169/* From presentations, 16x16 tiles externally. Use shift for fast computation
170 * of tile numbers. */
171
172#define MALI_TILE_SHIFT 4
173#define MALI_TILE_LENGTH (1 << MALI_TILE_SHIFT)
174
175"""
176
177def to_alphanum(name):
178    substitutions = {
179        ' ': '_',
180        '/': '_',
181        '[': '',
182        ']': '',
183        '(': '',
184        ')': '',
185        '-': '_',
186        ':': '',
187        '.': '',
188        ',': '',
189        '=': '',
190        '>': '',
191        '#': '',
192        '&': '',
193        '*': '',
194        '"': '',
195        '+': '',
196        '\'': '',
197    }
198
199    for i, j in substitutions.items():
200        name = name.replace(i, j)
201
202    return name
203
204def safe_name(name):
205    name = to_alphanum(name)
206    if not name[0].isalpha():
207        name = '_' + name
208
209    return name
210
211def prefixed_upper_name(prefix, name):
212    if prefix:
213        name = prefix + "_" + name
214    return safe_name(name).upper()
215
216def enum_name(name):
217    return "{}_{}".format(global_prefix, safe_name(name)).lower()
218
219def num_from_str(num_str):
220    if num_str.lower().startswith('0x'):
221        return int(num_str, base=16)
222    else:
223        assert(not num_str.startswith('0') and 'octals numbers not allowed')
224        return int(num_str)
225
226MODIFIERS = ["shr", "minus", "align", "log2"]
227
228def parse_modifier(modifier):
229    if modifier is None:
230        return None
231
232    for mod in MODIFIERS:
233        if modifier[0:len(mod)] == mod:
234            if mod == "log2":
235                assert(len(mod) == len(modifier))
236                return [mod]
237
238            if modifier[len(mod)] == '(' and modifier[-1] == ')':
239                ret = [mod, int(modifier[(len(mod) + 1):-1])]
240                if ret[0] == 'align':
241                    align = ret[1]
242                    # Make sure the alignment is a power of 2
243                    assert(align > 0 and not(align & (align - 1)));
244
245                return ret
246
247    print("Invalid modifier")
248    assert(False)
249
250class Aggregate(object):
251    def __init__(self, parser, name, attrs):
252        self.parser = parser
253        self.sections = []
254        self.name = name
255        self.explicit_size = int(attrs["size"]) if "size" in attrs else 0
256        self.size = 0
257
258    class Section:
259        def __init__(self, name):
260            self.name = name
261
262    def get_size(self):
263        if self.size > 0:
264            return self.size
265
266        size = 0
267        for section in self.sections:
268            size = max(size, section.offset + section.type.get_length())
269
270        if self.explicit_size > 0:
271            assert(self.explicit_size >= size)
272            self.size = self.explicit_size
273        else:
274            self.size = size
275        return self.size
276
277    def add_section(self, type_name, attrs):
278        assert("name" in attrs)
279        section = self.Section(safe_name(attrs["name"]).lower())
280        section.human_name = attrs["name"]
281        section.offset = int(attrs["offset"])
282        assert(section.offset % 4 == 0)
283        section.type = self.parser.structs[attrs["type"]]
284        section.type_name = type_name
285        self.sections.append(section)
286
287class Field(object):
288    def __init__(self, parser, attrs):
289        self.parser = parser
290        if "name" in attrs:
291            self.name = safe_name(attrs["name"]).lower()
292            self.human_name = attrs["name"]
293
294        if ":" in str(attrs["start"]):
295            (word, bit) = attrs["start"].split(":")
296            self.start = (int(word) * 32) + int(bit)
297        else:
298            self.start = int(attrs["start"])
299
300        self.end = self.start + int(attrs["size"]) - 1
301        self.type = attrs["type"]
302
303        if self.type == 'bool' and self.start != self.end:
304            print("#error Field {} has bool type but more than one bit of size".format(self.name));
305
306        if "prefix" in attrs:
307            self.prefix = safe_name(attrs["prefix"]).upper()
308        else:
309            self.prefix = None
310
311        if "exact" in attrs:
312            self.exact = int(attrs["exact"])
313        else:
314            self.exact = None
315
316        self.default = attrs.get("default")
317
318        # Map enum values
319        if self.type in self.parser.enums and self.default is not None:
320            self.default = safe_name('{}_{}_{}'.format(global_prefix, self.type, self.default)).upper()
321
322        self.modifier  = parse_modifier(attrs.get("modifier"))
323
324    def emit_template_struct(self, dim):
325        if self.type == 'address':
326            type = 'uint64_t'
327        elif self.type == 'bool':
328            type = 'bool'
329        elif self.type == 'float':
330            type = 'float'
331        elif self.type == 'uint' and self.end - self.start > 32:
332            type = 'uint64_t'
333        elif self.type == 'int':
334            type = 'int32_t'
335        elif self.type in ['uint', 'padded']:
336            type = 'uint32_t'
337        elif self.type in self.parser.structs:
338            type = 'struct ' + self.parser.gen_prefix(safe_name(self.type.upper()))
339        elif self.type in self.parser.enums:
340            type = 'enum ' + enum_name(self.type)
341        else:
342            print("#error unhandled type: %s" % self.type)
343            type = "uint32_t"
344
345        print("   %-36s %s%s;" % (type, self.name, dim))
346
347        for value in self.values:
348            name = prefixed_upper_name(self.prefix, value.name)
349            print("#define %-40s %d" % (name, value.value))
350
351    def overlaps(self, field):
352        return self != field and max(self.start, field.start) <= min(self.end, field.end)
353
354class Group(object):
355    def __init__(self, parser, parent, start, count):
356        self.parser = parser
357        self.parent = parent
358        self.start = start
359        self.count = count
360        self.size = 0
361        self.length = 0
362        self.fields = []
363
364    def get_length(self):
365        # Determine number of bytes in this group.
366        calculated = max(field.end // 8 for field in self.fields) + 1 if len(self.fields) > 0 else 0
367        if self.length > 0:
368            assert(self.length >= calculated)
369        else:
370            self.length = calculated
371        return self.length
372
373
374    def emit_template_struct(self, dim):
375        if self.count == 0:
376            print("   /* variable length fields follow */")
377        else:
378            if self.count > 1:
379                dim = "%s[%d]" % (dim, self.count)
380
381            if len(self.fields) == 0:
382                print("   int dummy;")
383
384            for field in self.fields:
385                if field.exact is not None:
386                    continue
387
388                field.emit_template_struct(dim)
389
390    class Word:
391        def __init__(self):
392            self.size = 32
393            self.contributors = []
394
395    class FieldRef:
396        def __init__(self, field, path, start, end):
397            self.field = field
398            self.path = path
399            self.start = start
400            self.end = end
401
402    def collect_fields(self, fields, offset, path, all_fields):
403        for field in fields:
404            field_path = '{}{}'.format(path, field.name)
405            field_offset = offset + field.start
406
407            if field.type in self.parser.structs:
408                sub_struct = self.parser.structs[field.type]
409                self.collect_fields(sub_struct.fields, field_offset, field_path + '.', all_fields)
410                continue
411
412            start = field_offset
413            end = offset + field.end
414            all_fields.append(self.FieldRef(field, field_path, start, end))
415
416    def collect_words(self, fields, offset, path, words):
417        for field in fields:
418            field_path = '{}{}'.format(path, field.name)
419            start = offset + field.start
420
421            if field.type in self.parser.structs:
422                sub_fields = self.parser.structs[field.type].fields
423                self.collect_words(sub_fields, start, field_path + '.', words)
424                continue
425
426            end = offset + field.end
427            contributor = self.FieldRef(field, field_path, start, end)
428            first_word = contributor.start // 32
429            last_word = contributor.end // 32
430            for b in range(first_word, last_word + 1):
431                if not b in words:
432                    words[b] = self.Word()
433                words[b].contributors.append(contributor)
434
435    def emit_pack_function(self):
436        self.get_length()
437
438        words = {}
439        self.collect_words(self.fields, 0, '', words)
440
441        # Validate the modifier is lossless
442        for field in self.fields:
443            if field.modifier is None:
444                continue
445
446            assert(field.exact is None)
447
448            if field.modifier[0] == "shr":
449                shift = field.modifier[1]
450                mask = hex((1 << shift) - 1)
451                print("   assert((values->{} & {}) == 0);".format(field.name, mask))
452            elif field.modifier[0] == "minus":
453                print("   assert(values->{} >= {});".format(field.name, field.modifier[1]))
454            elif field.modifier[0] == "log2":
455                print("   assert(util_is_power_of_two_nonzero(values->{}));".format(field.name))
456
457        for index in range(self.length // 4):
458            # Handle MBZ words
459            if not index in words:
460                print("   cl[%2d] = 0;" % index)
461                continue
462
463            word = words[index]
464
465            word_start = index * 32
466
467            v = None
468            prefix = "   cl[%2d] =" % index
469
470            for contributor in word.contributors:
471                field = contributor.field
472                name = field.name
473                start = contributor.start
474                end = contributor.end
475                contrib_word_start = (start // 32) * 32
476                start -= contrib_word_start
477                end -= contrib_word_start
478
479                value = str(field.exact) if field.exact is not None else "values->{}".format(contributor.path)
480                if field.modifier is not None:
481                    if field.modifier[0] == "shr":
482                        value = "{} >> {}".format(value, field.modifier[1])
483                    elif field.modifier[0] == "minus":
484                        value = "{} - {}".format(value, field.modifier[1])
485                    elif field.modifier[0] == "align":
486                        value = "ALIGN_POT({}, {})".format(value, field.modifier[1])
487                    elif field.modifier[0] == "log2":
488                        value = "util_logbase2({})".format(value)
489
490                if field.type == "uint" or field.type == "address":
491                    s = "__gen_uint(%s, %d, %d)" % \
492                        (value, start, end)
493                elif field.type == "padded":
494                    s = "__gen_padded(%s, %d, %d)" % \
495                        (value, start, end)
496                elif field.type in self.parser.enums:
497                    s = "__gen_uint(%s, %d, %d)" % \
498                        (value, start, end)
499                elif field.type == "int":
500                    s = "__gen_sint(%s, %d, %d)" % \
501                        (value, start, end)
502                elif field.type == "bool":
503                    s = "__gen_uint(%s, %d, %d)" % \
504                        (value, start, end)
505                elif field.type == "float":
506                    assert(start == 0 and end == 31)
507                    s = "__gen_uint(fui({}), 0, 32)".format(value)
508                else:
509                    s = "#error unhandled field {}, type {}".format(contributor.path, field.type)
510
511                if not s == None:
512                    shift = word_start - contrib_word_start
513                    if shift:
514                        s = "%s >> %d" % (s, shift)
515
516                    if contributor == word.contributors[-1]:
517                        print("%s %s;" % (prefix, s))
518                    else:
519                        print("%s %s |" % (prefix, s))
520                    prefix = "           "
521
522            continue
523
524    # Given a field (start, end) contained in word `index`, generate the 32-bit
525    # mask of present bits relative to the word
526    def mask_for_word(self, index, start, end):
527        field_word_start = index * 32
528        start -= field_word_start
529        end -= field_word_start
530        # Cap multiword at one word
531        start = max(start, 0)
532        end = min(end, 32 - 1)
533        count = (end - start + 1)
534        return (((1 << count) - 1) << start)
535
536    def emit_unpack_function(self):
537        # First, verify there is no garbage in unused bits
538        words = {}
539        self.collect_words(self.fields, 0, '', words)
540
541        for index in range(self.length // 4):
542            base = index * 32
543            word = words.get(index, self.Word())
544            masks = [self.mask_for_word(index, c.start, c.end) for c in word.contributors]
545            mask = reduce(lambda x,y: x | y, masks, 0)
546
547            ALL_ONES = 0xffffffff
548
549            if mask != ALL_ONES:
550                TMPL = '   if (((const uint32_t *) cl)[{}] & {}) fprintf(stderr, "XXX: Invalid field unpacked at word {}\\n");'
551                print(TMPL.format(index, hex(mask ^ ALL_ONES), index))
552
553        fieldrefs = []
554        self.collect_fields(self.fields, 0, '', fieldrefs)
555        for fieldref in fieldrefs:
556            field = fieldref.field
557            convert = None
558
559            args = []
560            args.append('cl')
561            args.append(str(fieldref.start))
562            args.append(str(fieldref.end))
563
564            if field.type in set(["uint", "address"]) | self.parser.enums:
565                convert = "__gen_unpack_uint"
566            elif field.type == "int":
567                convert = "__gen_unpack_sint"
568            elif field.type == "padded":
569                convert = "__gen_unpack_padded"
570            elif field.type == "bool":
571                convert = "__gen_unpack_uint"
572            elif field.type == "float":
573                convert = "__gen_unpack_float"
574            else:
575                s = "/* unhandled field %s, type %s */\n" % (field.name, field.type)
576
577            suffix = ""
578            prefix = ""
579            if field.modifier:
580                if field.modifier[0] == "minus":
581                    suffix = " + {}".format(field.modifier[1])
582                elif field.modifier[0] == "shr":
583                    suffix = " << {}".format(field.modifier[1])
584                if field.modifier[0] == "log2":
585                    prefix = "1 << "
586
587            decoded = '{}{}({}){}'.format(prefix, convert, ', '.join(args), suffix)
588
589            print('   values->{} = {};'.format(fieldref.path, decoded))
590            if field.modifier and field.modifier[0] == "align":
591                mask = hex(field.modifier[1] - 1)
592                print('   assert(!(values->{} & {}));'.format(fieldref.path, mask))
593
594    def emit_print_function(self):
595        for field in self.fields:
596            convert = None
597            name, val = field.human_name, 'values->{}'.format(field.name)
598
599            if field.type in self.parser.structs:
600                pack_name = self.parser.gen_prefix(safe_name(field.type)).upper()
601                print('   fprintf(fp, "%*s{}:\\n", indent, "");'.format(field.human_name))
602                print("   {}_print(fp, &values->{}, indent + 2);".format(pack_name, field.name))
603            elif field.type == "address":
604                # TODO resolve to name
605                print('   fprintf(fp, "%*s{}: 0x%" PRIx64 "\\n", indent, "", {});'.format(name, val))
606            elif field.type in self.parser.enums:
607                print('   fprintf(fp, "%*s{}: %s\\n", indent, "", {}_as_str({}));'.format(name, enum_name(field.type), val))
608            elif field.type == "int":
609                print('   fprintf(fp, "%*s{}: %d\\n", indent, "", {});'.format(name, val))
610            elif field.type == "bool":
611                print('   fprintf(fp, "%*s{}: %s\\n", indent, "", {} ? "true" : "false");'.format(name, val))
612            elif field.type == "float":
613                print('   fprintf(fp, "%*s{}: %f\\n", indent, "", {});'.format(name, val))
614            elif field.type == "uint" and (field.end - field.start) >= 32:
615                print('   fprintf(fp, "%*s{}: 0x%" PRIx64 "\\n", indent, "", {});'.format(name, val))
616            else:
617                print('   fprintf(fp, "%*s{}: %u\\n", indent, "", {});'.format(name, val))
618
619class Value(object):
620    def __init__(self, attrs):
621        self.name = attrs["name"]
622        self.value = int(attrs["value"], 0)
623
624class Parser(object):
625    def __init__(self):
626        self.parser = xml.parsers.expat.ParserCreate()
627        self.parser.StartElementHandler = self.start_element
628        self.parser.EndElementHandler = self.end_element
629
630        self.struct = None
631        self.structs = {}
632        # Set of enum names we've seen.
633        self.enums = set()
634        self.aggregate = None
635        self.aggregates = {}
636
637    def gen_prefix(self, name):
638        return '{}_{}'.format(global_prefix.upper(), name)
639
640    def start_element(self, name, attrs):
641        if name == "panxml":
642            print(pack_header)
643        elif name == "struct":
644            name = attrs["name"]
645            self.no_direct_packing = attrs.get("no-direct-packing", False)
646            object_name = self.gen_prefix(safe_name(name.upper()))
647            self.struct = object_name
648
649            self.group = Group(self, None, 0, 1)
650            if "size" in attrs:
651                self.group.length = int(attrs["size"]) * 4
652            self.structs[attrs["name"]] = self.group
653        elif name == "field":
654            self.group.fields.append(Field(self, attrs))
655            self.values = []
656        elif name == "enum":
657            self.values = []
658            self.enum = safe_name(attrs["name"])
659            self.enums.add(attrs["name"])
660            if "prefix" in attrs:
661                self.prefix = attrs["prefix"]
662            else:
663                self.prefix= None
664        elif name == "value":
665            self.values.append(Value(attrs))
666        elif name == "aggregate":
667            aggregate_name = self.gen_prefix(safe_name(attrs["name"].upper()))
668            self.aggregate = Aggregate(self, aggregate_name, attrs)
669            self.aggregates[attrs['name']] = self.aggregate
670        elif name == "section":
671            type_name = self.gen_prefix(safe_name(attrs["type"].upper()))
672            self.aggregate.add_section(type_name, attrs)
673
674    def end_element(self, name):
675        if name == "struct":
676            self.emit_struct()
677            self.struct = None
678            self.group = None
679        elif name  == "field":
680            self.group.fields[-1].values = self.values
681        elif name  == "enum":
682            self.emit_enum()
683            self.enum = None
684        elif name == "aggregate":
685            self.emit_aggregate()
686            self.aggregate = None
687        elif name == "panxml":
688            # Include at the end so it can depend on us but not the converse
689            print('#include "panfrost-job.h"')
690            print('#endif')
691
692    def emit_header(self, name):
693        default_fields = []
694        for field in self.group.fields:
695            if not type(field) is Field:
696                continue
697            if field.default is not None:
698                default_fields.append("   .{} = {}".format(field.name, field.default))
699            elif field.type in self.structs:
700                default_fields.append("   .{} = {{ {}_header }}".format(field.name, self.gen_prefix(safe_name(field.type.upper()))))
701
702        print('#define %-40s\\' % (name + '_header'))
703        if default_fields:
704            print(",  \\\n".join(default_fields))
705        else:
706            print('   0')
707        print('')
708
709    def emit_template_struct(self, name, group):
710        print("struct %s {" % name)
711        group.emit_template_struct("")
712        print("};\n")
713
714    def emit_aggregate(self):
715        aggregate = self.aggregate
716        print("struct %s_packed {" % aggregate.name.lower())
717        print("   uint32_t opaque[{}];".format(aggregate.get_size() // 4))
718        print("};\n")
719        print('#define {}_LENGTH {}'.format(aggregate.name.upper(), aggregate.size))
720        for section in aggregate.sections:
721            print('#define {}_SECTION_{}_TYPE struct {}'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
722            print('#define {}_SECTION_{}_header {}_header'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
723            print('#define {}_SECTION_{}_pack {}_pack'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
724            print('#define {}_SECTION_{}_unpack {}_unpack'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
725            print('#define {}_SECTION_{}_print {}_print'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
726            print('#define {}_SECTION_{}_OFFSET {}'.format(aggregate.name.upper(), section.name.upper(), section.offset))
727        print("")
728
729    def emit_pack_function(self, name, group):
730        print("static inline void\n%s_pack(uint32_t * restrict cl,\n%sconst struct %s * restrict values)\n{" %
731              (name, ' ' * (len(name) + 6), name))
732
733        group.emit_pack_function()
734
735        print("}\n\n")
736
737        # Should be a whole number of words
738        assert((self.group.length % 4) == 0)
739
740        print('#define {} {}'.format (name + "_LENGTH", self.group.length))
741        print('struct {}_packed {{ uint32_t opaque[{}]; }};'.format(name.lower(), self.group.length // 4))
742
743    def emit_unpack_function(self, name, group):
744        print("static inline void")
745        print("%s_unpack(const uint8_t * restrict cl,\n%sstruct %s * restrict values)\n{" %
746              (name.upper(), ' ' * (len(name) + 8), name))
747
748        group.emit_unpack_function()
749
750        print("}\n")
751
752    def emit_print_function(self, name, group):
753        print("static inline void")
754        print("{}_print(FILE *fp, const struct {} * values, unsigned indent)\n{{".format(name.upper(), name))
755
756        group.emit_print_function()
757
758        print("}\n")
759
760    def emit_struct(self):
761        name = self.struct
762
763        self.emit_template_struct(self.struct, self.group)
764        self.emit_header(name)
765        if self.no_direct_packing == False:
766            self.emit_pack_function(self.struct, self.group)
767            self.emit_unpack_function(self.struct, self.group)
768        self.emit_print_function(self.struct, self.group)
769
770    def enum_prefix(self, name):
771        return
772
773    def emit_enum(self):
774        e_name = enum_name(self.enum)
775        prefix = e_name if self.enum != 'Format' else global_prefix
776        print('enum {} {{'.format(e_name))
777
778        for value in self.values:
779            name = '{}_{}'.format(prefix, value.name)
780            name = safe_name(name).upper()
781            print('        % -36s = %6d,' % (name, value.value))
782        print('};\n')
783
784        print("static inline const char *")
785        print("{}_as_str(enum {} imm)\n{{".format(e_name.lower(), e_name))
786        print("    switch (imm) {")
787        for value in self.values:
788            name = '{}_{}'.format(prefix, value.name)
789            name = safe_name(name).upper()
790            print('    case {}: return "{}";'.format(name, value.name))
791        print('    default: return "XXX: INVALID";')
792        print("    }")
793        print("}\n")
794
795    def parse(self, filename):
796        file = open(filename, "rb")
797        self.parser.ParseFile(file)
798        file.close()
799
800if len(sys.argv) < 2:
801    print("No input xml file specified")
802    sys.exit(1)
803
804input_file = sys.argv[1]
805
806p = Parser()
807p.parse(input_file)
808