1 /* Copyright 2022 Advanced Micro Devices, Inc.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
17 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19 * OTHER DEALINGS IN THE SOFTWARE.
20 *
21 * Authors: AMD
22 *
23 */
24
25 #pragma once
26
27 #include <stdint.h>
28 #include <stdbool.h>
29 #include <limits.h>
30 #include <stddef.h>
31 #include "vpe_assert.h"
32
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36
37 #ifndef LLONG_MAX
38 #define LLONG_MAX 9223372036854775807ll
39 #endif
40 #ifndef LLONG_MIN
41 #define LLONG_MIN (-LLONG_MAX - 1ll)
42 #endif
43
44 #define FIXED31_32_BITS_PER_FRACTIONAL_PART 32
45 #ifndef LLONG_MIN
46 #define LLONG_MIN (1LL << 63)
47 #endif
48 #ifndef LLONG_MAX
49 #define LLONG_MAX (-1LL >> 1)
50 #endif
51
52 #ifndef ASSERT
53 #define ASSERT assert
54 #endif
55
56 /*
57 * @brief
58 * Arithmetic operations on real numbers
59 * represented as fixed-point numbers.
60 * There are: 1 bit for sign,
61 * 31 bit for integer part,
62 * 32 bits for fractional part.
63 *
64 * @note
65 * Currently, overflows and underflows are asserted;
66 * no special result returned.
67 */
68
69 struct fixed31_32 {
70 long long value;
71 };
72
73 /*
74 * @brief
75 * Useful constants
76 */
77
78 static const struct fixed31_32 vpe_fixpt_zero = {0};
79 static const struct fixed31_32 vpe_fixpt_epsilon = {1LL};
80 static const struct fixed31_32 vpe_fixpt_half = {0x80000000LL};
81 static const struct fixed31_32 vpe_fixpt_one = {0x100000000LL};
82
83 static const struct fixed31_32 vpe_fixpt_pi = {13493037705LL};
84 static const struct fixed31_32 vpe_fixpt_two_pi = {26986075409LL};
85 static const struct fixed31_32 vpe_fixpt_e = {11674931555LL};
86 static const struct fixed31_32 vpe_fixpt_ln2 = {2977044471LL};
87 static const struct fixed31_32 vpe_fixpt_ln2_div_2 = {1488522236LL};
88
89 /*
90 * @brief
91 * Initialization routines
92 */
93
94 /*
95 * @brief
96 * result = numerator / denominator
97 */
98 struct fixed31_32 vpe_fixpt_from_fraction(long long numerator, long long denominator);
99
100 /*
101 * @brief
102 * result = arg
103 */
vpe_fixpt_from_int(long long arg)104 static inline struct fixed31_32 vpe_fixpt_from_int(long long arg)
105 {
106 struct fixed31_32 res;
107
108 res.value = (long long)arg << FIXED31_32_BITS_PER_FRACTIONAL_PART;
109
110 return res;
111 }
112
113 /*
114 * @brief
115 * Unary operators
116 */
117
118 /*
119 * @brief
120 * result = -arg
121 */
vpe_fixpt_neg(struct fixed31_32 arg)122 static inline struct fixed31_32 vpe_fixpt_neg(struct fixed31_32 arg)
123 {
124 struct fixed31_32 res;
125
126 res.value = -arg.value;
127
128 return res;
129 }
130
131 /*
132 * @brief
133 * result = abs(arg) := (arg >= 0) ? arg : -arg
134 */
vpe_fixpt_abs(struct fixed31_32 arg)135 static inline struct fixed31_32 vpe_fixpt_abs(struct fixed31_32 arg)
136 {
137 if (arg.value < 0)
138 return vpe_fixpt_neg(arg);
139 else
140 return arg;
141 }
142
143 /*
144 * @brief
145 * Binary relational operators
146 */
147
148 /*
149 * @brief
150 * result = arg1 < arg2
151 */
vpe_fixpt_lt(struct fixed31_32 arg1,struct fixed31_32 arg2)152 static inline bool vpe_fixpt_lt(struct fixed31_32 arg1, struct fixed31_32 arg2)
153 {
154 return arg1.value < arg2.value;
155 }
156
157 /*
158 * @brief
159 * result = arg1 <= arg2
160 */
vpe_fixpt_le(struct fixed31_32 arg1,struct fixed31_32 arg2)161 static inline bool vpe_fixpt_le(struct fixed31_32 arg1, struct fixed31_32 arg2)
162 {
163 return arg1.value <= arg2.value;
164 }
165
166 /*
167 * @brief
168 * result = arg1 == arg2
169 */
vpe_fixpt_eq(struct fixed31_32 arg1,struct fixed31_32 arg2)170 static inline bool vpe_fixpt_eq(struct fixed31_32 arg1, struct fixed31_32 arg2)
171 {
172 return arg1.value == arg2.value;
173 }
174
175 /*
176 * @brief
177 * result = min(arg1, arg2) := (arg1 <= arg2) ? arg1 : arg2
178 */
vpe_fixpt_min(struct fixed31_32 arg1,struct fixed31_32 arg2)179 static inline struct fixed31_32 vpe_fixpt_min(struct fixed31_32 arg1, struct fixed31_32 arg2)
180 {
181 if (arg1.value <= arg2.value)
182 return arg1;
183 else
184 return arg2;
185 }
186
187 /*
188 * @brief
189 * result = max(arg1, arg2) := (arg1 <= arg2) ? arg2 : arg1
190 */
vpe_fixpt_max(struct fixed31_32 arg1,struct fixed31_32 arg2)191 static inline struct fixed31_32 vpe_fixpt_max(struct fixed31_32 arg1, struct fixed31_32 arg2)
192 {
193 if (arg1.value <= arg2.value)
194 return arg2;
195 else
196 return arg1;
197 }
198
199 /*
200 * @brief
201 * | min_value, when arg <= min_value
202 * result = | arg, when min_value < arg < max_value
203 * | max_value, when arg >= max_value
204 */
vpe_fixpt_clamp(struct fixed31_32 arg,struct fixed31_32 min_value,struct fixed31_32 max_value)205 static inline struct fixed31_32 vpe_fixpt_clamp(
206 struct fixed31_32 arg, struct fixed31_32 min_value, struct fixed31_32 max_value)
207 {
208 if (vpe_fixpt_le(arg, min_value))
209 return min_value;
210 else if (vpe_fixpt_le(max_value, arg))
211 return max_value;
212 else
213 return arg;
214 }
215
216 /*
217 * @brief
218 * Binary shift operators
219 */
220
221 /*
222 * @brief
223 * result = arg << shift
224 */
vpe_fixpt_shl(struct fixed31_32 arg,unsigned char shift)225 static inline struct fixed31_32 vpe_fixpt_shl(struct fixed31_32 arg, unsigned char shift)
226 {
227 VPE_ASSERT(((arg.value >= 0) && (arg.value <= LLONG_MAX >> shift)) ||
228 ((arg.value < 0) && (arg.value >= ~(LLONG_MAX >> shift))));
229
230 arg.value = arg.value << shift;
231
232 return arg;
233 }
234
235 /*
236 * @brief
237 * result = arg >> shift
238 */
vpe_fixpt_shr(struct fixed31_32 arg,unsigned char shift)239 static inline struct fixed31_32 vpe_fixpt_shr(struct fixed31_32 arg, unsigned char shift)
240 {
241 bool negative = arg.value < 0;
242
243 if (negative)
244 arg.value = -arg.value;
245 arg.value = arg.value >> shift;
246 if (negative)
247 arg.value = -arg.value;
248 return arg;
249 }
250
251 /*
252 * @brief
253 * Binary additive operators
254 */
255
256 /*
257 * @brief
258 * result = arg1 + arg2
259 */
vpe_fixpt_add(struct fixed31_32 arg1,struct fixed31_32 arg2)260 static inline struct fixed31_32 vpe_fixpt_add(struct fixed31_32 arg1, struct fixed31_32 arg2)
261 {
262 struct fixed31_32 res;
263
264 VPE_ASSERT(((arg1.value >= 0) && (LLONG_MAX - arg1.value >= arg2.value)) ||
265 ((arg1.value < 0) && (LLONG_MIN - arg1.value <= arg2.value)));
266
267 res.value = arg1.value + arg2.value;
268
269 return res;
270 }
271
272 /*
273 * @brief
274 * result = arg1 + arg2
275 */
vpe_fixpt_add_int(struct fixed31_32 arg1,int arg2)276 static inline struct fixed31_32 vpe_fixpt_add_int(struct fixed31_32 arg1, int arg2)
277 {
278 return vpe_fixpt_add(arg1, vpe_fixpt_from_int(arg2));
279 }
280
281 /*
282 * @brief
283 * result = arg1 - arg2
284 */
vpe_fixpt_sub(struct fixed31_32 arg1,struct fixed31_32 arg2)285 static inline struct fixed31_32 vpe_fixpt_sub(struct fixed31_32 arg1, struct fixed31_32 arg2)
286 {
287 struct fixed31_32 res;
288
289 VPE_ASSERT(((arg2.value >= 0) && (LLONG_MIN + arg2.value <= arg1.value)) ||
290 ((arg2.value < 0) && (LLONG_MAX + arg2.value >= arg1.value)));
291
292 res.value = arg1.value - arg2.value;
293
294 return res;
295 }
296
297 /*
298 * @brief
299 * result = arg1 - arg2
300 */
vpe_fixpt_sub_int(struct fixed31_32 arg1,int arg2)301 static inline struct fixed31_32 vpe_fixpt_sub_int(struct fixed31_32 arg1, int arg2)
302 {
303 return vpe_fixpt_sub(arg1, vpe_fixpt_from_int(arg2));
304 }
305
306 /*
307 * @brief
308 * Binary multiplicative operators
309 */
310
311 /*
312 * @brief
313 * result = arg1 * arg2
314 */
315 struct fixed31_32 vpe_fixpt_mul(struct fixed31_32 arg1, struct fixed31_32 arg2);
316
317 /*
318 * @brief
319 * result = arg1 * arg2
320 */
vpe_fixpt_mul_int(struct fixed31_32 arg1,int arg2)321 static inline struct fixed31_32 vpe_fixpt_mul_int(struct fixed31_32 arg1, int arg2)
322 {
323 return vpe_fixpt_mul(arg1, vpe_fixpt_from_int(arg2));
324 }
325
326 /*
327 * @brief
328 * result = square(arg) := arg * arg
329 */
330 struct fixed31_32 vpe_fixpt_sqr(struct fixed31_32 arg);
331
332 /*
333 * @brief
334 * result = arg1 / arg2
335 */
vpe_fixpt_div_int(struct fixed31_32 arg1,long long arg2)336 static inline struct fixed31_32 vpe_fixpt_div_int(struct fixed31_32 arg1, long long arg2)
337 {
338 return vpe_fixpt_from_fraction(arg1.value, vpe_fixpt_from_int(arg2).value);
339 }
340
341 /*
342 * @brief
343 * result = arg1 / arg2
344 */
vpe_fixpt_div(struct fixed31_32 arg1,struct fixed31_32 arg2)345 static inline struct fixed31_32 vpe_fixpt_div(struct fixed31_32 arg1, struct fixed31_32 arg2)
346 {
347 return vpe_fixpt_from_fraction(arg1.value, arg2.value);
348 }
349
350 /*
351 * @brief
352 * Reciprocal function
353 */
354
355 /*
356 * @brief
357 * result = reciprocal(arg) := 1 / arg
358 *
359 * @note
360 * No special actions taken in case argument is zero.
361 */
362 struct fixed31_32 vpe_fixpt_recip(struct fixed31_32 arg);
363
364 /*
365 * @brief
366 * Trigonometric functions
367 */
368
369 /*
370 * @brief
371 * result = sinc(arg) := sin(arg) / arg
372 *
373 * @note
374 * Argument specified in radians,
375 * internally it's normalized to [-2pi...2pi] range.
376 */
377 struct fixed31_32 vpe_fixpt_sinc(struct fixed31_32 arg);
378
379 /*
380 * @brief
381 * result = sin(arg)
382 *
383 * @note
384 * Argument specified in radians,
385 * internally it's normalized to [-2pi...2pi] range.
386 */
387 struct fixed31_32 vpe_fixpt_sin(struct fixed31_32 arg);
388
389 /*
390 * @brief
391 * result = cos(arg)
392 *
393 * @note
394 * Argument specified in radians
395 * and should be in [-2pi...2pi] range -
396 * passing arguments outside that range
397 * will cause incorrect result!
398 */
399 struct fixed31_32 vpe_fixpt_cos(struct fixed31_32 arg);
400
401 /*
402 * @brief
403 * Transcendent functions
404 */
405
406 /*
407 * @brief
408 * result = exp(arg)
409 *
410 * @note
411 * Currently, function is verified for abs(arg) <= 1.
412 */
413 struct fixed31_32 vpe_fixpt_exp(struct fixed31_32 arg);
414
415 /*
416 * @brief
417 * result = log(arg)
418 *
419 * @note
420 * Currently, abs(arg) should be less than 1.
421 * No normalization is done.
422 * Currently, no special actions taken
423 * in case of invalid argument(s). Take care!
424 */
425 struct fixed31_32 vpe_fixpt_log(struct fixed31_32 arg);
426
427 /*
428 * @brief
429 * Power function
430 */
431
432 /*
433 * @brief
434 * result = pow(arg1, arg2)
435 *
436 * @note
437 * Currently, abs(arg1) should be less than 1. Take care!
438 */
vpe_fixpt_pow(struct fixed31_32 arg1,struct fixed31_32 arg2)439 static inline struct fixed31_32 vpe_fixpt_pow(struct fixed31_32 arg1, struct fixed31_32 arg2)
440 {
441 if (arg1.value == 0)
442 return arg2.value == 0 ? vpe_fixpt_one : vpe_fixpt_zero;
443
444 return vpe_fixpt_exp(vpe_fixpt_mul(vpe_fixpt_log(arg1), arg2));
445 }
446
447 /*
448 * @brief
449 * Rounding functions
450 */
451
452 /*
453 * @brief
454 * result = floor(arg) := greatest integer lower than or equal to arg
455 */
vpe_fixpt_floor(struct fixed31_32 arg)456 static inline int vpe_fixpt_floor(struct fixed31_32 arg)
457 {
458 unsigned long long arg_value = (unsigned long long)(arg.value > 0 ? arg.value : -arg.value);
459
460 if (arg.value >= 0)
461 return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
462 else
463 return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
464 }
465
466 /*
467 * @brief
468 * result = round(arg) := integer nearest to arg
469 */
vpe_fixpt_round(struct fixed31_32 arg)470 static inline int vpe_fixpt_round(struct fixed31_32 arg)
471 {
472 unsigned long long arg_value = (unsigned long long)(arg.value > 0 ? arg.value : -arg.value);
473
474 const long long summand = vpe_fixpt_half.value;
475
476 VPE_ASSERT(LLONG_MAX - (long long)arg_value >= summand);
477
478 arg_value += (unsigned long long)summand;
479
480 if (arg.value >= 0)
481 return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
482 else
483 return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
484 }
485
486 /*
487 * @brief
488 * result = ceil(arg) := lowest integer greater than or equal to arg
489 */
vpe_fixpt_ceil(struct fixed31_32 arg)490 static inline int vpe_fixpt_ceil(struct fixed31_32 arg)
491 {
492 unsigned long long arg_value = (unsigned long long)(arg.value > 0 ? arg.value : -arg.value);
493
494 const long long summand = vpe_fixpt_one.value - vpe_fixpt_epsilon.value;
495
496 VPE_ASSERT(LLONG_MAX - (long long)arg_value >= summand);
497
498 arg_value += (unsigned long long)summand;
499
500 if (arg.value >= 0)
501 return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
502 else
503 return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
504 }
505
506 /* the following two function are used in scaler hw programming to convert fixed
507 * point value to format 2 bits from integer part and 19 bits from fractional
508 * part. The same applies for u0d19, 0 bits from integer part and 19 bits from
509 * fractional
510 */
511
512 unsigned int vpe_fixpt_u4d19(struct fixed31_32 arg);
513
514 unsigned int vpe_fixpt_u3d19(struct fixed31_32 arg);
515
516 unsigned int vpe_fixpt_u2d19(struct fixed31_32 arg);
517
518 unsigned int vpe_fixpt_u0d19(struct fixed31_32 arg);
519
520 unsigned int vpe_fixpt_clamp_u0d14(struct fixed31_32 arg);
521
522 unsigned int vpe_fixpt_clamp_u0d10(struct fixed31_32 arg);
523
524 int vpe_fixpt_s4d19(struct fixed31_32 arg);
525
vpe_fixpt_truncate(struct fixed31_32 arg,unsigned int frac_bits)526 static inline struct fixed31_32 vpe_fixpt_truncate(struct fixed31_32 arg, unsigned int frac_bits)
527 {
528 bool negative = arg.value < 0;
529
530 if (frac_bits >= FIXED31_32_BITS_PER_FRACTIONAL_PART) {
531 VPE_ASSERT(frac_bits == FIXED31_32_BITS_PER_FRACTIONAL_PART);
532 return arg;
533 }
534
535 if (negative)
536 arg.value = -arg.value;
537 arg.value &= (~0ULL) << (FIXED31_32_BITS_PER_FRACTIONAL_PART - frac_bits);
538 if (negative)
539 arg.value = -arg.value;
540 return arg;
541 }
542
543 unsigned int vpe_to_fixed_point(
544 unsigned int decimalBits, double value, unsigned int mask, double d_pix);
545
546 #ifdef __cplusplus
547 }
548 #endif
549