gen_pack_header.py revision 01e04c3f
1#encoding=utf-8 2 3from __future__ import ( 4 absolute_import, division, print_function, unicode_literals 5) 6import ast 7import xml.parsers.expat 8import re 9import sys 10import copy 11import textwrap 12 13license = """/* 14 * Copyright (C) 2016 Intel Corporation 15 * 16 * Permission is hereby granted, free of charge, to any person obtaining a 17 * copy of this software and associated documentation files (the "Software"), 18 * to deal in the Software without restriction, including without limitation 19 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 20 * and/or sell copies of the Software, and to permit persons to whom the 21 * Software is furnished to do so, subject to the following conditions: 22 * 23 * The above copyright notice and this permission notice (including the next 24 * paragraph) shall be included in all copies or substantial portions of the 25 * Software. 26 * 27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 30 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 32 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 33 * IN THE SOFTWARE. 34 */ 35""" 36 37pack_header = """%(license)s 38 39/* Instructions, enums and structures for %(platform)s. 40 * 41 * This file has been generated, do not hand edit. 42 */ 43 44#ifndef %(guard)s 45#define %(guard)s 46 47#include <stdio.h> 48#include <stdint.h> 49#include <stdbool.h> 50#include <assert.h> 51#include <math.h> 52 53#ifndef __gen_validate_value 54#define __gen_validate_value(x) 55#endif 56 57#ifndef __gen_field_functions 58#define __gen_field_functions 59 60#ifdef NDEBUG 61#define NDEBUG_UNUSED __attribute__((unused)) 62#else 63#define NDEBUG_UNUSED 64#endif 65 66union __gen_value { 67 float f; 68 uint32_t dw; 69}; 70 71static inline uint64_t 72__gen_mbo(uint32_t start, uint32_t end) 73{ 74 return (~0ull >> (64 - (end - start + 1))) << start; 75} 76 77static inline uint64_t 78__gen_uint(uint64_t v, uint32_t start, NDEBUG_UNUSED uint32_t end) 79{ 80 __gen_validate_value(v); 81 82#ifndef NDEBUG 83 const int width = end - start + 1; 84 if (width < 64) { 85 const uint64_t max = (1ull << width) - 1; 86 assert(v <= max); 87 } 88#endif 89 90 return v << start; 91} 92 93static inline uint64_t 94__gen_sint(int64_t v, uint32_t start, uint32_t end) 95{ 96 const int width = end - start + 1; 97 98 __gen_validate_value(v); 99 100#ifndef NDEBUG 101 if (width < 64) { 102 const int64_t max = (1ll << (width - 1)) - 1; 103 const int64_t min = -(1ll << (width - 1)); 104 assert(min <= v && v <= max); 105 } 106#endif 107 108 const uint64_t mask = ~0ull >> (64 - width); 109 110 return (v & mask) << start; 111} 112 113static inline uint64_t 114__gen_offset(uint64_t v, NDEBUG_UNUSED uint32_t start, NDEBUG_UNUSED uint32_t end) 115{ 116 __gen_validate_value(v); 117#ifndef NDEBUG 118 uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start; 119 120 assert((v & ~mask) == 0); 121#endif 122 123 return v; 124} 125 126static inline uint32_t 127__gen_float(float v) 128{ 129 __gen_validate_value(v); 130 return ((union __gen_value) { .f = (v) }).dw; 131} 132 133static inline uint64_t 134__gen_sfixed(float v, uint32_t start, uint32_t end, uint32_t fract_bits) 135{ 136 __gen_validate_value(v); 137 138 const float factor = (1 << fract_bits); 139 140#ifndef NDEBUG 141 const float max = ((1 << (end - start)) - 1) / factor; 142 const float min = -(1 << (end - start)) / factor; 143 assert(min <= v && v <= max); 144#endif 145 146 const int64_t int_val = llroundf(v * factor); 147 const uint64_t mask = ~0ull >> (64 - (end - start + 1)); 148 149 return (int_val & mask) << start; 150} 151 152static inline uint64_t 153__gen_ufixed(float v, uint32_t start, NDEBUG_UNUSED uint32_t end, uint32_t fract_bits) 154{ 155 __gen_validate_value(v); 156 157 const float factor = (1 << fract_bits); 158 159#ifndef NDEBUG 160 const float max = ((1 << (end - start + 1)) - 1) / factor; 161 const float min = 0.0f; 162 assert(min <= v && v <= max); 163#endif 164 165 const uint64_t uint_val = llroundf(v * factor); 166 167 return uint_val << start; 168} 169 170#ifndef __gen_address_type 171#error #define __gen_address_type before including this file 172#endif 173 174#ifndef __gen_user_data 175#error #define __gen_combine_address before including this file 176#endif 177 178#undef NDEBUG_UNUSED 179 180#endif 181 182""" 183 184def to_alphanum(name): 185 substitutions = { 186 ' ': '', 187 '/': '', 188 '[': '', 189 ']': '', 190 '(': '', 191 ')': '', 192 '-': '', 193 ':': '', 194 '.': '', 195 ',': '', 196 '=': '', 197 '>': '', 198 '#': '', 199 'α': 'alpha', 200 '&': '', 201 '*': '', 202 '"': '', 203 '+': '', 204 '\'': '', 205 } 206 207 for i, j in substitutions.items(): 208 name = name.replace(i, j) 209 210 return name 211 212def safe_name(name): 213 name = to_alphanum(name) 214 if not name[0].isalpha(): 215 name = '_' + name 216 217 return name 218 219def num_from_str(num_str): 220 if num_str.lower().startswith('0x'): 221 return int(num_str, base=16) 222 223 assert not num_str.startswith('0'), 'octals numbers not allowed' 224 return int(num_str) 225 226class Field(object): 227 ufixed_pattern = re.compile(r"u(\d+)\.(\d+)") 228 sfixed_pattern = re.compile(r"s(\d+)\.(\d+)") 229 230 def __init__(self, parser, attrs): 231 self.parser = parser 232 if "name" in attrs: 233 self.name = safe_name(attrs["name"]) 234 self.start = int(attrs["start"]) 235 self.end = int(attrs["end"]) 236 self.type = attrs["type"] 237 238 assert self.start <= self.end, \ 239 'field {} has end ({}) < start ({})'.format(self.name, self.end, 240 self.start) 241 if self.type == 'bool': 242 assert self.end == self.start, \ 243 'bool field ({}) is too wide'.format(self.name) 244 245 if "prefix" in attrs: 246 self.prefix = attrs["prefix"] 247 else: 248 self.prefix = None 249 250 if "default" in attrs: 251 # Base 0 recognizes 0x, 0o, 0b prefixes in addition to decimal ints. 252 self.default = int(attrs["default"], base=0) 253 else: 254 self.default = None 255 256 ufixed_match = Field.ufixed_pattern.match(self.type) 257 if ufixed_match: 258 self.type = 'ufixed' 259 self.fractional_size = int(ufixed_match.group(2)) 260 261 sfixed_match = Field.sfixed_pattern.match(self.type) 262 if sfixed_match: 263 self.type = 'sfixed' 264 self.fractional_size = int(sfixed_match.group(2)) 265 266 def is_builtin_type(self): 267 builtins = [ 'address', 'bool', 'float', 'ufixed', 268 'offset', 'sfixed', 'offset', 'int', 'uint', 'mbo' ] 269 return self.type in builtins 270 271 def is_struct_type(self): 272 return self.type in self.parser.structs 273 274 def is_enum_type(self): 275 return self.type in self.parser.enums 276 277 def emit_template_struct(self, dim): 278 if self.type == 'address': 279 type = '__gen_address_type' 280 elif self.type == 'bool': 281 type = 'bool' 282 elif self.type == 'float': 283 type = 'float' 284 elif self.type == 'ufixed': 285 type = 'float' 286 elif self.type == 'sfixed': 287 type = 'float' 288 elif self.type == 'uint' and self.end - self.start > 32: 289 type = 'uint64_t' 290 elif self.type == 'offset': 291 type = 'uint64_t' 292 elif self.type == 'int': 293 type = 'int32_t' 294 elif self.type == 'uint': 295 type = 'uint32_t' 296 elif self.is_struct_type(): 297 type = 'struct ' + self.parser.gen_prefix(safe_name(self.type)) 298 elif self.is_enum_type(): 299 type = 'enum ' + self.parser.gen_prefix(safe_name(self.type)) 300 elif self.type == 'mbo': 301 return 302 else: 303 print("#error unhandled type: %s" % self.type) 304 return 305 306 print(" %-36s %s%s;" % (type, self.name, dim)) 307 308 prefix = "" 309 if self.values and self.default is None: 310 if self.prefix: 311 prefix = self.prefix + "_" 312 313 for value in self.values: 314 print("#define %-40s %d" % (prefix + value.name, value.value)) 315 316class Group(object): 317 def __init__(self, parser, parent, start, count, size): 318 self.parser = parser 319 self.parent = parent 320 self.start = start 321 self.count = count 322 self.size = size 323 self.fields = [] 324 325 def emit_template_struct(self, dim): 326 if self.count == 0: 327 print(" /* variable length fields follow */") 328 else: 329 if self.count > 1: 330 dim = "%s[%d]" % (dim, self.count) 331 332 for field in self.fields: 333 field.emit_template_struct(dim) 334 335 class DWord: 336 def __init__(self): 337 self.size = 32 338 self.fields = [] 339 self.address = None 340 341 def collect_dwords(self, dwords, start, dim): 342 for field in self.fields: 343 if isinstance(field, Group): 344 if field.count == 1: 345 field.collect_dwords(dwords, start + field.start, dim) 346 else: 347 for i in range(field.count): 348 field.collect_dwords(dwords, 349 start + field.start + i * field.size, 350 "%s[%d]" % (dim, i)) 351 continue 352 353 index = (start + field.start) // 32 354 if not index in dwords: 355 dwords[index] = self.DWord() 356 357 clone = copy.copy(field) 358 clone.start = clone.start + start 359 clone.end = clone.end + start 360 clone.dim = dim 361 dwords[index].fields.append(clone) 362 363 if field.type == "address": 364 # assert dwords[index].address == None 365 dwords[index].address = field 366 367 # Coalesce all the dwords covered by this field. The two cases we 368 # handle are where multiple fields are in a 64 bit word (typically 369 # and address and a few bits) or where a single struct field 370 # completely covers multiple dwords. 371 while index < (start + field.end) // 32: 372 if index + 1 in dwords and not dwords[index] == dwords[index + 1]: 373 dwords[index].fields.extend(dwords[index + 1].fields) 374 dwords[index].size = 64 375 dwords[index + 1] = dwords[index] 376 index = index + 1 377 378 def collect_dwords_and_length(self): 379 dwords = {} 380 self.collect_dwords(dwords, 0, "") 381 382 # Determine number of dwords in this group. If we have a size, use 383 # that, since that'll account for MBZ dwords at the end of a group 384 # (like dword 8 on BDW+ 3DSTATE_HS). Otherwise, use the largest dword 385 # index we've seen plus one. 386 if self.size > 0: 387 length = self.size // 32 388 elif dwords: 389 length = max(dwords.keys()) + 1 390 else: 391 length = 0 392 393 return (dwords, length) 394 395 def emit_pack_function(self, dwords, length): 396 for index in range(length): 397 # Handle MBZ dwords 398 if not index in dwords: 399 print("") 400 print(" dw[%d] = 0;" % index) 401 continue 402 403 # For 64 bit dwords, we aliased the two dword entries in the dword 404 # dict it occupies. Now that we're emitting the pack function, 405 # skip the duplicate entries. 406 dw = dwords[index] 407 if index > 0 and index - 1 in dwords and dw == dwords[index - 1]: 408 continue 409 410 # Special case: only one field and it's a struct at the beginning 411 # of the dword. In this case we pack directly into the 412 # destination. This is the only way we handle embedded structs 413 # larger than 32 bits. 414 if len(dw.fields) == 1: 415 field = dw.fields[0] 416 name = field.name + field.dim 417 if field.is_struct_type() and field.start % 32 == 0: 418 print("") 419 print(" %s_pack(data, &dw[%d], &values->%s);" % 420 (self.parser.gen_prefix(safe_name(field.type)), index, name)) 421 continue 422 423 # Pack any fields of struct type first so we have integer values 424 # to the dword for those fields. 425 field_index = 0 426 for field in dw.fields: 427 if isinstance(field, Field) and field.is_struct_type(): 428 name = field.name + field.dim 429 print("") 430 print(" uint32_t v%d_%d;" % (index, field_index)) 431 print(" %s_pack(data, &v%d_%d, &values->%s);" % 432 (self.parser.gen_prefix(safe_name(field.type)), index, field_index, name)) 433 field_index = field_index + 1 434 435 print("") 436 dword_start = index * 32 437 if dw.address == None: 438 address_count = 0 439 else: 440 address_count = 1 441 442 if dw.size == 32 and dw.address == None: 443 v = None 444 print(" dw[%d] =" % index) 445 elif len(dw.fields) > address_count: 446 v = "v%d" % index 447 print(" const uint%d_t %s =" % (dw.size, v)) 448 else: 449 v = "0" 450 451 field_index = 0 452 non_address_fields = [] 453 for field in dw.fields: 454 if field.type != "mbo": 455 name = field.name + field.dim 456 457 if field.type == "mbo": 458 non_address_fields.append("__gen_mbo(%d, %d)" % \ 459 (field.start - dword_start, field.end - dword_start)) 460 elif field.type == "address": 461 pass 462 elif field.type == "uint": 463 non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \ 464 (name, field.start - dword_start, field.end - dword_start)) 465 elif field.is_enum_type(): 466 non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \ 467 (name, field.start - dword_start, field.end - dword_start)) 468 elif field.type == "int": 469 non_address_fields.append("__gen_sint(values->%s, %d, %d)" % \ 470 (name, field.start - dword_start, field.end - dword_start)) 471 elif field.type == "bool": 472 non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \ 473 (name, field.start - dword_start, field.end - dword_start)) 474 elif field.type == "float": 475 non_address_fields.append("__gen_float(values->%s)" % name) 476 elif field.type == "offset": 477 non_address_fields.append("__gen_offset(values->%s, %d, %d)" % \ 478 (name, field.start - dword_start, field.end - dword_start)) 479 elif field.type == 'ufixed': 480 non_address_fields.append("__gen_ufixed(values->%s, %d, %d, %d)" % \ 481 (name, field.start - dword_start, field.end - dword_start, field.fractional_size)) 482 elif field.type == 'sfixed': 483 non_address_fields.append("__gen_sfixed(values->%s, %d, %d, %d)" % \ 484 (name, field.start - dword_start, field.end - dword_start, field.fractional_size)) 485 elif field.is_struct_type(): 486 non_address_fields.append("__gen_uint(v%d_%d, %d, %d)" % \ 487 (index, field_index, field.start - dword_start, field.end - dword_start)) 488 field_index = field_index + 1 489 else: 490 non_address_fields.append("/* unhandled field %s, type %s */\n" % \ 491 (name, field.type)) 492 493 if non_address_fields: 494 print(" |\n".join(" " + f for f in non_address_fields) + ";") 495 496 if dw.size == 32: 497 if dw.address: 498 print(" dw[%d] = __gen_combine_address(data, &dw[%d], values->%s, %s);" % (index, index, dw.address.name + field.dim, v)) 499 continue 500 501 if dw.address: 502 v_address = "v%d_address" % index 503 print(" const uint64_t %s =\n __gen_combine_address(data, &dw[%d], values->%s, %s);" % 504 (v_address, index, dw.address.name + field.dim, v)) 505 if len(dw.fields) > address_count: 506 print(" dw[%d] = %s;" % (index, v_address)) 507 print(" dw[%d] = (%s >> 32) | (%s >> 32);" % (index + 1, v_address, v)) 508 continue 509 else: 510 v = v_address 511 print(" dw[%d] = %s;" % (index, v)) 512 print(" dw[%d] = %s >> 32;" % (index + 1, v)) 513 514class Value(object): 515 def __init__(self, attrs): 516 self.name = safe_name(attrs["name"]) 517 self.value = ast.literal_eval(attrs["value"]) 518 519class Parser(object): 520 def __init__(self): 521 self.parser = xml.parsers.expat.ParserCreate() 522 self.parser.StartElementHandler = self.start_element 523 self.parser.EndElementHandler = self.end_element 524 525 self.instruction = None 526 self.structs = {} 527 # Set of enum names we've seen. 528 self.enums = set() 529 self.registers = {} 530 531 def gen_prefix(self, name): 532 if name[0] == "_": 533 return 'GEN%s%s' % (self.gen, name) 534 return 'GEN%s_%s' % (self.gen, name) 535 536 def gen_guard(self): 537 return self.gen_prefix("PACK_H") 538 539 def start_element(self, name, attrs): 540 if name == "genxml": 541 self.platform = attrs["name"] 542 self.gen = attrs["gen"].replace('.', '') 543 print(pack_header % {'license': license, 'platform': self.platform, 'guard': self.gen_guard()}) 544 elif name in ("instruction", "struct", "register"): 545 if name == "instruction": 546 self.instruction = safe_name(attrs["name"]) 547 self.length_bias = int(attrs["bias"]) 548 elif name == "struct": 549 self.struct = safe_name(attrs["name"]) 550 self.structs[attrs["name"]] = 1 551 elif name == "register": 552 self.register = safe_name(attrs["name"]) 553 self.reg_num = num_from_str(attrs["num"]) 554 self.registers[attrs["name"]] = 1 555 if "length" in attrs: 556 self.length = int(attrs["length"]) 557 size = self.length * 32 558 else: 559 self.length = None 560 size = 0 561 self.group = Group(self, None, 0, 1, size) 562 563 elif name == "group": 564 group = Group(self, self.group, 565 int(attrs["start"]), int(attrs["count"]), int(attrs["size"])) 566 self.group.fields.append(group) 567 self.group = group 568 elif name == "field": 569 self.group.fields.append(Field(self, attrs)) 570 self.values = [] 571 elif name == "enum": 572 self.values = [] 573 self.enum = safe_name(attrs["name"]) 574 self.enums.add(attrs["name"]) 575 if "prefix" in attrs: 576 self.prefix = safe_name(attrs["prefix"]) 577 else: 578 self.prefix= None 579 elif name == "value": 580 self.values.append(Value(attrs)) 581 582 def end_element(self, name): 583 if name == "instruction": 584 self.emit_instruction() 585 self.instruction = None 586 self.group = None 587 elif name == "struct": 588 self.emit_struct() 589 self.struct = None 590 self.group = None 591 elif name == "register": 592 self.emit_register() 593 self.register = None 594 self.reg_num = None 595 self.group = None 596 elif name == "group": 597 self.group = self.group.parent 598 elif name == "field": 599 self.group.fields[-1].values = self.values 600 elif name == "enum": 601 self.emit_enum() 602 self.enum = None 603 elif name == "genxml": 604 print('#endif /* %s */' % self.gen_guard()) 605 606 def emit_template_struct(self, name, group): 607 print("struct %s {" % self.gen_prefix(name)) 608 group.emit_template_struct("") 609 print("};\n") 610 611 def emit_pack_function(self, name, group): 612 name = self.gen_prefix(name) 613 print(textwrap.dedent("""\ 614 static inline void 615 %s_pack(__attribute__((unused)) __gen_user_data *data, 616 %s__attribute__((unused)) void * restrict dst, 617 %s__attribute__((unused)) const struct %s * restrict values) 618 {""") % (name, ' ' * len(name), ' ' * len(name), name)) 619 620 (dwords, length) = group.collect_dwords_and_length() 621 if length: 622 # Cast dst to make header C++ friendly 623 print(" uint32_t * restrict dw = (uint32_t * restrict) dst;") 624 625 group.emit_pack_function(dwords, length) 626 627 print("}\n") 628 629 def emit_instruction(self): 630 name = self.instruction 631 if not self.length is None: 632 print('#define %-33s %6d' % 633 (self.gen_prefix(name + "_length"), self.length)) 634 print('#define %-33s %6d' % 635 (self.gen_prefix(name + "_length_bias"), self.length_bias)) 636 637 default_fields = [] 638 for field in self.group.fields: 639 if not isinstance(field, Field): 640 continue 641 if field.default is None: 642 continue 643 default_fields.append(" .%-35s = %6d" % (field.name, field.default)) 644 645 if default_fields: 646 print('#define %-40s\\' % (self.gen_prefix(name + '_header'))) 647 print(", \\\n".join(default_fields)) 648 print('') 649 650 self.emit_template_struct(self.instruction, self.group) 651 652 self.emit_pack_function(self.instruction, self.group) 653 654 def emit_register(self): 655 name = self.register 656 if not self.reg_num is None: 657 print('#define %-33s 0x%04x' % 658 (self.gen_prefix(name + "_num"), self.reg_num)) 659 660 if not self.length is None: 661 print('#define %-33s %6d' % 662 (self.gen_prefix(name + "_length"), self.length)) 663 664 self.emit_template_struct(self.register, self.group) 665 self.emit_pack_function(self.register, self.group) 666 667 def emit_struct(self): 668 name = self.struct 669 if not self.length is None: 670 print('#define %-33s %6d' % 671 (self.gen_prefix(name + "_length"), self.length)) 672 673 self.emit_template_struct(self.struct, self.group) 674 self.emit_pack_function(self.struct, self.group) 675 676 def emit_enum(self): 677 print('enum %s {' % self.gen_prefix(self.enum)) 678 for value in self.values: 679 if self.prefix: 680 name = self.prefix + "_" + value.name 681 else: 682 name = value.name 683 print(' %-36s = %6d,' % (name.upper(), value.value)) 684 print('};\n') 685 686 def parse(self, filename): 687 file = open(filename, "rb") 688 self.parser.ParseFile(file) 689 file.close() 690 691if len(sys.argv) < 2: 692 print("No input xml file specified") 693 sys.exit(1) 694 695input_file = sys.argv[1] 696 697p = Parser() 698p.parse(input_file) 699