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