]> Git Repo - linux.git/blob - drivers/gpu/drm/msm/registers/gen_header.py
Linux 6.14-rc3
[linux.git] / drivers / gpu / drm / msm / registers / gen_header.py
1 #!/usr/bin/python3
2 #
3 # Copyright © 2019-2024 Google, Inc.
4 #
5 # SPDX-License-Identifier: MIT
6
7 import xml.parsers.expat
8 import sys
9 import os
10 import collections
11 import argparse
12 import time
13 import datetime
14
15 class Error(Exception):
16         def __init__(self, message):
17                 self.message = message
18
19 class 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
50 class 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
112 def 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
118 def mask(low, high):
119         return ((0xffffffffffffffff >> (64 - (high + 1 - low))) << low)
120
121 def 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)
135 def indices_varlist(indices):
136         return ", ".join(["i%d" % i for i in range(len(indices))])
137
138 def indices_prototype(indices):
139         return ", ".join(["%s i%d" % (ctype, idx)
140                         for (idx, (ctype, stride, offset)) in  enumerate(indices)])
141
142 def 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
148 class 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
279 class 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
365 class 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
423 class 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
859 def 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
872 This file was generated by the rules-ng-ng gen_header.py tool in this git repository:
873 http://gitlab.freedesktop.org/mesa/mesa/
874 git clone https://gitlab.freedesktop.org/mesa/mesa.git
875
876 The 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
918 def 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
923 def 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
928 def 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
947 def 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
970 if __name__ == '__main__':
971         main()
This page took 0.092099 seconds and 4 git commands to generate.