1#!/usr/bin/python3 2# 3# Copyright © 2019-2024 Google, Inc. 4# 5# SPDX-License-Identifier: MIT 6 7import xml.parsers.expat 8import sys 9import os 10import collections 11import argparse 12import time 13import datetime 14import re 15 16class Error(Exception): 17 def __init__(self, message): 18 self.message = message 19 20class Enum(object): 21 def __init__(self, name): 22 self.name = name 23 self.values = [] 24 25 def has_name(self, name): 26 for (n, value) in self.values: 27 if n == name: 28 return True 29 return False 30 31 def names(self): 32 return [n for (n, value) in self.values] 33 34 def dump(self): 35 use_hex = False 36 for (name, value) in self.values: 37 if value > 0x1000: 38 use_hex = True 39 40 print("enum %s {" % self.name) 41 for (name, value) in self.values: 42 if use_hex: 43 print("\t%s = 0x%08x," % (name, value)) 44 else: 45 print("\t%s = %d," % (name, value)) 46 print("};\n") 47 48 def dump_pack_struct(self): 49 pass 50 51class Field(object): 52 def __init__(self, name, low, high, shr, type, parser): 53 self.name = name 54 self.low = low 55 self.high = high 56 self.shr = shr 57 self.type = type 58 59 builtin_types = [ None, "a3xx_regid", "boolean", "uint", "hex", "int", "fixed", "ufixed", "float", "address", "waddress" ] 60 61 maxpos = parser.current_bitsize - 1 62 63 if low < 0 or low > maxpos: 64 raise parser.error("low attribute out of range: %d" % low) 65 if high < 0 or high > maxpos: 66 raise parser.error("high attribute out of range: %d" % high) 67 if high < low: 68 raise parser.error("low is greater than high: low=%d, high=%d" % (low, high)) 69 if self.type == "boolean" and not low == high: 70 raise parser.error("booleans should be 1 bit fields") 71 elif self.type == "float" and not (high - low == 31 or high - low == 15): 72 raise parser.error("floats should be 16 or 32 bit fields") 73 elif not self.type in builtin_types and not self.type in parser.enums: 74 raise parser.error("unknown type '%s'" % self.type) 75 76 def ctype(self, var_name): 77 if self.type == None: 78 type = "uint32_t" 79 val = var_name 80 elif self.type == "boolean": 81 type = "bool" 82 val = var_name 83 elif self.type == "uint" or self.type == "hex" or self.type == "a3xx_regid": 84 type = "uint32_t" 85 val = var_name 86 elif self.type == "int": 87 type = "int32_t" 88 val = var_name 89 elif self.type == "fixed": 90 type = "float" 91 val = "((int32_t)(%s * %d.0))" % (var_name, 1 << self.radix) 92 elif self.type == "ufixed": 93 type = "float" 94 val = "((uint32_t)(%s * %d.0))" % (var_name, 1 << self.radix) 95 elif self.type == "float" and self.high - self.low == 31: 96 type = "float" 97 val = "fui(%s)" % var_name 98 elif self.type == "float" and self.high - self.low == 15: 99 type = "float" 100 val = "_mesa_float_to_half(%s)" % var_name 101 elif self.type in [ "address", "waddress" ]: 102 type = "uint64_t" 103 val = var_name 104 else: 105 type = "enum %s" % self.type 106 val = var_name 107 108 if self.shr > 0: 109 val = "(%s >> %d)" % (val, self.shr) 110 111 return (type, val) 112 113def tab_to(name, value): 114 tab_count = (68 - (len(name) & ~7)) // 8 115 if tab_count <= 0: 116 tab_count = 1 117 print(name + ('\t' * tab_count) + value) 118 119def mask(low, high): 120 return ((0xffffffffffffffff >> (64 - (high + 1 - low))) << low) 121 122def field_name(reg, f): 123 if f.name: 124 name = f.name.lower() 125 else: 126 # We hit this path when a reg is defined with no bitset fields, ie. 127 # <reg32 offset="0x88db" name="RB_BLIT_DST_ARRAY_PITCH" low="0" high="28" shr="6" type="uint"/> 128 name = reg.name.lower() 129 130 if (name in [ "double", "float", "int" ]) or not (name[0].isalpha()): 131 name = "_" + name 132 133 return name 134 135# indices - array of (ctype, stride, __offsets_NAME) 136def indices_varlist(indices): 137 return ", ".join(["i%d" % i for i in range(len(indices))]) 138 139def indices_prototype(indices): 140 return ", ".join(["%s i%d" % (ctype, idx) 141 for (idx, (ctype, stride, offset)) in enumerate(indices)]) 142 143def indices_strides(indices): 144 return " + ".join(["0x%x*i%d" % (stride, idx) 145 if stride else 146 "%s(i%d)" % (offset, idx) 147 for (idx, (ctype, stride, offset)) in enumerate(indices)]) 148 149class Bitset(object): 150 def __init__(self, name, template): 151 self.name = name 152 self.inline = False 153 if template: 154 self.fields = template.fields[:] 155 else: 156 self.fields = [] 157 158 # Get address field if there is one in the bitset, else return None: 159 def get_address_field(self): 160 for f in self.fields: 161 if f.type in [ "address", "waddress" ]: 162 return f 163 return None 164 165 def dump_regpair_builder(self, reg): 166 print("#ifndef NDEBUG") 167 known_mask = 0 168 for f in self.fields: 169 known_mask |= mask(f.low, f.high) 170 if f.type in [ "boolean", "address", "waddress" ]: 171 continue 172 type, val = f.ctype("fields.%s" % field_name(reg, f)) 173 print(" assert((%-40s & 0x%08x) == 0);" % (val, 0xffffffff ^ mask(0 , f.high - f.low))) 174 print(" assert((%-40s & 0x%08x) == 0);" % ("fields.unknown", known_mask)) 175 print("#endif\n") 176 177 print(" return (struct fd_reg_pair) {") 178 if reg.array: 179 print(" .reg = REG_%s(__i)," % reg.full_name) 180 else: 181 print(" .reg = REG_%s," % reg.full_name) 182 183 print(" .value =") 184 for f in self.fields: 185 if f.type in [ "address", "waddress" ]: 186 continue 187 else: 188 type, val = f.ctype("fields.%s" % field_name(reg, f)) 189 print(" (%-40s << %2d) |" % (val, f.low)) 190 value_name = "dword" 191 if reg.bit_size == 64: 192 value_name = "qword" 193 print(" fields.unknown | fields.%s," % (value_name,)) 194 195 address = self.get_address_field() 196 if address: 197 print(" .bo = fields.bo,") 198 print(" .is_address = true,") 199 if f.type == "waddress": 200 print(" .bo_write = true,") 201 print(" .bo_offset = fields.bo_offset,") 202 print(" .bo_shift = %d," % address.shr) 203 print(" .bo_low = %d," % address.low) 204 205 print(" };") 206 207 def dump_pack_struct(self, reg=None): 208 if not reg: 209 return 210 211 prefix = reg.full_name 212 213 print("struct %s {" % prefix) 214 for f in self.fields: 215 if f.type in [ "address", "waddress" ]: 216 tab_to(" __bo_type", "bo;") 217 tab_to(" uint32_t", "bo_offset;") 218 continue 219 name = field_name(reg, f) 220 221 type, val = f.ctype("var") 222 223 tab_to(" %s" % type, "%s;" % name) 224 if reg.bit_size == 64: 225 tab_to(" uint64_t", "unknown;") 226 tab_to(" uint64_t", "qword;") 227 else: 228 tab_to(" uint32_t", "unknown;") 229 tab_to(" uint32_t", "dword;") 230 print("};\n") 231 232 if reg.array: 233 print("static inline struct fd_reg_pair\npack_%s(uint32_t __i, struct %s fields)\n{" % 234 (prefix, prefix)) 235 else: 236 print("static inline struct fd_reg_pair\npack_%s(struct %s fields)\n{" % 237 (prefix, prefix)) 238 239 self.dump_regpair_builder(reg) 240 241 print("\n}\n") 242 243 if self.get_address_field(): 244 skip = ", { .reg = 0 }" 245 else: 246 skip = "" 247 248 if reg.array: 249 print("#define %s(__i, ...) pack_%s(__i, __struct_cast(%s) { __VA_ARGS__ })%s\n" % 250 (prefix, prefix, prefix, skip)) 251 else: 252 print("#define %s(...) pack_%s(__struct_cast(%s) { __VA_ARGS__ })%s\n" % 253 (prefix, prefix, prefix, skip)) 254 255 256 def dump(self, prefix=None): 257 if prefix == None: 258 prefix = self.name 259 for f in self.fields: 260 if f.name: 261 name = prefix + "_" + f.name 262 else: 263 name = prefix 264 265 if not f.name and f.low == 0 and f.shr == 0 and not f.type in ["float", "fixed", "ufixed"]: 266 pass 267 elif f.type == "boolean" or (f.type == None and f.low == f.high): 268 tab_to("#define %s" % name, "0x%08x" % (1 << f.low)) 269 else: 270 tab_to("#define %s__MASK" % name, "0x%08x" % mask(f.low, f.high)) 271 tab_to("#define %s__SHIFT" % name, "%d" % f.low) 272 type, val = f.ctype("val") 273 274 print("static inline uint32_t %s(%s val)\n{" % (name, type)) 275 if f.shr > 0: 276 print("\tassert(!(val & 0x%x));" % mask(0, f.shr - 1)) 277 print("\treturn ((%s) << %s__SHIFT) & %s__MASK;\n}" % (val, name, name)) 278 print() 279 280class Array(object): 281 def __init__(self, attrs, domain, variant, parent, index_type): 282 if "name" in attrs: 283 self.local_name = attrs["name"] 284 else: 285 self.local_name = "" 286 self.domain = domain 287 self.variant = variant 288 self.parent = parent 289 if self.parent: 290 self.name = self.parent.name + "_" + self.local_name 291 else: 292 self.name = self.local_name 293 if "offsets" in attrs: 294 self.offsets = map(lambda i: "0x%08x" % int(i, 0), attrs["offsets"].split(",")) 295 self.fixed_offsets = True 296 elif "doffsets" in attrs: 297 self.offsets = map(lambda s: "(%s)" % s , attrs["doffsets"].split(",")) 298 self.fixed_offsets = True 299 else: 300 self.offset = int(attrs["offset"], 0) 301 self.stride = int(attrs["stride"], 0) 302 self.fixed_offsets = False 303 if "index" in attrs: 304 self.index_type = index_type 305 else: 306 self.index_type = None 307 self.length = int(attrs["length"], 0) 308 if "usage" in attrs: 309 self.usages = attrs["usage"].split(',') 310 else: 311 self.usages = None 312 313 def index_ctype(self): 314 if not self.index_type: 315 return "uint32_t" 316 else: 317 return "enum %s" % self.index_type.name 318 319 # Generate array of (ctype, stride, __offsets_NAME) 320 def indices(self): 321 if self.parent: 322 indices = self.parent.indices() 323 else: 324 indices = [] 325 if self.length != 1: 326 if self.fixed_offsets: 327 indices.append((self.index_ctype(), None, "__offset_%s" % self.local_name)) 328 else: 329 indices.append((self.index_ctype(), self.stride, None)) 330 return indices 331 332 def total_offset(self): 333 offset = 0 334 if not self.fixed_offsets: 335 offset += self.offset 336 if self.parent: 337 offset += self.parent.total_offset() 338 return offset 339 340 def dump(self): 341 proto = indices_varlist(self.indices()) 342 strides = indices_strides(self.indices()) 343 array_offset = self.total_offset() 344 if self.fixed_offsets: 345 print("static inline uint32_t __offset_%s(%s idx)" % (self.local_name, self.index_ctype())) 346 print("{\n\tswitch (idx) {") 347 if self.index_type: 348 for val, offset in zip(self.index_type.names(), self.offsets): 349 print("\t\tcase %s: return %s;" % (val, offset)) 350 else: 351 for idx, offset in enumerate(self.offsets): 352 print("\t\tcase %d: return %s;" % (idx, offset)) 353 print("\t\tdefault: return INVALID_IDX(idx);") 354 print("\t}\n}") 355 if proto == '': 356 tab_to("#define REG_%s_%s" % (self.domain, self.name), "0x%08x\n" % array_offset) 357 else: 358 tab_to("#define REG_%s_%s(%s)" % (self.domain, self.name, proto), "(0x%08x + %s )\n" % (array_offset, strides)) 359 360 def dump_pack_struct(self): 361 pass 362 363 def dump_regpair_builder(self): 364 pass 365 366class Reg(object): 367 def __init__(self, attrs, domain, array, bit_size): 368 self.name = attrs["name"] 369 self.domain = domain 370 self.array = array 371 self.offset = int(attrs["offset"], 0) 372 self.type = None 373 self.bit_size = bit_size 374 if array: 375 self.name = array.name + "_" + self.name 376 self.full_name = self.domain + "_" + self.name 377 if "stride" in attrs: 378 self.stride = int(attrs["stride"], 0) 379 self.length = int(attrs["length"], 0) 380 else: 381 self.stride = None 382 self.length = None 383 384 # Generate array of (ctype, stride, __offsets_NAME) 385 def indices(self): 386 if self.array: 387 indices = self.array.indices() 388 else: 389 indices = [] 390 if self.stride: 391 indices.append(("uint32_t", self.stride, None)) 392 return indices 393 394 def total_offset(self): 395 if self.array: 396 return self.array.total_offset() + self.offset 397 else: 398 return self.offset 399 400 def dump(self): 401 proto = indices_prototype(self.indices()) 402 strides = indices_strides(self.indices()) 403 offset = self.total_offset() 404 if proto == '': 405 tab_to("#define REG_%s" % self.full_name, "0x%08x" % offset) 406 else: 407 print("static inline uint32_t REG_%s(%s) { return 0x%08x + %s; }" % (self.full_name, proto, offset, strides)) 408 409 if self.bitset.inline: 410 self.bitset.dump(self.full_name) 411 412 def dump_pack_struct(self): 413 if self.bitset.inline: 414 self.bitset.dump_pack_struct(self) 415 416 def dump_regpair_builder(self): 417 if self.bitset.inline: 418 self.bitset.dump_regpair_builder(self) 419 420 def dump_py(self): 421 print("\tREG_%s = 0x%08x" % (self.full_name, self.offset)) 422 423 424class Parser(object): 425 def __init__(self): 426 self.current_array = None 427 self.current_domain = None 428 self.current_prefix = None 429 self.current_prefix_type = None 430 self.current_stripe = None 431 self.current_bitset = None 432 self.current_bitsize = 32 433 # The varset attribute on the domain specifies the enum which 434 # specifies all possible hw variants: 435 self.current_varset = None 436 # Regs that have multiple variants.. we only generated the C++ 437 # template based struct-packers for these 438 self.variant_regs = {} 439 # Information in which contexts regs are used, to be used in 440 # debug options 441 self.usage_regs = collections.defaultdict(list) 442 self.bitsets = {} 443 self.enums = {} 444 self.variants = set() 445 self.file = [] 446 self.xml_files = [] 447 self.copyright_year = None 448 self.authors = [] 449 self.license = None 450 451 def error(self, message): 452 parser, filename = self.stack[-1] 453 return Error("%s:%d:%d: %s" % (filename, parser.CurrentLineNumber, parser.CurrentColumnNumber, message)) 454 455 def prefix(self, variant=None): 456 if self.current_prefix_type == "variant" and variant: 457 return variant 458 elif self.current_stripe: 459 return self.current_stripe + "_" + self.current_domain 460 elif self.current_prefix: 461 return self.current_prefix + "_" + self.current_domain 462 else: 463 return self.current_domain 464 465 def parse_field(self, name, attrs): 466 try: 467 if "pos" in attrs: 468 high = low = int(attrs["pos"], 0) 469 elif "high" in attrs and "low" in attrs: 470 high = int(attrs["high"], 0) 471 low = int(attrs["low"], 0) 472 else: 473 low = 0 474 high = self.current_bitsize - 1 475 476 if "type" in attrs: 477 type = attrs["type"] 478 else: 479 type = None 480 481 if "shr" in attrs: 482 shr = int(attrs["shr"], 0) 483 else: 484 shr = 0 485 486 b = Field(name, low, high, shr, type, self) 487 488 if type == "fixed" or type == "ufixed": 489 b.radix = int(attrs["radix"], 0) 490 491 self.current_bitset.fields.append(b) 492 except ValueError as e: 493 raise self.error(e) 494 495 def parse_varset(self, attrs): 496 # Inherit the varset from the enclosing domain if not overriden: 497 varset = self.current_varset 498 if "varset" in attrs: 499 varset = self.enums[attrs["varset"]] 500 return varset 501 502 def parse_variants(self, attrs): 503 if not "variants" in attrs: 504 return None 505 variant = attrs["variants"].split(",")[0] 506 if "-" in variant: 507 variant = variant[:variant.index("-")] 508 509 varset = self.parse_varset(attrs) 510 511 assert varset.has_name(variant) 512 513 return variant 514 515 def add_all_variants(self, reg, attrs, parent_variant): 516 # TODO this should really handle *all* variants, including dealing 517 # with open ended ranges (ie. "A2XX,A4XX-") (we have the varset 518 # enum now to make that possible) 519 variant = self.parse_variants(attrs) 520 if not variant: 521 variant = parent_variant 522 523 if reg.name not in self.variant_regs: 524 self.variant_regs[reg.name] = {} 525 else: 526 # All variants must be same size: 527 v = next(iter(self.variant_regs[reg.name])) 528 assert self.variant_regs[reg.name][v].bit_size == reg.bit_size 529 530 self.variant_regs[reg.name][variant] = reg 531 532 def add_all_usages(self, reg, usages): 533 if not usages: 534 return 535 536 for usage in usages: 537 self.usage_regs[usage].append(reg) 538 539 self.variants.add(reg.domain) 540 541 def do_validate(self, schemafile): 542 if not self.validate: 543 return 544 545 try: 546 from lxml import etree 547 548 parser, filename = self.stack[-1] 549 dirname = os.path.dirname(filename) 550 551 # we expect this to look like <namespace url> schema.xsd.. I think 552 # technically it is supposed to be just a URL, but that doesn't 553 # quite match up to what we do.. Just skip over everything up to 554 # and including the first whitespace character: 555 schemafile = schemafile[schemafile.rindex(" ")+1:] 556 557 # this is a bit cheezy, but the xml file to validate could be 558 # in a child director, ie. we don't really know where the schema 559 # file is, the way the rnn C code does. So if it doesn't exist 560 # just look one level up 561 if not os.path.exists(dirname + "/" + schemafile): 562 schemafile = "../" + schemafile 563 564 if not os.path.exists(dirname + "/" + schemafile): 565 raise self.error("Cannot find schema for: " + filename) 566 567 xmlschema_doc = etree.parse(dirname + "/" + schemafile) 568 xmlschema = etree.XMLSchema(xmlschema_doc) 569 570 xml_doc = etree.parse(filename) 571 if not xmlschema.validate(xml_doc): 572 error_str = str(xmlschema.error_log.filter_from_errors()[0]) 573 raise self.error("Schema validation failed for: " + filename + "\n" + error_str) 574 except ImportError as e: 575 if self.validate: 576 raise e 577 578 print("lxml not found, skipping validation", file=sys.stderr) 579 580 def do_parse(self, filename): 581 filepath = os.path.abspath(filename) 582 if filepath in self.xml_files: 583 return 584 self.xml_files.append(filepath) 585 file = open(filename, "rb") 586 parser = xml.parsers.expat.ParserCreate() 587 self.stack.append((parser, filename)) 588 parser.StartElementHandler = self.start_element 589 parser.EndElementHandler = self.end_element 590 parser.CharacterDataHandler = self.character_data 591 parser.buffer_text = True 592 parser.ParseFile(file) 593 self.stack.pop() 594 file.close() 595 596 def parse(self, rnn_path, filename, validate): 597 self.path = rnn_path 598 self.stack = [] 599 self.validate = validate 600 self.do_parse(filename) 601 602 def parse_reg(self, attrs, bit_size): 603 self.current_bitsize = bit_size 604 if "type" in attrs and attrs["type"] in self.bitsets: 605 bitset = self.bitsets[attrs["type"]] 606 if bitset.inline: 607 self.current_bitset = Bitset(attrs["name"], bitset) 608 self.current_bitset.inline = True 609 else: 610 self.current_bitset = bitset 611 else: 612 self.current_bitset = Bitset(attrs["name"], None) 613 self.current_bitset.inline = True 614 if "type" in attrs: 615 self.parse_field(None, attrs) 616 617 variant = self.parse_variants(attrs) 618 if not variant and self.current_array: 619 variant = self.current_array.variant 620 621 self.current_reg = Reg(attrs, self.prefix(variant), self.current_array, bit_size) 622 self.current_reg.bitset = self.current_bitset 623 624 if len(self.stack) == 1: 625 self.file.append(self.current_reg) 626 627 if variant is not None: 628 self.add_all_variants(self.current_reg, attrs, variant) 629 630 usages = None 631 if "usage" in attrs: 632 usages = attrs["usage"].split(',') 633 elif self.current_array: 634 usages = self.current_array.usages 635 636 self.add_all_usages(self.current_reg, usages) 637 638 def start_element(self, name, attrs): 639 self.cdata = "" 640 if name == "import": 641 filename = attrs["file"] 642 self.do_parse(os.path.join(self.path, filename)) 643 elif name == "domain": 644 self.current_domain = attrs["name"] 645 if "prefix" in attrs: 646 self.current_prefix = self.parse_variants(attrs) 647 self.current_prefix_type = attrs["prefix"] 648 else: 649 self.current_prefix = None 650 self.current_prefix_type = None 651 if "varset" in attrs: 652 self.current_varset = self.enums[attrs["varset"]] 653 elif name == "stripe": 654 self.current_stripe = self.parse_variants(attrs) 655 elif name == "enum": 656 self.current_enum_value = 0 657 self.current_enum = Enum(attrs["name"]) 658 self.enums[attrs["name"]] = self.current_enum 659 if len(self.stack) == 1: 660 self.file.append(self.current_enum) 661 elif name == "value": 662 if "value" in attrs: 663 value = int(attrs["value"], 0) 664 else: 665 value = self.current_enum_value 666 self.current_enum.values.append((attrs["name"], value)) 667 elif name == "reg32": 668 self.parse_reg(attrs, 32) 669 elif name == "reg64": 670 self.parse_reg(attrs, 64) 671 elif name == "array": 672 self.current_bitsize = 32 673 variant = self.parse_variants(attrs) 674 index_type = self.enums[attrs["index"]] if "index" in attrs else None 675 self.current_array = Array(attrs, self.prefix(variant), variant, self.current_array, index_type) 676 if len(self.stack) == 1: 677 self.file.append(self.current_array) 678 elif name == "bitset": 679 self.current_bitset = Bitset(attrs["name"], None) 680 if "inline" in attrs and attrs["inline"] == "yes": 681 self.current_bitset.inline = True 682 self.bitsets[self.current_bitset.name] = self.current_bitset 683 if len(self.stack) == 1 and not self.current_bitset.inline: 684 self.file.append(self.current_bitset) 685 elif name == "bitfield" and self.current_bitset: 686 self.parse_field(attrs["name"], attrs) 687 elif name == "database": 688 self.do_validate(attrs["xsi:schemaLocation"]) 689 elif name == "copyright": 690 self.copyright_year = attrs["year"] 691 elif name == "author": 692 self.authors.append(attrs["name"] + " <" + attrs["email"] + "> " + attrs["name"]) 693 694 def end_element(self, name): 695 if name == "domain": 696 self.current_domain = None 697 self.current_prefix = None 698 self.current_prefix_type = None 699 elif name == "stripe": 700 self.current_stripe = None 701 elif name == "bitset": 702 self.current_bitset = None 703 elif name == "reg32": 704 self.current_reg = None 705 elif name == "array": 706 self.current_array = self.current_array.parent 707 elif name == "enum": 708 self.current_enum = None 709 elif name == "license": 710 self.license = self.cdata 711 712 def character_data(self, data): 713 self.cdata += data 714 715 def dump_reg_usages(self): 716 d = collections.defaultdict(list) 717 for usage, regs in self.usage_regs.items(): 718 for reg in regs: 719 variants = self.variant_regs.get(reg.name) 720 if variants: 721 for variant, vreg in variants.items(): 722 if reg == vreg: 723 d[(usage, variant)].append(reg) 724 else: 725 for variant in self.variants: 726 d[(usage, variant)].append(reg) 727 728 print("#ifdef __cplusplus") 729 730 for usage, regs in self.usage_regs.items(): 731 print("template<chip CHIP> constexpr inline uint16_t %s_REGS[] = {};" % (usage.upper())) 732 733 for (usage, variant), regs in d.items(): 734 offsets = [] 735 736 for reg in regs: 737 if reg.array: 738 for i in range(reg.array.length): 739 offsets.append(reg.array.offset + reg.offset + i * reg.array.stride) 740 if reg.bit_size == 64: 741 offsets.append(offsets[-1] + 1) 742 else: 743 offsets.append(reg.offset) 744 if reg.bit_size == 64: 745 offsets.append(offsets[-1] + 1) 746 747 offsets.sort() 748 749 print("template<> constexpr inline uint16_t %s_REGS<%s>[] = {" % (usage.upper(), variant)) 750 for offset in offsets: 751 print("\t%s," % hex(offset)) 752 print("};") 753 754 print("#endif") 755 756 def dump(self): 757 enums = [] 758 bitsets = [] 759 regs = [] 760 for e in self.file: 761 if isinstance(e, Enum): 762 enums.append(e) 763 elif isinstance(e, Bitset): 764 bitsets.append(e) 765 else: 766 regs.append(e) 767 768 for e in enums + bitsets + regs: 769 e.dump() 770 771 self.dump_reg_usages() 772 773 774 def dump_regs_py(self): 775 regs = [] 776 for e in self.file: 777 if isinstance(e, Reg): 778 regs.append(e) 779 780 for e in regs: 781 e.dump_py() 782 783 784 def dump_reg_variants(self, regname, variants): 785 # Don't bother for things that only have a single variant: 786 if len(variants) == 1: 787 return 788 print("#ifdef __cplusplus") 789 print("struct __%s {" % regname) 790 # TODO be more clever.. we should probably figure out which 791 # fields have the same type in all variants (in which they 792 # appear) and stuff everything else in a variant specific 793 # sub-structure. 794 seen_fields = [] 795 bit_size = 32 796 array = False 797 address = None 798 for variant in variants.keys(): 799 print(" /* %s fields: */" % variant) 800 reg = variants[variant] 801 bit_size = reg.bit_size 802 array = reg.array 803 for f in reg.bitset.fields: 804 fld_name = field_name(reg, f) 805 if fld_name in seen_fields: 806 continue 807 seen_fields.append(fld_name) 808 name = fld_name.lower() 809 if f.type in [ "address", "waddress" ]: 810 if address: 811 continue 812 address = f 813 tab_to(" __bo_type", "bo;") 814 tab_to(" uint32_t", "bo_offset;") 815 continue 816 type, val = f.ctype("var") 817 tab_to(" %s" %type, "%s;" %name) 818 print(" /* fallback fields: */") 819 if bit_size == 64: 820 tab_to(" uint64_t", "unknown;") 821 tab_to(" uint64_t", "qword;") 822 else: 823 tab_to(" uint32_t", "unknown;") 824 tab_to(" uint32_t", "dword;") 825 print("};") 826 # TODO don't hardcode the varset enum name 827 varenum = "chip" 828 print("template <%s %s>" % (varenum, varenum.upper())) 829 print("static inline struct fd_reg_pair") 830 xtra = "" 831 xtravar = "" 832 if array: 833 xtra = "int __i, " 834 xtravar = "__i, " 835 print("__%s(%sstruct __%s fields) {" % (regname, xtra, regname)) 836 for variant in variants.keys(): 837 print(" if (%s == %s) {" % (varenum.upper(), variant)) 838 reg = variants[variant] 839 reg.dump_regpair_builder() 840 print(" } else") 841 print(" assert(!\"invalid variant\");") 842 print("}") 843 844 if bit_size == 64: 845 skip = ", { .reg = 0 }" 846 else: 847 skip = "" 848 849 print("#define %s(VARIANT, %s...) __%s<VARIANT>(%s{__VA_ARGS__})%s" % (regname, xtravar, regname, xtravar, skip)) 850 print("#endif /* __cplusplus */") 851 852 def dump_structs(self): 853 for e in self.file: 854 e.dump_pack_struct() 855 856 for regname in self.variant_regs: 857 self.dump_reg_variants(regname, self.variant_regs[regname]) 858 859 860def dump_c(args, guard, func): 861 p = Parser() 862 863 try: 864 p.parse(args.rnn, args.xml, args.validate) 865 except Error as e: 866 print(e, file=sys.stderr) 867 exit(1) 868 869 print("#ifndef %s\n#define %s\n" % (guard, guard)) 870 871 print("""/* Autogenerated file, DO NOT EDIT manually! 872 873This file was generated by the rules-ng-ng gen_header.py tool in this git repository: 874http://gitlab.freedesktop.org/mesa/mesa/ 875git clone https://gitlab.freedesktop.org/mesa/mesa.git 876 877The rules-ng-ng source files this header was generated from are: 878""") 879 maxlen = 0 880 for filepath in p.xml_files: 881 new_filepath = re.sub("^.+drivers","drivers",filepath) 882 maxlen = max(maxlen, len(new_filepath)) 883 for filepath in p.xml_files: 884 pad = " " * (maxlen - len(new_filepath)) 885 filesize = str(os.path.getsize(filepath)) 886 filesize = " " * (7 - len(filesize)) + filesize 887 filetime = time.ctime(os.path.getmtime(filepath)) 888 print("- " + new_filepath + pad + " (" + filesize + " bytes, from <stripped>)") 889 if p.copyright_year: 890 current_year = str(datetime.date.today().year) 891 print() 892 print("Copyright (C) %s-%s by the following authors:" % (p.copyright_year, current_year)) 893 for author in p.authors: 894 print("- " + author) 895 if p.license: 896 print(p.license) 897 print("*/") 898 899 print() 900 print("#ifdef __KERNEL__") 901 print("#include <linux/bug.h>") 902 print("#define assert(x) BUG_ON(!(x))") 903 print("#else") 904 print("#include <assert.h>") 905 print("#endif") 906 print() 907 908 print("#ifdef __cplusplus") 909 print("#define __struct_cast(X)") 910 print("#else") 911 print("#define __struct_cast(X) (struct X)") 912 print("#endif") 913 print() 914 915 func(p) 916 917 print("\n#endif /* %s */" % guard) 918 919 920def dump_c_defines(args): 921 guard = str.replace(os.path.basename(args.xml), '.', '_').upper() 922 dump_c(args, guard, lambda p: p.dump()) 923 924 925def dump_c_pack_structs(args): 926 guard = str.replace(os.path.basename(args.xml), '.', '_').upper() + '_STRUCTS' 927 dump_c(args, guard, lambda p: p.dump_structs()) 928 929 930def dump_py_defines(args): 931 p = Parser() 932 933 try: 934 p.parse(args.rnn, args.xml) 935 except Error as e: 936 print(e, file=sys.stderr) 937 exit(1) 938 939 file_name = os.path.splitext(os.path.basename(args.xml))[0] 940 941 print("from enum import IntEnum") 942 print("class %sRegs(IntEnum):" % file_name.upper()) 943 944 os.path.basename(args.xml) 945 946 p.dump_regs_py() 947 948 949def main(): 950 parser = argparse.ArgumentParser() 951 parser.add_argument('--rnn', type=str, required=True) 952 parser.add_argument('--xml', type=str, required=True) 953 parser.add_argument('--validate', default=False, action='store_true') 954 parser.add_argument('--no-validate', dest='validate', action='store_false') 955 956 subparsers = parser.add_subparsers() 957 subparsers.required = True 958 959 parser_c_defines = subparsers.add_parser('c-defines') 960 parser_c_defines.set_defaults(func=dump_c_defines) 961 962 parser_c_pack_structs = subparsers.add_parser('c-pack-structs') 963 parser_c_pack_structs.set_defaults(func=dump_c_pack_structs) 964 965 parser_py_defines = subparsers.add_parser('py-defines') 966 parser_py_defines.set_defaults(func=dump_py_defines) 967 968 args = parser.parse_args() 969 args.func(args) 970 971 972if __name__ == '__main__': 973 main() 974