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