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