1// SPDX-License-Identifier: MIT
2//
3// Copyright 2024 Advanced Micro Devices, Inc.
4
5#include "spl_debug.h"
6#include "spl_custom_float.h"
7
8static bool spl_build_custom_float(struct spl_fixed31_32 value,
9 const struct spl_custom_float_format *format,
10 bool *negative,
11 uint32_t *mantissa,
12 uint32_t *exponenta)
13{
14 uint32_t exp_offset = (1 << (format->exponenta_bits - 1)) - 1;
15
16 const struct spl_fixed31_32 mantissa_constant_plus_max_fraction =
17 spl_fixpt_from_fraction(numerator: (1LL << (format->mantissa_bits + 1)) - 1,
18 denominator: 1LL << format->mantissa_bits);
19
20 struct spl_fixed31_32 mantiss;
21
22 if (spl_fixpt_eq(arg1: value, arg2: spl_fixpt_zero)) {
23 *negative = false;
24 *mantissa = 0;
25 *exponenta = 0;
26 return true;
27 }
28
29 if (spl_fixpt_lt(arg1: value, arg2: spl_fixpt_zero)) {
30 *negative = format->sign;
31 value = spl_fixpt_neg(arg: value);
32 } else {
33 *negative = false;
34 }
35
36 if (spl_fixpt_lt(arg1: value, arg2: spl_fixpt_one)) {
37 uint32_t i = 1;
38
39 do {
40 value = spl_fixpt_shl(arg: value, shift: 1);
41 ++i;
42 } while (spl_fixpt_lt(arg1: value, arg2: spl_fixpt_one));
43
44 --i;
45
46 if (exp_offset <= i) {
47 *mantissa = 0;
48 *exponenta = 0;
49 return true;
50 }
51
52 *exponenta = exp_offset - i;
53 } else if (spl_fixpt_le(arg1: mantissa_constant_plus_max_fraction, arg2: value)) {
54 uint32_t i = 1;
55
56 do {
57 value = spl_fixpt_shr(arg: value, shift: 1);
58 ++i;
59 } while (spl_fixpt_lt(arg1: mantissa_constant_plus_max_fraction, arg2: value));
60
61 *exponenta = exp_offset + i - 1;
62 } else {
63 *exponenta = exp_offset;
64 }
65
66 mantiss = spl_fixpt_sub(arg1: value, arg2: spl_fixpt_one);
67
68 if (spl_fixpt_lt(arg1: mantiss, arg2: spl_fixpt_zero) ||
69 spl_fixpt_lt(arg1: spl_fixpt_one, arg2: mantiss))
70 mantiss = spl_fixpt_zero;
71 else
72 mantiss = spl_fixpt_shl(arg: mantiss, shift: format->mantissa_bits);
73
74 *mantissa = spl_fixpt_floor(arg: mantiss);
75
76 return true;
77}
78
79static bool spl_setup_custom_float(const struct spl_custom_float_format *format,
80 bool negative,
81 uint32_t mantissa,
82 uint32_t exponenta,
83 uint32_t *result)
84{
85 uint32_t i = 0;
86 uint32_t j = 0;
87 uint32_t value = 0;
88
89 /* verification code:
90 * once calculation is ok we can remove it
91 */
92
93 const uint32_t mantissa_mask =
94 (1 << (format->mantissa_bits + 1)) - 1;
95
96 const uint32_t exponenta_mask =
97 (1 << (format->exponenta_bits + 1)) - 1;
98
99 if (mantissa & ~mantissa_mask) {
100 SPL_BREAK_TO_DEBUGGER();
101 mantissa = mantissa_mask;
102 }
103
104 if (exponenta & ~exponenta_mask) {
105 SPL_BREAK_TO_DEBUGGER();
106 exponenta = exponenta_mask;
107 }
108
109 /* end of verification code */
110
111 while (i < format->mantissa_bits) {
112 uint32_t mask = 1 << i;
113
114 if (mantissa & mask)
115 value |= mask;
116
117 ++i;
118 }
119
120 while (j < format->exponenta_bits) {
121 uint32_t mask = 1 << j;
122
123 if (exponenta & mask)
124 value |= mask << i;
125
126 ++j;
127 }
128
129 if (negative && format->sign)
130 value |= 1 << (i + j);
131
132 *result = value;
133
134 return true;
135}
136
137bool spl_convert_to_custom_float_format(struct spl_fixed31_32 value,
138 const struct spl_custom_float_format *format,
139 uint32_t *result)
140{
141 uint32_t mantissa;
142 uint32_t exponenta;
143 bool negative;
144
145 return spl_build_custom_float(value, format, negative: &negative, mantissa: &mantissa, exponenta: &exponenta) &&
146 spl_setup_custom_float(format,
147 negative,
148 mantissa,
149 exponenta,
150 result);
151}
152

source code of linux/drivers/gpu/drm/amd/display/dc/sspl/spl_custom_float.c