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