• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#encoding=utf-8
2
3# Copyright (C) 2016 Intel Corporation
4# Copyright (C) 2016 Broadcom
5#
6# Permission is hereby granted, free of charge, to any person obtaining a
7# copy of this software and associated documentation files (the "Software"),
8# to deal in the Software without restriction, including without limitation
9# the rights to use, copy, modify, merge, publish, distribute, sublicense,
10# and/or sell copies of the Software, and to permit persons to whom the
11# Software is furnished to do so, subject to the following conditions:
12#
13# The above copyright notice and this permission notice (including the next
14# paragraph) shall be included in all copies or substantial portions of the
15# Software.
16#
17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23# IN THE SOFTWARE.
24
25from __future__ import (
26    absolute_import, division, print_function, unicode_literals
27)
28import xml.parsers.expat
29import re
30import sys
31import copy
32
33license =  """/* Generated code, see packets.xml and gen_packet_header.py */
34"""
35
36pack_header = """%(license)s
37
38/* Packets, enums and structures for %(platform)s.
39 *
40 * This file has been generated, do not hand edit.
41 */
42
43#ifndef %(guard)s
44#define %(guard)s
45
46#include "v3d_packet_helpers.h"
47
48"""
49
50def to_alphanum(name):
51    substitutions = {
52        ' ': '_',
53        '/': '_',
54        '[': '',
55        ']': '',
56        '(': '',
57        ')': '',
58        '-': '_',
59        ':': '',
60        '.': '',
61        ',': '',
62        '=': '',
63        '>': '',
64        '#': '',
65        'α': 'alpha',
66        '&': '',
67        '*': '',
68        '"': '',
69        '+': '',
70        '\'': '',
71    }
72
73    for i, j in substitutions.items():
74        name = name.replace(i, j)
75
76    return name
77
78def safe_name(name):
79    name = to_alphanum(name)
80    if not name[0].isalpha():
81        name = '_' + name
82
83    return name
84
85def prefixed_upper_name(prefix, name):
86    if prefix:
87        name = prefix + "_" + name
88    return safe_name(name).upper()
89
90def num_from_str(num_str):
91    if num_str.lower().startswith('0x'):
92        return int(num_str, base=16)
93    else:
94        assert(not num_str.startswith('0') and 'octals numbers not allowed')
95        return int(num_str)
96
97class Field(object):
98    ufixed_pattern = re.compile(r"u(\d+)\.(\d+)")
99    sfixed_pattern = re.compile(r"s(\d+)\.(\d+)")
100
101    def __init__(self, parser, attrs):
102        self.parser = parser
103        if "name" in attrs:
104            self.name = safe_name(attrs["name"]).lower()
105
106        if str(attrs["start"]).endswith("b"):
107            self.start = int(attrs["start"][:-1]) * 8
108        else:
109            self.start = int(attrs["start"])
110        # packet <field> entries in XML start from the bit after the
111        # opcode, so shift everything up by 8 since we'll also have a
112        # Field for the opcode.
113        if not parser.struct:
114            self.start += 8
115
116        self.end = self.start + int(attrs["size"]) - 1
117        self.type = attrs["type"]
118
119        if self.type == 'bool' and self.start != self.end:
120            print("#error Field {} has bool type but more than one bit of size".format(self.name));
121
122        if "prefix" in attrs:
123            self.prefix = safe_name(attrs["prefix"]).upper()
124        else:
125            self.prefix = None
126
127        if "default" in attrs:
128            self.default = int(attrs["default"])
129        else:
130            self.default = None
131
132        ufixed_match = Field.ufixed_pattern.match(self.type)
133        if ufixed_match:
134            self.type = 'ufixed'
135            self.fractional_size = int(ufixed_match.group(2))
136
137        sfixed_match = Field.sfixed_pattern.match(self.type)
138        if sfixed_match:
139            self.type = 'sfixed'
140            self.fractional_size = int(sfixed_match.group(2))
141
142    def emit_template_struct(self, dim):
143        if self.type == 'address':
144            type = '__gen_address_type'
145        elif self.type == 'bool':
146            type = 'bool'
147        elif self.type == 'float':
148            type = 'float'
149        elif self.type == 'ufixed':
150            type = 'float'
151        elif self.type == 'sfixed':
152            type = 'float'
153        elif self.type == 'uint' and self.end - self.start > 32:
154            type = 'uint64_t'
155        elif self.type == 'offset':
156            type = 'uint64_t'
157        elif self.type == 'int':
158            type = 'int32_t'
159        elif self.type == 'uint':
160            type = 'uint32_t'
161        elif self.type in self.parser.structs:
162            type = 'struct ' + self.parser.gen_prefix(safe_name(self.type))
163        elif self.type in self.parser.enums:
164            type = 'enum ' + self.parser.gen_prefix(safe_name(self.type))
165        elif self.type == 'mbo':
166            return
167        else:
168            print("#error unhandled type: %s" % self.type)
169            type = "uint32_t"
170
171        print("   %-36s %s%s;" % (type, self.name, dim))
172
173        for value in self.values:
174            name = prefixed_upper_name(self.prefix, value.name)
175            print("#define %-40s %d" % (name, value.value))
176
177    def overlaps(self, field):
178        return self != field and max(self.start, field.start) <= min(self.end, field.end)
179
180
181class Group(object):
182    def __init__(self, parser, parent, start, count):
183        self.parser = parser
184        self.parent = parent
185        self.start = start
186        self.count = count
187        self.size = 0
188        self.fields = []
189
190    def emit_template_struct(self, dim):
191        if self.count == 0:
192            print("   /* variable length fields follow */")
193        else:
194            if self.count > 1:
195                dim = "%s[%d]" % (dim, self.count)
196
197            for field in self.fields:
198                field.emit_template_struct(dim)
199
200    class Byte:
201        def __init__(self):
202            self.size = 8
203            self.fields = []
204            self.address = None
205
206    def collect_bytes(self, bytes):
207        for field in self.fields:
208            first_byte = field.start // 8
209            last_byte = field.end // 8
210
211            for b in xrange(first_byte, last_byte + 1):
212                if not b in bytes:
213                    bytes[b] = self.Byte()
214
215                bytes[b].fields.append(field)
216
217                if field.type == "address":
218                    # assert bytes[index].address == None
219                    bytes[b].address = field
220
221    def emit_pack_function(self, start):
222        # Determine number of bytes in this group.
223        self.length = max(field.end // 8 for field in self.fields) + 1
224
225        bytes = {}
226        self.collect_bytes(bytes)
227
228        relocs_emitted = set()
229        memcpy_fields = set()
230
231        for index in range(self.length):
232            # Handle MBZ bytes
233            if not index in bytes:
234                print("   cl[%2d] = 0;" % index)
235                continue
236            byte = bytes[index]
237
238            # Call out to the driver to note our relocations.  Inside of the
239            # packet we only store offsets within the BOs, and we store the
240            # handle to the packet outside.  Unlike Intel genxml, we don't
241            # need to have the other bits that will be stored together with
242            # the address during the reloc process, so there's no need for the
243            # complicated combine_address() function.
244            if byte.address and byte.address not in relocs_emitted:
245                print("   __gen_emit_reloc(data, &values->%s);" % byte.address.name)
246                relocs_emitted.add(byte.address)
247
248            # Special case: floats can't have any other fields packed into
249            # them (since they'd change the meaning of the float), and the
250            # per-byte bitshifting math below bloats the pack code for floats,
251            # so just copy them directly here.  Also handle 16/32-bit
252            # uints/ints with no merged fields.
253            if len(byte.fields) == 1:
254                field = byte.fields[0]
255                if field.type in ["float", "uint", "int"] and field.start % 8 == 0 and field.end - field.start == 31:
256                    if field in memcpy_fields:
257                        continue
258
259                    if not any(field.overlaps(scan_field) for scan_field in self.fields):
260                        assert(field.start == index * 8)
261                        print("")
262                        print("   memcpy(&cl[%d], &values->%s, sizeof(values->%s));" %
263                                (index, field.name, field.name))
264                        memcpy_fields.add(field)
265                        continue
266
267            byte_start = index * 8
268
269            v = None
270            prefix = "   cl[%2d] =" % index
271
272            field_index = 0
273            for field in byte.fields:
274                if field.type != "mbo":
275                    name = field.name
276
277                start = field.start
278                end = field.end
279                field_byte_start = (field.start // 8) * 8
280                start -= field_byte_start
281                end -= field_byte_start
282                extra_shift = 0
283
284                if field.type == "mbo":
285                    s = "__gen_mbo(%d, %d)" % \
286                        (start, end)
287                elif field.type == "address":
288                    extra_shift = (31 - (end - start)) // 8 * 8
289                    s = "__gen_address_offset(&values->%s)" % byte.address.name
290                elif field.type == "uint":
291                    s = "__gen_uint(values->%s, %d, %d)" % \
292                        (name, start, end)
293                elif field.type in self.parser.enums:
294                    s = "__gen_uint(values->%s, %d, %d)" % \
295                        (name, start, end)
296                elif field.type == "int":
297                    s = "__gen_sint(values->%s, %d, %d)" % \
298                        (name, start, end)
299                elif field.type == "bool":
300                    s = "__gen_uint(values->%s, %d, %d)" % \
301                        (name, start, end)
302                elif field.type == "float":
303                    s = "#error %s float value mixed in with other fields" % name
304                elif field.type == "offset":
305                    s = "__gen_offset(values->%s, %d, %d)" % \
306                        (name, start, end)
307                elif field.type == 'ufixed':
308                    s = "__gen_ufixed(values->%s, %d, %d, %d)" % \
309                        (name, start, end, field.fractional_size)
310                elif field.type == 'sfixed':
311                    s = "__gen_sfixed(values->%s, %d, %d, %d)" % \
312                        (name, start, end, field.fractional_size)
313                elif field.type in self.parser.structs:
314                    s = "__gen_uint(v%d_%d, %d, %d)" % \
315                        (index, field_index, start, end)
316                    field_index = field_index + 1
317                else:
318                    print("/* unhandled field %s, type %s */\n" % (name, field.type))
319                    s = None
320
321                if not s == None:
322                    shift = byte_start - field_byte_start + extra_shift
323                    if shift:
324                        s = "%s >> %d" % (s, shift)
325
326                    if field == byte.fields[-1]:
327                        print("%s %s;" % (prefix, s))
328                    else:
329                        print("%s %s |" % (prefix, s))
330                    prefix = "           "
331
332            print("")
333            continue
334
335    def emit_unpack_function(self, start):
336        for field in self.fields:
337            if field.type != "mbo":
338                convert = None
339
340                args = []
341                args.append('cl')
342                args.append(str(start + field.start))
343                args.append(str(start + field.end))
344
345                if field.type == "address":
346                    convert = "__gen_unpack_address"
347                elif field.type == "uint":
348                    convert = "__gen_unpack_uint"
349                elif field.type in self.parser.enums:
350                    convert = "__gen_unpack_uint"
351                elif field.type == "int":
352                    convert = "__gen_unpack_sint"
353                elif field.type == "bool":
354                    convert = "__gen_unpack_uint"
355                elif field.type == "float":
356                    convert = "__gen_unpack_float"
357                elif field.type == "offset":
358                    convert = "__gen_unpack_offset"
359                elif field.type == 'ufixed':
360                    args.append(str(field.fractional_size))
361                    convert = "__gen_unpack_ufixed"
362                elif field.type == 'sfixed':
363                    args.append(str(field.fractional_size))
364                    convert = "__gen_unpack_sfixed"
365                else:
366                    print("/* unhandled field %s, type %s */\n" % (field.name, field.type))
367                    s = None
368
369                print("   values->%s = %s(%s);" % \
370                      (field.name, convert, ', '.join(args)))
371
372class Value(object):
373    def __init__(self, attrs):
374        self.name = attrs["name"]
375        self.value = int(attrs["value"])
376
377class Parser(object):
378    def __init__(self):
379        self.parser = xml.parsers.expat.ParserCreate()
380        self.parser.StartElementHandler = self.start_element
381        self.parser.EndElementHandler = self.end_element
382
383        self.packet = None
384        self.struct = None
385        self.structs = {}
386        # Set of enum names we've seen.
387        self.enums = set()
388        self.registers = {}
389
390    def gen_prefix(self, name):
391        if name[0] == "_":
392            return 'V3D%s%s' % (self.ver, name)
393        else:
394            return 'V3D%s_%s' % (self.ver, name)
395
396    def gen_guard(self):
397        return self.gen_prefix("PACK_H")
398
399    def start_element(self, name, attrs):
400        if name == "vcxml":
401            self.platform = "V3D {}".format(attrs["gen"])
402            self.ver = attrs["gen"].replace('.', '')
403            print(pack_header % {'license': license, 'platform': self.platform, 'guard': self.gen_guard()})
404        elif name in ("packet", "struct", "register"):
405            default_field = None
406
407            object_name = self.gen_prefix(safe_name(attrs["name"].upper()))
408            if name == "packet":
409                self.packet = object_name
410
411                # Add a fixed Field for the opcode.  We only make <field>s in
412                # the XML for the fields listed in the spec, and all of those
413                # start from bit 0 after of the opcode.
414                default_field = {
415                    "name" : "opcode",
416                    "default" : attrs["code"],
417                    "type" : "uint",
418                    "start" : -8,
419                    "size" : 8,
420                }
421            elif name == "struct":
422                self.struct = object_name
423                self.structs[attrs["name"]] = 1
424            elif name == "register":
425                self.register = object_name
426                self.reg_num = num_from_str(attrs["num"])
427                self.registers[attrs["name"]] = 1
428
429            self.group = Group(self, None, 0, 1)
430            if default_field:
431                field = Field(self, default_field)
432                field.values = []
433                self.group.fields.append(field)
434
435        elif name == "field":
436            self.group.fields.append(Field(self, attrs))
437            self.values = []
438        elif name == "enum":
439            self.values = []
440            self.enum = safe_name(attrs["name"])
441            self.enums.add(attrs["name"])
442            if "prefix" in attrs:
443                self.prefix = attrs["prefix"]
444            else:
445                self.prefix= None
446        elif name == "value":
447            self.values.append(Value(attrs))
448
449    def end_element(self, name):
450        if name  == "packet":
451            self.emit_packet()
452            self.packet = None
453            self.group = None
454        elif name == "struct":
455            self.emit_struct()
456            self.struct = None
457            self.group = None
458        elif name == "register":
459            self.emit_register()
460            self.register = None
461            self.reg_num = None
462            self.group = None
463        elif name  == "field":
464            self.group.fields[-1].values = self.values
465        elif name  == "enum":
466            self.emit_enum()
467            self.enum = None
468        elif name == "vcxml":
469            print('#endif /* %s */' % self.gen_guard())
470
471    def emit_template_struct(self, name, group):
472        print("struct %s {" % name)
473        group.emit_template_struct("")
474        print("};\n")
475
476    def emit_pack_function(self, name, group):
477        print("static inline void\n%s_pack(__gen_user_data *data, uint8_t * restrict cl,\n%sconst struct %s * restrict values)\n{" %
478              (name, ' ' * (len(name) + 6), name))
479
480        group.emit_pack_function(0)
481
482        print("}\n")
483
484        print('#define %-33s %6d' %
485              (name + "_length", self.group.length))
486
487    def emit_unpack_function(self, name, group):
488        print("#ifdef __gen_unpack_address")
489        print("static inline void")
490        print("%s_unpack(const uint8_t * restrict cl,\n%sstruct %s * restrict values)\n{" %
491              (name, ' ' * (len(name) + 8), name))
492
493        group.emit_unpack_function(0)
494
495        print("}\n#endif\n")
496
497    def emit_header(self, name):
498        default_fields = []
499        for field in self.group.fields:
500            if not type(field) is Field:
501                continue
502            if field.default == None:
503                continue
504            default_fields.append("   .%-35s = %6d" % (field.name, field.default))
505
506        print('#define %-40s\\' % (name + '_header'))
507        print(",  \\\n".join(default_fields))
508        print('')
509
510    def emit_packet(self):
511        name = self.packet
512
513        assert(self.group.fields[0].name == "opcode")
514        print('#define %-33s %6d' %
515              (name + "_opcode", self.group.fields[0].default))
516
517        self.emit_header(name)
518        self.emit_template_struct(self.packet, self.group)
519        self.emit_pack_function(self.packet, self.group)
520        self.emit_unpack_function(self.packet, self.group)
521
522        print('')
523
524    def emit_register(self):
525        name = self.register
526        if not self.reg_num == None:
527            print('#define %-33s 0x%04x' %
528                  (self.gen_prefix(name + "_num"), self.reg_num))
529
530        self.emit_template_struct(self.register, self.group)
531        self.emit_pack_function(self.register, self.group)
532        self.emit_unpack_function(self.register, self.group)
533
534    def emit_struct(self):
535        name = self.struct
536
537        self.emit_header(name)
538        self.emit_template_struct(self.struct, self.group)
539        self.emit_pack_function(self.struct, self.group)
540        self.emit_unpack_function(self.struct, self.group)
541
542        print('')
543
544    def emit_enum(self):
545        print('enum %s {' % self.gen_prefix(self.enum))
546        for value in self.values:
547            name = value.name
548            if self.prefix:
549                name = self.prefix + "_" + name
550            name = safe_name(name).upper()
551            print('        % -36s = %6d,' % (name, value.value))
552        print('};\n')
553
554    def parse(self, filename):
555        file = open(filename, "rb")
556        self.parser.ParseFile(file)
557        file.close()
558
559if len(sys.argv) < 2:
560    print("No input xml file specified")
561    sys.exit(1)
562
563input_file = sys.argv[1]
564
565p = Parser()
566p.parse(input_file)
567