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