Path: blob/21.2-virgl/src/broadcom/cle/gen_pack_header.py
4560 views
#encoding=utf-812# Copyright (C) 2016 Intel Corporation3# Copyright (C) 2016 Broadcom4#5# Permission is hereby granted, free of charge, to any person obtaining a6# copy of this software and associated documentation files (the "Software"),7# to deal in the Software without restriction, including without limitation8# the rights to use, copy, modify, merge, publish, distribute, sublicense,9# and/or sell copies of the Software, and to permit persons to whom the10# Software is furnished to do so, subject to the following conditions:11#12# The above copyright notice and this permission notice (including the next13# paragraph) shall be included in all copies or substantial portions of the14# Software.15#16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,18# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL19# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING21# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS22# IN THE SOFTWARE.2324from __future__ import (25absolute_import, division, print_function, unicode_literals26)27import xml.parsers.expat28import re29import sys30import copy3132license = """/* Generated code, see v3d_packet_v21.xml, v3d_packet_v33.xml and gen_pack_header.py */33"""3435pack_header = """%(license)s3637/* Packets, enums and structures for %(platform)s.38*39* This file has been generated, do not hand edit.40*/4142#ifndef %(guard)s43#define %(guard)s4445#include "cle/v3d_packet_helpers.h"4647"""4849def to_alphanum(name):50substitutions = {51' ': '_',52'/': '_',53'[': '',54']': '',55'(': '',56')': '',57'-': '_',58':': '',59'.': '',60',': '',61'=': '',62'>': '',63'#': '',64'&': '',65'*': '',66'"': '',67'+': '',68'\'': '',69}7071for i, j in substitutions.items():72name = name.replace(i, j)7374return name7576def safe_name(name):77name = to_alphanum(name)78if not name[0].isalpha():79name = '_' + name8081return name8283def prefixed_upper_name(prefix, name):84if prefix:85name = prefix + "_" + name86return safe_name(name).upper()8788def num_from_str(num_str):89if num_str.lower().startswith('0x'):90return int(num_str, base=16)91else:92assert(not num_str.startswith('0') and 'octals numbers not allowed')93return int(num_str)9495class Field(object):96ufixed_pattern = re.compile(r"u(\d+)\.(\d+)")97sfixed_pattern = re.compile(r"s(\d+)\.(\d+)")9899def __init__(self, parser, attrs):100self.parser = parser101if "name" in attrs:102self.name = safe_name(attrs["name"]).lower()103104if str(attrs["start"]).endswith("b"):105self.start = int(attrs["start"][:-1]) * 8106else:107self.start = int(attrs["start"])108# packet <field> entries in XML start from the bit after the109# opcode, so shift everything up by 8 since we'll also have a110# Field for the opcode.111if not parser.struct:112self.start += 8113114self.end = self.start + int(attrs["size"]) - 1115self.type = attrs["type"]116117if self.type == 'bool' and self.start != self.end:118print("#error Field {} has bool type but more than one bit of size".format(self.name));119120if "prefix" in attrs:121self.prefix = safe_name(attrs["prefix"]).upper()122else:123self.prefix = None124125if "default" in attrs:126self.default = int(attrs["default"])127else:128self.default = None129130if "minus_one" in attrs:131assert(attrs["minus_one"] == "true")132self.minus_one = True133else:134self.minus_one = False135136ufixed_match = Field.ufixed_pattern.match(self.type)137if ufixed_match:138self.type = 'ufixed'139self.fractional_size = int(ufixed_match.group(2))140141sfixed_match = Field.sfixed_pattern.match(self.type)142if sfixed_match:143self.type = 'sfixed'144self.fractional_size = int(sfixed_match.group(2))145146def emit_template_struct(self, dim):147if self.type == 'address':148type = '__gen_address_type'149elif self.type == 'bool':150type = 'bool'151elif self.type == 'float':152type = 'float'153elif self.type == 'f187':154type = 'float'155elif self.type == 'ufixed':156type = 'float'157elif self.type == 'sfixed':158type = 'float'159elif self.type == 'uint' and self.end - self.start > 32:160type = 'uint64_t'161elif self.type == 'offset':162type = 'uint64_t'163elif self.type == 'int':164type = 'int32_t'165elif self.type == 'uint':166type = 'uint32_t'167elif self.type in self.parser.structs:168type = 'struct ' + self.parser.gen_prefix(safe_name(self.type))169elif self.type in self.parser.enums:170type = 'enum ' + self.parser.gen_prefix(safe_name(self.type))171elif self.type == 'mbo':172return173else:174print("#error unhandled type: %s" % self.type)175type = "uint32_t"176177print(" %-36s %s%s;" % (type, self.name, dim))178179for value in self.values:180name = prefixed_upper_name(self.prefix, value.name)181print("#define %-40s %d" % (name, value.value))182183def overlaps(self, field):184return self != field and max(self.start, field.start) <= min(self.end, field.end)185186187class Group(object):188def __init__(self, parser, parent, start, count):189self.parser = parser190self.parent = parent191self.start = start192self.count = count193self.size = 0194self.fields = []195self.min_ver = 0196self.max_ver = 0197198def emit_template_struct(self, dim):199if self.count == 0:200print(" /* variable length fields follow */")201else:202if self.count > 1:203dim = "%s[%d]" % (dim, self.count)204205for field in self.fields:206field.emit_template_struct(dim)207208class Byte:209def __init__(self):210self.size = 8211self.fields = []212self.address = None213214def collect_bytes(self, bytes):215for field in self.fields:216first_byte = field.start // 8217last_byte = field.end // 8218219for b in range(first_byte, last_byte + 1):220if not b in bytes:221bytes[b] = self.Byte()222223bytes[b].fields.append(field)224225if field.type == "address":226# assert bytes[index].address == None227bytes[b].address = field228229def emit_pack_function(self, start):230# Determine number of bytes in this group.231self.length = max(field.end // 8 for field in self.fields) + 1232233bytes = {}234self.collect_bytes(bytes)235236relocs_emitted = set()237memcpy_fields = set()238239for field in self.fields:240if field.minus_one:241print(" assert(values->%s >= 1);" % field.name)242243for index in range(self.length):244# Handle MBZ bytes245if not index in bytes:246print(" cl[%2d] = 0;" % index)247continue248byte = bytes[index]249250# Call out to the driver to note our relocations. Inside of the251# packet we only store offsets within the BOs, and we store the252# handle to the packet outside. Unlike Intel genxml, we don't253# need to have the other bits that will be stored together with254# the address during the reloc process, so there's no need for the255# complicated combine_address() function.256if byte.address and byte.address not in relocs_emitted:257print(" __gen_emit_reloc(data, &values->%s);" % byte.address.name)258relocs_emitted.add(byte.address)259260# Special case: floats can't have any other fields packed into261# them (since they'd change the meaning of the float), and the262# per-byte bitshifting math below bloats the pack code for floats,263# so just copy them directly here. Also handle 16/32-bit264# uints/ints with no merged fields.265if len(byte.fields) == 1:266field = byte.fields[0]267if field.type in ["float", "uint", "int"] and field.start % 8 == 0 and field.end - field.start == 31 and not field.minus_one:268if field in memcpy_fields:269continue270271if not any(field.overlaps(scan_field) for scan_field in self.fields):272assert(field.start == index * 8)273print("")274print(" memcpy(&cl[%d], &values->%s, sizeof(values->%s));" %275(index, field.name, field.name))276memcpy_fields.add(field)277continue278279byte_start = index * 8280281v = None282prefix = " cl[%2d] =" % index283284field_index = 0285for field in byte.fields:286if field.type != "mbo":287name = field.name288289start = field.start290end = field.end291field_byte_start = (field.start // 8) * 8292start -= field_byte_start293end -= field_byte_start294extra_shift = 0295296value = "values->%s" % name297if field.minus_one:298value = "%s - 1" % value299300if field.type == "mbo":301s = "__gen_mbo(%d, %d)" % \302(start, end)303elif field.type == "address":304extra_shift = (31 - (end - start)) // 8 * 8305s = "__gen_address_offset(&values->%s)" % byte.address.name306elif field.type == "uint":307s = "__gen_uint(%s, %d, %d)" % \308(value, start, end)309elif field.type in self.parser.enums:310s = "__gen_uint(%s, %d, %d)" % \311(value, start, end)312elif field.type == "int":313s = "__gen_sint(%s, %d, %d)" % \314(value, start, end)315elif field.type == "bool":316s = "__gen_uint(%s, %d, %d)" % \317(value, start, end)318elif field.type == "float":319s = "#error %s float value mixed in with other fields" % name320elif field.type == "f187":321s = "__gen_uint(fui(%s) >> 16, %d, %d)" % \322(value, start, end)323elif field.type == "offset":324s = "__gen_offset(%s, %d, %d)" % \325(value, start, end)326elif field.type == 'ufixed':327s = "__gen_ufixed(%s, %d, %d, %d)" % \328(value, start, end, field.fractional_size)329elif field.type == 'sfixed':330s = "__gen_sfixed(%s, %d, %d, %d)" % \331(value, start, end, field.fractional_size)332elif field.type in self.parser.structs:333s = "__gen_uint(v%d_%d, %d, %d)" % \334(index, field_index, start, end)335field_index = field_index + 1336else:337print("/* unhandled field %s, type %s */\n" % (name, field.type))338s = None339340if not s == None:341shift = byte_start - field_byte_start + extra_shift342if shift:343s = "%s >> %d" % (s, shift)344345if field == byte.fields[-1]:346print("%s %s;" % (prefix, s))347else:348print("%s %s |" % (prefix, s))349prefix = " "350351print("")352continue353354def emit_unpack_function(self, start):355for field in self.fields:356if field.type != "mbo":357convert = None358359args = []360args.append('cl')361args.append(str(start + field.start))362args.append(str(start + field.end))363364if field.type == "address":365convert = "__gen_unpack_address"366elif field.type == "uint":367convert = "__gen_unpack_uint"368elif field.type in self.parser.enums:369convert = "__gen_unpack_uint"370elif field.type == "int":371convert = "__gen_unpack_sint"372elif field.type == "bool":373convert = "__gen_unpack_uint"374elif field.type == "float":375convert = "__gen_unpack_float"376elif field.type == "f187":377convert = "__gen_unpack_f187"378elif field.type == "offset":379convert = "__gen_unpack_offset"380elif field.type == 'ufixed':381args.append(str(field.fractional_size))382convert = "__gen_unpack_ufixed"383elif field.type == 'sfixed':384args.append(str(field.fractional_size))385convert = "__gen_unpack_sfixed"386else:387print("/* unhandled field %s, type %s */\n" % (field.name, field.type))388s = None389390plusone = ""391if field.minus_one:392plusone = " + 1"393print(" values->%s = %s(%s)%s;" % \394(field.name, convert, ', '.join(args), plusone))395396class Value(object):397def __init__(self, attrs):398self.name = attrs["name"]399self.value = int(attrs["value"])400401class Parser(object):402def __init__(self, ver):403self.parser = xml.parsers.expat.ParserCreate()404self.parser.StartElementHandler = self.start_element405self.parser.EndElementHandler = self.end_element406407self.packet = None408self.struct = None409self.structs = {}410# Set of enum names we've seen.411self.enums = set()412self.registers = {}413self.ver = ver414415def gen_prefix(self, name):416if name[0] == "_":417return 'V3D%s%s' % (self.ver, name)418else:419return 'V3D%s_%s' % (self.ver, name)420421def gen_guard(self):422return self.gen_prefix("PACK_H")423424def attrs_version_valid(self, attrs):425if "min_ver" in attrs and self.ver < attrs["min_ver"]:426return False427428if "max_ver" in attrs and self.ver > attrs["max_ver"]:429return False430431return True432433def group_enabled(self):434if self.group.min_ver != 0 and self.ver < self.group.min_ver:435return False436437if self.group.max_ver != 0 and self.ver > self.group.max_ver:438return False439440return True441442def start_element(self, name, attrs):443if name == "vcxml":444self.platform = "V3D {}.{}".format(self.ver[0], self.ver[1])445print(pack_header % {'license': license, 'platform': self.platform, 'guard': self.gen_guard()})446elif name in ("packet", "struct", "register"):447default_field = None448449object_name = self.gen_prefix(safe_name(attrs["name"].upper()))450if name == "packet":451self.packet = object_name452453# Add a fixed Field for the opcode. We only make <field>s in454# the XML for the fields listed in the spec, and all of those455# start from bit 0 after of the opcode.456default_field = {457"name" : "opcode",458"default" : attrs["code"],459"type" : "uint",460"start" : -8,461"size" : 8,462}463elif name == "struct":464self.struct = object_name465self.structs[attrs["name"]] = 1466elif name == "register":467self.register = object_name468self.reg_num = num_from_str(attrs["num"])469self.registers[attrs["name"]] = 1470471self.group = Group(self, None, 0, 1)472if default_field:473field = Field(self, default_field)474field.values = []475self.group.fields.append(field)476477if "min_ver" in attrs:478self.group.min_ver = attrs["min_ver"]479if "max_ver" in attrs:480self.group.max_ver = attrs["max_ver"]481482elif name == "field":483self.group.fields.append(Field(self, attrs))484self.values = []485elif name == "enum":486self.values = []487self.enum = safe_name(attrs["name"])488self.enums.add(attrs["name"])489self.enum_enabled = self.attrs_version_valid(attrs)490if "prefix" in attrs:491self.prefix = attrs["prefix"]492else:493self.prefix= None494elif name == "value":495if self.attrs_version_valid(attrs):496self.values.append(Value(attrs))497498def end_element(self, name):499if name == "packet":500self.emit_packet()501self.packet = None502self.group = None503elif name == "struct":504self.emit_struct()505self.struct = None506self.group = None507elif name == "register":508self.emit_register()509self.register = None510self.reg_num = None511self.group = None512elif name == "field":513self.group.fields[-1].values = self.values514elif name == "enum":515if self.enum_enabled:516self.emit_enum()517self.enum = None518elif name == "vcxml":519print('#endif /* %s */' % self.gen_guard())520521def emit_template_struct(self, name, group):522print("struct %s {" % name)523group.emit_template_struct("")524print("};\n")525526def emit_pack_function(self, name, group):527print("static inline void\n%s_pack(__gen_user_data *data, uint8_t * restrict cl,\n%sconst struct %s * restrict values)\n{" %528(name, ' ' * (len(name) + 6), name))529530group.emit_pack_function(0)531532print("}\n")533534print('#define %-33s %6d' %535(name + "_length", self.group.length))536537def emit_unpack_function(self, name, group):538print("#ifdef __gen_unpack_address")539print("static inline void")540print("%s_unpack(const uint8_t * restrict cl,\n%sstruct %s * restrict values)\n{" %541(name, ' ' * (len(name) + 8), name))542543group.emit_unpack_function(0)544545print("}\n#endif\n")546547def emit_header(self, name):548default_fields = []549for field in self.group.fields:550if not type(field) is Field:551continue552if field.default == None:553continue554default_fields.append(" .%-35s = %6d" % (field.name, field.default))555556print('#define %-40s\\' % (name + '_header'))557print(", \\\n".join(default_fields))558print('')559560def emit_packet(self):561if not self.group_enabled():562return563564name = self.packet565566assert(self.group.fields[0].name == "opcode")567print('#define %-33s %6d' %568(name + "_opcode", self.group.fields[0].default))569570self.emit_header(name)571self.emit_template_struct(self.packet, self.group)572self.emit_pack_function(self.packet, self.group)573self.emit_unpack_function(self.packet, self.group)574575print('')576577def emit_register(self):578if not self.group_enabled():579return580581name = self.register582if not self.reg_num == None:583print('#define %-33s 0x%04x' %584(self.gen_prefix(name + "_num"), self.reg_num))585586self.emit_template_struct(self.register, self.group)587self.emit_pack_function(self.register, self.group)588self.emit_unpack_function(self.register, self.group)589590def emit_struct(self):591if not self.group_enabled():592return593594name = self.struct595596self.emit_header(name)597self.emit_template_struct(self.struct, self.group)598self.emit_pack_function(self.struct, self.group)599self.emit_unpack_function(self.struct, self.group)600601print('')602603def emit_enum(self):604print('enum %s {' % self.gen_prefix(self.enum))605for value in self.values:606name = value.name607if self.prefix:608name = self.prefix + "_" + name609name = safe_name(name).upper()610print(' % -36s = %6d,' % (name, value.value))611print('};\n')612613def parse(self, filename):614file = open(filename, "rb")615self.parser.ParseFile(file)616file.close()617618if len(sys.argv) < 2:619print("No input xml file specified")620sys.exit(1)621622input_file = sys.argv[1]623624p = Parser(sys.argv[2])625p.parse(input_file)626627628