brintos

brintos / linux-shallow public Read only

0
0
Text · 26.9 KiB · 3926485 Raw
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