| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971 |
- #!/usr/bin/python3
- #
- # Copyright © 2019-2024 Google, Inc.
- #
- # SPDX-License-Identifier: MIT
- import xml.parsers.expat
- import sys
- import os
- import collections
- import argparse
- import time
- import datetime
- class Error(Exception):
- def __init__(self, message):
- self.message = message
- class Enum(object):
- def __init__(self, name):
- self.name = name
- self.values = []
- def has_name(self, name):
- for (n, value) in self.values:
- if n == name:
- return True
- return False
- def names(self):
- return [n for (n, value) in self.values]
- def dump(self):
- use_hex = False
- for (name, value) in self.values:
- if value > 0x1000:
- use_hex = True
- print("enum %s {" % self.name)
- for (name, value) in self.values:
- if use_hex:
- print("\t%s = 0x%08x," % (name, value))
- else:
- print("\t%s = %d," % (name, value))
- print("};\n")
- def dump_pack_struct(self):
- pass
- class Field(object):
- def __init__(self, name, low, high, shr, type, parser):
- self.name = name
- self.low = low
- self.high = high
- self.shr = shr
- self.type = type
- builtin_types = [ None, "a3xx_regid", "boolean", "uint", "hex", "int", "fixed", "ufixed", "float", "address", "waddress" ]
- maxpos = parser.current_bitsize - 1
- if low < 0 or low > maxpos:
- raise parser.error("low attribute out of range: %d" % low)
- if high < 0 or high > maxpos:
- raise parser.error("high attribute out of range: %d" % high)
- if high < low:
- raise parser.error("low is greater than high: low=%d, high=%d" % (low, high))
- if self.type == "boolean" and not low == high:
- raise parser.error("booleans should be 1 bit fields")
- elif self.type == "float" and not (high - low == 31 or high - low == 15):
- raise parser.error("floats should be 16 or 32 bit fields")
- elif not self.type in builtin_types and not self.type in parser.enums:
- raise parser.error("unknown type '%s'" % self.type)
- def ctype(self, var_name):
- if self.type == None:
- type = "uint32_t"
- val = var_name
- elif self.type == "boolean":
- type = "bool"
- val = var_name
- elif self.type == "uint" or self.type == "hex" or self.type == "a3xx_regid":
- type = "uint32_t"
- val = var_name
- elif self.type == "int":
- type = "int32_t"
- val = var_name
- elif self.type == "fixed":
- type = "float"
- val = "((int32_t)(%s * %d.0))" % (var_name, 1 << self.radix)
- elif self.type == "ufixed":
- type = "float"
- val = "((uint32_t)(%s * %d.0))" % (var_name, 1 << self.radix)
- elif self.type == "float" and self.high - self.low == 31:
- type = "float"
- val = "fui(%s)" % var_name
- elif self.type == "float" and self.high - self.low == 15:
- type = "float"
- val = "_mesa_float_to_half(%s)" % var_name
- elif self.type in [ "address", "waddress" ]:
- type = "uint64_t"
- val = var_name
- else:
- type = "enum %s" % self.type
- val = var_name
- if self.shr > 0:
- val = "(%s >> %d)" % (val, self.shr)
- return (type, val)
- def tab_to(name, value):
- tab_count = (68 - (len(name) & ~7)) // 8
- if tab_count <= 0:
- tab_count = 1
- print(name + ('\t' * tab_count) + value)
- def mask(low, high):
- return ((0xffffffffffffffff >> (64 - (high + 1 - low))) << low)
- def field_name(reg, f):
- if f.name:
- name = f.name.lower()
- else:
- # We hit this path when a reg is defined with no bitset fields, ie.
- # <reg32 offset="0x88db" name="RB_BLIT_DST_ARRAY_PITCH" low="0" high="28" shr="6" type="uint"/>
- name = reg.name.lower()
- if (name in [ "double", "float", "int" ]) or not (name[0].isalpha()):
- name = "_" + name
- return name
- # indices - array of (ctype, stride, __offsets_NAME)
- def indices_varlist(indices):
- return ", ".join(["i%d" % i for i in range(len(indices))])
- def indices_prototype(indices):
- return ", ".join(["%s i%d" % (ctype, idx)
- for (idx, (ctype, stride, offset)) in enumerate(indices)])
- def indices_strides(indices):
- return " + ".join(["0x%x*i%d" % (stride, idx)
- if stride else
- "%s(i%d)" % (offset, idx)
- for (idx, (ctype, stride, offset)) in enumerate(indices)])
- class Bitset(object):
- def __init__(self, name, template):
- self.name = name
- self.inline = False
- if template:
- self.fields = template.fields[:]
- else:
- self.fields = []
- # Get address field if there is one in the bitset, else return None:
- def get_address_field(self):
- for f in self.fields:
- if f.type in [ "address", "waddress" ]:
- return f
- return None
- def dump_regpair_builder(self, reg):
- print("#ifndef NDEBUG")
- known_mask = 0
- for f in self.fields:
- known_mask |= mask(f.low, f.high)
- if f.type in [ "boolean", "address", "waddress" ]:
- continue
- type, val = f.ctype("fields.%s" % field_name(reg, f))
- print(" assert((%-40s & 0x%08x) == 0);" % (val, 0xffffffff ^ mask(0 , f.high - f.low)))
- print(" assert((%-40s & 0x%08x) == 0);" % ("fields.unknown", known_mask))
- print("#endif\n")
- print(" return (struct fd_reg_pair) {")
- if reg.array:
- print(" .reg = REG_%s(__i)," % reg.full_name)
- else:
- print(" .reg = REG_%s," % reg.full_name)
- print(" .value =")
- for f in self.fields:
- if f.type in [ "address", "waddress" ]:
- continue
- else:
- type, val = f.ctype("fields.%s" % field_name(reg, f))
- print(" (%-40s << %2d) |" % (val, f.low))
- value_name = "dword"
- if reg.bit_size == 64:
- value_name = "qword"
- print(" fields.unknown | fields.%s," % (value_name,))
- address = self.get_address_field()
- if address:
- print(" .bo = fields.bo,")
- print(" .is_address = true,")
- if f.type == "waddress":
- print(" .bo_write = true,")
- print(" .bo_offset = fields.bo_offset,")
- print(" .bo_shift = %d," % address.shr)
- print(" .bo_low = %d," % address.low)
- print(" };")
- def dump_pack_struct(self, reg=None):
- if not reg:
- return
- prefix = reg.full_name
- print("struct %s {" % prefix)
- for f in self.fields:
- if f.type in [ "address", "waddress" ]:
- tab_to(" __bo_type", "bo;")
- tab_to(" uint32_t", "bo_offset;")
- continue
- name = field_name(reg, f)
- type, val = f.ctype("var")
- tab_to(" %s" % type, "%s;" % name)
- if reg.bit_size == 64:
- tab_to(" uint64_t", "unknown;")
- tab_to(" uint64_t", "qword;")
- else:
- tab_to(" uint32_t", "unknown;")
- tab_to(" uint32_t", "dword;")
- print("};\n")
- if reg.array:
- print("static inline struct fd_reg_pair\npack_%s(uint32_t __i, struct %s fields)\n{" %
- (prefix, prefix))
- else:
- print("static inline struct fd_reg_pair\npack_%s(struct %s fields)\n{" %
- (prefix, prefix))
- self.dump_regpair_builder(reg)
- print("\n}\n")
- if self.get_address_field():
- skip = ", { .reg = 0 }"
- else:
- skip = ""
- if reg.array:
- print("#define %s(__i, ...) pack_%s(__i, __struct_cast(%s) { __VA_ARGS__ })%s\n" %
- (prefix, prefix, prefix, skip))
- else:
- print("#define %s(...) pack_%s(__struct_cast(%s) { __VA_ARGS__ })%s\n" %
- (prefix, prefix, prefix, skip))
- def dump(self, prefix=None):
- if prefix == None:
- prefix = self.name
- for f in self.fields:
- if f.name:
- name = prefix + "_" + f.name
- else:
- name = prefix
- if not f.name and f.low == 0 and f.shr == 0 and not f.type in ["float", "fixed", "ufixed"]:
- pass
- elif f.type == "boolean" or (f.type == None and f.low == f.high):
- tab_to("#define %s" % name, "0x%08x" % (1 << f.low))
- else:
- tab_to("#define %s__MASK" % name, "0x%08x" % mask(f.low, f.high))
- tab_to("#define %s__SHIFT" % name, "%d" % f.low)
- type, val = f.ctype("val")
- print("static inline uint32_t %s(%s val)\n{" % (name, type))
- if f.shr > 0:
- print("\tassert(!(val & 0x%x));" % mask(0, f.shr - 1))
- print("\treturn ((%s) << %s__SHIFT) & %s__MASK;\n}" % (val, name, name))
- print()
- class Array(object):
- def __init__(self, attrs, domain, variant, parent, index_type):
- if "name" in attrs:
- self.local_name = attrs["name"]
- else:
- self.local_name = ""
- self.domain = domain
- self.variant = variant
- self.parent = parent
- if self.parent:
- self.name = self.parent.name + "_" + self.local_name
- else:
- self.name = self.local_name
- if "offsets" in attrs:
- self.offsets = map(lambda i: "0x%08x" % int(i, 0), attrs["offsets"].split(","))
- self.fixed_offsets = True
- elif "doffsets" in attrs:
- self.offsets = map(lambda s: "(%s)" % s , attrs["doffsets"].split(","))
- self.fixed_offsets = True
- else:
- self.offset = int(attrs["offset"], 0)
- self.stride = int(attrs["stride"], 0)
- self.fixed_offsets = False
- if "index" in attrs:
- self.index_type = index_type
- else:
- self.index_type = None
- self.length = int(attrs["length"], 0)
- if "usage" in attrs:
- self.usages = attrs["usage"].split(',')
- else:
- self.usages = None
- def index_ctype(self):
- if not self.index_type:
- return "uint32_t"
- else:
- return "enum %s" % self.index_type.name
- # Generate array of (ctype, stride, __offsets_NAME)
- def indices(self):
- if self.parent:
- indices = self.parent.indices()
- else:
- indices = []
- if self.length != 1:
- if self.fixed_offsets:
- indices.append((self.index_ctype(), None, "__offset_%s" % self.local_name))
- else:
- indices.append((self.index_ctype(), self.stride, None))
- return indices
- def total_offset(self):
- offset = 0
- if not self.fixed_offsets:
- offset += self.offset
- if self.parent:
- offset += self.parent.total_offset()
- return offset
- def dump(self):
- proto = indices_varlist(self.indices())
- strides = indices_strides(self.indices())
- array_offset = self.total_offset()
- if self.fixed_offsets:
- print("static inline uint32_t __offset_%s(%s idx)" % (self.local_name, self.index_ctype()))
- print("{\n\tswitch (idx) {")
- if self.index_type:
- for val, offset in zip(self.index_type.names(), self.offsets):
- print("\t\tcase %s: return %s;" % (val, offset))
- else:
- for idx, offset in enumerate(self.offsets):
- print("\t\tcase %d: return %s;" % (idx, offset))
- print("\t\tdefault: return INVALID_IDX(idx);")
- print("\t}\n}")
- if proto == '':
- tab_to("#define REG_%s_%s" % (self.domain, self.name), "0x%08x\n" % array_offset)
- else:
- tab_to("#define REG_%s_%s(%s)" % (self.domain, self.name, proto), "(0x%08x + %s )\n" % (array_offset, strides))
- def dump_pack_struct(self):
- pass
- def dump_regpair_builder(self):
- pass
- class Reg(object):
- def __init__(self, attrs, domain, array, bit_size):
- self.name = attrs["name"]
- self.domain = domain
- self.array = array
- self.offset = int(attrs["offset"], 0)
- self.type = None
- self.bit_size = bit_size
- if array:
- self.name = array.name + "_" + self.name
- self.full_name = self.domain + "_" + self.name
- if "stride" in attrs:
- self.stride = int(attrs["stride"], 0)
- self.length = int(attrs["length"], 0)
- else:
- self.stride = None
- self.length = None
- # Generate array of (ctype, stride, __offsets_NAME)
- def indices(self):
- if self.array:
- indices = self.array.indices()
- else:
- indices = []
- if self.stride:
- indices.append(("uint32_t", self.stride, None))
- return indices
- def total_offset(self):
- if self.array:
- return self.array.total_offset() + self.offset
- else:
- return self.offset
- def dump(self):
- proto = indices_prototype(self.indices())
- strides = indices_strides(self.indices())
- offset = self.total_offset()
- if proto == '':
- tab_to("#define REG_%s" % self.full_name, "0x%08x" % offset)
- else:
- print("static inline uint32_t REG_%s(%s) { return 0x%08x + %s; }" % (self.full_name, proto, offset, strides))
- if self.bitset.inline:
- self.bitset.dump(self.full_name)
- def dump_pack_struct(self):
- if self.bitset.inline:
- self.bitset.dump_pack_struct(self)
- def dump_regpair_builder(self):
- if self.bitset.inline:
- self.bitset.dump_regpair_builder(self)
- def dump_py(self):
- print("\tREG_%s = 0x%08x" % (self.full_name, self.offset))
- class Parser(object):
- def __init__(self):
- self.current_array = None
- self.current_domain = None
- self.current_prefix = None
- self.current_prefix_type = None
- self.current_stripe = None
- self.current_bitset = None
- self.current_bitsize = 32
- # The varset attribute on the domain specifies the enum which
- # specifies all possible hw variants:
- self.current_varset = None
- # Regs that have multiple variants.. we only generated the C++
- # template based struct-packers for these
- self.variant_regs = {}
- # Information in which contexts regs are used, to be used in
- # debug options
- self.usage_regs = collections.defaultdict(list)
- self.bitsets = {}
- self.enums = {}
- self.variants = set()
- self.file = []
- self.xml_files = []
- self.copyright_year = None
- self.authors = []
- self.license = None
- def error(self, message):
- parser, filename = self.stack[-1]
- return Error("%s:%d:%d: %s" % (filename, parser.CurrentLineNumber, parser.CurrentColumnNumber, message))
- def prefix(self, variant=None):
- if self.current_prefix_type == "variant" and variant:
- return variant
- elif self.current_stripe:
- return self.current_stripe + "_" + self.current_domain
- elif self.current_prefix:
- return self.current_prefix + "_" + self.current_domain
- else:
- return self.current_domain
- def parse_field(self, name, attrs):
- try:
- if "pos" in attrs:
- high = low = int(attrs["pos"], 0)
- elif "high" in attrs and "low" in attrs:
- high = int(attrs["high"], 0)
- low = int(attrs["low"], 0)
- else:
- low = 0
- high = self.current_bitsize - 1
- if "type" in attrs:
- type = attrs["type"]
- else:
- type = None
- if "shr" in attrs:
- shr = int(attrs["shr"], 0)
- else:
- shr = 0
- b = Field(name, low, high, shr, type, self)
- if type == "fixed" or type == "ufixed":
- b.radix = int(attrs["radix"], 0)
- self.current_bitset.fields.append(b)
- except ValueError as e:
- raise self.error(e)
- def parse_varset(self, attrs):
- # Inherit the varset from the enclosing domain if not overriden:
- varset = self.current_varset
- if "varset" in attrs:
- varset = self.enums[attrs["varset"]]
- return varset
- def parse_variants(self, attrs):
- if not "variants" in attrs:
- return None
- variant = attrs["variants"].split(",")[0]
- if "-" in variant:
- variant = variant[:variant.index("-")]
- varset = self.parse_varset(attrs)
- assert varset.has_name(variant)
- return variant
- def add_all_variants(self, reg, attrs, parent_variant):
- # TODO this should really handle *all* variants, including dealing
- # with open ended ranges (ie. "A2XX,A4XX-") (we have the varset
- # enum now to make that possible)
- variant = self.parse_variants(attrs)
- if not variant:
- variant = parent_variant
- if reg.name not in self.variant_regs:
- self.variant_regs[reg.name] = {}
- else:
- # All variants must be same size:
- v = next(iter(self.variant_regs[reg.name]))
- assert self.variant_regs[reg.name][v].bit_size == reg.bit_size
- self.variant_regs[reg.name][variant] = reg
- def add_all_usages(self, reg, usages):
- if not usages:
- return
- for usage in usages:
- self.usage_regs[usage].append(reg)
- self.variants.add(reg.domain)
- def do_validate(self, schemafile):
- if not self.validate:
- return
- try:
- from lxml import etree
- parser, filename = self.stack[-1]
- dirname = os.path.dirname(filename)
- # we expect this to look like <namespace url> schema.xsd.. I think
- # technically it is supposed to be just a URL, but that doesn't
- # quite match up to what we do.. Just skip over everything up to
- # and including the first whitespace character:
- schemafile = schemafile[schemafile.rindex(" ")+1:]
- # this is a bit cheezy, but the xml file to validate could be
- # in a child director, ie. we don't really know where the schema
- # file is, the way the rnn C code does. So if it doesn't exist
- # just look one level up
- if not os.path.exists(dirname + "/" + schemafile):
- schemafile = "../" + schemafile
- if not os.path.exists(dirname + "/" + schemafile):
- raise self.error("Cannot find schema for: " + filename)
- xmlschema_doc = etree.parse(dirname + "/" + schemafile)
- xmlschema = etree.XMLSchema(xmlschema_doc)
- xml_doc = etree.parse(filename)
- if not xmlschema.validate(xml_doc):
- error_str = str(xmlschema.error_log.filter_from_errors()[0])
- raise self.error("Schema validation failed for: " + filename + "\n" + error_str)
- except ImportError as e:
- if self.validate:
- raise e
- print("lxml not found, skipping validation", file=sys.stderr)
- def do_parse(self, filename):
- filepath = os.path.abspath(filename)
- if filepath in self.xml_files:
- return
- self.xml_files.append(filepath)
- file = open(filename, "rb")
- parser = xml.parsers.expat.ParserCreate()
- self.stack.append((parser, filename))
- parser.StartElementHandler = self.start_element
- parser.EndElementHandler = self.end_element
- parser.CharacterDataHandler = self.character_data
- parser.buffer_text = True
- parser.ParseFile(file)
- self.stack.pop()
- file.close()
- def parse(self, rnn_path, filename, validate):
- self.path = rnn_path
- self.stack = []
- self.validate = validate
- self.do_parse(filename)
- def parse_reg(self, attrs, bit_size):
- self.current_bitsize = bit_size
- if "type" in attrs and attrs["type"] in self.bitsets:
- bitset = self.bitsets[attrs["type"]]
- if bitset.inline:
- self.current_bitset = Bitset(attrs["name"], bitset)
- self.current_bitset.inline = True
- else:
- self.current_bitset = bitset
- else:
- self.current_bitset = Bitset(attrs["name"], None)
- self.current_bitset.inline = True
- if "type" in attrs:
- self.parse_field(None, attrs)
- variant = self.parse_variants(attrs)
- if not variant and self.current_array:
- variant = self.current_array.variant
- self.current_reg = Reg(attrs, self.prefix(variant), self.current_array, bit_size)
- self.current_reg.bitset = self.current_bitset
- if len(self.stack) == 1:
- self.file.append(self.current_reg)
- if variant is not None:
- self.add_all_variants(self.current_reg, attrs, variant)
- usages = None
- if "usage" in attrs:
- usages = attrs["usage"].split(',')
- elif self.current_array:
- usages = self.current_array.usages
- self.add_all_usages(self.current_reg, usages)
- def start_element(self, name, attrs):
- self.cdata = ""
- if name == "import":
- filename = attrs["file"]
- self.do_parse(os.path.join(self.path, filename))
- elif name == "domain":
- self.current_domain = attrs["name"]
- if "prefix" in attrs:
- self.current_prefix = self.parse_variants(attrs)
- self.current_prefix_type = attrs["prefix"]
- else:
- self.current_prefix = None
- self.current_prefix_type = None
- if "varset" in attrs:
- self.current_varset = self.enums[attrs["varset"]]
- elif name == "stripe":
- self.current_stripe = self.parse_variants(attrs)
- elif name == "enum":
- self.current_enum_value = 0
- self.current_enum = Enum(attrs["name"])
- self.enums[attrs["name"]] = self.current_enum
- if len(self.stack) == 1:
- self.file.append(self.current_enum)
- elif name == "value":
- if "value" in attrs:
- value = int(attrs["value"], 0)
- else:
- value = self.current_enum_value
- self.current_enum.values.append((attrs["name"], value))
- elif name == "reg32":
- self.parse_reg(attrs, 32)
- elif name == "reg64":
- self.parse_reg(attrs, 64)
- elif name == "array":
- self.current_bitsize = 32
- variant = self.parse_variants(attrs)
- index_type = self.enums[attrs["index"]] if "index" in attrs else None
- self.current_array = Array(attrs, self.prefix(variant), variant, self.current_array, index_type)
- if len(self.stack) == 1:
- self.file.append(self.current_array)
- elif name == "bitset":
- self.current_bitset = Bitset(attrs["name"], None)
- if "inline" in attrs and attrs["inline"] == "yes":
- self.current_bitset.inline = True
- self.bitsets[self.current_bitset.name] = self.current_bitset
- if len(self.stack) == 1 and not self.current_bitset.inline:
- self.file.append(self.current_bitset)
- elif name == "bitfield" and self.current_bitset:
- self.parse_field(attrs["name"], attrs)
- elif name == "database":
- self.do_validate(attrs["xsi:schemaLocation"])
- elif name == "copyright":
- self.copyright_year = attrs["year"]
- elif name == "author":
- self.authors.append(attrs["name"] + " <" + attrs["email"] + "> " + attrs["name"])
- def end_element(self, name):
- if name == "domain":
- self.current_domain = None
- self.current_prefix = None
- self.current_prefix_type = None
- elif name == "stripe":
- self.current_stripe = None
- elif name == "bitset":
- self.current_bitset = None
- elif name == "reg32":
- self.current_reg = None
- elif name == "array":
- self.current_array = self.current_array.parent
- elif name == "enum":
- self.current_enum = None
- elif name == "license":
- self.license = self.cdata
- def character_data(self, data):
- self.cdata += data
- def dump_reg_usages(self):
- d = collections.defaultdict(list)
- for usage, regs in self.usage_regs.items():
- for reg in regs:
- variants = self.variant_regs.get(reg.name)
- if variants:
- for variant, vreg in variants.items():
- if reg == vreg:
- d[(usage, variant)].append(reg)
- else:
- for variant in self.variants:
- d[(usage, variant)].append(reg)
- print("#ifdef __cplusplus")
- for usage, regs in self.usage_regs.items():
- print("template<chip CHIP> constexpr inline uint16_t %s_REGS[] = {};" % (usage.upper()))
- for (usage, variant), regs in d.items():
- offsets = []
- for reg in regs:
- if reg.array:
- for i in range(reg.array.length):
- offsets.append(reg.array.offset + reg.offset + i * reg.array.stride)
- if reg.bit_size == 64:
- offsets.append(offsets[-1] + 1)
- else:
- offsets.append(reg.offset)
- if reg.bit_size == 64:
- offsets.append(offsets[-1] + 1)
- offsets.sort()
- print("template<> constexpr inline uint16_t %s_REGS<%s>[] = {" % (usage.upper(), variant))
- for offset in offsets:
- print("\t%s," % hex(offset))
- print("};")
- print("#endif")
- def dump(self):
- enums = []
- bitsets = []
- regs = []
- for e in self.file:
- if isinstance(e, Enum):
- enums.append(e)
- elif isinstance(e, Bitset):
- bitsets.append(e)
- else:
- regs.append(e)
- for e in enums + bitsets + regs:
- e.dump()
- self.dump_reg_usages()
- def dump_regs_py(self):
- regs = []
- for e in self.file:
- if isinstance(e, Reg):
- regs.append(e)
- for e in regs:
- e.dump_py()
- def dump_reg_variants(self, regname, variants):
- # Don't bother for things that only have a single variant:
- if len(variants) == 1:
- return
- print("#ifdef __cplusplus")
- print("struct __%s {" % regname)
- # TODO be more clever.. we should probably figure out which
- # fields have the same type in all variants (in which they
- # appear) and stuff everything else in a variant specific
- # sub-structure.
- seen_fields = []
- bit_size = 32
- array = False
- address = None
- for variant in variants.keys():
- print(" /* %s fields: */" % variant)
- reg = variants[variant]
- bit_size = reg.bit_size
- array = reg.array
- for f in reg.bitset.fields:
- fld_name = field_name(reg, f)
- if fld_name in seen_fields:
- continue
- seen_fields.append(fld_name)
- name = fld_name.lower()
- if f.type in [ "address", "waddress" ]:
- if address:
- continue
- address = f
- tab_to(" __bo_type", "bo;")
- tab_to(" uint32_t", "bo_offset;")
- continue
- type, val = f.ctype("var")
- tab_to(" %s" %type, "%s;" %name)
- print(" /* fallback fields: */")
- if bit_size == 64:
- tab_to(" uint64_t", "unknown;")
- tab_to(" uint64_t", "qword;")
- else:
- tab_to(" uint32_t", "unknown;")
- tab_to(" uint32_t", "dword;")
- print("};")
- # TODO don't hardcode the varset enum name
- varenum = "chip"
- print("template <%s %s>" % (varenum, varenum.upper()))
- print("static inline struct fd_reg_pair")
- xtra = ""
- xtravar = ""
- if array:
- xtra = "int __i, "
- xtravar = "__i, "
- print("__%s(%sstruct __%s fields) {" % (regname, xtra, regname))
- for variant in variants.keys():
- print(" if (%s == %s) {" % (varenum.upper(), variant))
- reg = variants[variant]
- reg.dump_regpair_builder()
- print(" } else")
- print(" assert(!\"invalid variant\");")
- print("}")
- if bit_size == 64:
- skip = ", { .reg = 0 }"
- else:
- skip = ""
- print("#define %s(VARIANT, %s...) __%s<VARIANT>(%s{__VA_ARGS__})%s" % (regname, xtravar, regname, xtravar, skip))
- print("#endif /* __cplusplus */")
- def dump_structs(self):
- for e in self.file:
- e.dump_pack_struct()
- for regname in self.variant_regs:
- self.dump_reg_variants(regname, self.variant_regs[regname])
- def dump_c(args, guard, func):
- p = Parser()
- try:
- p.parse(args.rnn, args.xml, args.validate)
- except Error as e:
- print(e, file=sys.stderr)
- exit(1)
- print("#ifndef %s\n#define %s\n" % (guard, guard))
- print("""/* Autogenerated file, DO NOT EDIT manually!
- This file was generated by the rules-ng-ng gen_header.py tool in this git repository:
- http://gitlab.freedesktop.org/mesa/mesa/
- git clone https://gitlab.freedesktop.org/mesa/mesa.git
- The rules-ng-ng source files this header was generated from are:
- """)
- maxlen = 0
- for filepath in p.xml_files:
- maxlen = max(maxlen, len(filepath))
- for filepath in p.xml_files:
- pad = " " * (maxlen - len(filepath))
- filesize = str(os.path.getsize(filepath))
- filesize = " " * (7 - len(filesize)) + filesize
- filetime = time.ctime(os.path.getmtime(filepath))
- print("- " + filepath + pad + " (" + filesize + " bytes, from " + filetime + ")")
- if p.copyright_year:
- current_year = str(datetime.date.today().year)
- print()
- print("Copyright (C) %s-%s by the following authors:" % (p.copyright_year, current_year))
- for author in p.authors:
- print("- " + author)
- if p.license:
- print(p.license)
- print("*/")
- print()
- print("#ifdef __KERNEL__")
- print("#include <linux/bug.h>")
- print("#define assert(x) BUG_ON(!(x))")
- print("#else")
- print("#include <assert.h>")
- print("#endif")
- print()
- print("#ifdef __cplusplus")
- print("#define __struct_cast(X)")
- print("#else")
- print("#define __struct_cast(X) (struct X)")
- print("#endif")
- print()
- func(p)
- print("\n#endif /* %s */" % guard)
- def dump_c_defines(args):
- guard = str.replace(os.path.basename(args.xml), '.', '_').upper()
- dump_c(args, guard, lambda p: p.dump())
- def dump_c_pack_structs(args):
- guard = str.replace(os.path.basename(args.xml), '.', '_').upper() + '_STRUCTS'
- dump_c(args, guard, lambda p: p.dump_structs())
- def dump_py_defines(args):
- p = Parser()
- try:
- p.parse(args.rnn, args.xml)
- except Error as e:
- print(e, file=sys.stderr)
- exit(1)
- file_name = os.path.splitext(os.path.basename(args.xml))[0]
- print("from enum import IntEnum")
- print("class %sRegs(IntEnum):" % file_name.upper())
- os.path.basename(args.xml)
- p.dump_regs_py()
- def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('--rnn', type=str, required=True)
- parser.add_argument('--xml', type=str, required=True)
- parser.add_argument('--validate', default=False, action='store_true')
- parser.add_argument('--no-validate', dest='validate', action='store_false')
- subparsers = parser.add_subparsers()
- subparsers.required = True
- parser_c_defines = subparsers.add_parser('c-defines')
- parser_c_defines.set_defaults(func=dump_c_defines)
- parser_c_pack_structs = subparsers.add_parser('c-pack-structs')
- parser_c_pack_structs.set_defaults(func=dump_c_pack_structs)
- parser_py_defines = subparsers.add_parser('py-defines')
- parser_py_defines.set_defaults(func=dump_py_defines)
- args = parser.parse_args()
- args.func(args)
- if __name__ == '__main__':
- main()
|