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