972 lines · python
1#!/usr/bin/python32#3# Copyright © 2019-2024 Google, Inc.4#5# SPDX-License-Identifier: MIT6 7import xml.parsers.expat8import sys9import os10import collections11import argparse12import time13import datetime14 15class Error(Exception):16 def __init__(self, message):17 self.message = message18 19class Enum(object):20 def __init__(self, name):21 self.name = name22 self.values = []23 24 def has_name(self, name):25 for (n, value) in self.values:26 if n == name:27 return True28 return False29 30 def names(self):31 return [n for (n, value) in self.values]32 33 def dump(self):34 use_hex = False35 for (name, value) in self.values:36 if value > 0x1000:37 use_hex = True38 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):48 pass49 50class Field(object):51 def __init__(self, name, low, high, shr, type, parser):52 self.name = name53 self.low = low54 self.high = high55 self.shr = shr56 self.type = type57 58 builtin_types = [ None, "a3xx_regid", "boolean", "uint", "hex", "int", "fixed", "ufixed", "float", "address", "waddress" ]59 60 maxpos = parser.current_bitsize - 161 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 not self.type in builtin_types and not self.type in parser.enums:73 raise parser.error("unknown type '%s'" % self.type)74 75 def ctype(self, var_name):76 if self.type == None:77 type = "uint32_t"78 val = var_name79 elif self.type == "boolean":80 type = "bool"81 val = var_name82 elif self.type == "uint" or self.type == "hex" or self.type == "a3xx_regid":83 type = "uint32_t"84 val = var_name85 elif self.type == "int":86 type = "int32_t"87 val = var_name88 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_name97 elif self.type == "float" and self.high - self.low == 15:98 type = "float"99 val = "_mesa_float_to_half(%s)" % var_name100 elif self.type in [ "address", "waddress" ]:101 type = "uint64_t"102 val = var_name103 else:104 type = "enum %s" % self.type105 val = var_name106 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)) // 8114 if tab_count <= 0:115 tab_count = 1116 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_BLIT_DST_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 = "_" + name131 132 return name133 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 else145 "%s(i%d)" % (offset, idx)146 for (idx, (ctype, stride, offset)) in enumerate(indices)])147 148class Bitset(object):149 def __init__(self, name, template):150 self.name = name151 self.inline = False152 if template:153 self.fields = template.fields[:]154 else:155 self.fields = []156 157 # Get address field if there is one in the bitset, else return None:158 def get_address_field(self):159 for f in self.fields:160 if f.type in [ "address", "waddress" ]:161 return f162 return None163 164 def dump_regpair_builder(self, reg):165 print("#ifndef NDEBUG")166 known_mask = 0167 for f in self.fields:168 known_mask |= mask(f.low, f.high)169 if f.type in [ "boolean", "address", "waddress" ]:170 continue171 type, val = f.ctype("fields.%s" % field_name(reg, f))172 print(" assert((%-40s & 0x%08x) == 0);" % (val, 0xffffffff ^ mask(0 , f.high - f.low)))173 print(" assert((%-40s & 0x%08x) == 0);" % ("fields.unknown", known_mask))174 print("#endif\n")175 176 print(" return (struct fd_reg_pair) {")177 if reg.array:178 print(" .reg = REG_%s(__i)," % reg.full_name)179 else:180 print(" .reg = REG_%s," % reg.full_name)181 182 print(" .value =")183 for f in self.fields:184 if f.type in [ "address", "waddress" ]:185 continue186 else:187 type, val = f.ctype("fields.%s" % field_name(reg, f))188 print(" (%-40s << %2d) |" % (val, f.low))189 value_name = "dword"190 if reg.bit_size == 64:191 value_name = "qword"192 print(" fields.unknown | fields.%s," % (value_name,))193 194 address = self.get_address_field()195 if address:196 print(" .bo = fields.bo,")197 print(" .is_address = true,")198 if f.type == "waddress":199 print(" .bo_write = true,")200 print(" .bo_offset = fields.bo_offset,")201 print(" .bo_shift = %d," % address.shr)202 print(" .bo_low = %d," % address.low)203 204 print(" };")205 206 def dump_pack_struct(self, reg=None):207 if not reg:208 return209 210 prefix = reg.full_name211 212 print("struct %s {" % prefix)213 for f in self.fields:214 if f.type in [ "address", "waddress" ]:215 tab_to(" __bo_type", "bo;")216 tab_to(" uint32_t", "bo_offset;")217 continue218 name = field_name(reg, f)219 220 type, val = f.ctype("var")221 222 tab_to(" %s" % type, "%s;" % name)223 if reg.bit_size == 64:224 tab_to(" uint64_t", "unknown;")225 tab_to(" uint64_t", "qword;")226 else:227 tab_to(" uint32_t", "unknown;")228 tab_to(" uint32_t", "dword;")229 print("};\n")230 231 if reg.array:232 print("static inline struct fd_reg_pair\npack_%s(uint32_t __i, struct %s fields)\n{" %233 (prefix, prefix))234 else:235 print("static inline struct fd_reg_pair\npack_%s(struct %s fields)\n{" %236 (prefix, prefix))237 238 self.dump_regpair_builder(reg)239 240 print("\n}\n")241 242 if self.get_address_field():243 skip = ", { .reg = 0 }"244 else:245 skip = ""246 247 if reg.array:248 print("#define %s(__i, ...) pack_%s(__i, __struct_cast(%s) { __VA_ARGS__ })%s\n" %249 (prefix, prefix, prefix, skip))250 else:251 print("#define %s(...) pack_%s(__struct_cast(%s) { __VA_ARGS__ })%s\n" %252 (prefix, prefix, prefix, skip))253 254 255 def dump(self, prefix=None):256 if prefix == None:257 prefix = self.name258 for f in self.fields:259 if f.name:260 name = prefix + "_" + f.name261 else:262 name = prefix263 264 if not f.name and f.low == 0 and f.shr == 0 and not f.type in ["float", "fixed", "ufixed"]:265 pass266 elif f.type == "boolean" or (f.type == None and f.low == f.high):267 tab_to("#define %s" % name, "0x%08x" % (1 << f.low))268 else:269 tab_to("#define %s__MASK" % name, "0x%08x" % mask(f.low, f.high))270 tab_to("#define %s__SHIFT" % name, "%d" % f.low)271 type, val = f.ctype("val")272 273 print("static inline uint32_t %s(%s val)\n{" % (name, type))274 if f.shr > 0:275 print("\tassert(!(val & 0x%x));" % mask(0, f.shr - 1))276 print("\treturn ((%s) << %s__SHIFT) & %s__MASK;\n}" % (val, name, name))277 print()278 279class Array(object):280 def __init__(self, attrs, domain, variant, parent, index_type):281 if "name" in attrs:282 self.local_name = attrs["name"]283 else:284 self.local_name = ""285 self.domain = domain286 self.variant = variant287 self.parent = parent288 if self.parent:289 self.name = self.parent.name + "_" + self.local_name290 else:291 self.name = self.local_name292 if "offsets" in attrs:293 self.offsets = map(lambda i: "0x%08x" % int(i, 0), attrs["offsets"].split(","))294 self.fixed_offsets = True295 elif "doffsets" in attrs:296 self.offsets = map(lambda s: "(%s)" % s , attrs["doffsets"].split(","))297 self.fixed_offsets = True298 else:299 self.offset = int(attrs["offset"], 0)300 self.stride = int(attrs["stride"], 0)301 self.fixed_offsets = False302 if "index" in attrs:303 self.index_type = index_type304 else:305 self.index_type = None306 self.length = int(attrs["length"], 0)307 if "usage" in attrs:308 self.usages = attrs["usage"].split(',')309 else:310 self.usages = None311 312 def index_ctype(self):313 if not self.index_type:314 return "uint32_t"315 else:316 return "enum %s" % self.index_type.name317 318 # Generate array of (ctype, stride, __offsets_NAME)319 def indices(self):320 if self.parent:321 indices = self.parent.indices()322 else:323 indices = []324 if self.length != 1:325 if self.fixed_offsets:326 indices.append((self.index_ctype(), None, "__offset_%s" % self.local_name))327 else:328 indices.append((self.index_ctype(), self.stride, None))329 return indices330 331 def total_offset(self):332 offset = 0333 if not self.fixed_offsets:334 offset += self.offset335 if self.parent:336 offset += self.parent.total_offset()337 return offset338 339 def dump(self):340 proto = indices_varlist(self.indices())341 strides = indices_strides(self.indices())342 array_offset = self.total_offset()343 if self.fixed_offsets:344 print("static inline uint32_t __offset_%s(%s idx)" % (self.local_name, self.index_ctype()))345 print("{\n\tswitch (idx) {")346 if self.index_type:347 for val, offset in zip(self.index_type.names(), self.offsets):348 print("\t\tcase %s: return %s;" % (val, offset))349 else:350 for idx, offset in enumerate(self.offsets):351 print("\t\tcase %d: return %s;" % (idx, offset))352 print("\t\tdefault: return INVALID_IDX(idx);")353 print("\t}\n}")354 if proto == '':355 tab_to("#define REG_%s_%s" % (self.domain, self.name), "0x%08x\n" % array_offset)356 else:357 tab_to("#define REG_%s_%s(%s)" % (self.domain, self.name, proto), "(0x%08x + %s )\n" % (array_offset, strides))358 359 def dump_pack_struct(self):360 pass361 362 def dump_regpair_builder(self):363 pass364 365class Reg(object):366 def __init__(self, attrs, domain, array, bit_size):367 self.name = attrs["name"]368 self.domain = domain369 self.array = array370 self.offset = int(attrs["offset"], 0)371 self.type = None372 self.bit_size = bit_size373 if array:374 self.name = array.name + "_" + self.name375 self.full_name = self.domain + "_" + self.name376 if "stride" in attrs:377 self.stride = int(attrs["stride"], 0)378 self.length = int(attrs["length"], 0)379 else:380 self.stride = None381 self.length = None382 383 # Generate array of (ctype, stride, __offsets_NAME)384 def indices(self):385 if self.array:386 indices = self.array.indices()387 else:388 indices = []389 if self.stride:390 indices.append(("uint32_t", self.stride, None))391 return indices392 393 def total_offset(self):394 if self.array:395 return self.array.total_offset() + self.offset396 else:397 return self.offset398 399 def dump(self):400 proto = indices_prototype(self.indices())401 strides = indices_strides(self.indices())402 offset = self.total_offset()403 if proto == '':404 tab_to("#define REG_%s" % self.full_name, "0x%08x" % offset)405 else:406 print("static inline uint32_t REG_%s(%s) { return 0x%08x + %s; }" % (self.full_name, proto, offset, strides))407 408 if self.bitset.inline:409 self.bitset.dump(self.full_name)410 411 def dump_pack_struct(self):412 if self.bitset.inline:413 self.bitset.dump_pack_struct(self)414 415 def dump_regpair_builder(self):416 if self.bitset.inline:417 self.bitset.dump_regpair_builder(self)418 419 def dump_py(self):420 print("\tREG_%s = 0x%08x" % (self.full_name, self.offset))421 422 423class Parser(object):424 def __init__(self):425 self.current_array = None426 self.current_domain = None427 self.current_prefix = None428 self.current_prefix_type = None429 self.current_stripe = None430 self.current_bitset = None431 self.current_bitsize = 32432 # The varset attribute on the domain specifies the enum which433 # specifies all possible hw variants:434 self.current_varset = None435 # Regs that have multiple variants.. we only generated the C++436 # template based struct-packers for these437 self.variant_regs = {}438 # Information in which contexts regs are used, to be used in439 # debug options440 self.usage_regs = collections.defaultdict(list)441 self.bitsets = {}442 self.enums = {}443 self.variants = set()444 self.file = []445 self.xml_files = []446 self.copyright_year = None447 self.authors = []448 self.license = None449 450 def error(self, message):451 parser, filename = self.stack[-1]452 return Error("%s:%d:%d: %s" % (filename, parser.CurrentLineNumber, parser.CurrentColumnNumber, message))453 454 def prefix(self, variant=None):455 if self.current_prefix_type == "variant" and variant:456 return variant457 elif self.current_stripe:458 return self.current_stripe + "_" + self.current_domain459 elif self.current_prefix:460 return self.current_prefix + "_" + self.current_domain461 else:462 return self.current_domain463 464 def parse_field(self, name, attrs):465 try:466 if "pos" in attrs:467 high = low = int(attrs["pos"], 0)468 elif "high" in attrs and "low" in attrs:469 high = int(attrs["high"], 0)470 low = int(attrs["low"], 0)471 else:472 low = 0473 high = self.current_bitsize - 1474 475 if "type" in attrs:476 type = attrs["type"]477 else:478 type = None479 480 if "shr" in attrs:481 shr = int(attrs["shr"], 0)482 else:483 shr = 0484 485 b = Field(name, low, high, shr, type, self)486 487 if type == "fixed" or type == "ufixed":488 b.radix = int(attrs["radix"], 0)489 490 self.current_bitset.fields.append(b)491 except ValueError as e:492 raise self.error(e)493 494 def parse_varset(self, attrs):495 # Inherit the varset from the enclosing domain if not overriden:496 varset = self.current_varset497 if "varset" in attrs:498 varset = self.enums[attrs["varset"]]499 return varset500 501 def parse_variants(self, attrs):502 if not "variants" in attrs:503 return None504 variant = attrs["variants"].split(",")[0]505 if "-" in variant:506 variant = variant[:variant.index("-")]507 508 varset = self.parse_varset(attrs)509 510 assert varset.has_name(variant)511 512 return variant513 514 def add_all_variants(self, reg, attrs, parent_variant):515 # TODO this should really handle *all* variants, including dealing516 # with open ended ranges (ie. "A2XX,A4XX-") (we have the varset517 # enum now to make that possible)518 variant = self.parse_variants(attrs)519 if not variant:520 variant = parent_variant521 522 if reg.name not in self.variant_regs:523 self.variant_regs[reg.name] = {}524 else:525 # All variants must be same size:526 v = next(iter(self.variant_regs[reg.name]))527 assert self.variant_regs[reg.name][v].bit_size == reg.bit_size528 529 self.variant_regs[reg.name][variant] = reg530 531 def add_all_usages(self, reg, usages):532 if not usages:533 return534 535 for usage in usages:536 self.usage_regs[usage].append(reg)537 538 self.variants.add(reg.domain)539 540 def do_validate(self, schemafile):541 if not self.validate:542 return543 544 try:545 from lxml import etree546 547 parser, filename = self.stack[-1]548 dirname = os.path.dirname(filename)549 550 # we expect this to look like <namespace url> schema.xsd.. I think551 # technically it is supposed to be just a URL, but that doesn't552 # quite match up to what we do.. Just skip over everything up to553 # and including the first whitespace character:554 schemafile = schemafile[schemafile.rindex(" ")+1:]555 556 # this is a bit cheezy, but the xml file to validate could be557 # in a child director, ie. we don't really know where the schema558 # file is, the way the rnn C code does. So if it doesn't exist559 # just look one level up560 if not os.path.exists(dirname + "/" + schemafile):561 schemafile = "../" + schemafile562 563 if not os.path.exists(dirname + "/" + schemafile):564 raise self.error("Cannot find schema for: " + filename)565 566 xmlschema_doc = etree.parse(dirname + "/" + schemafile)567 xmlschema = etree.XMLSchema(xmlschema_doc)568 569 xml_doc = etree.parse(filename)570 if not xmlschema.validate(xml_doc):571 error_str = str(xmlschema.error_log.filter_from_errors()[0])572 raise self.error("Schema validation failed for: " + filename + "\n" + error_str)573 except ImportError as e:574 if self.validate:575 raise e576 577 print("lxml not found, skipping validation", file=sys.stderr)578 579 def do_parse(self, filename):580 filepath = os.path.abspath(filename)581 if filepath in self.xml_files:582 return583 self.xml_files.append(filepath)584 file = open(filename, "rb")585 parser = xml.parsers.expat.ParserCreate()586 self.stack.append((parser, filename))587 parser.StartElementHandler = self.start_element588 parser.EndElementHandler = self.end_element589 parser.CharacterDataHandler = self.character_data590 parser.buffer_text = True591 parser.ParseFile(file)592 self.stack.pop()593 file.close()594 595 def parse(self, rnn_path, filename, validate):596 self.path = rnn_path597 self.stack = []598 self.validate = validate599 self.do_parse(filename)600 601 def parse_reg(self, attrs, bit_size):602 self.current_bitsize = bit_size603 if "type" in attrs and attrs["type"] in self.bitsets:604 bitset = self.bitsets[attrs["type"]]605 if bitset.inline:606 self.current_bitset = Bitset(attrs["name"], bitset)607 self.current_bitset.inline = True608 else:609 self.current_bitset = bitset610 else:611 self.current_bitset = Bitset(attrs["name"], None)612 self.current_bitset.inline = True613 if "type" in attrs:614 self.parse_field(None, attrs)615 616 variant = self.parse_variants(attrs)617 if not variant and self.current_array:618 variant = self.current_array.variant619 620 self.current_reg = Reg(attrs, self.prefix(variant), self.current_array, bit_size)621 self.current_reg.bitset = self.current_bitset622 623 if len(self.stack) == 1:624 self.file.append(self.current_reg)625 626 if variant is not None:627 self.add_all_variants(self.current_reg, attrs, variant)628 629 usages = None630 if "usage" in attrs:631 usages = attrs["usage"].split(',')632 elif self.current_array:633 usages = self.current_array.usages634 635 self.add_all_usages(self.current_reg, usages)636 637 def start_element(self, name, attrs):638 self.cdata = ""639 if name == "import":640 filename = attrs["file"]641 self.do_parse(os.path.join(self.path, filename))642 elif name == "domain":643 self.current_domain = attrs["name"]644 if "prefix" in attrs:645 self.current_prefix = self.parse_variants(attrs)646 self.current_prefix_type = attrs["prefix"]647 else:648 self.current_prefix = None649 self.current_prefix_type = None650 if "varset" in attrs:651 self.current_varset = self.enums[attrs["varset"]]652 elif name == "stripe":653 self.current_stripe = self.parse_variants(attrs)654 elif name == "enum":655 self.current_enum_value = 0656 self.current_enum = Enum(attrs["name"])657 self.enums[attrs["name"]] = self.current_enum658 if len(self.stack) == 1:659 self.file.append(self.current_enum)660 elif name == "value":661 if "value" in attrs:662 value = int(attrs["value"], 0)663 else:664 value = self.current_enum_value665 self.current_enum.values.append((attrs["name"], value))666 elif name == "reg32":667 self.parse_reg(attrs, 32)668 elif name == "reg64":669 self.parse_reg(attrs, 64)670 elif name == "array":671 self.current_bitsize = 32672 variant = self.parse_variants(attrs)673 index_type = self.enums[attrs["index"]] if "index" in attrs else None674 self.current_array = Array(attrs, self.prefix(variant), variant, self.current_array, index_type)675 if len(self.stack) == 1:676 self.file.append(self.current_array)677 elif name == "bitset":678 self.current_bitset = Bitset(attrs["name"], None)679 if "inline" in attrs and attrs["inline"] == "yes":680 self.current_bitset.inline = True681 self.bitsets[self.current_bitset.name] = self.current_bitset682 if len(self.stack) == 1 and not self.current_bitset.inline:683 self.file.append(self.current_bitset)684 elif name == "bitfield" and self.current_bitset:685 self.parse_field(attrs["name"], attrs)686 elif name == "database":687 self.do_validate(attrs["xsi:schemaLocation"])688 elif name == "copyright":689 self.copyright_year = attrs["year"]690 elif name == "author":691 self.authors.append(attrs["name"] + " <" + attrs["email"] + "> " + attrs["name"])692 693 def end_element(self, name):694 if name == "domain":695 self.current_domain = None696 self.current_prefix = None697 self.current_prefix_type = None698 elif name == "stripe":699 self.current_stripe = None700 elif name == "bitset":701 self.current_bitset = None702 elif name == "reg32":703 self.current_reg = None704 elif name == "array":705 self.current_array = self.current_array.parent706 elif name == "enum":707 self.current_enum = None708 elif name == "license":709 self.license = self.cdata710 711 def character_data(self, data):712 self.cdata += data713 714 def dump_reg_usages(self):715 d = collections.defaultdict(list)716 for usage, regs in self.usage_regs.items():717 for reg in regs:718 variants = self.variant_regs.get(reg.name)719 if variants:720 for variant, vreg in variants.items():721 if reg == vreg:722 d[(usage, variant)].append(reg)723 else:724 for variant in self.variants:725 d[(usage, variant)].append(reg)726 727 print("#ifdef __cplusplus")728 729 for usage, regs in self.usage_regs.items():730 print("template<chip CHIP> constexpr inline uint16_t %s_REGS[] = {};" % (usage.upper()))731 732 for (usage, variant), regs in d.items():733 offsets = []734 735 for reg in regs:736 if reg.array:737 for i in range(reg.array.length):738 offsets.append(reg.array.offset + reg.offset + i * reg.array.stride)739 if reg.bit_size == 64:740 offsets.append(offsets[-1] + 1)741 else:742 offsets.append(reg.offset)743 if reg.bit_size == 64:744 offsets.append(offsets[-1] + 1)745 746 offsets.sort()747 748 print("template<> constexpr inline uint16_t %s_REGS<%s>[] = {" % (usage.upper(), variant))749 for offset in offsets:750 print("\t%s," % hex(offset))751 print("};")752 753 print("#endif")754 755 def dump(self):756 enums = []757 bitsets = []758 regs = []759 for e in self.file:760 if isinstance(e, Enum):761 enums.append(e)762 elif isinstance(e, Bitset):763 bitsets.append(e)764 else:765 regs.append(e)766 767 for e in enums + bitsets + regs:768 e.dump()769 770 self.dump_reg_usages()771 772 773 def dump_regs_py(self):774 regs = []775 for e in self.file:776 if isinstance(e, Reg):777 regs.append(e)778 779 for e in regs:780 e.dump_py()781 782 783 def dump_reg_variants(self, regname, variants):784 # Don't bother for things that only have a single variant:785 if len(variants) == 1:786 return787 print("#ifdef __cplusplus")788 print("struct __%s {" % regname)789 # TODO be more clever.. we should probably figure out which790 # fields have the same type in all variants (in which they791 # appear) and stuff everything else in a variant specific792 # sub-structure.793 seen_fields = []794 bit_size = 32795 array = False796 address = None797 for variant in variants.keys():798 print(" /* %s fields: */" % variant)799 reg = variants[variant]800 bit_size = reg.bit_size801 array = reg.array802 for f in reg.bitset.fields:803 fld_name = field_name(reg, f)804 if fld_name in seen_fields:805 continue806 seen_fields.append(fld_name)807 name = fld_name.lower()808 if f.type in [ "address", "waddress" ]:809 if address:810 continue811 address = f812 tab_to(" __bo_type", "bo;")813 tab_to(" uint32_t", "bo_offset;")814 continue815 type, val = f.ctype("var")816 tab_to(" %s" %type, "%s;" %name)817 print(" /* fallback fields: */")818 if bit_size == 64:819 tab_to(" uint64_t", "unknown;")820 tab_to(" uint64_t", "qword;")821 else:822 tab_to(" uint32_t", "unknown;")823 tab_to(" uint32_t", "dword;")824 print("};")825 # TODO don't hardcode the varset enum name826 varenum = "chip"827 print("template <%s %s>" % (varenum, varenum.upper()))828 print("static inline struct fd_reg_pair")829 xtra = ""830 xtravar = ""831 if array:832 xtra = "int __i, "833 xtravar = "__i, "834 print("__%s(%sstruct __%s fields) {" % (regname, xtra, regname))835 for variant in variants.keys():836 print(" if (%s == %s) {" % (varenum.upper(), variant))837 reg = variants[variant]838 reg.dump_regpair_builder()839 print(" } else")840 print(" assert(!\"invalid variant\");")841 print("}")842 843 if bit_size == 64:844 skip = ", { .reg = 0 }"845 else:846 skip = ""847 848 print("#define %s(VARIANT, %s...) __%s<VARIANT>(%s{__VA_ARGS__})%s" % (regname, xtravar, regname, xtravar, skip))849 print("#endif /* __cplusplus */")850 851 def dump_structs(self):852 for e in self.file:853 e.dump_pack_struct()854 855 for regname in self.variant_regs:856 self.dump_reg_variants(regname, self.variant_regs[regname])857 858 859def dump_c(args, guard, func):860 p = Parser()861 862 try:863 p.parse(args.rnn, args.xml, args.validate)864 except Error as e:865 print(e, file=sys.stderr)866 exit(1)867 868 print("#ifndef %s\n#define %s\n" % (guard, guard))869 870 print("""/* Autogenerated file, DO NOT EDIT manually!871 872This file was generated by the rules-ng-ng gen_header.py tool in this git repository:873http://gitlab.freedesktop.org/mesa/mesa/874git clone https://gitlab.freedesktop.org/mesa/mesa.git875 876The rules-ng-ng source files this header was generated from are:877""")878 maxlen = 0879 for filepath in p.xml_files:880 maxlen = max(maxlen, len(filepath))881 for filepath in p.xml_files:882 pad = " " * (maxlen - len(filepath))883 filesize = str(os.path.getsize(filepath))884 filesize = " " * (7 - len(filesize)) + filesize885 filetime = time.ctime(os.path.getmtime(filepath))886 print("- " + filepath + pad + " (" + filesize + " bytes, from " + filetime + ")")887 if p.copyright_year:888 current_year = str(datetime.date.today().year)889 print()890 print("Copyright (C) %s-%s by the following authors:" % (p.copyright_year, current_year))891 for author in p.authors:892 print("- " + author)893 if p.license:894 print(p.license)895 print("*/")896 897 print()898 print("#ifdef __KERNEL__")899 print("#include <linux/bug.h>")900 print("#define assert(x) BUG_ON(!(x))")901 print("#else")902 print("#include <assert.h>")903 print("#endif")904 print()905 906 print("#ifdef __cplusplus")907 print("#define __struct_cast(X)")908 print("#else")909 print("#define __struct_cast(X) (struct X)")910 print("#endif")911 print()912 913 func(p)914 915 print("\n#endif /* %s */" % guard)916 917 918def dump_c_defines(args):919 guard = str.replace(os.path.basename(args.xml), '.', '_').upper()920 dump_c(args, guard, lambda p: p.dump())921 922 923def dump_c_pack_structs(args):924 guard = str.replace(os.path.basename(args.xml), '.', '_').upper() + '_STRUCTS'925 dump_c(args, guard, lambda p: p.dump_structs())926 927 928def dump_py_defines(args):929 p = Parser()930 931 try:932 p.parse(args.rnn, args.xml)933 except Error as e:934 print(e, file=sys.stderr)935 exit(1)936 937 file_name = os.path.splitext(os.path.basename(args.xml))[0]938 939 print("from enum import IntEnum")940 print("class %sRegs(IntEnum):" % file_name.upper())941 942 os.path.basename(args.xml)943 944 p.dump_regs_py()945 946 947def main():948 parser = argparse.ArgumentParser()949 parser.add_argument('--rnn', type=str, required=True)950 parser.add_argument('--xml', type=str, required=True)951 parser.add_argument('--validate', default=False, action='store_true')952 parser.add_argument('--no-validate', dest='validate', action='store_false')953 954 subparsers = parser.add_subparsers()955 subparsers.required = True956 957 parser_c_defines = subparsers.add_parser('c-defines')958 parser_c_defines.set_defaults(func=dump_c_defines)959 960 parser_c_pack_structs = subparsers.add_parser('c-pack-structs')961 parser_c_pack_structs.set_defaults(func=dump_c_pack_structs)962 963 parser_py_defines = subparsers.add_parser('py-defines')964 parser_py_defines.set_defaults(func=dump_py_defines)965 966 args = parser.parse_args()967 args.func(args)968 969 970if __name__ == '__main__':971 main()972