freedreno: New struct packing macros
Reviewed-by: Eric Anholt <eric@anholt.net> Reviewed-by: Rob Clark <robdclark@chromium.org> Signed-off-by: Kristian H. Kristensen <hoegsberg@google.com>
This commit is contained in:
parent
b27b0e8550
commit
bdd98b892f
|
@ -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)
|
||||
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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 */
|
Loading…
Reference in New Issue