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