pvr: csbgen: Add *_unpack() functions for all generated struct types

Signed-off-by: Matt Coster <matt.coster@imgtec.com>
Reviewed-by: Frank Binns <frank.binns@imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16884>
This commit is contained in:
Matt Coster 2022-05-12 12:00:44 +01:00 committed by Marge Bot
parent 4c0941f0d4
commit 7c615b4103
5 changed files with 151 additions and 0 deletions

View File

@ -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"]

View File

@ -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;
@ -78,6 +82,15 @@ __pvr_uint(uint64_t v, uint32_t start, NDEBUG_UNUSED uint32_t end)
return v << start;
}
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)
{
@ -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,
@ -113,6 +135,20 @@ __pvr_offset(uint64_t v,
return 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,
@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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"