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