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