1 // SPDX-License-Identifier: ISC
3 * Copyright (c) 2010 Broadcom Corporation
9 * Description: This function make 16 bit unsigned multiplication.
10 * To fit the output into 16 bits the 32 bit multiplication result is right
13 u16
qm_mulu16(u16 op1
, u16 op2
)
15 return (u16
) (((u32
) op1
* (u32
) op2
) >> 16);
19 * Description: This function make 16 bit multiplication and return the result
20 * in 16 bits. To fit the multiplication result into 16 bits the multiplication
21 * result is right shifted by 15 bits. Right shifting 15 bits instead of 16 bits
22 * is done to remove the extra sign bit formed due to the multiplication.
23 * When both the 16bit inputs are 0x8000 then the output is saturated to
26 s16
qm_muls16(s16 op1
, s16 op2
)
29 if (op1
== (s16
) 0x8000 && op2
== (s16
) 0x8000)
32 result
= ((s32
) (op1
) * (s32
) (op2
));
34 return (s16
) (result
>> 15);
38 * Description: This function add two 32 bit numbers and return the 32bit
39 * result. If the result overflow 32 bits, the output will be saturated to
42 s32
qm_add32(s32 op1
, s32 op2
)
46 if (op1
< 0 && op2
< 0 && result
> 0)
48 else if (op1
> 0 && op2
> 0 && result
< 0)
55 * Description: This function add two 16 bit numbers and return the 16bit
56 * result. If the result overflow 16 bits, the output will be saturated to
59 s16
qm_add16(s16 op1
, s16 op2
)
62 s32 temp
= (s32
) op1
+ (s32
) op2
;
63 if (temp
> (s32
) 0x7fff)
64 result
= (s16
) 0x7fff;
65 else if (temp
< (s32
) 0xffff8000)
66 result
= (s16
) 0xffff8000;
74 * Description: This function make 16 bit subtraction and return the 16bit
75 * result. If the result overflow 16 bits, the output will be saturated to
78 s16
qm_sub16(s16 op1
, s16 op2
)
81 s32 temp
= (s32
) op1
- (s32
) op2
;
82 if (temp
> (s32
) 0x7fff)
83 result
= (s16
) 0x7fff;
84 else if (temp
< (s32
) 0xffff8000)
85 result
= (s16
) 0xffff8000;
93 * Description: This function make a 32 bit saturated left shift when the
94 * specified shift is +ve. This function will make a 32 bit right shift when
95 * the specified shift is -ve. This function return the result after shifting
98 s32
qm_shl32(s32 op
, int shift
)
105 else if (shift
< -31)
108 for (i
= 0; i
< shift
; i
++)
109 result
= qm_add32(result
, result
);
111 result
= result
>> (-shift
);
118 * Description: This function make a 16 bit saturated left shift when the
119 * specified shift is +ve. This function will make a 16 bit right shift when
120 * the specified shift is -ve. This function return the result after shifting
123 s16
qm_shl16(s16 op
, int shift
)
130 else if (shift
< -15)
133 for (i
= 0; i
< shift
; i
++)
134 result
= qm_add16(result
, result
);
136 result
= result
>> (-shift
);
143 * Description: This function make a 16 bit right shift when shift is +ve.
144 * This function make a 16 bit saturated left shift when shift is -ve. This
145 * function return the result of the shift operation.
147 s16
qm_shr16(s16 op
, int shift
)
149 return qm_shl16(op
, -shift
);
153 * Description: This function return the number of redundant sign bits in a
154 * 32 bit number. Example: qm_norm32(0x00000080) = 23
156 s16
qm_norm32(s32 op
)
158 u16 u16extraSignBits
;
162 u16extraSignBits
= 0;
163 while ((op
>> 31) == (op
>> 30)) {
168 return u16extraSignBits
;
171 /* This table is log2(1+(i/32)) where i=[0:1:32], in q.15 format */
172 static const s16 log_table
[] = {
208 #define LOG_TABLE_SIZE 32 /* log_table size */
209 #define LOG2_LOG_TABLE_SIZE 5 /* log2(log_table size) */
210 #define Q_LOG_TABLE 15 /* qformat of log_table */
211 #define LOG10_2 19728 /* log10(2) in q.16 */
215 * This routine takes the input number N and its q format qN and compute
216 * the log10(N). This routine first normalizes the input no N. Then N is in
217 * mag*(2^x) format. mag is any number in the range 2^30-(2^31 - 1).
218 * Then log2(mag * 2^x) = log2(mag) + x is computed. From that
219 * log10(mag * 2^x) = log2(mag * 2^x) * log10(2) is computed.
220 * This routine looks the log2 value in the table considering
221 * LOG2_LOG_TABLE_SIZE+1 MSBs. As the MSB is always 1, only next
222 * LOG2_OF_LOG_TABLE_SIZE MSBs are used for table lookup. Next 16 MSBs are used
225 * N - number to which log10 has to be found.
227 * log10N - address where log10(N) will be written.
228 * qLog10N - address where log10N qformat will be written.
230 * For accurate results input should be in normalized or near normalized form.
232 void qm_log10(s32 N
, s16 qN
, s16
*log10N
, s16
*qLog10N
)
234 s16 s16norm
, s16tableIndex
, s16errorApproximation
;
238 /* normalize the N. */
239 s16norm
= qm_norm32(N
);
242 /* The qformat of N after normalization.
243 * -30 is added to treat the no as between 1.0 to 2.0
244 * i.e. after adding the -30 to the qformat the decimal point will be
245 * just rigtht of the MSB. (i.e. after sign bit and 1st MSB). i.e.
246 * at the right side of 30th bit.
248 qN
= qN
+ s16norm
- 30;
250 /* take the table index as the LOG2_OF_LOG_TABLE_SIZE bits right of the
252 s16tableIndex
= (s16
) (N
>> (32 - (2 + LOG2_LOG_TABLE_SIZE
)));
254 /* remove the MSB. the MSB is always 1 after normalization. */
256 s16tableIndex
& (s16
) ((1 << LOG2_LOG_TABLE_SIZE
) - 1);
258 /* remove the (1+LOG2_OF_LOG_TABLE_SIZE) MSBs in the N. */
259 N
= N
& ((1 << (32 - (2 + LOG2_LOG_TABLE_SIZE
))) - 1);
261 /* take the offset as the 16 MSBS after table index.
263 u16offset
= (u16
) (N
>> (32 - (2 + LOG2_LOG_TABLE_SIZE
+ 16)));
265 /* look the log value in the table. */
266 s32log
= log_table
[s16tableIndex
]; /* q.15 format */
268 /* interpolate using the offset. q.15 format. */
269 s16errorApproximation
= (s16
) qm_mulu16(u16offset
,
270 (u16
) (log_table
[s16tableIndex
+ 1] -
271 log_table
[s16tableIndex
]));
274 s32log
= qm_add16((s16
) s32log
, s16errorApproximation
);
276 /* adjust for the qformat of the N as
277 * log2(mag * 2^x) = log2(mag) + x
279 s32log
= qm_add32(s32log
, ((s32
) -qN
) << 15); /* q.15 format */
281 /* normalize the result. */
282 s16norm
= qm_norm32(s32log
);
284 /* bring all the important bits into lower 16 bits */
285 /* q.15+s16norm-16 format */
286 s32log
= qm_shl32(s32log
, s16norm
- 16);
288 /* compute the log10(N) by multiplying log2(N) with log10(2).
289 * as log10(mag * 2^x) = log2(mag * 2^x) * log10(2)
290 * log10N in q.15+s16norm-16+1 (LOG10_2 is in q.16)
292 *log10N
= qm_muls16((s16
) s32log
, (s16
) LOG10_2
);
294 /* write the q format of the result. */
295 *qLog10N
= 15 + s16norm
- 16 + 1;