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