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