freedreno: New struct packing macros
authorKristian H. Kristensen <hoegsberg@google.com>
Fri, 8 Nov 2019 04:03:21 +0000 (20:03 -0800)
committerKristian H. Kristensen <hoegsberg@gmail.com>
Wed, 11 Dec 2019 22:25:47 +0000 (22:25 +0000)
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Rob Clark <robdclark@chromium.org>
Signed-off-by: Kristian H. Kristensen <hoegsberg@google.com>
src/freedreno/registers/gen_header.py
src/freedreno/registers/meson.build
src/gallium/drivers/freedreno/a6xx/fd6_pack.h [new file with mode: 0644]

index cb565bb2fd452f3b3a367ce81bfc262dd8667984..f11724d707a764accd6feeb3022be19fcb691c07 100644 (file)
@@ -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)
 
index 4d36150477727c56171dbe211fe062d7e7834768..33a9fce32028b9daf123f9b66cc944f179c6925c 100644 (file)
@@ -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 (file)
index 0000000..84b232e
--- /dev/null
@@ -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 */