1/* 2 * Copyright © 2022 Imagination Technologies Ltd. 3 * 4 * based in part on anv driver which is: 5 * Copyright © 2016 Intel Corporation 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the next 15 * paragraph) shall be included in all copies or substantial portions of the 16 * Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 * SOFTWARE. 25 */ 26 27#ifndef PVR_PACKET_HELPERS_H 28#define PVR_PACKET_HELPERS_H 29 30#include <assert.h> 31#include <math.h> 32#include <stdbool.h> 33#include <stdint.h> 34#include <stdio.h> 35 36#ifndef __pvr_validate_value 37# define __pvr_validate_value(x) 38#endif 39 40#ifdef NDEBUG 41# define NDEBUG_UNUSED __attribute__((unused)) 42#else 43# define NDEBUG_UNUSED 44#endif 45 46#ifndef __pvr_address_type 47# error #define __pvr_address_type before including this file 48#endif 49 50#ifndef __pvr_get_address 51# error #define __pvr_get_address before including this file 52#endif 53 54#ifndef __pvr_make_address 55# error #define __pvr_make_address before including this file 56#endif 57 58union __pvr_value { 59 float f; 60 uint32_t dw; 61}; 62 63static inline __attribute__((always_inline)) uint64_t __pvr_mbo(uint32_t start, 64 uint32_t end) 65{ 66 return (~0ull >> (64 - (end - start + 1))) << start; 67} 68 69static inline __attribute__((always_inline)) uint64_t 70__pvr_uint(uint64_t v, uint32_t start, NDEBUG_UNUSED uint32_t end) 71{ 72 __pvr_validate_value(v); 73 74#ifndef NDEBUG 75 const int width = end - start + 1; 76 if (width < 64) { 77 const uint64_t max = (1ull << width) - 1; 78 assert(v <= max); 79 } 80#endif 81 82 return v << start; 83} 84 85static inline __attribute__((always_inline)) uint64_t 86__pvr_uint_unpack(uint64_t packed, uint32_t start, uint32_t end) 87{ 88 const int width = end - start + 1; 89 const uint64_t mask = ~0ull >> (64 - width); 90 91 return (packed >> start) & mask; 92} 93 94static inline __attribute__((always_inline)) uint64_t 95__pvr_sint(int64_t v, uint32_t start, uint32_t end) 96{ 97 const int width = end - start + 1; 98 99 __pvr_validate_value(v); 100 101#ifndef NDEBUG 102 if (width < 64) { 103 const int64_t max = (1ll << (width - 1)) - 1; 104 const int64_t min = -(1ll << (width - 1)); 105 assert(min <= v && v <= max); 106 } 107#endif 108 109 const uint64_t mask = ~0ull >> (64 - width); 110 111 return (v & mask) << start; 112} 113 114static inline __attribute__((always_inline)) int64_t 115__pvr_sint_unpack(uint64_t packed, uint32_t start, uint32_t end) 116{ 117 const int width = end - start + 1; 118 const uint64_t mask = ~0ull >> (64 - width); 119 120 return (int64_t)((packed >> start) & mask); 121} 122 123static inline __attribute__((always_inline)) uint64_t 124__pvr_offset(uint64_t v, 125 NDEBUG_UNUSED uint32_t start, 126 NDEBUG_UNUSED uint32_t end) 127{ 128 __pvr_validate_value(v); 129#ifndef NDEBUG 130 uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start; 131 132 assert((v & ~mask) == 0); 133#endif 134 135 return v; 136} 137 138static inline __attribute__((always_inline)) uint64_t 139__pvr_offset_unpack(uint64_t packed, 140 NDEBUG_UNUSED uint32_t start, 141 NDEBUG_UNUSED uint32_t end) 142{ 143#ifndef NDEBUG 144 uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start; 145 146 assert((packed & ~mask) == 0); 147#endif 148 149 return packed; 150} 151 152static inline __attribute__((always_inline)) uint64_t 153__pvr_address(__pvr_address_type address, 154 uint32_t shift, 155 uint32_t start, 156 uint32_t end) 157{ 158 uint64_t addr_u64 = __pvr_get_address(address); 159 uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start; 160 161 return ((addr_u64 >> shift) << start) & mask; 162} 163 164static inline __attribute__((always_inline)) __pvr_address_type 165__pvr_address_unpack(uint64_t packed, 166 uint32_t shift, 167 uint32_t start, 168 uint32_t end) 169{ 170 uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start; 171 uint64_t addr_u64 = ((packed & mask) >> start) << shift; 172 173 return __pvr_make_address(addr_u64); 174} 175 176static inline __attribute__((always_inline)) uint32_t __pvr_float(float v) 177{ 178 __pvr_validate_value(v); 179 return ((union __pvr_value){ .f = (v) }).dw; 180} 181 182static inline __attribute__((always_inline)) float 183__pvr_float_unpack(uint32_t packed) 184{ 185 return ((union __pvr_value){ .dw = (packed) }).f; 186} 187 188static inline __attribute__((always_inline)) uint64_t 189__pvr_sfixed(float v, uint32_t start, uint32_t end, uint32_t fract_bits) 190{ 191 __pvr_validate_value(v); 192 193 const float factor = (1 << fract_bits); 194 195#ifndef NDEBUG 196 const float max = ((1 << (end - start)) - 1) / factor; 197 const float min = -(1 << (end - start)) / factor; 198 assert(min <= v && v <= max); 199#endif 200 201 const int64_t int_val = llroundf(v * factor); 202 const uint64_t mask = ~0ull >> (64 - (end - start + 1)); 203 204 return (int_val & mask) << start; 205} 206 207static inline __attribute__((always_inline)) uint64_t 208__pvr_ufixed(float v, 209 uint32_t start, 210 NDEBUG_UNUSED uint32_t end, 211 uint32_t fract_bits) 212{ 213 __pvr_validate_value(v); 214 215 const float factor = (1 << fract_bits); 216 217#ifndef NDEBUG 218 const float max = ((1 << (end - start + 1)) - 1) / factor; 219 const float min = 0.0f; 220 assert(min <= v && v <= max); 221#endif 222 223 const uint64_t uint_val = llroundf(v * factor); 224 225 return uint_val << start; 226} 227 228#undef NDEBUG_UNUSED 229 230#endif /* PVR_PACKET_HELPERS_H */ 231