From: Kristian H. Kristensen Date: Fri, 8 Nov 2019 04:03:21 +0000 (-0800) Subject: freedreno: New struct packing macros X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=bdd98b892f33433391b879223a44e8070e06ec84;p=mesa.git freedreno: New struct packing macros Reviewed-by: Eric Anholt Reviewed-by: Rob Clark Signed-off-by: Kristian H. Kristensen --- diff --git a/src/freedreno/registers/gen_header.py b/src/freedreno/registers/gen_header.py index cb565bb2fd4..f11724d707a 100644 --- a/src/freedreno/registers/gen_header.py +++ b/src/freedreno/registers/gen_header.py @@ -28,6 +28,9 @@ class Enum(object): 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 @@ -36,7 +39,7 @@ class Field(object): self.shr = shr self.type = type - builtin_types = [ None, "boolean", "uint", "hex", "int", "fixed", "ufixed", "float" ] + builtin_types = [ None, "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) @@ -51,37 +54,40 @@ class Field(object): 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): + def ctype(self, var_name): if self.type == None: type = "uint32_t" - val = "val" + val = var_name elif self.type == "boolean": type = "bool" - val = "val" + val = var_name elif self.type == "uint" or self.type == "hex": type = "uint32_t" - val = "val" + val = var_name elif self.type == "int": type = "int32_t" - val = "val" + val = var_name elif self.type == "fixed": type = "float" - val = "((int32_t)(val * %d.0))" % (1 << self.radix) + val = "((int32_t)(%s * %d.0))" % (var_name, 1 << self.radix) elif self.type == "ufixed": type = "float" - val = "((uint32_t)(val * %d.0))" % (1 << self.radix) + 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(val)" + val = "fui(%s)" % var_name elif self.type == "float" and self.high - self.low == 15: type = "float" - val = "util_float_to_half(val)" + val = "util_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 = "val" + val = var_name if self.shr > 0: - val = "%s >> %d" % (val, self.shr) + val = "(%s >> %d)" % (val, self.shr) return (type, val) @@ -103,6 +109,97 @@ class Bitset(object): 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 + + 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(prefix, f.name) + + type, val = f.ctype("var") + + tab_to(" %s" % type, "%s;" % name) + 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.dword,") + + if address: + 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 @@ -119,12 +216,13 @@ class Bitset(object): 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() + 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): @@ -137,27 +235,39 @@ class Array(object): 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): + 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: - name = self.domain + "_" + self.array.name + "_" + self.name offset = self.array.offset + self.offset - print("static inline uint32_t REG_%s(uint32_t i0) { return 0x%08x + 0x%x*i0; }" % (name, offset, self.array.stride)) + print("static inline uint32_t REG_%s(uint32_t i0) { return 0x%08x + 0x%x*i0; }" % (self.full_name, offset, self.array.stride)) else: - name = self.domain + "_" + self.name - tab_to("#define REG_%s" % name, "0x%08x" % self.offset) + tab_to("#define REG_%s" % self.full_name, "0x%08x" % self.offset) if self.bitset.inline: - self.bitset.dump(name) + 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 @@ -235,6 +345,21 @@ class Parser(object): 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 = os.path.basename(attrs["file"]) @@ -259,19 +384,9 @@ class Parser(object): self.current_enum.values.append((attrs["name"], value)) # self.current_enum_value = value + 1 elif name == "reg32": - 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) - self.current_reg.bitset = self.current_bitset - - if len(self.stack) == 1: - self.file.append(self.current_reg) + 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: @@ -316,11 +431,21 @@ class Parser(object): 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() xml_file = sys.argv[1] + if len(sys.argv) > 2 and sys.argv[2] == '--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() - guard = str.replace(os.path.basename(xml_file), '.', '_').upper() print("#ifndef %s\n#define %s\n" % (guard, guard)) try: @@ -329,7 +454,10 @@ def main(): print(e) exit(1) - p.dump() + if do_structs: + p.dump_structs() + else: + p.dump() print("\n#endif /* %s */" % guard) diff --git a/src/freedreno/registers/meson.build b/src/freedreno/registers/meson.build index 4d361504777..33a9fce3202 100644 --- a/src/freedreno/registers/meson.build +++ b/src/freedreno/registers/meson.build @@ -39,3 +39,11 @@ foreach f : xml_files capture : true, ) endforeach + +freedreno_xml_header_files += custom_target( + 'a6xx-pack.xml.h', + input : ['gen_header.py', 'a6xx.xml'], + output : 'a6xx-pack.xml.h', + command : [prog_python, '@INPUT@', '--pack-structs'], + capture : true, + ) diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_pack.h b/src/gallium/drivers/freedreno/a6xx/fd6_pack.h new file mode 100644 index 00000000000..84b232e74a2 --- /dev/null +++ b/src/gallium/drivers/freedreno/a6xx/fd6_pack.h @@ -0,0 +1,109 @@ +/* + * Copyright © 2019 Google, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef FD6_PACK_H +#define FD6_PACK_H + +#include "a6xx.xml.h" + +struct fd_reg_pair { + uint32_t reg; + uint64_t value; + struct fd_bo *bo; + bool bo_write; + uint32_t bo_offset; + uint32_t bo_shift; +}; + +#define __bo_type struct fd_bo * + +#include "a6xx-pack.xml.h" + +#define __assert_eq(a, b) \ + do { \ + if ((a) != (b)) { \ + fprintf(stderr, "assert failed: " #a " (0x%x) != " #b " (0x%x)\n", a, b); \ + assert((a) == (b)); \ + } \ + } while (0) + +#define __ONE_REG(i, ...) \ + do { \ + const struct fd_reg_pair regs[] = { __VA_ARGS__ }; \ + if (i < ARRAY_SIZE(regs) && regs[i].reg > 0) { \ + __assert_eq(regs[0].reg + i, regs[i].reg); \ + if (regs[i].bo) { \ + struct fd_reloc reloc = { \ + .bo = regs[i].bo, \ + .flags = FD_RELOC_READ | \ + (regs[i].bo_write ? FD_RELOC_WRITE : 0), \ + \ + .offset = regs[i].bo_offset, \ + .or = regs[i].value, \ + .shift = regs[i].bo_shift, \ + .orhi = regs[i].value >> 32 \ + }; \ + ring->cur = p; \ + p += 2; \ + fd_ringbuffer_reloc(ring, &reloc); \ + } else { \ + *p++ = regs[i].value; \ + } \ + } \ + } while (0) + +#define OUT_REG(ring, ...) \ + do { \ + const struct fd_reg_pair regs[] = { __VA_ARGS__ }; \ + unsigned count = ARRAY_SIZE(regs); \ + uint32_t *p = ring->cur; \ + \ + STATIC_ASSERT(count > 0); \ + STATIC_ASSERT(count <= 16); \ + \ + BEGIN_RING(ring, count + 1); \ + *p++ = CP_TYPE4_PKT | count | \ + (_odd_parity_bit(count) << 7) | \ + ((regs[0].reg & 0x3ffff) << 8) | \ + ((_odd_parity_bit(regs[0].reg) << 27)); \ + \ + __ONE_REG( 0, __VA_ARGS__); \ + __ONE_REG( 1, __VA_ARGS__); \ + __ONE_REG( 2, __VA_ARGS__); \ + __ONE_REG( 3, __VA_ARGS__); \ + __ONE_REG( 4, __VA_ARGS__); \ + __ONE_REG( 5, __VA_ARGS__); \ + __ONE_REG( 6, __VA_ARGS__); \ + __ONE_REG( 7, __VA_ARGS__); \ + __ONE_REG( 8, __VA_ARGS__); \ + __ONE_REG( 9, __VA_ARGS__); \ + __ONE_REG(10, __VA_ARGS__); \ + __ONE_REG(11, __VA_ARGS__); \ + __ONE_REG(12, __VA_ARGS__); \ + __ONE_REG(13, __VA_ARGS__); \ + __ONE_REG(14, __VA_ARGS__); \ + __ONE_REG(15, __VA_ARGS__); \ + ring->cur = p; \ + } while (0) + +#endif /* FD6_PACK_H */