xref: /linux/drivers/gpu/drm/msm/registers/gen_header.py (revision 5f2b6c5f6b692c696a232d12c43b8e41c0d393b9)
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