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