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