1 /* SPDX-License-Identifier: MIT */
2
3 /* Copyright 2024 Advanced Micro Devices, Inc. */
4
5 #ifndef __SPL_FIXED31_32_H__
6 #define __SPL_FIXED31_32_H__
7
8 #include "os_types.h"
9 #include "spl_os_types.h" // swap
10 #ifndef ASSERT
11 #define ASSERT(_bool) ((void *)0)
12 #endif
13
14 #ifndef LLONG_MAX
15 #define LLONG_MAX 9223372036854775807ll
16 #endif
17 #ifndef LLONG_MIN
18 #define LLONG_MIN (-LLONG_MAX - 1ll)
19 #endif
20
21 #define FIXED31_32_BITS_PER_FRACTIONAL_PART 32
22 #ifndef LLONG_MIN
23 #define LLONG_MIN (1LL<<63)
24 #endif
25 #ifndef LLONG_MAX
26 #define LLONG_MAX (-1LL>>1)
27 #endif
28
29 /*
30 * @brief
31 * Arithmetic operations on real numbers
32 * represented as fixed-point numbers.
33 * There are: 1 bit for sign,
34 * 31 bit for integer part,
35 * 32 bits for fractional part.
36 *
37 * @note
38 * Currently, overflows and underflows are asserted;
39 * no special result returned.
40 */
41
42 struct spl_fixed31_32 {
43 long long value;
44 };
45
46
47 /*
48 * @brief
49 * Useful constants
50 */
51
52 static const struct spl_fixed31_32 spl_fixpt_zero = { 0 };
53 static const struct spl_fixed31_32 spl_fixpt_epsilon = { 1LL };
54 static const struct spl_fixed31_32 spl_fixpt_half = { 0x80000000LL };
55 static const struct spl_fixed31_32 spl_fixpt_one = { 0x100000000LL };
56
57 /*
58 * @brief
59 * Initialization routines
60 */
61
62 /*
63 * @brief
64 * result = numerator / denominator
65 */
66 struct spl_fixed31_32 spl_fixpt_from_fraction(long long numerator, long long denominator);
67
68 /*
69 * @brief
70 * result = arg
71 */
spl_fixpt_from_int(int arg)72 static inline struct spl_fixed31_32 spl_fixpt_from_int(int arg)
73 {
74 struct spl_fixed31_32 res;
75
76 res.value = (long long) arg << FIXED31_32_BITS_PER_FRACTIONAL_PART;
77
78 return res;
79 }
80
81 /*
82 * @brief
83 * Unary operators
84 */
85
86 /*
87 * @brief
88 * result = -arg
89 */
spl_fixpt_neg(struct spl_fixed31_32 arg)90 static inline struct spl_fixed31_32 spl_fixpt_neg(struct spl_fixed31_32 arg)
91 {
92 struct spl_fixed31_32 res;
93
94 res.value = -arg.value;
95
96 return res;
97 }
98
99 /*
100 * @brief
101 * result = abs(arg) := (arg >= 0) ? arg : -arg
102 */
spl_fixpt_abs(struct spl_fixed31_32 arg)103 static inline struct spl_fixed31_32 spl_fixpt_abs(struct spl_fixed31_32 arg)
104 {
105 if (arg.value < 0)
106 return spl_fixpt_neg(arg);
107 else
108 return arg;
109 }
110
111 /*
112 * @brief
113 * Binary relational operators
114 */
115
116 /*
117 * @brief
118 * result = arg1 < arg2
119 */
spl_fixpt_lt(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)120 static inline bool spl_fixpt_lt(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
121 {
122 return arg1.value < arg2.value;
123 }
124
125 /*
126 * @brief
127 * result = arg1 <= arg2
128 */
spl_fixpt_le(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)129 static inline bool spl_fixpt_le(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
130 {
131 return arg1.value <= arg2.value;
132 }
133
134 /*
135 * @brief
136 * result = arg1 == arg2
137 */
spl_fixpt_eq(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)138 static inline bool spl_fixpt_eq(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
139 {
140 return arg1.value == arg2.value;
141 }
142
143 /*
144 * @brief
145 * result = min(arg1, arg2) := (arg1 <= arg2) ? arg1 : arg2
146 */
spl_fixpt_min(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)147 static inline struct spl_fixed31_32 spl_fixpt_min(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
148 {
149 if (arg1.value <= arg2.value)
150 return arg1;
151 else
152 return arg2;
153 }
154
155 /*
156 * @brief
157 * result = max(arg1, arg2) := (arg1 <= arg2) ? arg2 : arg1
158 */
spl_fixpt_max(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)159 static inline struct spl_fixed31_32 spl_fixpt_max(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
160 {
161 if (arg1.value <= arg2.value)
162 return arg2;
163 else
164 return arg1;
165 }
166
167 /*
168 * @brief
169 * | min_value, when arg <= min_value
170 * result = | arg, when min_value < arg < max_value
171 * | max_value, when arg >= max_value
172 */
spl_fixpt_clamp(struct spl_fixed31_32 arg,struct spl_fixed31_32 min_value,struct spl_fixed31_32 max_value)173 static inline struct spl_fixed31_32 spl_fixpt_clamp(
174 struct spl_fixed31_32 arg,
175 struct spl_fixed31_32 min_value,
176 struct spl_fixed31_32 max_value)
177 {
178 if (spl_fixpt_le(arg, min_value))
179 return min_value;
180 else if (spl_fixpt_le(max_value, arg))
181 return max_value;
182 else
183 return arg;
184 }
185
186 /*
187 * @brief
188 * Binary shift operators
189 */
190
191 /*
192 * @brief
193 * result = arg << shift
194 */
spl_fixpt_shl(struct spl_fixed31_32 arg,unsigned char shift)195 static inline struct spl_fixed31_32 spl_fixpt_shl(struct spl_fixed31_32 arg, unsigned char shift)
196 {
197 ASSERT(((arg.value >= 0) && (arg.value <= LLONG_MAX >> shift)) ||
198 ((arg.value < 0) && (arg.value >= ~(LLONG_MAX >> shift))));
199
200 arg.value = arg.value << shift;
201
202 return arg;
203 }
204
205 /*
206 * @brief
207 * result = arg >> shift
208 */
spl_fixpt_shr(struct spl_fixed31_32 arg,unsigned char shift)209 static inline struct spl_fixed31_32 spl_fixpt_shr(struct spl_fixed31_32 arg, unsigned char shift)
210 {
211 bool negative = arg.value < 0;
212
213 if (negative)
214 arg.value = -arg.value;
215 arg.value = arg.value >> shift;
216 if (negative)
217 arg.value = -arg.value;
218 return arg;
219 }
220
221 /*
222 * @brief
223 * Binary additive operators
224 */
225
226 /*
227 * @brief
228 * result = arg1 + arg2
229 */
spl_fixpt_add(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)230 static inline struct spl_fixed31_32 spl_fixpt_add(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
231 {
232 struct spl_fixed31_32 res;
233
234 ASSERT(((arg1.value >= 0) && (LLONG_MAX - arg1.value >= arg2.value)) ||
235 ((arg1.value < 0) && (LLONG_MIN - arg1.value <= arg2.value)));
236
237 res.value = arg1.value + arg2.value;
238
239 return res;
240 }
241
242 /*
243 * @brief
244 * result = arg1 + arg2
245 */
spl_fixpt_add_int(struct spl_fixed31_32 arg1,int arg2)246 static inline struct spl_fixed31_32 spl_fixpt_add_int(struct spl_fixed31_32 arg1, int arg2)
247 {
248 return spl_fixpt_add(arg1, spl_fixpt_from_int(arg2));
249 }
250
251 /*
252 * @brief
253 * result = arg1 - arg2
254 */
spl_fixpt_sub(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)255 static inline struct spl_fixed31_32 spl_fixpt_sub(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
256 {
257 struct spl_fixed31_32 res;
258
259 ASSERT(((arg2.value >= 0) && (LLONG_MIN + arg2.value <= arg1.value)) ||
260 ((arg2.value < 0) && (LLONG_MAX + arg2.value >= arg1.value)));
261
262 res.value = arg1.value - arg2.value;
263
264 return res;
265 }
266
267 /*
268 * @brief
269 * result = arg1 - arg2
270 */
spl_fixpt_sub_int(struct spl_fixed31_32 arg1,int arg2)271 static inline struct spl_fixed31_32 spl_fixpt_sub_int(struct spl_fixed31_32 arg1, int arg2)
272 {
273 return spl_fixpt_sub(arg1, spl_fixpt_from_int(arg2));
274 }
275
276
277 /*
278 * @brief
279 * Binary multiplicative operators
280 */
281
282 /*
283 * @brief
284 * result = arg1 * arg2
285 */
286 struct spl_fixed31_32 spl_fixpt_mul(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2);
287
288
289 /*
290 * @brief
291 * result = arg1 * arg2
292 */
spl_fixpt_mul_int(struct spl_fixed31_32 arg1,int arg2)293 static inline struct spl_fixed31_32 spl_fixpt_mul_int(struct spl_fixed31_32 arg1, int arg2)
294 {
295 return spl_fixpt_mul(arg1, spl_fixpt_from_int(arg2));
296 }
297
298 /*
299 * @brief
300 * result = square(arg) := arg * arg
301 */
302 struct spl_fixed31_32 spl_fixpt_sqr(struct spl_fixed31_32 arg);
303
304 /*
305 * @brief
306 * result = arg1 / arg2
307 */
spl_fixpt_div_int(struct spl_fixed31_32 arg1,long long arg2)308 static inline struct spl_fixed31_32 spl_fixpt_div_int(struct spl_fixed31_32 arg1, long long arg2)
309 {
310 return spl_fixpt_from_fraction(arg1.value, spl_fixpt_from_int((int)arg2).value);
311 }
312
313 /*
314 * @brief
315 * result = arg1 / arg2
316 */
spl_fixpt_div(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)317 static inline struct spl_fixed31_32 spl_fixpt_div(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
318 {
319 return spl_fixpt_from_fraction(arg1.value, arg2.value);
320 }
321
322 /*
323 * @brief
324 * Reciprocal function
325 */
326
327 /*
328 * @brief
329 * result = reciprocal(arg) := 1 / arg
330 *
331 * @note
332 * No special actions taken in case argument is zero.
333 */
334 struct spl_fixed31_32 spl_fixpt_recip(struct spl_fixed31_32 arg);
335
336 /*
337 * @brief
338 * Trigonometric functions
339 */
340
341 /*
342 * @brief
343 * result = sinc(arg) := sin(arg) / arg
344 *
345 * @note
346 * Argument specified in radians,
347 * internally it's normalized to [-2pi...2pi] range.
348 */
349 struct spl_fixed31_32 spl_fixpt_sinc(struct spl_fixed31_32 arg);
350
351 /*
352 * @brief
353 * result = sin(arg)
354 *
355 * @note
356 * Argument specified in radians,
357 * internally it's normalized to [-2pi...2pi] range.
358 */
359 struct spl_fixed31_32 spl_fixpt_sin(struct spl_fixed31_32 arg);
360
361 /*
362 * @brief
363 * result = cos(arg)
364 *
365 * @note
366 * Argument specified in radians
367 * and should be in [-2pi...2pi] range -
368 * passing arguments outside that range
369 * will cause incorrect result!
370 */
371 struct spl_fixed31_32 spl_fixpt_cos(struct spl_fixed31_32 arg);
372
373 /*
374 * @brief
375 * Transcendent functions
376 */
377
378 /*
379 * @brief
380 * result = exp(arg)
381 *
382 * @note
383 * Currently, function is verified for abs(arg) <= 1.
384 */
385 struct spl_fixed31_32 spl_fixpt_exp(struct spl_fixed31_32 arg);
386
387 /*
388 * @brief
389 * result = log(arg)
390 *
391 * @note
392 * Currently, abs(arg) should be less than 1.
393 * No normalization is done.
394 * Currently, no special actions taken
395 * in case of invalid argument(s). Take care!
396 */
397 struct spl_fixed31_32 spl_fixpt_log(struct spl_fixed31_32 arg);
398
399 /*
400 * @brief
401 * Power function
402 */
403
404 /*
405 * @brief
406 * result = pow(arg1, arg2)
407 *
408 * @note
409 * Currently, abs(arg1) should be less than 1. Take care!
410 */
spl_fixpt_pow(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)411 static inline struct spl_fixed31_32 spl_fixpt_pow(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
412 {
413 if (arg1.value == 0)
414 return arg2.value == 0 ? spl_fixpt_one : spl_fixpt_zero;
415
416 return spl_fixpt_exp(
417 spl_fixpt_mul(
418 spl_fixpt_log(arg1),
419 arg2));
420 }
421
422 /*
423 * @brief
424 * Rounding functions
425 */
426
427 /*
428 * @brief
429 * result = floor(arg) := greatest integer lower than or equal to arg
430 */
spl_fixpt_floor(struct spl_fixed31_32 arg)431 static inline int spl_fixpt_floor(struct spl_fixed31_32 arg)
432 {
433 unsigned long long arg_value = arg.value > 0 ? arg.value : -arg.value;
434
435 if (arg.value >= 0)
436 return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
437 else
438 return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
439 }
440
441 /*
442 * @brief
443 * result = round(arg) := integer nearest to arg
444 */
spl_fixpt_round(struct spl_fixed31_32 arg)445 static inline int spl_fixpt_round(struct spl_fixed31_32 arg)
446 {
447 unsigned long long arg_value = arg.value > 0 ? arg.value : -arg.value;
448
449 const long long summand = spl_fixpt_half.value;
450
451 ASSERT(LLONG_MAX - (long long)arg_value >= summand);
452
453 arg_value += summand;
454
455 if (arg.value >= 0)
456 return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
457 else
458 return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
459 }
460
461 /*
462 * @brief
463 * result = ceil(arg) := lowest integer greater than or equal to arg
464 */
spl_fixpt_ceil(struct spl_fixed31_32 arg)465 static inline int spl_fixpt_ceil(struct spl_fixed31_32 arg)
466 {
467 unsigned long long arg_value = arg.value > 0 ? arg.value : -arg.value;
468
469 const long long summand = spl_fixpt_one.value -
470 spl_fixpt_epsilon.value;
471
472 ASSERT(LLONG_MAX - (long long)arg_value >= summand);
473
474 arg_value += summand;
475
476 if (arg.value >= 0)
477 return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
478 else
479 return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
480 }
481
482 /* the following two function are used in scaler hw programming to convert fixed
483 * point value to format 2 bits from integer part and 19 bits from fractional
484 * part. The same applies for u0d19, 0 bits from integer part and 19 bits from
485 * fractional
486 */
487
488 unsigned int spl_fixpt_u4d19(struct spl_fixed31_32 arg);
489
490 unsigned int spl_fixpt_u3d19(struct spl_fixed31_32 arg);
491
492 unsigned int spl_fixpt_u2d19(struct spl_fixed31_32 arg);
493
494 unsigned int spl_fixpt_u0d19(struct spl_fixed31_32 arg);
495
496 unsigned int spl_fixpt_clamp_u0d14(struct spl_fixed31_32 arg);
497
498 unsigned int spl_fixpt_clamp_u0d10(struct spl_fixed31_32 arg);
499
500 int spl_fixpt_s4d19(struct spl_fixed31_32 arg);
501
spl_fixpt_truncate(struct spl_fixed31_32 arg,unsigned int frac_bits)502 static inline struct spl_fixed31_32 spl_fixpt_truncate(struct spl_fixed31_32 arg, unsigned int frac_bits)
503 {
504 bool negative = arg.value < 0;
505
506 if (frac_bits >= FIXED31_32_BITS_PER_FRACTIONAL_PART) {
507 ASSERT(frac_bits == FIXED31_32_BITS_PER_FRACTIONAL_PART);
508 return arg;
509 }
510
511 if (negative)
512 arg.value = -arg.value;
513 arg.value &= (~0ULL) << (FIXED31_32_BITS_PER_FRACTIONAL_PART - frac_bits);
514 if (negative)
515 arg.value = -arg.value;
516 return arg;
517 }
518
519 struct spl_fixed31_32 spl_fixpt_from_ux_dy(unsigned int value, unsigned int integer_bits, unsigned int fractional_bits);
520 struct spl_fixed31_32 spl_fixpt_from_int_dy(unsigned int int_value,
521 unsigned int frac_value,
522 unsigned int integer_bits,
523 unsigned int fractional_bits);
524
525 #endif
526