101e04c3fSmrg#encoding=utf-8
201e04c3fSmrg
39f464c52Smayaimport argparse
401e04c3fSmrgimport ast
501e04c3fSmrgimport xml.parsers.expat
601e04c3fSmrgimport re
701e04c3fSmrgimport sys
801e04c3fSmrgimport copy
901e04c3fSmrgimport textwrap
107ec681f3Smrgfrom util import *
1101e04c3fSmrg
1201e04c3fSmrglicense =  """/*
1301e04c3fSmrg * Copyright (C) 2016 Intel Corporation
1401e04c3fSmrg *
1501e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
1601e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
1701e04c3fSmrg * to deal in the Software without restriction, including without limitation
1801e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1901e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
2001e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
2101e04c3fSmrg *
2201e04c3fSmrg * The above copyright notice and this permission notice (including the next
2301e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
2401e04c3fSmrg * Software.
2501e04c3fSmrg *
2601e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2701e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2801e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2901e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3001e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
3101e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
3201e04c3fSmrg * IN THE SOFTWARE.
3301e04c3fSmrg */
3401e04c3fSmrg"""
3501e04c3fSmrg
3601e04c3fSmrgpack_header = """%(license)s
3701e04c3fSmrg
3801e04c3fSmrg/* Instructions, enums and structures for %(platform)s.
3901e04c3fSmrg *
4001e04c3fSmrg * This file has been generated, do not hand edit.
4101e04c3fSmrg */
4201e04c3fSmrg
4301e04c3fSmrg#ifndef %(guard)s
4401e04c3fSmrg#define %(guard)s
4501e04c3fSmrg
4601e04c3fSmrg#include <stdio.h>
4701e04c3fSmrg#include <stdint.h>
4801e04c3fSmrg#include <stdbool.h>
4901e04c3fSmrg#include <assert.h>
5001e04c3fSmrg#include <math.h>
5101e04c3fSmrg
5201e04c3fSmrg#ifndef __gen_validate_value
5301e04c3fSmrg#define __gen_validate_value(x)
5401e04c3fSmrg#endif
5501e04c3fSmrg
567ec681f3Smrg#ifndef __intel_field_functions
577ec681f3Smrg#define __intel_field_functions
5801e04c3fSmrg
5901e04c3fSmrg#ifdef NDEBUG
6001e04c3fSmrg#define NDEBUG_UNUSED __attribute__((unused))
6101e04c3fSmrg#else
6201e04c3fSmrg#define NDEBUG_UNUSED
6301e04c3fSmrg#endif
6401e04c3fSmrg
657ec681f3Smrgunion __intel_value {
6601e04c3fSmrg   float f;
6701e04c3fSmrg   uint32_t dw;
6801e04c3fSmrg};
6901e04c3fSmrg
707ec681f3Smrgstatic inline __attribute__((always_inline)) uint64_t
7101e04c3fSmrg__gen_mbo(uint32_t start, uint32_t end)
7201e04c3fSmrg{
7301e04c3fSmrg   return (~0ull >> (64 - (end - start + 1))) << start;
7401e04c3fSmrg}
7501e04c3fSmrg
767ec681f3Smrgstatic inline __attribute__((always_inline)) uint64_t
7701e04c3fSmrg__gen_uint(uint64_t v, uint32_t start, NDEBUG_UNUSED uint32_t end)
7801e04c3fSmrg{
7901e04c3fSmrg   __gen_validate_value(v);
8001e04c3fSmrg
8101e04c3fSmrg#ifndef NDEBUG
8201e04c3fSmrg   const int width = end - start + 1;
8301e04c3fSmrg   if (width < 64) {
8401e04c3fSmrg      const uint64_t max = (1ull << width) - 1;
8501e04c3fSmrg      assert(v <= max);
8601e04c3fSmrg   }
8701e04c3fSmrg#endif
8801e04c3fSmrg
8901e04c3fSmrg   return v << start;
9001e04c3fSmrg}
9101e04c3fSmrg
927ec681f3Smrgstatic inline __attribute__((always_inline)) uint64_t
9301e04c3fSmrg__gen_sint(int64_t v, uint32_t start, uint32_t end)
9401e04c3fSmrg{
9501e04c3fSmrg   const int width = end - start + 1;
9601e04c3fSmrg
9701e04c3fSmrg   __gen_validate_value(v);
9801e04c3fSmrg
9901e04c3fSmrg#ifndef NDEBUG
10001e04c3fSmrg   if (width < 64) {
10101e04c3fSmrg      const int64_t max = (1ll << (width - 1)) - 1;
10201e04c3fSmrg      const int64_t min = -(1ll << (width - 1));
10301e04c3fSmrg      assert(min <= v && v <= max);
10401e04c3fSmrg   }
10501e04c3fSmrg#endif
10601e04c3fSmrg
10701e04c3fSmrg   const uint64_t mask = ~0ull >> (64 - width);
10801e04c3fSmrg
10901e04c3fSmrg   return (v & mask) << start;
11001e04c3fSmrg}
11101e04c3fSmrg
1127ec681f3Smrgstatic inline __attribute__((always_inline)) uint64_t
11301e04c3fSmrg__gen_offset(uint64_t v, NDEBUG_UNUSED uint32_t start, NDEBUG_UNUSED uint32_t end)
11401e04c3fSmrg{
11501e04c3fSmrg   __gen_validate_value(v);
11601e04c3fSmrg#ifndef NDEBUG
11701e04c3fSmrg   uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start;
11801e04c3fSmrg
11901e04c3fSmrg   assert((v & ~mask) == 0);
12001e04c3fSmrg#endif
12101e04c3fSmrg
12201e04c3fSmrg   return v;
12301e04c3fSmrg}
12401e04c3fSmrg
1257ec681f3Smrgstatic inline __attribute__((always_inline)) uint64_t
1267ec681f3Smrg__gen_address(__gen_user_data *data, void *location,
1277ec681f3Smrg              __gen_address_type address, uint32_t delta,
1287ec681f3Smrg              __attribute__((unused)) uint32_t start, uint32_t end)
1297ec681f3Smrg{
1307ec681f3Smrg   uint64_t addr_u64 = __gen_combine_address(data, location, address, delta);
1317ec681f3Smrg   if (end == 31) {
1327ec681f3Smrg      return addr_u64;
1337ec681f3Smrg   } else if (end < 63) {
1347ec681f3Smrg      const unsigned shift = 63 - end;
1357ec681f3Smrg      return (addr_u64 << shift) >> shift;
1367ec681f3Smrg   } else {
1377ec681f3Smrg      return addr_u64;
1387ec681f3Smrg   }
1397ec681f3Smrg}
1407ec681f3Smrg
1417ec681f3Smrgstatic inline __attribute__((always_inline)) uint32_t
14201e04c3fSmrg__gen_float(float v)
14301e04c3fSmrg{
14401e04c3fSmrg   __gen_validate_value(v);
1457ec681f3Smrg   return ((union __intel_value) { .f = (v) }).dw;
14601e04c3fSmrg}
14701e04c3fSmrg
1487ec681f3Smrgstatic inline __attribute__((always_inline)) uint64_t
14901e04c3fSmrg__gen_sfixed(float v, uint32_t start, uint32_t end, uint32_t fract_bits)
15001e04c3fSmrg{
15101e04c3fSmrg   __gen_validate_value(v);
15201e04c3fSmrg
15301e04c3fSmrg   const float factor = (1 << fract_bits);
15401e04c3fSmrg
15501e04c3fSmrg#ifndef NDEBUG
15601e04c3fSmrg   const float max = ((1 << (end - start)) - 1) / factor;
15701e04c3fSmrg   const float min = -(1 << (end - start)) / factor;
15801e04c3fSmrg   assert(min <= v && v <= max);
15901e04c3fSmrg#endif
16001e04c3fSmrg
16101e04c3fSmrg   const int64_t int_val = llroundf(v * factor);
16201e04c3fSmrg   const uint64_t mask = ~0ull >> (64 - (end - start + 1));
16301e04c3fSmrg
16401e04c3fSmrg   return (int_val & mask) << start;
16501e04c3fSmrg}
16601e04c3fSmrg
1677ec681f3Smrgstatic inline __attribute__((always_inline)) uint64_t
16801e04c3fSmrg__gen_ufixed(float v, uint32_t start, NDEBUG_UNUSED uint32_t end, uint32_t fract_bits)
16901e04c3fSmrg{
17001e04c3fSmrg   __gen_validate_value(v);
17101e04c3fSmrg
17201e04c3fSmrg   const float factor = (1 << fract_bits);
17301e04c3fSmrg
17401e04c3fSmrg#ifndef NDEBUG
17501e04c3fSmrg   const float max = ((1 << (end - start + 1)) - 1) / factor;
17601e04c3fSmrg   const float min = 0.0f;
17701e04c3fSmrg   assert(min <= v && v <= max);
17801e04c3fSmrg#endif
17901e04c3fSmrg
18001e04c3fSmrg   const uint64_t uint_val = llroundf(v * factor);
18101e04c3fSmrg
18201e04c3fSmrg   return uint_val << start;
18301e04c3fSmrg}
18401e04c3fSmrg
18501e04c3fSmrg#ifndef __gen_address_type
18601e04c3fSmrg#error #define __gen_address_type before including this file
18701e04c3fSmrg#endif
18801e04c3fSmrg
18901e04c3fSmrg#ifndef __gen_user_data
19001e04c3fSmrg#error #define __gen_combine_address before including this file
19101e04c3fSmrg#endif
19201e04c3fSmrg
19301e04c3fSmrg#undef NDEBUG_UNUSED
19401e04c3fSmrg
19501e04c3fSmrg#endif
19601e04c3fSmrg
19701e04c3fSmrg"""
19801e04c3fSmrg
19901e04c3fSmrgdef num_from_str(num_str):
20001e04c3fSmrg    if num_str.lower().startswith('0x'):
20101e04c3fSmrg        return int(num_str, base=16)
20201e04c3fSmrg
20301e04c3fSmrg    assert not num_str.startswith('0'), 'octals numbers not allowed'
20401e04c3fSmrg    return int(num_str)
20501e04c3fSmrg
20601e04c3fSmrgclass Field(object):
20701e04c3fSmrg    ufixed_pattern = re.compile(r"u(\d+)\.(\d+)")
20801e04c3fSmrg    sfixed_pattern = re.compile(r"s(\d+)\.(\d+)")
20901e04c3fSmrg
21001e04c3fSmrg    def __init__(self, parser, attrs):
21101e04c3fSmrg        self.parser = parser
21201e04c3fSmrg        if "name" in attrs:
21301e04c3fSmrg            self.name = safe_name(attrs["name"])
21401e04c3fSmrg        self.start = int(attrs["start"])
21501e04c3fSmrg        self.end = int(attrs["end"])
21601e04c3fSmrg        self.type = attrs["type"]
21701e04c3fSmrg
21801e04c3fSmrg        assert self.start <= self.end, \
21901e04c3fSmrg               'field {} has end ({}) < start ({})'.format(self.name, self.end,
22001e04c3fSmrg                                                           self.start)
22101e04c3fSmrg        if self.type == 'bool':
22201e04c3fSmrg            assert self.end == self.start, \
22301e04c3fSmrg                   'bool field ({}) is too wide'.format(self.name)
22401e04c3fSmrg
22501e04c3fSmrg        if "prefix" in attrs:
22601e04c3fSmrg            self.prefix = attrs["prefix"]
22701e04c3fSmrg        else:
22801e04c3fSmrg            self.prefix = None
22901e04c3fSmrg
23001e04c3fSmrg        if "default" in attrs:
23101e04c3fSmrg            # Base 0 recognizes 0x, 0o, 0b prefixes in addition to decimal ints.
23201e04c3fSmrg            self.default = int(attrs["default"], base=0)
23301e04c3fSmrg        else:
23401e04c3fSmrg            self.default = None
23501e04c3fSmrg
23601e04c3fSmrg        ufixed_match = Field.ufixed_pattern.match(self.type)
23701e04c3fSmrg        if ufixed_match:
23801e04c3fSmrg            self.type = 'ufixed'
23901e04c3fSmrg            self.fractional_size = int(ufixed_match.group(2))
24001e04c3fSmrg
24101e04c3fSmrg        sfixed_match = Field.sfixed_pattern.match(self.type)
24201e04c3fSmrg        if sfixed_match:
24301e04c3fSmrg            self.type = 'sfixed'
24401e04c3fSmrg            self.fractional_size = int(sfixed_match.group(2))
24501e04c3fSmrg
24601e04c3fSmrg    def is_builtin_type(self):
24701e04c3fSmrg        builtins =  [ 'address', 'bool', 'float', 'ufixed',
24801e04c3fSmrg                      'offset', 'sfixed', 'offset', 'int', 'uint', 'mbo' ]
24901e04c3fSmrg        return self.type in builtins
25001e04c3fSmrg
25101e04c3fSmrg    def is_struct_type(self):
25201e04c3fSmrg        return self.type in self.parser.structs
25301e04c3fSmrg
25401e04c3fSmrg    def is_enum_type(self):
25501e04c3fSmrg        return self.type in self.parser.enums
25601e04c3fSmrg
25701e04c3fSmrg    def emit_template_struct(self, dim):
25801e04c3fSmrg        if self.type == 'address':
25901e04c3fSmrg            type = '__gen_address_type'
26001e04c3fSmrg        elif self.type == 'bool':
26101e04c3fSmrg            type = 'bool'
26201e04c3fSmrg        elif self.type == 'float':
26301e04c3fSmrg            type = 'float'
26401e04c3fSmrg        elif self.type == 'ufixed':
26501e04c3fSmrg            type = 'float'
26601e04c3fSmrg        elif self.type == 'sfixed':
26701e04c3fSmrg            type = 'float'
26801e04c3fSmrg        elif self.type == 'uint' and self.end - self.start > 32:
26901e04c3fSmrg            type = 'uint64_t'
27001e04c3fSmrg        elif self.type == 'offset':
27101e04c3fSmrg            type = 'uint64_t'
27201e04c3fSmrg        elif self.type == 'int':
27301e04c3fSmrg            type = 'int32_t'
27401e04c3fSmrg        elif self.type == 'uint':
27501e04c3fSmrg            type = 'uint32_t'
27601e04c3fSmrg        elif self.is_struct_type():
27701e04c3fSmrg            type = 'struct ' + self.parser.gen_prefix(safe_name(self.type))
27801e04c3fSmrg        elif self.is_enum_type():
27901e04c3fSmrg            type = 'enum ' + self.parser.gen_prefix(safe_name(self.type))
28001e04c3fSmrg        elif self.type == 'mbo':
28101e04c3fSmrg            return
28201e04c3fSmrg        else:
28301e04c3fSmrg            print("#error unhandled type: %s" % self.type)
28401e04c3fSmrg            return
28501e04c3fSmrg
28601e04c3fSmrg        print("   %-36s %s%s;" % (type, self.name, dim))
28701e04c3fSmrg
28801e04c3fSmrg        prefix = ""
28901e04c3fSmrg        if self.values and self.default is None:
29001e04c3fSmrg            if self.prefix:
29101e04c3fSmrg                prefix = self.prefix + "_"
29201e04c3fSmrg
29301e04c3fSmrg        for value in self.values:
29401e04c3fSmrg            print("#define %-40s %d" % (prefix + value.name, value.value))
29501e04c3fSmrg
29601e04c3fSmrgclass Group(object):
29701e04c3fSmrg    def __init__(self, parser, parent, start, count, size):
29801e04c3fSmrg        self.parser = parser
29901e04c3fSmrg        self.parent = parent
30001e04c3fSmrg        self.start = start
30101e04c3fSmrg        self.count = count
30201e04c3fSmrg        self.size = size
30301e04c3fSmrg        self.fields = []
30401e04c3fSmrg
30501e04c3fSmrg    def emit_template_struct(self, dim):
30601e04c3fSmrg        if self.count == 0:
30701e04c3fSmrg            print("   /* variable length fields follow */")
30801e04c3fSmrg        else:
30901e04c3fSmrg            if self.count > 1:
31001e04c3fSmrg                dim = "%s[%d]" % (dim, self.count)
31101e04c3fSmrg
31201e04c3fSmrg            for field in self.fields:
31301e04c3fSmrg                field.emit_template_struct(dim)
31401e04c3fSmrg
31501e04c3fSmrg    class DWord:
31601e04c3fSmrg        def __init__(self):
31701e04c3fSmrg            self.size = 32
31801e04c3fSmrg            self.fields = []
31901e04c3fSmrg            self.address = None
32001e04c3fSmrg
32101e04c3fSmrg    def collect_dwords(self, dwords, start, dim):
32201e04c3fSmrg        for field in self.fields:
32301e04c3fSmrg            if isinstance(field, Group):
32401e04c3fSmrg                if field.count == 1:
32501e04c3fSmrg                    field.collect_dwords(dwords, start + field.start, dim)
32601e04c3fSmrg                else:
32701e04c3fSmrg                    for i in range(field.count):
32801e04c3fSmrg                        field.collect_dwords(dwords,
32901e04c3fSmrg                                             start + field.start + i * field.size,
33001e04c3fSmrg                                             "%s[%d]" % (dim, i))
33101e04c3fSmrg                continue
33201e04c3fSmrg
33301e04c3fSmrg            index = (start + field.start) // 32
33401e04c3fSmrg            if not index in dwords:
33501e04c3fSmrg                dwords[index] = self.DWord()
33601e04c3fSmrg
33701e04c3fSmrg            clone = copy.copy(field)
33801e04c3fSmrg            clone.start = clone.start + start
33901e04c3fSmrg            clone.end = clone.end + start
34001e04c3fSmrg            clone.dim = dim
34101e04c3fSmrg            dwords[index].fields.append(clone)
34201e04c3fSmrg
34301e04c3fSmrg            if field.type == "address":
34401e04c3fSmrg                # assert dwords[index].address == None
3457ec681f3Smrg                dwords[index].address = clone
34601e04c3fSmrg
34701e04c3fSmrg            # Coalesce all the dwords covered by this field. The two cases we
34801e04c3fSmrg            # handle are where multiple fields are in a 64 bit word (typically
34901e04c3fSmrg            # and address and a few bits) or where a single struct field
35001e04c3fSmrg            # completely covers multiple dwords.
35101e04c3fSmrg            while index < (start + field.end) // 32:
35201e04c3fSmrg                if index + 1 in dwords and not dwords[index] == dwords[index + 1]:
35301e04c3fSmrg                    dwords[index].fields.extend(dwords[index + 1].fields)
35401e04c3fSmrg                dwords[index].size = 64
35501e04c3fSmrg                dwords[index + 1] = dwords[index]
35601e04c3fSmrg                index = index + 1
35701e04c3fSmrg
35801e04c3fSmrg    def collect_dwords_and_length(self):
35901e04c3fSmrg        dwords = {}
36001e04c3fSmrg        self.collect_dwords(dwords, 0, "")
36101e04c3fSmrg
36201e04c3fSmrg        # Determine number of dwords in this group. If we have a size, use
36301e04c3fSmrg        # that, since that'll account for MBZ dwords at the end of a group
36401e04c3fSmrg        # (like dword 8 on BDW+ 3DSTATE_HS). Otherwise, use the largest dword
36501e04c3fSmrg        # index we've seen plus one.
36601e04c3fSmrg        if self.size > 0:
36701e04c3fSmrg            length = self.size // 32
36801e04c3fSmrg        elif dwords:
36901e04c3fSmrg            length = max(dwords.keys()) + 1
37001e04c3fSmrg        else:
37101e04c3fSmrg            length = 0
37201e04c3fSmrg
37301e04c3fSmrg        return (dwords, length)
37401e04c3fSmrg
37501e04c3fSmrg    def emit_pack_function(self, dwords, length):
37601e04c3fSmrg        for index in range(length):
37701e04c3fSmrg            # Handle MBZ dwords
37801e04c3fSmrg            if not index in dwords:
37901e04c3fSmrg                print("")
38001e04c3fSmrg                print("   dw[%d] = 0;" % index)
38101e04c3fSmrg                continue
38201e04c3fSmrg
38301e04c3fSmrg            # For 64 bit dwords, we aliased the two dword entries in the dword
38401e04c3fSmrg            # dict it occupies. Now that we're emitting the pack function,
38501e04c3fSmrg            # skip the duplicate entries.
38601e04c3fSmrg            dw = dwords[index]
38701e04c3fSmrg            if index > 0 and index - 1 in dwords and dw == dwords[index - 1]:
38801e04c3fSmrg                continue
38901e04c3fSmrg
39001e04c3fSmrg            # Special case: only one field and it's a struct at the beginning
39101e04c3fSmrg            # of the dword. In this case we pack directly into the
39201e04c3fSmrg            # destination. This is the only way we handle embedded structs
39301e04c3fSmrg            # larger than 32 bits.
39401e04c3fSmrg            if len(dw.fields) == 1:
39501e04c3fSmrg                field = dw.fields[0]
39601e04c3fSmrg                name = field.name + field.dim
39701e04c3fSmrg                if field.is_struct_type() and field.start % 32 == 0:
39801e04c3fSmrg                    print("")
39901e04c3fSmrg                    print("   %s_pack(data, &dw[%d], &values->%s);" %
40001e04c3fSmrg                          (self.parser.gen_prefix(safe_name(field.type)), index, name))
40101e04c3fSmrg                    continue
40201e04c3fSmrg
40301e04c3fSmrg            # Pack any fields of struct type first so we have integer values
40401e04c3fSmrg            # to the dword for those fields.
40501e04c3fSmrg            field_index = 0
40601e04c3fSmrg            for field in dw.fields:
40701e04c3fSmrg                if isinstance(field, Field) and field.is_struct_type():
40801e04c3fSmrg                    name = field.name + field.dim
40901e04c3fSmrg                    print("")
41001e04c3fSmrg                    print("   uint32_t v%d_%d;" % (index, field_index))
41101e04c3fSmrg                    print("   %s_pack(data, &v%d_%d, &values->%s);" %
41201e04c3fSmrg                          (self.parser.gen_prefix(safe_name(field.type)), index, field_index, name))
41301e04c3fSmrg                    field_index = field_index + 1
41401e04c3fSmrg
41501e04c3fSmrg            print("")
41601e04c3fSmrg            dword_start = index * 32
41701e04c3fSmrg            if dw.address == None:
41801e04c3fSmrg                address_count = 0
41901e04c3fSmrg            else:
42001e04c3fSmrg                address_count = 1
42101e04c3fSmrg
42201e04c3fSmrg            if dw.size == 32 and dw.address == None:
42301e04c3fSmrg                v = None
42401e04c3fSmrg                print("   dw[%d] =" % index)
42501e04c3fSmrg            elif len(dw.fields) > address_count:
42601e04c3fSmrg                v = "v%d" % index
42701e04c3fSmrg                print("   const uint%d_t %s =" % (dw.size, v))
42801e04c3fSmrg            else:
42901e04c3fSmrg                v = "0"
43001e04c3fSmrg
43101e04c3fSmrg            field_index = 0
43201e04c3fSmrg            non_address_fields = []
43301e04c3fSmrg            for field in dw.fields:
43401e04c3fSmrg                if field.type != "mbo":
43501e04c3fSmrg                    name = field.name + field.dim
43601e04c3fSmrg
43701e04c3fSmrg                if field.type == "mbo":
43801e04c3fSmrg                    non_address_fields.append("__gen_mbo(%d, %d)" % \
43901e04c3fSmrg                        (field.start - dword_start, field.end - dword_start))
44001e04c3fSmrg                elif field.type == "address":
44101e04c3fSmrg                    pass
44201e04c3fSmrg                elif field.type == "uint":
44301e04c3fSmrg                    non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \
44401e04c3fSmrg                        (name, field.start - dword_start, field.end - dword_start))
44501e04c3fSmrg                elif field.is_enum_type():
44601e04c3fSmrg                    non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \
44701e04c3fSmrg                        (name, field.start - dword_start, field.end - dword_start))
44801e04c3fSmrg                elif field.type == "int":
44901e04c3fSmrg                    non_address_fields.append("__gen_sint(values->%s, %d, %d)" % \
45001e04c3fSmrg                        (name, field.start - dword_start, field.end - dword_start))
45101e04c3fSmrg                elif field.type == "bool":
45201e04c3fSmrg                    non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \
45301e04c3fSmrg                        (name, field.start - dword_start, field.end - dword_start))
45401e04c3fSmrg                elif field.type == "float":
45501e04c3fSmrg                    non_address_fields.append("__gen_float(values->%s)" % name)
45601e04c3fSmrg                elif field.type == "offset":
45701e04c3fSmrg                    non_address_fields.append("__gen_offset(values->%s, %d, %d)" % \
45801e04c3fSmrg                        (name, field.start - dword_start, field.end - dword_start))
45901e04c3fSmrg                elif field.type == 'ufixed':
46001e04c3fSmrg                    non_address_fields.append("__gen_ufixed(values->%s, %d, %d, %d)" % \
46101e04c3fSmrg                        (name, field.start - dword_start, field.end - dword_start, field.fractional_size))
46201e04c3fSmrg                elif field.type == 'sfixed':
46301e04c3fSmrg                    non_address_fields.append("__gen_sfixed(values->%s, %d, %d, %d)" % \
46401e04c3fSmrg                        (name, field.start - dword_start, field.end - dword_start, field.fractional_size))
46501e04c3fSmrg                elif field.is_struct_type():
46601e04c3fSmrg                    non_address_fields.append("__gen_uint(v%d_%d, %d, %d)" % \
46701e04c3fSmrg                        (index, field_index, field.start - dword_start, field.end - dword_start))
46801e04c3fSmrg                    field_index = field_index + 1
46901e04c3fSmrg                else:
47001e04c3fSmrg                    non_address_fields.append("/* unhandled field %s, type %s */\n" % \
47101e04c3fSmrg                                              (name, field.type))
47201e04c3fSmrg
47301e04c3fSmrg            if non_address_fields:
47401e04c3fSmrg                print(" |\n".join("      " + f for f in non_address_fields) + ";")
47501e04c3fSmrg
47601e04c3fSmrg            if dw.size == 32:
47701e04c3fSmrg                if dw.address:
4787ec681f3Smrg                    print("   dw[%d] = __gen_address(data, &dw[%d], values->%s, %s, %d, %d);" %
4797ec681f3Smrg                    (index, index, dw.address.name + field.dim, v,
4807ec681f3Smrg                     dw.address.start - dword_start, dw.address.end - dword_start))
48101e04c3fSmrg                continue
48201e04c3fSmrg
48301e04c3fSmrg            if dw.address:
48401e04c3fSmrg                v_address = "v%d_address" % index
4857ec681f3Smrg                print("   const uint64_t %s =\n      __gen_address(data, &dw[%d], values->%s, %s, %d, %d);" %
4867ec681f3Smrg                      (v_address, index, dw.address.name + field.dim, v,
4877ec681f3Smrg                       dw.address.start - dword_start, dw.address.end - dword_start))
48801e04c3fSmrg                if len(dw.fields) > address_count:
48901e04c3fSmrg                    print("   dw[%d] = %s;" % (index, v_address))
49001e04c3fSmrg                    print("   dw[%d] = (%s >> 32) | (%s >> 32);" % (index + 1, v_address, v))
49101e04c3fSmrg                    continue
49201e04c3fSmrg                else:
49301e04c3fSmrg                    v = v_address
49401e04c3fSmrg            print("   dw[%d] = %s;" % (index, v))
49501e04c3fSmrg            print("   dw[%d] = %s >> 32;" % (index + 1, v))
49601e04c3fSmrg
49701e04c3fSmrgclass Value(object):
49801e04c3fSmrg    def __init__(self, attrs):
49901e04c3fSmrg        self.name = safe_name(attrs["name"])
50001e04c3fSmrg        self.value = ast.literal_eval(attrs["value"])
50101e04c3fSmrg
50201e04c3fSmrgclass Parser(object):
50301e04c3fSmrg    def __init__(self):
50401e04c3fSmrg        self.parser = xml.parsers.expat.ParserCreate()
50501e04c3fSmrg        self.parser.StartElementHandler = self.start_element
50601e04c3fSmrg        self.parser.EndElementHandler = self.end_element
50701e04c3fSmrg
50801e04c3fSmrg        self.instruction = None
50901e04c3fSmrg        self.structs = {}
51001e04c3fSmrg        # Set of enum names we've seen.
51101e04c3fSmrg        self.enums = set()
51201e04c3fSmrg        self.registers = {}
51301e04c3fSmrg
51401e04c3fSmrg    def gen_prefix(self, name):
51501e04c3fSmrg        if name[0] == "_":
5167ec681f3Smrg            return 'GFX%s%s' % (self.gen, name)
5177ec681f3Smrg        return 'GFX%s_%s' % (self.gen, name)
51801e04c3fSmrg
51901e04c3fSmrg    def gen_guard(self):
52001e04c3fSmrg        return self.gen_prefix("PACK_H")
52101e04c3fSmrg
52201e04c3fSmrg    def start_element(self, name, attrs):
52301e04c3fSmrg        if name == "genxml":
52401e04c3fSmrg            self.platform = attrs["name"]
52501e04c3fSmrg            self.gen = attrs["gen"].replace('.', '')
52601e04c3fSmrg            print(pack_header % {'license': license, 'platform': self.platform, 'guard': self.gen_guard()})
52701e04c3fSmrg        elif name in ("instruction", "struct", "register"):
52801e04c3fSmrg            if name == "instruction":
52901e04c3fSmrg                self.instruction = safe_name(attrs["name"])
53001e04c3fSmrg                self.length_bias = int(attrs["bias"])
5319f464c52Smaya                if "engine" in attrs:
5329f464c52Smaya                    self.instruction_engines = set(attrs["engine"].split('|'))
5339f464c52Smaya                else:
5349f464c52Smaya                    # When an instruction doesn't have the engine specified,
5359f464c52Smaya                    # it is considered to be for all engines, so 'None' is used
5369f464c52Smaya                    # to signify that the instruction belongs to all engines.
5379f464c52Smaya                    self.instruction_engines = None
53801e04c3fSmrg            elif name == "struct":
53901e04c3fSmrg                self.struct = safe_name(attrs["name"])
54001e04c3fSmrg                self.structs[attrs["name"]] = 1
54101e04c3fSmrg            elif name == "register":
54201e04c3fSmrg                self.register = safe_name(attrs["name"])
54301e04c3fSmrg                self.reg_num = num_from_str(attrs["num"])
54401e04c3fSmrg                self.registers[attrs["name"]] = 1
54501e04c3fSmrg            if "length" in attrs:
54601e04c3fSmrg                self.length = int(attrs["length"])
54701e04c3fSmrg                size = self.length * 32
54801e04c3fSmrg            else:
54901e04c3fSmrg                self.length = None
55001e04c3fSmrg                size = 0
55101e04c3fSmrg            self.group = Group(self, None, 0, 1, size)
55201e04c3fSmrg
55301e04c3fSmrg        elif name == "group":
55401e04c3fSmrg            group = Group(self, self.group,
55501e04c3fSmrg                          int(attrs["start"]), int(attrs["count"]), int(attrs["size"]))
55601e04c3fSmrg            self.group.fields.append(group)
55701e04c3fSmrg            self.group = group
55801e04c3fSmrg        elif name == "field":
55901e04c3fSmrg            self.group.fields.append(Field(self, attrs))
56001e04c3fSmrg            self.values = []
56101e04c3fSmrg        elif name == "enum":
56201e04c3fSmrg            self.values = []
56301e04c3fSmrg            self.enum = safe_name(attrs["name"])
56401e04c3fSmrg            self.enums.add(attrs["name"])
56501e04c3fSmrg            if "prefix" in attrs:
56601e04c3fSmrg                self.prefix = safe_name(attrs["prefix"])
56701e04c3fSmrg            else:
56801e04c3fSmrg                self.prefix= None
56901e04c3fSmrg        elif name == "value":
57001e04c3fSmrg            self.values.append(Value(attrs))
57101e04c3fSmrg
57201e04c3fSmrg    def end_element(self, name):
57301e04c3fSmrg        if name  == "instruction":
57401e04c3fSmrg            self.emit_instruction()
57501e04c3fSmrg            self.instruction = None
57601e04c3fSmrg            self.group = None
57701e04c3fSmrg        elif name == "struct":
57801e04c3fSmrg            self.emit_struct()
57901e04c3fSmrg            self.struct = None
58001e04c3fSmrg            self.group = None
58101e04c3fSmrg        elif name == "register":
58201e04c3fSmrg            self.emit_register()
58301e04c3fSmrg            self.register = None
58401e04c3fSmrg            self.reg_num = None
58501e04c3fSmrg            self.group = None
58601e04c3fSmrg        elif name == "group":
58701e04c3fSmrg            self.group = self.group.parent
58801e04c3fSmrg        elif name  == "field":
58901e04c3fSmrg            self.group.fields[-1].values = self.values
59001e04c3fSmrg        elif name  == "enum":
59101e04c3fSmrg            self.emit_enum()
59201e04c3fSmrg            self.enum = None
59301e04c3fSmrg        elif name == "genxml":
59401e04c3fSmrg            print('#endif /* %s */' % self.gen_guard())
59501e04c3fSmrg
59601e04c3fSmrg    def emit_template_struct(self, name, group):
59701e04c3fSmrg        print("struct %s {" % self.gen_prefix(name))
59801e04c3fSmrg        group.emit_template_struct("")
59901e04c3fSmrg        print("};\n")
60001e04c3fSmrg
60101e04c3fSmrg    def emit_pack_function(self, name, group):
60201e04c3fSmrg        name = self.gen_prefix(name)
60301e04c3fSmrg        print(textwrap.dedent("""\
6047ec681f3Smrg            static inline __attribute__((always_inline)) void
60501e04c3fSmrg            %s_pack(__attribute__((unused)) __gen_user_data *data,
60601e04c3fSmrg                  %s__attribute__((unused)) void * restrict dst,
60701e04c3fSmrg                  %s__attribute__((unused)) const struct %s * restrict values)
60801e04c3fSmrg            {""") % (name, ' ' * len(name), ' ' * len(name), name))
60901e04c3fSmrg
61001e04c3fSmrg        (dwords, length) = group.collect_dwords_and_length()
61101e04c3fSmrg        if length:
61201e04c3fSmrg            # Cast dst to make header C++ friendly
61301e04c3fSmrg            print("   uint32_t * restrict dw = (uint32_t * restrict) dst;")
61401e04c3fSmrg
61501e04c3fSmrg            group.emit_pack_function(dwords, length)
61601e04c3fSmrg
61701e04c3fSmrg        print("}\n")
61801e04c3fSmrg
61901e04c3fSmrg    def emit_instruction(self):
62001e04c3fSmrg        name = self.instruction
6219f464c52Smaya        if self.instruction_engines and not self.instruction_engines & self.engines:
6229f464c52Smaya            return
6239f464c52Smaya
62401e04c3fSmrg        if not self.length is None:
62501e04c3fSmrg            print('#define %-33s %6d' %
62601e04c3fSmrg                  (self.gen_prefix(name + "_length"), self.length))
62701e04c3fSmrg        print('#define %-33s %6d' %
62801e04c3fSmrg              (self.gen_prefix(name + "_length_bias"), self.length_bias))
62901e04c3fSmrg
63001e04c3fSmrg        default_fields = []
63101e04c3fSmrg        for field in self.group.fields:
63201e04c3fSmrg            if not isinstance(field, Field):
63301e04c3fSmrg                continue
63401e04c3fSmrg            if field.default is None:
63501e04c3fSmrg                continue
6367ec681f3Smrg
6377ec681f3Smrg            if field.is_builtin_type():
6387ec681f3Smrg                default_fields.append("   .%-35s = %6d" % (field.name, field.default))
6397ec681f3Smrg            else:
6407ec681f3Smrg                # Default values should not apply to structures
6417ec681f3Smrg                assert field.is_enum_type()
6427ec681f3Smrg                default_fields.append("   .%-35s = (enum %s) %6d" % (field.name, self.gen_prefix(safe_name(field.type)), field.default))
64301e04c3fSmrg
64401e04c3fSmrg        if default_fields:
64501e04c3fSmrg            print('#define %-40s\\' % (self.gen_prefix(name + '_header')))
64601e04c3fSmrg            print(",  \\\n".join(default_fields))
64701e04c3fSmrg            print('')
64801e04c3fSmrg
64901e04c3fSmrg        self.emit_template_struct(self.instruction, self.group)
65001e04c3fSmrg
65101e04c3fSmrg        self.emit_pack_function(self.instruction, self.group)
65201e04c3fSmrg
65301e04c3fSmrg    def emit_register(self):
65401e04c3fSmrg        name = self.register
65501e04c3fSmrg        if not self.reg_num is None:
65601e04c3fSmrg            print('#define %-33s 0x%04x' %
65701e04c3fSmrg                  (self.gen_prefix(name + "_num"), self.reg_num))
65801e04c3fSmrg
65901e04c3fSmrg        if not self.length is None:
66001e04c3fSmrg            print('#define %-33s %6d' %
66101e04c3fSmrg                  (self.gen_prefix(name + "_length"), self.length))
66201e04c3fSmrg
66301e04c3fSmrg        self.emit_template_struct(self.register, self.group)
66401e04c3fSmrg        self.emit_pack_function(self.register, self.group)
66501e04c3fSmrg
66601e04c3fSmrg    def emit_struct(self):
66701e04c3fSmrg        name = self.struct
66801e04c3fSmrg        if not self.length is None:
66901e04c3fSmrg            print('#define %-33s %6d' %
67001e04c3fSmrg                  (self.gen_prefix(name + "_length"), self.length))
67101e04c3fSmrg
67201e04c3fSmrg        self.emit_template_struct(self.struct, self.group)
67301e04c3fSmrg        self.emit_pack_function(self.struct, self.group)
67401e04c3fSmrg
67501e04c3fSmrg    def emit_enum(self):
67601e04c3fSmrg        print('enum %s {' % self.gen_prefix(self.enum))
67701e04c3fSmrg        for value in self.values:
67801e04c3fSmrg            if self.prefix:
67901e04c3fSmrg                name = self.prefix + "_" + value.name
68001e04c3fSmrg            else:
68101e04c3fSmrg                name = value.name
68201e04c3fSmrg            print('   %-36s = %6d,' % (name.upper(), value.value))
68301e04c3fSmrg        print('};\n')
68401e04c3fSmrg
68501e04c3fSmrg    def parse(self, filename):
68601e04c3fSmrg        file = open(filename, "rb")
68701e04c3fSmrg        self.parser.ParseFile(file)
68801e04c3fSmrg        file.close()
68901e04c3fSmrg
6909f464c52Smayadef parse_args():
6919f464c52Smaya    p = argparse.ArgumentParser()
6929f464c52Smaya    p.add_argument('xml_source', metavar='XML_SOURCE',
6939f464c52Smaya                   help="Input xml file")
6949f464c52Smaya    p.add_argument('--engines', nargs='?', type=str, default='render',
6959f464c52Smaya                   help="Comma-separated list of engines whose instructions should be parsed (default: %(default)s)")
6969f464c52Smaya
6979f464c52Smaya    pargs = p.parse_args()
6989f464c52Smaya
6999f464c52Smaya    if pargs.engines is None:
7009f464c52Smaya        print("No engines specified")
7019f464c52Smaya        sys.exit(1)
7029f464c52Smaya
7039f464c52Smaya    return pargs
7049f464c52Smaya
7059f464c52Smayadef main():
7069f464c52Smaya    pargs = parse_args()
7079f464c52Smaya
7089f464c52Smaya    input_file = pargs.xml_source
7099f464c52Smaya    engines = pargs.engines.split(',')
7109f464c52Smaya    valid_engines = [ 'render', 'blitter', 'video' ]
7119f464c52Smaya    if set(engines) - set(valid_engines):
7129f464c52Smaya        print("Invalid engine specified, valid engines are:\n")
7139f464c52Smaya        for e in valid_engines:
7149f464c52Smaya            print("\t%s" % e)
7159f464c52Smaya        sys.exit(1)
71601e04c3fSmrg
7179f464c52Smaya    p = Parser()
7189f464c52Smaya    p.engines = set(engines)
7199f464c52Smaya    p.parse(input_file)
72001e04c3fSmrg
7219f464c52Smayaif __name__ == '__main__':
7229f464c52Smaya    main()
723