From 7c615b4103819e7c71e000b42f4821def70e780b Mon Sep 17 00:00:00 2001 From: Matt Coster Date: Thu, 12 May 2022 12:00:44 +0100 Subject: [PATCH] pvr: csbgen: Add *_unpack() functions for all generated struct types Signed-off-by: Matt Coster Reviewed-by: Frank Binns Part-of: --- src/imagination/csbgen/gen_pack_header.py | 88 ++++++++++++++++++++++++++ src/imagination/csbgen/pvr_packet_helpers.h | 54 ++++++++++++++++ src/imagination/include/hwdef/rogue_hw_utils.h | 4 ++ src/imagination/rogue/rogue_build_data.c | 2 + src/imagination/vulkan/pvr_csb.h | 3 + 5 files changed, 151 insertions(+) diff --git a/src/imagination/csbgen/gen_pack_header.py b/src/imagination/csbgen/gen_pack_header.py index 9a932c4..1261837 100644 --- a/src/imagination/csbgen/gen_pack_header.py +++ b/src/imagination/csbgen/gen_pack_header.py @@ -200,6 +200,9 @@ class Csbgen(Node): def get_enum(self, enum_name: str) -> Enum: return self._enums[enum_name] + def get_struct(self, struct_name: str) -> Struct: + return self._structs[struct_name] + class Enum(Node): __slots__ = ["_values"] @@ -369,6 +372,23 @@ class Struct(Node): print("}\n") + def _emit_unpack_function(self, root: Csbgen) -> None: + print(textwrap.dedent("""\ + static inline __attribute__((always_inline)) void + %s_unpack(__attribute__((unused)) const void * restrict src, + %s__attribute__((unused)) struct %s * restrict values) + {""") % (self.full_name, ' ' * len(self.full_name), self.full_name)) + + group = Group(0, 1, self.size, self.fields) + dwords, length = group.collect_dwords_and_length() + if length: + # Cast src to make header C++ friendly + print(" const uint32_t * restrict dw = (const uint32_t * restrict) src;") + + group.emit_unpack_function(root, dwords, length) + + print("}\n") + def emit(self, root: Csbgen) -> None: print("#define %-33s %6d" % (self.full_name + "_length", self.length)) @@ -382,6 +402,7 @@ class Struct(Node): print("};\n") self._emit_pack_function(root) + self._emit_unpack_function(root) class Field(Node): @@ -839,6 +860,73 @@ class Group: print(" dw[%d] = %s;" % (index, v)) print(" dw[%d] = %s >> 32;" % (index + 1, v)) + def emit_unpack_function(self, root: Csbgen, dwords: t.Dict[int, Group.DWord], length: int) -> None: + for index in range(length): + # Ignore MBZ dwords + if index not in dwords: + continue + + # For 64 bit dwords, we aliased the two dword entries in the dword + # dict it occupies. Now that we're emitting the unpack function, + # skip the duplicate entries. + dw = dwords[index] + if index > 0 and index - 1 in dwords and dw == dwords[index - 1]: + continue + + # Special case: only one field and it's a struct at the beginning + # of the dword. In this case we unpack directly from the + # source. This is the only way we handle embedded structs + # larger than 32 bits. + if len(dw.fields) == 1: + field = dw.fields[0] + if root.is_known_struct(field.type) and field.start % 32 == 0: + prefix = root.get_struct(field.type) + print("") + print(" %s_unpack(data, &dw[%d], &values->%s);" % (prefix, index, field.name)) + continue + + dword_start = index * 32 + + if dw.size == 32: + v = "dw[%d]" % index + elif dw.size == 64: + v = "v%d" % index + print(" const uint%d_t %s = dw[%d] | ((uint64_t)dw[%d] << 32);" % (dw.size, v, index, index + 1)) + else: + raise RuntimeError("Unsupported dword size %d" % dw.size) + + # Unpack any fields of struct type first. + for field_index, field in enumerate(f for f in dw.fields if root.is_known_struct(f.type)): + prefix = root.get_struct(field.type).prefix + vname = "v%d_%d" % (index, field_index) + print("") + print(" uint32_t %s = __pvr_uint_unpack(%s, %d, %d);" + % (vname, v, field.start - dword_start, field.end - dword_start)) + print(" %s_unpack(data, &%s, &values->%s);" % (prefix, vname, field.name)) + + for field in dw.fields: + dword_field_start = field.start - dword_start + dword_field_end = field.end - dword_start + + if field.type == "mbo" or root.is_known_struct(field.type): + continue + elif field.type == "uint" or root.is_known_enum(field.type) or field.type == "bool": + print(" values->%s = __pvr_uint_unpack(%s, %d, %d);" + % (field.name, v, dword_field_start, dword_field_end)) + elif field.type == "int": + print(" values->%s = __pvr_sint_unpack(%s, %d, %d);" + % (field.name, v, dword_field_start, dword_field_end)) + elif field.type == "float": + print(" values->%s = __pvr_float_unpack(%s);" % (field.name, v)) + elif field.type == "offset": + print(" values->%s = __pvr_offset_unpack(%s, %d, %d);" + % (field.name, v, dword_field_start, dword_field_end)) + elif field.type == "address": + print(" values->%s = __pvr_address_unpack(%s, %d, %d, %d);" + % (field.name, v, field.shift, dword_field_start, dword_field_end)) + else: + print("/* unhandled field %s, type %s */" % (field.name, field.type)) + class Parser: __slots__ = ["parser", "context", "filename"] diff --git a/src/imagination/csbgen/pvr_packet_helpers.h b/src/imagination/csbgen/pvr_packet_helpers.h index 9cef132..ae2b5fd 100644 --- a/src/imagination/csbgen/pvr_packet_helpers.h +++ b/src/imagination/csbgen/pvr_packet_helpers.h @@ -51,6 +51,10 @@ # error #define __pvr_get_address before including this file #endif +#ifndef __pvr_make_address +# error #define __pvr_make_address before including this file +#endif + union __pvr_value { float f; uint32_t dw; @@ -79,6 +83,15 @@ __pvr_uint(uint64_t v, uint32_t start, NDEBUG_UNUSED uint32_t end) } static inline __attribute__((always_inline)) uint64_t +__pvr_uint_unpack(uint64_t packed, uint32_t start, uint32_t end) +{ + const int width = end - start + 1; + const uint64_t mask = ~0ull >> (64 - width); + + return (packed >> start) & mask; +} + +static inline __attribute__((always_inline)) uint64_t __pvr_sint(int64_t v, uint32_t start, uint32_t end) { const int width = end - start + 1; @@ -98,6 +111,15 @@ __pvr_sint(int64_t v, uint32_t start, uint32_t end) return (v & mask) << start; } +static inline __attribute__((always_inline)) int64_t +__pvr_sint_unpack(uint64_t packed, uint32_t start, uint32_t end) +{ + const int width = end - start + 1; + const uint64_t mask = ~0ull >> (64 - width); + + return (int64_t)((packed >> start) & mask); +} + static inline __attribute__((always_inline)) uint64_t __pvr_offset(uint64_t v, NDEBUG_UNUSED uint32_t start, @@ -114,6 +136,20 @@ __pvr_offset(uint64_t v, } static inline __attribute__((always_inline)) uint64_t +__pvr_offset_unpack(uint64_t packed, + NDEBUG_UNUSED uint32_t start, + NDEBUG_UNUSED uint32_t end) +{ +#ifndef NDEBUG + uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start; + + assert((packed & ~mask) == 0); +#endif + + return packed; +} + +static inline __attribute__((always_inline)) uint64_t __pvr_address(__pvr_address_type address, uint32_t shift, uint32_t start, @@ -125,12 +161,30 @@ __pvr_address(__pvr_address_type address, return ((addr_u64 >> shift) << start) & mask; } +static inline __attribute__((always_inline)) __pvr_address_type +__pvr_address_unpack(uint64_t packed, + uint32_t shift, + uint32_t start, + uint32_t end) +{ + uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start; + uint64_t addr_u64 = ((packed & mask) >> start) << shift; + + return __pvr_make_address(addr_u64); +} + static inline __attribute__((always_inline)) uint32_t __pvr_float(float v) { __pvr_validate_value(v); return ((union __pvr_value){ .f = (v) }).dw; } +static inline __attribute__((always_inline)) float +__pvr_float_unpack(uint32_t packed) +{ + return ((union __pvr_value){ .dw = (packed) }).f; +} + static inline __attribute__((always_inline)) uint64_t __pvr_sfixed(float v, uint32_t start, uint32_t end, uint32_t fract_bits) { diff --git a/src/imagination/include/hwdef/rogue_hw_utils.h b/src/imagination/include/hwdef/rogue_hw_utils.h index 39e3bea..db95dfc 100644 --- a/src/imagination/include/hwdef/rogue_hw_utils.h +++ b/src/imagination/include/hwdef/rogue_hw_utils.h @@ -35,10 +35,14 @@ #define __pvr_address_type pvr_dev_addr_t #define __pvr_get_address(pvr_dev_addr) (pvr_dev_addr).addr +/* clang-format off */ +#define __pvr_make_address(addr_u64) (pvr_dev_addr_t){ .addr = addr_u64 } +/* clang-format on */ #include "csbgen/rogue_cdm.h" #include "csbgen/rogue_lls.h" +#undef __pvr_make_address #undef __pvr_get_address #undef __pvr_address_type diff --git a/src/imagination/rogue/rogue_build_data.c b/src/imagination/rogue/rogue_build_data.c index 010a109..2eebf82 100644 --- a/src/imagination/rogue/rogue_build_data.c +++ b/src/imagination/rogue/rogue_build_data.c @@ -36,9 +36,11 @@ #define __pvr_address_type uint64_t #define __pvr_get_address(pvr_dev_addr) (pvr_dev_addr) +#define __pvr_make_address(addr_u64) (addr_u64) #include "csbgen/rogue_pds.h" +#undef __pvr_make_address #undef __pvr_get_address #undef __pvr_address_type diff --git a/src/imagination/vulkan/pvr_csb.h b/src/imagination/vulkan/pvr_csb.h index 372c41e..500b5e1 100644 --- a/src/imagination/vulkan/pvr_csb.h +++ b/src/imagination/vulkan/pvr_csb.h @@ -42,6 +42,9 @@ #define __pvr_address_type pvr_dev_addr_t #define __pvr_get_address(pvr_dev_addr) (pvr_dev_addr).addr +/* clang-format off */ +#define __pvr_make_address(addr_u64) (pvr_dev_addr_t){ .addr = addr_u64 } +/* clang-format on */ #include "csbgen/rogue_hwdefs.h" -- 2.7.4