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