gen_pack_header.py revision 01e04c3f
1#encoding=utf-8
2
3from __future__ import (
4    absolute_import, division, print_function, unicode_literals
5)
6import ast
7import xml.parsers.expat
8import re
9import sys
10import copy
11import textwrap
12
13license =  """/*
14 * Copyright (C) 2016 Intel Corporation
15 *
16 * Permission is hereby granted, free of charge, to any person obtaining a
17 * copy of this software and associated documentation files (the "Software"),
18 * to deal in the Software without restriction, including without limitation
19 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20 * and/or sell copies of the Software, and to permit persons to whom the
21 * Software is furnished to do so, subject to the following conditions:
22 *
23 * The above copyright notice and this permission notice (including the next
24 * paragraph) shall be included in all copies or substantial portions of the
25 * Software.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
30 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
33 * IN THE SOFTWARE.
34 */
35"""
36
37pack_header = """%(license)s
38
39/* Instructions, enums and structures for %(platform)s.
40 *
41 * This file has been generated, do not hand edit.
42 */
43
44#ifndef %(guard)s
45#define %(guard)s
46
47#include <stdio.h>
48#include <stdint.h>
49#include <stdbool.h>
50#include <assert.h>
51#include <math.h>
52
53#ifndef __gen_validate_value
54#define __gen_validate_value(x)
55#endif
56
57#ifndef __gen_field_functions
58#define __gen_field_functions
59
60#ifdef NDEBUG
61#define NDEBUG_UNUSED __attribute__((unused))
62#else
63#define NDEBUG_UNUSED
64#endif
65
66union __gen_value {
67   float f;
68   uint32_t dw;
69};
70
71static inline uint64_t
72__gen_mbo(uint32_t start, uint32_t end)
73{
74   return (~0ull >> (64 - (end - start + 1))) << start;
75}
76
77static inline uint64_t
78__gen_uint(uint64_t v, uint32_t start, NDEBUG_UNUSED uint32_t end)
79{
80   __gen_validate_value(v);
81
82#ifndef NDEBUG
83   const int width = end - start + 1;
84   if (width < 64) {
85      const uint64_t max = (1ull << width) - 1;
86      assert(v <= max);
87   }
88#endif
89
90   return v << start;
91}
92
93static inline uint64_t
94__gen_sint(int64_t v, uint32_t start, uint32_t end)
95{
96   const int width = end - start + 1;
97
98   __gen_validate_value(v);
99
100#ifndef NDEBUG
101   if (width < 64) {
102      const int64_t max = (1ll << (width - 1)) - 1;
103      const int64_t min = -(1ll << (width - 1));
104      assert(min <= v && v <= max);
105   }
106#endif
107
108   const uint64_t mask = ~0ull >> (64 - width);
109
110   return (v & mask) << start;
111}
112
113static inline uint64_t
114__gen_offset(uint64_t v, NDEBUG_UNUSED uint32_t start, NDEBUG_UNUSED uint32_t end)
115{
116   __gen_validate_value(v);
117#ifndef NDEBUG
118   uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start;
119
120   assert((v & ~mask) == 0);
121#endif
122
123   return v;
124}
125
126static inline uint32_t
127__gen_float(float v)
128{
129   __gen_validate_value(v);
130   return ((union __gen_value) { .f = (v) }).dw;
131}
132
133static inline uint64_t
134__gen_sfixed(float v, uint32_t start, uint32_t end, uint32_t fract_bits)
135{
136   __gen_validate_value(v);
137
138   const float factor = (1 << fract_bits);
139
140#ifndef NDEBUG
141   const float max = ((1 << (end - start)) - 1) / factor;
142   const float min = -(1 << (end - start)) / factor;
143   assert(min <= v && v <= max);
144#endif
145
146   const int64_t int_val = llroundf(v * factor);
147   const uint64_t mask = ~0ull >> (64 - (end - start + 1));
148
149   return (int_val & mask) << start;
150}
151
152static inline uint64_t
153__gen_ufixed(float v, uint32_t start, NDEBUG_UNUSED uint32_t end, uint32_t fract_bits)
154{
155   __gen_validate_value(v);
156
157   const float factor = (1 << fract_bits);
158
159#ifndef NDEBUG
160   const float max = ((1 << (end - start + 1)) - 1) / factor;
161   const float min = 0.0f;
162   assert(min <= v && v <= max);
163#endif
164
165   const uint64_t uint_val = llroundf(v * factor);
166
167   return uint_val << start;
168}
169
170#ifndef __gen_address_type
171#error #define __gen_address_type before including this file
172#endif
173
174#ifndef __gen_user_data
175#error #define __gen_combine_address before including this file
176#endif
177
178#undef NDEBUG_UNUSED
179
180#endif
181
182"""
183
184def to_alphanum(name):
185    substitutions = {
186        ' ': '',
187        '/': '',
188        '[': '',
189        ']': '',
190        '(': '',
191        ')': '',
192        '-': '',
193        ':': '',
194        '.': '',
195        ',': '',
196        '=': '',
197        '>': '',
198        '#': '',
199        'α': 'alpha',
200        '&': '',
201        '*': '',
202        '"': '',
203        '+': '',
204        '\'': '',
205    }
206
207    for i, j in substitutions.items():
208        name = name.replace(i, j)
209
210    return name
211
212def safe_name(name):
213    name = to_alphanum(name)
214    if not name[0].isalpha():
215        name = '_' + name
216
217    return name
218
219def num_from_str(num_str):
220    if num_str.lower().startswith('0x'):
221        return int(num_str, base=16)
222
223    assert not num_str.startswith('0'), 'octals numbers not allowed'
224    return int(num_str)
225
226class Field(object):
227    ufixed_pattern = re.compile(r"u(\d+)\.(\d+)")
228    sfixed_pattern = re.compile(r"s(\d+)\.(\d+)")
229
230    def __init__(self, parser, attrs):
231        self.parser = parser
232        if "name" in attrs:
233            self.name = safe_name(attrs["name"])
234        self.start = int(attrs["start"])
235        self.end = int(attrs["end"])
236        self.type = attrs["type"]
237
238        assert self.start <= self.end, \
239               'field {} has end ({}) < start ({})'.format(self.name, self.end,
240                                                           self.start)
241        if self.type == 'bool':
242            assert self.end == self.start, \
243                   'bool field ({}) is too wide'.format(self.name)
244
245        if "prefix" in attrs:
246            self.prefix = attrs["prefix"]
247        else:
248            self.prefix = None
249
250        if "default" in attrs:
251            # Base 0 recognizes 0x, 0o, 0b prefixes in addition to decimal ints.
252            self.default = int(attrs["default"], base=0)
253        else:
254            self.default = None
255
256        ufixed_match = Field.ufixed_pattern.match(self.type)
257        if ufixed_match:
258            self.type = 'ufixed'
259            self.fractional_size = int(ufixed_match.group(2))
260
261        sfixed_match = Field.sfixed_pattern.match(self.type)
262        if sfixed_match:
263            self.type = 'sfixed'
264            self.fractional_size = int(sfixed_match.group(2))
265
266    def is_builtin_type(self):
267        builtins =  [ 'address', 'bool', 'float', 'ufixed',
268                      'offset', 'sfixed', 'offset', 'int', 'uint', 'mbo' ]
269        return self.type in builtins
270
271    def is_struct_type(self):
272        return self.type in self.parser.structs
273
274    def is_enum_type(self):
275        return self.type in self.parser.enums
276
277    def emit_template_struct(self, dim):
278        if self.type == 'address':
279            type = '__gen_address_type'
280        elif self.type == 'bool':
281            type = 'bool'
282        elif self.type == 'float':
283            type = 'float'
284        elif self.type == 'ufixed':
285            type = 'float'
286        elif self.type == 'sfixed':
287            type = 'float'
288        elif self.type == 'uint' and self.end - self.start > 32:
289            type = 'uint64_t'
290        elif self.type == 'offset':
291            type = 'uint64_t'
292        elif self.type == 'int':
293            type = 'int32_t'
294        elif self.type == 'uint':
295            type = 'uint32_t'
296        elif self.is_struct_type():
297            type = 'struct ' + self.parser.gen_prefix(safe_name(self.type))
298        elif self.is_enum_type():
299            type = 'enum ' + self.parser.gen_prefix(safe_name(self.type))
300        elif self.type == 'mbo':
301            return
302        else:
303            print("#error unhandled type: %s" % self.type)
304            return
305
306        print("   %-36s %s%s;" % (type, self.name, dim))
307
308        prefix = ""
309        if self.values and self.default is None:
310            if self.prefix:
311                prefix = self.prefix + "_"
312
313        for value in self.values:
314            print("#define %-40s %d" % (prefix + value.name, value.value))
315
316class Group(object):
317    def __init__(self, parser, parent, start, count, size):
318        self.parser = parser
319        self.parent = parent
320        self.start = start
321        self.count = count
322        self.size = size
323        self.fields = []
324
325    def emit_template_struct(self, dim):
326        if self.count == 0:
327            print("   /* variable length fields follow */")
328        else:
329            if self.count > 1:
330                dim = "%s[%d]" % (dim, self.count)
331
332            for field in self.fields:
333                field.emit_template_struct(dim)
334
335    class DWord:
336        def __init__(self):
337            self.size = 32
338            self.fields = []
339            self.address = None
340
341    def collect_dwords(self, dwords, start, dim):
342        for field in self.fields:
343            if isinstance(field, Group):
344                if field.count == 1:
345                    field.collect_dwords(dwords, start + field.start, dim)
346                else:
347                    for i in range(field.count):
348                        field.collect_dwords(dwords,
349                                             start + field.start + i * field.size,
350                                             "%s[%d]" % (dim, i))
351                continue
352
353            index = (start + field.start) // 32
354            if not index in dwords:
355                dwords[index] = self.DWord()
356
357            clone = copy.copy(field)
358            clone.start = clone.start + start
359            clone.end = clone.end + start
360            clone.dim = dim
361            dwords[index].fields.append(clone)
362
363            if field.type == "address":
364                # assert dwords[index].address == None
365                dwords[index].address = field
366
367            # Coalesce all the dwords covered by this field. The two cases we
368            # handle are where multiple fields are in a 64 bit word (typically
369            # and address and a few bits) or where a single struct field
370            # completely covers multiple dwords.
371            while index < (start + field.end) // 32:
372                if index + 1 in dwords and not dwords[index] == dwords[index + 1]:
373                    dwords[index].fields.extend(dwords[index + 1].fields)
374                dwords[index].size = 64
375                dwords[index + 1] = dwords[index]
376                index = index + 1
377
378    def collect_dwords_and_length(self):
379        dwords = {}
380        self.collect_dwords(dwords, 0, "")
381
382        # Determine number of dwords in this group. If we have a size, use
383        # that, since that'll account for MBZ dwords at the end of a group
384        # (like dword 8 on BDW+ 3DSTATE_HS). Otherwise, use the largest dword
385        # index we've seen plus one.
386        if self.size > 0:
387            length = self.size // 32
388        elif dwords:
389            length = max(dwords.keys()) + 1
390        else:
391            length = 0
392
393        return (dwords, length)
394
395    def emit_pack_function(self, dwords, length):
396        for index in range(length):
397            # Handle MBZ dwords
398            if not index in dwords:
399                print("")
400                print("   dw[%d] = 0;" % index)
401                continue
402
403            # For 64 bit dwords, we aliased the two dword entries in the dword
404            # dict it occupies. Now that we're emitting the pack function,
405            # skip the duplicate entries.
406            dw = dwords[index]
407            if index > 0 and index - 1 in dwords and dw == dwords[index - 1]:
408                continue
409
410            # Special case: only one field and it's a struct at the beginning
411            # of the dword. In this case we pack directly into the
412            # destination. This is the only way we handle embedded structs
413            # larger than 32 bits.
414            if len(dw.fields) == 1:
415                field = dw.fields[0]
416                name = field.name + field.dim
417                if field.is_struct_type() and field.start % 32 == 0:
418                    print("")
419                    print("   %s_pack(data, &dw[%d], &values->%s);" %
420                          (self.parser.gen_prefix(safe_name(field.type)), index, name))
421                    continue
422
423            # Pack any fields of struct type first so we have integer values
424            # to the dword for those fields.
425            field_index = 0
426            for field in dw.fields:
427                if isinstance(field, Field) and field.is_struct_type():
428                    name = field.name + field.dim
429                    print("")
430                    print("   uint32_t v%d_%d;" % (index, field_index))
431                    print("   %s_pack(data, &v%d_%d, &values->%s);" %
432                          (self.parser.gen_prefix(safe_name(field.type)), index, field_index, name))
433                    field_index = field_index + 1
434
435            print("")
436            dword_start = index * 32
437            if dw.address == None:
438                address_count = 0
439            else:
440                address_count = 1
441
442            if dw.size == 32 and dw.address == None:
443                v = None
444                print("   dw[%d] =" % index)
445            elif len(dw.fields) > address_count:
446                v = "v%d" % index
447                print("   const uint%d_t %s =" % (dw.size, v))
448            else:
449                v = "0"
450
451            field_index = 0
452            non_address_fields = []
453            for field in dw.fields:
454                if field.type != "mbo":
455                    name = field.name + field.dim
456
457                if field.type == "mbo":
458                    non_address_fields.append("__gen_mbo(%d, %d)" % \
459                        (field.start - dword_start, field.end - dword_start))
460                elif field.type == "address":
461                    pass
462                elif field.type == "uint":
463                    non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \
464                        (name, field.start - dword_start, field.end - dword_start))
465                elif field.is_enum_type():
466                    non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \
467                        (name, field.start - dword_start, field.end - dword_start))
468                elif field.type == "int":
469                    non_address_fields.append("__gen_sint(values->%s, %d, %d)" % \
470                        (name, field.start - dword_start, field.end - dword_start))
471                elif field.type == "bool":
472                    non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \
473                        (name, field.start - dword_start, field.end - dword_start))
474                elif field.type == "float":
475                    non_address_fields.append("__gen_float(values->%s)" % name)
476                elif field.type == "offset":
477                    non_address_fields.append("__gen_offset(values->%s, %d, %d)" % \
478                        (name, field.start - dword_start, field.end - dword_start))
479                elif field.type == 'ufixed':
480                    non_address_fields.append("__gen_ufixed(values->%s, %d, %d, %d)" % \
481                        (name, field.start - dword_start, field.end - dword_start, field.fractional_size))
482                elif field.type == 'sfixed':
483                    non_address_fields.append("__gen_sfixed(values->%s, %d, %d, %d)" % \
484                        (name, field.start - dword_start, field.end - dword_start, field.fractional_size))
485                elif field.is_struct_type():
486                    non_address_fields.append("__gen_uint(v%d_%d, %d, %d)" % \
487                        (index, field_index, field.start - dword_start, field.end - dword_start))
488                    field_index = field_index + 1
489                else:
490                    non_address_fields.append("/* unhandled field %s, type %s */\n" % \
491                                              (name, field.type))
492
493            if non_address_fields:
494                print(" |\n".join("      " + f for f in non_address_fields) + ";")
495
496            if dw.size == 32:
497                if dw.address:
498                    print("   dw[%d] = __gen_combine_address(data, &dw[%d], values->%s, %s);" % (index, index, dw.address.name + field.dim, v))
499                continue
500
501            if dw.address:
502                v_address = "v%d_address" % index
503                print("   const uint64_t %s =\n      __gen_combine_address(data, &dw[%d], values->%s, %s);" %
504                      (v_address, index, dw.address.name + field.dim, v))
505                if len(dw.fields) > address_count:
506                    print("   dw[%d] = %s;" % (index, v_address))
507                    print("   dw[%d] = (%s >> 32) | (%s >> 32);" % (index + 1, v_address, v))
508                    continue
509                else:
510                    v = v_address
511            print("   dw[%d] = %s;" % (index, v))
512            print("   dw[%d] = %s >> 32;" % (index + 1, v))
513
514class Value(object):
515    def __init__(self, attrs):
516        self.name = safe_name(attrs["name"])
517        self.value = ast.literal_eval(attrs["value"])
518
519class Parser(object):
520    def __init__(self):
521        self.parser = xml.parsers.expat.ParserCreate()
522        self.parser.StartElementHandler = self.start_element
523        self.parser.EndElementHandler = self.end_element
524
525        self.instruction = None
526        self.structs = {}
527        # Set of enum names we've seen.
528        self.enums = set()
529        self.registers = {}
530
531    def gen_prefix(self, name):
532        if name[0] == "_":
533            return 'GEN%s%s' % (self.gen, name)
534        return 'GEN%s_%s' % (self.gen, name)
535
536    def gen_guard(self):
537        return self.gen_prefix("PACK_H")
538
539    def start_element(self, name, attrs):
540        if name == "genxml":
541            self.platform = attrs["name"]
542            self.gen = attrs["gen"].replace('.', '')
543            print(pack_header % {'license': license, 'platform': self.platform, 'guard': self.gen_guard()})
544        elif name in ("instruction", "struct", "register"):
545            if name == "instruction":
546                self.instruction = safe_name(attrs["name"])
547                self.length_bias = int(attrs["bias"])
548            elif name == "struct":
549                self.struct = safe_name(attrs["name"])
550                self.structs[attrs["name"]] = 1
551            elif name == "register":
552                self.register = safe_name(attrs["name"])
553                self.reg_num = num_from_str(attrs["num"])
554                self.registers[attrs["name"]] = 1
555            if "length" in attrs:
556                self.length = int(attrs["length"])
557                size = self.length * 32
558            else:
559                self.length = None
560                size = 0
561            self.group = Group(self, None, 0, 1, size)
562
563        elif name == "group":
564            group = Group(self, self.group,
565                          int(attrs["start"]), int(attrs["count"]), int(attrs["size"]))
566            self.group.fields.append(group)
567            self.group = group
568        elif name == "field":
569            self.group.fields.append(Field(self, attrs))
570            self.values = []
571        elif name == "enum":
572            self.values = []
573            self.enum = safe_name(attrs["name"])
574            self.enums.add(attrs["name"])
575            if "prefix" in attrs:
576                self.prefix = safe_name(attrs["prefix"])
577            else:
578                self.prefix= None
579        elif name == "value":
580            self.values.append(Value(attrs))
581
582    def end_element(self, name):
583        if name  == "instruction":
584            self.emit_instruction()
585            self.instruction = None
586            self.group = None
587        elif name == "struct":
588            self.emit_struct()
589            self.struct = None
590            self.group = None
591        elif name == "register":
592            self.emit_register()
593            self.register = None
594            self.reg_num = None
595            self.group = None
596        elif name == "group":
597            self.group = self.group.parent
598        elif name  == "field":
599            self.group.fields[-1].values = self.values
600        elif name  == "enum":
601            self.emit_enum()
602            self.enum = None
603        elif name == "genxml":
604            print('#endif /* %s */' % self.gen_guard())
605
606    def emit_template_struct(self, name, group):
607        print("struct %s {" % self.gen_prefix(name))
608        group.emit_template_struct("")
609        print("};\n")
610
611    def emit_pack_function(self, name, group):
612        name = self.gen_prefix(name)
613        print(textwrap.dedent("""\
614            static inline void
615            %s_pack(__attribute__((unused)) __gen_user_data *data,
616                  %s__attribute__((unused)) void * restrict dst,
617                  %s__attribute__((unused)) const struct %s * restrict values)
618            {""") % (name, ' ' * len(name), ' ' * len(name), name))
619
620        (dwords, length) = group.collect_dwords_and_length()
621        if length:
622            # Cast dst to make header C++ friendly
623            print("   uint32_t * restrict dw = (uint32_t * restrict) dst;")
624
625            group.emit_pack_function(dwords, length)
626
627        print("}\n")
628
629    def emit_instruction(self):
630        name = self.instruction
631        if not self.length is None:
632            print('#define %-33s %6d' %
633                  (self.gen_prefix(name + "_length"), self.length))
634        print('#define %-33s %6d' %
635              (self.gen_prefix(name + "_length_bias"), self.length_bias))
636
637        default_fields = []
638        for field in self.group.fields:
639            if not isinstance(field, Field):
640                continue
641            if field.default is None:
642                continue
643            default_fields.append("   .%-35s = %6d" % (field.name, field.default))
644
645        if default_fields:
646            print('#define %-40s\\' % (self.gen_prefix(name + '_header')))
647            print(",  \\\n".join(default_fields))
648            print('')
649
650        self.emit_template_struct(self.instruction, self.group)
651
652        self.emit_pack_function(self.instruction, self.group)
653
654    def emit_register(self):
655        name = self.register
656        if not self.reg_num is None:
657            print('#define %-33s 0x%04x' %
658                  (self.gen_prefix(name + "_num"), self.reg_num))
659
660        if not self.length is None:
661            print('#define %-33s %6d' %
662                  (self.gen_prefix(name + "_length"), self.length))
663
664        self.emit_template_struct(self.register, self.group)
665        self.emit_pack_function(self.register, self.group)
666
667    def emit_struct(self):
668        name = self.struct
669        if not self.length is None:
670            print('#define %-33s %6d' %
671                  (self.gen_prefix(name + "_length"), self.length))
672
673        self.emit_template_struct(self.struct, self.group)
674        self.emit_pack_function(self.struct, self.group)
675
676    def emit_enum(self):
677        print('enum %s {' % self.gen_prefix(self.enum))
678        for value in self.values:
679            if self.prefix:
680                name = self.prefix + "_" + value.name
681            else:
682                name = value.name
683            print('   %-36s = %6d,' % (name.upper(), value.value))
684        print('};\n')
685
686    def parse(self, filename):
687        file = open(filename, "rb")
688        self.parser.ParseFile(file)
689        file.close()
690
691if len(sys.argv) < 2:
692    print("No input xml file specified")
693    sys.exit(1)
694
695input_file = sys.argv[1]
696
697p = Parser()
698p.parse(input_file)
699