2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include "phy_qmath.h"
20 * Description: This function make 16 bit unsigned multiplication.
21 * To fit the output into 16 bits the 32 bit multiplication result is right
24 u16
qm_mulu16(u16 op1
, u16 op2
)
26 return (u16
) (((u32
) op1
* (u32
) op2
) >> 16);
30 * Description: This function make 16 bit multiplication and return the result
31 * in 16 bits. To fit the multiplication result into 16 bits the multiplication
32 * result is right shifted by 15 bits. Right shifting 15 bits instead of 16 bits
33 * is done to remove the extra sign bit formed due to the multiplication.
34 * When both the 16bit inputs are 0x8000 then the output is saturated to
37 s16
qm_muls16(s16 op1
, s16 op2
)
40 if (op1
== (s16
) 0x8000 && op2
== (s16
) 0x8000)
43 result
= ((s32
) (op1
) * (s32
) (op2
));
45 return (s16
) (result
>> 15);
49 * Description: This function add two 32 bit numbers and return the 32bit
50 * result. If the result overflow 32 bits, the output will be saturated to
53 s32
qm_add32(s32 op1
, s32 op2
)
57 if (op1
< 0 && op2
< 0 && result
> 0)
59 else if (op1
> 0 && op2
> 0 && result
< 0)
66 * Description: This function add two 16 bit numbers and return the 16bit
67 * result. If the result overflow 16 bits, the output will be saturated to
70 s16
qm_add16(s16 op1
, s16 op2
)
73 s32 temp
= (s32
) op1
+ (s32
) op2
;
74 if (temp
> (s32
) 0x7fff)
75 result
= (s16
) 0x7fff;
76 else if (temp
< (s32
) 0xffff8000)
77 result
= (s16
) 0xffff8000;
85 * Description: This function make 16 bit subtraction and return the 16bit
86 * result. If the result overflow 16 bits, the output will be saturated to
89 s16
qm_sub16(s16 op1
, s16 op2
)
92 s32 temp
= (s32
) op1
- (s32
) op2
;
93 if (temp
> (s32
) 0x7fff)
94 result
= (s16
) 0x7fff;
95 else if (temp
< (s32
) 0xffff8000)
96 result
= (s16
) 0xffff8000;
104 * Description: This function make a 32 bit saturated left shift when the
105 * specified shift is +ve. This function will make a 32 bit right shift when
106 * the specified shift is -ve. This function return the result after shifting
109 s32
qm_shl32(s32 op
, int shift
)
116 else if (shift
< -31)
119 for (i
= 0; i
< shift
; i
++)
120 result
= qm_add32(result
, result
);
122 result
= result
>> (-shift
);
129 * Description: This function make a 16 bit saturated left shift when the
130 * specified shift is +ve. This function will make a 16 bit right shift when
131 * the specified shift is -ve. This function return the result after shifting
134 s16
qm_shl16(s16 op
, int shift
)
141 else if (shift
< -15)
144 for (i
= 0; i
< shift
; i
++)
145 result
= qm_add16(result
, result
);
147 result
= result
>> (-shift
);
154 * Description: This function make a 16 bit right shift when shift is +ve.
155 * This function make a 16 bit saturated left shift when shift is -ve. This
156 * function return the result of the shift operation.
158 s16
qm_shr16(s16 op
, int shift
)
160 return qm_shl16(op
, -shift
);
164 * Description: This function return the number of redundant sign bits in a
165 * 32 bit number. Example: qm_norm32(0x00000080) = 23
167 s16
qm_norm32(s32 op
)
169 u16 u16extraSignBits
;
173 u16extraSignBits
= 0;
174 while ((op
>> 31) == (op
>> 30)) {
179 return u16extraSignBits
;
182 /* This table is log2(1+(i/32)) where i=[0:1:31], in q.15 format */
183 static const s16 log_table
[] = {
218 #define LOG_TABLE_SIZE 32 /* log_table size */
219 #define LOG2_LOG_TABLE_SIZE 5 /* log2(log_table size) */
220 #define Q_LOG_TABLE 15 /* qformat of log_table */
221 #define LOG10_2 19728 /* log10(2) in q.16 */
225 * This routine takes the input number N and its q format qN and compute
226 * the log10(N). This routine first normalizes the input no N. Then N is in
227 * mag*(2^x) format. mag is any number in the range 2^30-(2^31 - 1).
228 * Then log2(mag * 2^x) = log2(mag) + x is computed. From that
229 * log10(mag * 2^x) = log2(mag * 2^x) * log10(2) is computed.
230 * This routine looks the log2 value in the table considering
231 * LOG2_LOG_TABLE_SIZE+1 MSBs. As the MSB is always 1, only next
232 * LOG2_OF_LOG_TABLE_SIZE MSBs are used for table lookup. Next 16 MSBs are used
235 * N - number to which log10 has to be found.
237 * log10N - address where log10(N) will be written.
238 * qLog10N - address where log10N qformat will be written.
240 * For accurate results input should be in normalized or near normalized form.
242 void qm_log10(s32 N
, s16 qN
, s16
*log10N
, s16
*qLog10N
)
244 s16 s16norm
, s16tableIndex
, s16errorApproximation
;
248 /* normalize the N. */
249 s16norm
= qm_norm32(N
);
252 /* The qformat of N after normalization.
253 * -30 is added to treat the no as between 1.0 to 2.0
254 * i.e. after adding the -30 to the qformat the decimal point will be
255 * just rigtht of the MSB. (i.e. after sign bit and 1st MSB). i.e.
256 * at the right side of 30th bit.
258 qN
= qN
+ s16norm
- 30;
260 /* take the table index as the LOG2_OF_LOG_TABLE_SIZE bits right of the
262 s16tableIndex
= (s16
) (N
>> (32 - (2 + LOG2_LOG_TABLE_SIZE
)));
264 /* remove the MSB. the MSB is always 1 after normalization. */
266 s16tableIndex
& (s16
) ((1 << LOG2_LOG_TABLE_SIZE
) - 1);
268 /* remove the (1+LOG2_OF_LOG_TABLE_SIZE) MSBs in the N. */
269 N
= N
& ((1 << (32 - (2 + LOG2_LOG_TABLE_SIZE
))) - 1);
271 /* take the offset as the 16 MSBS after table index.
273 u16offset
= (u16
) (N
>> (32 - (2 + LOG2_LOG_TABLE_SIZE
+ 16)));
275 /* look the log value in the table. */
276 s32log
= log_table
[s16tableIndex
]; /* q.15 format */
278 /* interpolate using the offset. q.15 format. */
279 s16errorApproximation
= (s16
) qm_mulu16(u16offset
,
280 (u16
) (log_table
[s16tableIndex
+ 1] -
281 log_table
[s16tableIndex
]));
284 s32log
= qm_add16((s16
) s32log
, s16errorApproximation
);
286 /* adjust for the qformat of the N as
287 * log2(mag * 2^x) = log2(mag) + x
289 s32log
= qm_add32(s32log
, ((s32
) -qN
) << 15); /* q.15 format */
291 /* normalize the result. */
292 s16norm
= qm_norm32(s32log
);
294 /* bring all the important bits into lower 16 bits */
295 /* q.15+s16norm-16 format */
296 s32log
= qm_shl32(s32log
, s16norm
- 16);
298 /* compute the log10(N) by multiplying log2(N) with log10(2).
299 * as log10(mag * 2^x) = log2(mag * 2^x) * log10(2)
300 * log10N in q.15+s16norm-16+1 (LOG10_2 is in q.16)
302 *log10N
= qm_muls16((s16
) s32log
, (s16
) LOG10_2
);
304 /* write the q format of the result. */
305 *qLog10N
= 15 + s16norm
- 16 + 1;