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