Loading...
Note: File does not exist in v4.6.
1#!/usr/bin/python3
2#
3# Copyright © 2019-2024 Google, Inc.
4#
5# SPDX-License-Identifier: MIT
6
7import xml.parsers.expat
8import sys
9import os
10import collections
11import argparse
12import time
13import datetime
14
15class Error(Exception):
16 def __init__(self, message):
17 self.message = message
18
19class Enum(object):
20 def __init__(self, name):
21 self.name = name
22 self.values = []
23
24 def has_name(self, name):
25 for (n, value) in self.values:
26 if n == name:
27 return True
28 return False
29
30 def names(self):
31 return [n for (n, value) in self.values]
32
33 def dump(self):
34 use_hex = False
35 for (name, value) in self.values:
36 if value > 0x1000:
37 use_hex = True
38
39 print("enum %s {" % self.name)
40 for (name, value) in self.values:
41 if use_hex:
42 print("\t%s = 0x%08x," % (name, value))
43 else:
44 print("\t%s = %d," % (name, value))
45 print("};\n")
46
47 def dump_pack_struct(self):
48 pass
49
50class Field(object):
51 def __init__(self, name, low, high, shr, type, parser):
52 self.name = name
53 self.low = low
54 self.high = high
55 self.shr = shr
56 self.type = type
57
58 builtin_types = [ None, "a3xx_regid", "boolean", "uint", "hex", "int", "fixed", "ufixed", "float", "address", "waddress" ]
59
60 maxpos = parser.current_bitsize - 1
61
62 if low < 0 or low > maxpos:
63 raise parser.error("low attribute out of range: %d" % low)
64 if high < 0 or high > maxpos:
65 raise parser.error("high attribute out of range: %d" % high)
66 if high < low:
67 raise parser.error("low is greater than high: low=%d, high=%d" % (low, high))
68 if self.type == "boolean" and not low == high:
69 raise parser.error("booleans should be 1 bit fields")
70 elif self.type == "float" and not (high - low == 31 or high - low == 15):
71 raise parser.error("floats should be 16 or 32 bit fields")
72 elif 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_name
79 elif self.type == "boolean":
80 type = "bool"
81 val = var_name
82 elif self.type == "uint" or self.type == "hex" or self.type == "a3xx_regid":
83 type = "uint32_t"
84 val = var_name
85 elif self.type == "int":
86 type = "int32_t"
87 val = var_name
88 elif self.type == "fixed":
89 type = "float"
90 val = "((int32_t)(%s * %d.0))" % (var_name, 1 << self.radix)
91 elif self.type == "ufixed":
92 type = "float"
93 val = "((uint32_t)(%s * %d.0))" % (var_name, 1 << self.radix)
94 elif self.type == "float" and self.high - self.low == 31:
95 type = "float"
96 val = "fui(%s)" % var_name
97 elif self.type == "float" and self.high - self.low == 15:
98 type = "float"
99 val = "_mesa_float_to_half(%s)" % var_name
100 elif self.type in [ "address", "waddress" ]:
101 type = "uint64_t"
102 val = var_name
103 else:
104 type = "enum %s" % self.type
105 val = var_name
106
107 if self.shr > 0:
108 val = "(%s >> %d)" % (val, self.shr)
109
110 return (type, val)
111
112def tab_to(name, value):
113 tab_count = (68 - (len(name) & ~7)) // 8
114 if tab_count <= 0:
115 tab_count = 1
116 print(name + ('\t' * tab_count) + value)
117
118def mask(low, high):
119 return ((0xffffffffffffffff >> (64 - (high + 1 - low))) << low)
120
121def field_name(reg, f):
122 if f.name:
123 name = f.name.lower()
124 else:
125 # We hit this path when a reg is defined with no bitset fields, ie.
126 # <reg32 offset="0x88db" name="RB_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 = "_" + name
131
132 return name
133
134# indices - array of (ctype, stride, __offsets_NAME)
135def indices_varlist(indices):
136 return ", ".join(["i%d" % i for i in range(len(indices))])
137
138def indices_prototype(indices):
139 return ", ".join(["%s i%d" % (ctype, idx)
140 for (idx, (ctype, stride, offset)) in enumerate(indices)])
141
142def indices_strides(indices):
143 return " + ".join(["0x%x*i%d" % (stride, idx)
144 if stride else
145 "%s(i%d)" % (offset, idx)
146 for (idx, (ctype, stride, offset)) in enumerate(indices)])
147
148class Bitset(object):
149 def __init__(self, name, template):
150 self.name = name
151 self.inline = False
152 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 f
162 return None
163
164 def dump_regpair_builder(self, reg):
165 print("#ifndef NDEBUG")
166 known_mask = 0
167 for f in self.fields:
168 known_mask |= mask(f.low, f.high)
169 if f.type in [ "boolean", "address", "waddress" ]:
170 continue
171 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 continue
186 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 return
209
210 prefix = reg.full_name
211
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 continue
218 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.name
258 for f in self.fields:
259 if f.name:
260 name = prefix + "_" + f.name
261 else:
262 name = prefix
263
264 if not f.name and f.low == 0 and f.shr == 0 and not f.type in ["float", "fixed", "ufixed"]:
265 pass
266 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 = domain
286 self.variant = variant
287 self.parent = parent
288 if self.parent:
289 self.name = self.parent.name + "_" + self.local_name
290 else:
291 self.name = self.local_name
292 if "offsets" in attrs:
293 self.offsets = map(lambda i: "0x%08x" % int(i, 0), attrs["offsets"].split(","))
294 self.fixed_offsets = True
295 elif "doffsets" in attrs:
296 self.offsets = map(lambda s: "(%s)" % s , attrs["doffsets"].split(","))
297 self.fixed_offsets = True
298 else:
299 self.offset = int(attrs["offset"], 0)
300 self.stride = int(attrs["stride"], 0)
301 self.fixed_offsets = False
302 if "index" in attrs:
303 self.index_type = index_type
304 else:
305 self.index_type = None
306 self.length = int(attrs["length"], 0)
307 if "usage" in attrs:
308 self.usages = attrs["usage"].split(',')
309 else:
310 self.usages = None
311
312 def index_ctype(self):
313 if not self.index_type:
314 return "uint32_t"
315 else:
316 return "enum %s" % self.index_type.name
317
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 indices
330
331 def total_offset(self):
332 offset = 0
333 if not self.fixed_offsets:
334 offset += self.offset
335 if self.parent:
336 offset += self.parent.total_offset()
337 return offset
338
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 pass
361
362 def dump_regpair_builder(self):
363 pass
364
365class Reg(object):
366 def __init__(self, attrs, domain, array, bit_size):
367 self.name = attrs["name"]
368 self.domain = domain
369 self.array = array
370 self.offset = int(attrs["offset"], 0)
371 self.type = None
372 self.bit_size = bit_size
373 if array:
374 self.name = array.name + "_" + self.name
375 self.full_name = self.domain + "_" + self.name
376 if "stride" in attrs:
377 self.stride = int(attrs["stride"], 0)
378 self.length = int(attrs["length"], 0)
379 else:
380 self.stride = None
381 self.length = None
382
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 indices
392
393 def total_offset(self):
394 if self.array:
395 return self.array.total_offset() + self.offset
396 else:
397 return self.offset
398
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 = None
426 self.current_domain = None
427 self.current_prefix = None
428 self.current_prefix_type = None
429 self.current_stripe = None
430 self.current_bitset = None
431 self.current_bitsize = 32
432 # The varset attribute on the domain specifies the enum which
433 # specifies all possible hw variants:
434 self.current_varset = None
435 # Regs that have multiple variants.. we only generated the C++
436 # template based struct-packers for these
437 self.variant_regs = {}
438 # Information in which contexts regs are used, to be used in
439 # debug options
440 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 = None
447 self.authors = []
448 self.license = None
449
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 variant
457 elif self.current_stripe:
458 return self.current_stripe + "_" + self.current_domain
459 elif self.current_prefix:
460 return self.current_prefix + "_" + self.current_domain
461 else:
462 return self.current_domain
463
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 = 0
473 high = self.current_bitsize - 1
474
475 if "type" in attrs:
476 type = attrs["type"]
477 else:
478 type = None
479
480 if "shr" in attrs:
481 shr = int(attrs["shr"], 0)
482 else:
483 shr = 0
484
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_varset
497 if "varset" in attrs:
498 varset = self.enums[attrs["varset"]]
499 return varset
500
501 def parse_variants(self, attrs):
502 if not "variants" in attrs:
503 return None
504 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 variant
513
514 def add_all_variants(self, reg, attrs, parent_variant):
515 # TODO this should really handle *all* variants, including dealing
516 # with open ended ranges (ie. "A2XX,A4XX-") (we have the varset
517 # enum now to make that possible)
518 variant = self.parse_variants(attrs)
519 if not variant:
520 variant = parent_variant
521
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_size
528
529 self.variant_regs[reg.name][variant] = reg
530
531 def add_all_usages(self, reg, usages):
532 if not usages:
533 return
534
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 return
543
544 try:
545 from lxml import etree
546
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 think
551 # technically it is supposed to be just a URL, but that doesn't
552 # quite match up to what we do.. Just skip over everything up to
553 # 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 be
557 # in a child director, ie. we don't really know where the schema
558 # file is, the way the rnn C code does. So if it doesn't exist
559 # just look one level up
560 if not os.path.exists(dirname + "/" + schemafile):
561 schemafile = "../" + schemafile
562
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 e
576
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 return
583 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_element
588 parser.EndElementHandler = self.end_element
589 parser.CharacterDataHandler = self.character_data
590 parser.buffer_text = True
591 parser.ParseFile(file)
592 self.stack.pop()
593 file.close()
594
595 def parse(self, rnn_path, filename, validate):
596 self.path = rnn_path
597 self.stack = []
598 self.validate = validate
599 self.do_parse(filename)
600
601 def parse_reg(self, attrs, bit_size):
602 self.current_bitsize = bit_size
603 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 = True
608 else:
609 self.current_bitset = bitset
610 else:
611 self.current_bitset = Bitset(attrs["name"], None)
612 self.current_bitset.inline = True
613 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.variant
619
620 self.current_reg = Reg(attrs, self.prefix(variant), self.current_array, bit_size)
621 self.current_reg.bitset = self.current_bitset
622
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 = None
630 if "usage" in attrs:
631 usages = attrs["usage"].split(',')
632 elif self.current_array:
633 usages = self.current_array.usages
634
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 = None
649 self.current_prefix_type = None
650 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 = 0
656 self.current_enum = Enum(attrs["name"])
657 self.enums[attrs["name"]] = self.current_enum
658 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_value
665 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 = 32
672 variant = self.parse_variants(attrs)
673 index_type = self.enums[attrs["index"]] if "index" in attrs else None
674 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 = True
681 self.bitsets[self.current_bitset.name] = self.current_bitset
682 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 = None
696 self.current_prefix = None
697 self.current_prefix_type = None
698 elif name == "stripe":
699 self.current_stripe = None
700 elif name == "bitset":
701 self.current_bitset = None
702 elif name == "reg32":
703 self.current_reg = None
704 elif name == "array":
705 self.current_array = self.current_array.parent
706 elif name == "enum":
707 self.current_enum = None
708 elif name == "license":
709 self.license = self.cdata
710
711 def character_data(self, data):
712 self.cdata += data
713
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 return
787 print("#ifdef __cplusplus")
788 print("struct __%s {" % regname)
789 # TODO be more clever.. we should probably figure out which
790 # fields have the same type in all variants (in which they
791 # appear) and stuff everything else in a variant specific
792 # sub-structure.
793 seen_fields = []
794 bit_size = 32
795 array = False
796 address = None
797 for variant in variants.keys():
798 print(" /* %s fields: */" % variant)
799 reg = variants[variant]
800 bit_size = reg.bit_size
801 array = reg.array
802 for f in reg.bitset.fields:
803 fld_name = field_name(reg, f)
804 if fld_name in seen_fields:
805 continue
806 seen_fields.append(fld_name)
807 name = fld_name.lower()
808 if f.type in [ "address", "waddress" ]:
809 if address:
810 continue
811 address = f
812 tab_to(" __bo_type", "bo;")
813 tab_to(" uint32_t", "bo_offset;")
814 continue
815 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 name
826 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.git
875
876The rules-ng-ng source files this header was generated from are:
877""")
878 maxlen = 0
879 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)) + filesize
885 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 = True
956
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()