| #!/usr/bin/python3 |
| |
| import xml.parsers.expat |
| import sys |
| import os |
| |
| class Error(Exception): |
| def __init__(self, message): |
| self.message = message |
| |
| class Enum(object): |
| def __init__(self, name): |
| self.name = name |
| self.values = [] |
| |
| def dump(self): |
| prev = 0 |
| 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" ] |
| |
| if low < 0 or low > 31: |
| raise parser.error("low attribute out of range: %d" % low) |
| if high < 0 or high > 31: |
| 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 ((0xffffffff >> (32 - (high + 1 - low))) << low) |
| |
| class Bitset(object): |
| def __init__(self, name, template): |
| self.name = name |
| self.inline = False |
| if template: |
| self.fields = template.fields |
| else: |
| self.fields = [] |
| |
| def dump_pack_struct(self, prefix=None, array=None): |
| def field_name(prefix, name): |
| if f.name: |
| name = f.name.lower() |
| else: |
| name = prefix.lower() |
| |
| if (name in [ "double", "float", "int" ]) or not (name[0].isalpha()): |
| name = "_" + name |
| |
| return name |
| |
| if not prefix: |
| return |
| if prefix == None: |
| prefix = self.name |
| |
| value_name = "dword" |
| print("struct %s {" % prefix) |
| for f in self.fields: |
| if f.type == "waddress": |
| value_name = "qword" |
| if f.type in [ "address", "waddress" ]: |
| tab_to(" __bo_type", "bo;") |
| tab_to(" uint32_t", "bo_offset;") |
| continue |
| name = field_name(prefix, f.name) |
| |
| type, val = f.ctype("var") |
| |
| tab_to(" %s" % type, "%s;" % name) |
| if value_name == "qword": |
| tab_to(" uint64_t", "unknown;") |
| tab_to(" uint64_t", "qword;") |
| else: |
| tab_to(" uint32_t", "unknown;") |
| tab_to(" uint32_t", "dword;") |
| print("};\n") |
| |
| address = None; |
| for f in self.fields: |
| if f.type in [ "address", "waddress" ]: |
| address = f |
| if 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)); |
| |
| 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(prefix, f.name)) |
| 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 array: |
| print(" .reg = REG_%s(i)," % prefix) |
| else: |
| print(" .reg = REG_%s," % prefix) |
| |
| print(" .value =") |
| for f in self.fields: |
| if f.type in [ "address", "waddress" ]: |
| continue |
| else: |
| type, val = f.ctype("fields.%s" % field_name(prefix, f.name)) |
| print(" (%-40s << %2d) |" % (val, f.low)) |
| print(" fields.unknown | fields.%s," % (value_name,)) |
| |
| if address: |
| print(" .is_address = true,") |
| print(" .bo = fields.bo,") |
| if f.type == "waddress": |
| print(" .bo_write = true,") |
| print(" .bo_offset = fields.bo_offset,") |
| print(" .bo_shift = %d" % address.shr) |
| |
| print(" };\n}\n") |
| |
| if address: |
| skip = ", { .reg = 0 }" |
| else: |
| skip = "" |
| |
| if array: |
| print("#define %s(i, ...) pack_%s(i, (struct %s) { __VA_ARGS__ })%s\n" % |
| (prefix, prefix, prefix, skip)) |
| else: |
| print("#define %s(...) pack_%s((struct %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): |
| if "name" in attrs: |
| self.name = attrs["name"] |
| else: |
| self.name = "" |
| self.domain = domain |
| self.offset = int(attrs["offset"], 0) |
| self.stride = int(attrs["stride"], 0) |
| self.length = int(attrs["length"], 0) |
| |
| def dump(self): |
| print("static inline uint32_t REG_%s_%s(uint32_t i0) { return 0x%08x + 0x%x*i0; }\n" % (self.domain, self.name, self.offset, self.stride)) |
| |
| def dump_pack_struct(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 self.array: |
| self.full_name = self.domain + "_" + self.array.name + "_" + self.name |
| else: |
| self.full_name = self.domain + "_" + self.name |
| |
| def dump(self): |
| if self.array: |
| offset = self.array.offset + self.offset |
| print("static inline uint32_t REG_%s(uint32_t i0) { return 0x%08x + 0x%x*i0; }" % (self.full_name, offset, self.array.stride)) |
| else: |
| tab_to("#define REG_%s" % self.full_name, "0x%08x" % self.offset) |
| |
| if self.bitset.inline: |
| self.bitset.dump(self.full_name) |
| print("") |
| |
| def dump_pack_struct(self): |
| if self.bitset.inline: |
| self.bitset.dump_pack_struct(self.full_name, not self.array == None) |
| |
| |
| def parse_variants(attrs): |
| if not "variants" in attrs: |
| return None |
| variant = attrs["variants"].split(",")[0] |
| if "-" in variant: |
| variant = variant[:variant.index("-")] |
| |
| return variant |
| |
| class Parser(object): |
| def __init__(self): |
| self.current_array = None |
| self.current_domain = None |
| self.current_prefix = None |
| self.current_stripe = None |
| self.current_bitset = None |
| self.bitsets = {} |
| self.enums = {} |
| self.file = [] |
| |
| def error(self, message): |
| parser, filename = self.stack[-1] |
| return Error("%s:%d:%d: %s" % (filename, parser.CurrentLineNumber, parser.CurrentColumnNumber, message)) |
| |
| def prefix(self): |
| if 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 = 31 |
| |
| 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 do_parse(self, filename): |
| 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.ParseFile(file) |
| self.stack.pop() |
| file.close() |
| |
| def parse(self, rnn_path, filename): |
| self.path = rnn_path |
| self.stack = [] |
| self.do_parse(filename) |
| |
| def parse_reg(self, attrs, bit_size): |
| if "type" in attrs and attrs["type"] in self.bitsets: |
| self.current_bitset = self.bitsets[attrs["type"]] |
| else: |
| self.current_bitset = Bitset(attrs["name"], None) |
| self.current_bitset.inline = True |
| if "type" in attrs: |
| self.parse_field(None, attrs) |
| |
| self.current_reg = Reg(attrs, self.prefix(), self.current_array, bit_size) |
| self.current_reg.bitset = self.current_bitset |
| |
| if len(self.stack) == 1: |
| self.file.append(self.current_reg) |
| |
| def start_element(self, name, attrs): |
| 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 and attrs["prefix"] == "chip": |
| self.current_prefix = parse_variants(attrs) |
| elif name == "stripe": |
| self.current_stripe = 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)) |
| # self.current_enum_value = value + 1 |
| elif name == "reg32": |
| self.parse_reg(attrs, 32) |
| elif name == "reg64": |
| self.parse_reg(attrs, 64) |
| elif name == "array": |
| self.current_array = Array(attrs, self.prefix()) |
| 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) |
| |
| def end_element(self, name): |
| if name == "domain": |
| self.current_domain = None |
| self.current_prefix = 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 = None; |
| elif name == "enum": |
| self.current_enum = None |
| |
| 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() |
| |
| def dump_structs(self): |
| for e in self.file: |
| e.dump_pack_struct() |
| |
| |
| def main(): |
| p = Parser() |
| rnn_path = sys.argv[1] |
| xml_file = sys.argv[2] |
| if len(sys.argv) > 3 and sys.argv[3] == '--pack-structs': |
| do_structs = True |
| guard = str.replace(os.path.basename(xml_file), '.', '_').upper() + '_STRUCTS' |
| else: |
| do_structs = False |
| guard = str.replace(os.path.basename(xml_file), '.', '_').upper() |
| |
| print("#ifndef %s\n#define %s\n" % (guard, guard)) |
| |
| try: |
| p.parse(rnn_path, xml_file) |
| except Error as e: |
| print(e) |
| exit(1) |
| |
| if do_structs: |
| p.dump_structs() |
| else: |
| p.dump() |
| |
| print("\n#endif /* %s */" % guard) |
| |
| if __name__ == '__main__': |
| main() |