1*b4c3e9b5SBjoern A. Zeeb // SPDX-License-Identifier: ISC
2*b4c3e9b5SBjoern A. Zeeb /*
3*b4c3e9b5SBjoern A. Zeeb * Copyright (c) 2010 Broadcom Corporation
4*b4c3e9b5SBjoern A. Zeeb */
5*b4c3e9b5SBjoern A. Zeeb
6*b4c3e9b5SBjoern A. Zeeb #include "phy_qmath.h"
7*b4c3e9b5SBjoern A. Zeeb
8*b4c3e9b5SBjoern A. Zeeb /*
9*b4c3e9b5SBjoern A. Zeeb * Description: This function make 16 bit unsigned multiplication.
10*b4c3e9b5SBjoern A. Zeeb * To fit the output into 16 bits the 32 bit multiplication result is right
11*b4c3e9b5SBjoern A. Zeeb * shifted by 16 bits.
12*b4c3e9b5SBjoern A. Zeeb */
qm_mulu16(u16 op1,u16 op2)13*b4c3e9b5SBjoern A. Zeeb u16 qm_mulu16(u16 op1, u16 op2)
14*b4c3e9b5SBjoern A. Zeeb {
15*b4c3e9b5SBjoern A. Zeeb return (u16) (((u32) op1 * (u32) op2) >> 16);
16*b4c3e9b5SBjoern A. Zeeb }
17*b4c3e9b5SBjoern A. Zeeb
18*b4c3e9b5SBjoern A. Zeeb /*
19*b4c3e9b5SBjoern A. Zeeb * Description: This function make 16 bit multiplication and return the result
20*b4c3e9b5SBjoern A. Zeeb * in 16 bits. To fit the multiplication result into 16 bits the multiplication
21*b4c3e9b5SBjoern A. Zeeb * result is right shifted by 15 bits. Right shifting 15 bits instead of 16 bits
22*b4c3e9b5SBjoern A. Zeeb * is done to remove the extra sign bit formed due to the multiplication.
23*b4c3e9b5SBjoern A. Zeeb * When both the 16bit inputs are 0x8000 then the output is saturated to
24*b4c3e9b5SBjoern A. Zeeb * 0x7fffffff.
25*b4c3e9b5SBjoern A. Zeeb */
qm_muls16(s16 op1,s16 op2)26*b4c3e9b5SBjoern A. Zeeb s16 qm_muls16(s16 op1, s16 op2)
27*b4c3e9b5SBjoern A. Zeeb {
28*b4c3e9b5SBjoern A. Zeeb s32 result;
29*b4c3e9b5SBjoern A. Zeeb if (op1 == (s16) 0x8000 && op2 == (s16) 0x8000)
30*b4c3e9b5SBjoern A. Zeeb result = 0x7fffffff;
31*b4c3e9b5SBjoern A. Zeeb else
32*b4c3e9b5SBjoern A. Zeeb result = ((s32) (op1) * (s32) (op2));
33*b4c3e9b5SBjoern A. Zeeb
34*b4c3e9b5SBjoern A. Zeeb return (s16) (result >> 15);
35*b4c3e9b5SBjoern A. Zeeb }
36*b4c3e9b5SBjoern A. Zeeb
37*b4c3e9b5SBjoern A. Zeeb /*
38*b4c3e9b5SBjoern A. Zeeb * Description: This function add two 32 bit numbers and return the 32bit
39*b4c3e9b5SBjoern A. Zeeb * result. If the result overflow 32 bits, the output will be saturated to
40*b4c3e9b5SBjoern A. Zeeb * 32bits.
41*b4c3e9b5SBjoern A. Zeeb */
qm_add32(s32 op1,s32 op2)42*b4c3e9b5SBjoern A. Zeeb s32 qm_add32(s32 op1, s32 op2)
43*b4c3e9b5SBjoern A. Zeeb {
44*b4c3e9b5SBjoern A. Zeeb s32 result;
45*b4c3e9b5SBjoern A. Zeeb result = op1 + op2;
46*b4c3e9b5SBjoern A. Zeeb if (op1 < 0 && op2 < 0 && result > 0)
47*b4c3e9b5SBjoern A. Zeeb result = 0x80000000;
48*b4c3e9b5SBjoern A. Zeeb else if (op1 > 0 && op2 > 0 && result < 0)
49*b4c3e9b5SBjoern A. Zeeb result = 0x7fffffff;
50*b4c3e9b5SBjoern A. Zeeb
51*b4c3e9b5SBjoern A. Zeeb return result;
52*b4c3e9b5SBjoern A. Zeeb }
53*b4c3e9b5SBjoern A. Zeeb
54*b4c3e9b5SBjoern A. Zeeb /*
55*b4c3e9b5SBjoern A. Zeeb * Description: This function add two 16 bit numbers and return the 16bit
56*b4c3e9b5SBjoern A. Zeeb * result. If the result overflow 16 bits, the output will be saturated to
57*b4c3e9b5SBjoern A. Zeeb * 16bits.
58*b4c3e9b5SBjoern A. Zeeb */
qm_add16(s16 op1,s16 op2)59*b4c3e9b5SBjoern A. Zeeb s16 qm_add16(s16 op1, s16 op2)
60*b4c3e9b5SBjoern A. Zeeb {
61*b4c3e9b5SBjoern A. Zeeb s16 result;
62*b4c3e9b5SBjoern A. Zeeb s32 temp = (s32) op1 + (s32) op2;
63*b4c3e9b5SBjoern A. Zeeb if (temp > (s32) 0x7fff)
64*b4c3e9b5SBjoern A. Zeeb result = (s16) 0x7fff;
65*b4c3e9b5SBjoern A. Zeeb else if (temp < (s32) 0xffff8000)
66*b4c3e9b5SBjoern A. Zeeb result = (s16) 0xffff8000;
67*b4c3e9b5SBjoern A. Zeeb else
68*b4c3e9b5SBjoern A. Zeeb result = (s16) temp;
69*b4c3e9b5SBjoern A. Zeeb
70*b4c3e9b5SBjoern A. Zeeb return result;
71*b4c3e9b5SBjoern A. Zeeb }
72*b4c3e9b5SBjoern A. Zeeb
73*b4c3e9b5SBjoern A. Zeeb /*
74*b4c3e9b5SBjoern A. Zeeb * Description: This function make 16 bit subtraction and return the 16bit
75*b4c3e9b5SBjoern A. Zeeb * result. If the result overflow 16 bits, the output will be saturated to
76*b4c3e9b5SBjoern A. Zeeb * 16bits.
77*b4c3e9b5SBjoern A. Zeeb */
qm_sub16(s16 op1,s16 op2)78*b4c3e9b5SBjoern A. Zeeb s16 qm_sub16(s16 op1, s16 op2)
79*b4c3e9b5SBjoern A. Zeeb {
80*b4c3e9b5SBjoern A. Zeeb s16 result;
81*b4c3e9b5SBjoern A. Zeeb s32 temp = (s32) op1 - (s32) op2;
82*b4c3e9b5SBjoern A. Zeeb if (temp > (s32) 0x7fff)
83*b4c3e9b5SBjoern A. Zeeb result = (s16) 0x7fff;
84*b4c3e9b5SBjoern A. Zeeb else if (temp < (s32) 0xffff8000)
85*b4c3e9b5SBjoern A. Zeeb result = (s16) 0xffff8000;
86*b4c3e9b5SBjoern A. Zeeb else
87*b4c3e9b5SBjoern A. Zeeb result = (s16) temp;
88*b4c3e9b5SBjoern A. Zeeb
89*b4c3e9b5SBjoern A. Zeeb return result;
90*b4c3e9b5SBjoern A. Zeeb }
91*b4c3e9b5SBjoern A. Zeeb
92*b4c3e9b5SBjoern A. Zeeb /*
93*b4c3e9b5SBjoern A. Zeeb * Description: This function make a 32 bit saturated left shift when the
94*b4c3e9b5SBjoern A. Zeeb * specified shift is +ve. This function will make a 32 bit right shift when
95*b4c3e9b5SBjoern A. Zeeb * the specified shift is -ve. This function return the result after shifting
96*b4c3e9b5SBjoern A. Zeeb * operation.
97*b4c3e9b5SBjoern A. Zeeb */
qm_shl32(s32 op,int shift)98*b4c3e9b5SBjoern A. Zeeb s32 qm_shl32(s32 op, int shift)
99*b4c3e9b5SBjoern A. Zeeb {
100*b4c3e9b5SBjoern A. Zeeb int i;
101*b4c3e9b5SBjoern A. Zeeb s32 result;
102*b4c3e9b5SBjoern A. Zeeb result = op;
103*b4c3e9b5SBjoern A. Zeeb if (shift > 31)
104*b4c3e9b5SBjoern A. Zeeb shift = 31;
105*b4c3e9b5SBjoern A. Zeeb else if (shift < -31)
106*b4c3e9b5SBjoern A. Zeeb shift = -31;
107*b4c3e9b5SBjoern A. Zeeb if (shift >= 0) {
108*b4c3e9b5SBjoern A. Zeeb for (i = 0; i < shift; i++)
109*b4c3e9b5SBjoern A. Zeeb result = qm_add32(result, result);
110*b4c3e9b5SBjoern A. Zeeb } else {
111*b4c3e9b5SBjoern A. Zeeb result = result >> (-shift);
112*b4c3e9b5SBjoern A. Zeeb }
113*b4c3e9b5SBjoern A. Zeeb
114*b4c3e9b5SBjoern A. Zeeb return result;
115*b4c3e9b5SBjoern A. Zeeb }
116*b4c3e9b5SBjoern A. Zeeb
117*b4c3e9b5SBjoern A. Zeeb /*
118*b4c3e9b5SBjoern A. Zeeb * Description: This function make a 16 bit saturated left shift when the
119*b4c3e9b5SBjoern A. Zeeb * specified shift is +ve. This function will make a 16 bit right shift when
120*b4c3e9b5SBjoern A. Zeeb * the specified shift is -ve. This function return the result after shifting
121*b4c3e9b5SBjoern A. Zeeb * operation.
122*b4c3e9b5SBjoern A. Zeeb */
qm_shl16(s16 op,int shift)123*b4c3e9b5SBjoern A. Zeeb s16 qm_shl16(s16 op, int shift)
124*b4c3e9b5SBjoern A. Zeeb {
125*b4c3e9b5SBjoern A. Zeeb int i;
126*b4c3e9b5SBjoern A. Zeeb s16 result;
127*b4c3e9b5SBjoern A. Zeeb result = op;
128*b4c3e9b5SBjoern A. Zeeb if (shift > 15)
129*b4c3e9b5SBjoern A. Zeeb shift = 15;
130*b4c3e9b5SBjoern A. Zeeb else if (shift < -15)
131*b4c3e9b5SBjoern A. Zeeb shift = -15;
132*b4c3e9b5SBjoern A. Zeeb if (shift > 0) {
133*b4c3e9b5SBjoern A. Zeeb for (i = 0; i < shift; i++)
134*b4c3e9b5SBjoern A. Zeeb result = qm_add16(result, result);
135*b4c3e9b5SBjoern A. Zeeb } else {
136*b4c3e9b5SBjoern A. Zeeb result = result >> (-shift);
137*b4c3e9b5SBjoern A. Zeeb }
138*b4c3e9b5SBjoern A. Zeeb
139*b4c3e9b5SBjoern A. Zeeb return result;
140*b4c3e9b5SBjoern A. Zeeb }
141*b4c3e9b5SBjoern A. Zeeb
142*b4c3e9b5SBjoern A. Zeeb /*
143*b4c3e9b5SBjoern A. Zeeb * Description: This function make a 16 bit right shift when shift is +ve.
144*b4c3e9b5SBjoern A. Zeeb * This function make a 16 bit saturated left shift when shift is -ve. This
145*b4c3e9b5SBjoern A. Zeeb * function return the result of the shift operation.
146*b4c3e9b5SBjoern A. Zeeb */
qm_shr16(s16 op,int shift)147*b4c3e9b5SBjoern A. Zeeb s16 qm_shr16(s16 op, int shift)
148*b4c3e9b5SBjoern A. Zeeb {
149*b4c3e9b5SBjoern A. Zeeb return qm_shl16(op, -shift);
150*b4c3e9b5SBjoern A. Zeeb }
151*b4c3e9b5SBjoern A. Zeeb
152*b4c3e9b5SBjoern A. Zeeb /*
153*b4c3e9b5SBjoern A. Zeeb * Description: This function return the number of redundant sign bits in a
154*b4c3e9b5SBjoern A. Zeeb * 32 bit number. Example: qm_norm32(0x00000080) = 23
155*b4c3e9b5SBjoern A. Zeeb */
qm_norm32(s32 op)156*b4c3e9b5SBjoern A. Zeeb s16 qm_norm32(s32 op)
157*b4c3e9b5SBjoern A. Zeeb {
158*b4c3e9b5SBjoern A. Zeeb u16 u16extraSignBits;
159*b4c3e9b5SBjoern A. Zeeb if (op == 0) {
160*b4c3e9b5SBjoern A. Zeeb return 31;
161*b4c3e9b5SBjoern A. Zeeb } else {
162*b4c3e9b5SBjoern A. Zeeb u16extraSignBits = 0;
163*b4c3e9b5SBjoern A. Zeeb while ((op >> 31) == (op >> 30)) {
164*b4c3e9b5SBjoern A. Zeeb u16extraSignBits++;
165*b4c3e9b5SBjoern A. Zeeb op = op << 1;
166*b4c3e9b5SBjoern A. Zeeb }
167*b4c3e9b5SBjoern A. Zeeb }
168*b4c3e9b5SBjoern A. Zeeb return u16extraSignBits;
169*b4c3e9b5SBjoern A. Zeeb }
170*b4c3e9b5SBjoern A. Zeeb
171*b4c3e9b5SBjoern A. Zeeb /* This table is log2(1+(i/32)) where i=[0:1:32], in q.15 format */
172*b4c3e9b5SBjoern A. Zeeb static const s16 log_table[] = {
173*b4c3e9b5SBjoern A. Zeeb 0,
174*b4c3e9b5SBjoern A. Zeeb 1455,
175*b4c3e9b5SBjoern A. Zeeb 2866,
176*b4c3e9b5SBjoern A. Zeeb 4236,
177*b4c3e9b5SBjoern A. Zeeb 5568,
178*b4c3e9b5SBjoern A. Zeeb 6863,
179*b4c3e9b5SBjoern A. Zeeb 8124,
180*b4c3e9b5SBjoern A. Zeeb 9352,
181*b4c3e9b5SBjoern A. Zeeb 10549,
182*b4c3e9b5SBjoern A. Zeeb 11716,
183*b4c3e9b5SBjoern A. Zeeb 12855,
184*b4c3e9b5SBjoern A. Zeeb 13968,
185*b4c3e9b5SBjoern A. Zeeb 15055,
186*b4c3e9b5SBjoern A. Zeeb 16117,
187*b4c3e9b5SBjoern A. Zeeb 17156,
188*b4c3e9b5SBjoern A. Zeeb 18173,
189*b4c3e9b5SBjoern A. Zeeb 19168,
190*b4c3e9b5SBjoern A. Zeeb 20143,
191*b4c3e9b5SBjoern A. Zeeb 21098,
192*b4c3e9b5SBjoern A. Zeeb 22034,
193*b4c3e9b5SBjoern A. Zeeb 22952,
194*b4c3e9b5SBjoern A. Zeeb 23852,
195*b4c3e9b5SBjoern A. Zeeb 24736,
196*b4c3e9b5SBjoern A. Zeeb 25604,
197*b4c3e9b5SBjoern A. Zeeb 26455,
198*b4c3e9b5SBjoern A. Zeeb 27292,
199*b4c3e9b5SBjoern A. Zeeb 28114,
200*b4c3e9b5SBjoern A. Zeeb 28922,
201*b4c3e9b5SBjoern A. Zeeb 29717,
202*b4c3e9b5SBjoern A. Zeeb 30498,
203*b4c3e9b5SBjoern A. Zeeb 31267,
204*b4c3e9b5SBjoern A. Zeeb 32024,
205*b4c3e9b5SBjoern A. Zeeb 32767
206*b4c3e9b5SBjoern A. Zeeb };
207*b4c3e9b5SBjoern A. Zeeb
208*b4c3e9b5SBjoern A. Zeeb #define LOG_TABLE_SIZE 32 /* log_table size */
209*b4c3e9b5SBjoern A. Zeeb #define LOG2_LOG_TABLE_SIZE 5 /* log2(log_table size) */
210*b4c3e9b5SBjoern A. Zeeb #define Q_LOG_TABLE 15 /* qformat of log_table */
211*b4c3e9b5SBjoern A. Zeeb #define LOG10_2 19728 /* log10(2) in q.16 */
212*b4c3e9b5SBjoern A. Zeeb
213*b4c3e9b5SBjoern A. Zeeb /*
214*b4c3e9b5SBjoern A. Zeeb * Description:
215*b4c3e9b5SBjoern A. Zeeb * This routine takes the input number N and its q format qN and compute
216*b4c3e9b5SBjoern A. Zeeb * the log10(N). This routine first normalizes the input no N. Then N is in
217*b4c3e9b5SBjoern A. Zeeb * mag*(2^x) format. mag is any number in the range 2^30-(2^31 - 1).
218*b4c3e9b5SBjoern A. Zeeb * Then log2(mag * 2^x) = log2(mag) + x is computed. From that
219*b4c3e9b5SBjoern A. Zeeb * log10(mag * 2^x) = log2(mag * 2^x) * log10(2) is computed.
220*b4c3e9b5SBjoern A. Zeeb * This routine looks the log2 value in the table considering
221*b4c3e9b5SBjoern A. Zeeb * LOG2_LOG_TABLE_SIZE+1 MSBs. As the MSB is always 1, only next
222*b4c3e9b5SBjoern A. Zeeb * LOG2_OF_LOG_TABLE_SIZE MSBs are used for table lookup. Next 16 MSBs are used
223*b4c3e9b5SBjoern A. Zeeb * for interpolation.
224*b4c3e9b5SBjoern A. Zeeb * Inputs:
225*b4c3e9b5SBjoern A. Zeeb * N - number to which log10 has to be found.
226*b4c3e9b5SBjoern A. Zeeb * qN - q format of N
227*b4c3e9b5SBjoern A. Zeeb * log10N - address where log10(N) will be written.
228*b4c3e9b5SBjoern A. Zeeb * qLog10N - address where log10N qformat will be written.
229*b4c3e9b5SBjoern A. Zeeb * Note/Problem:
230*b4c3e9b5SBjoern A. Zeeb * For accurate results input should be in normalized or near normalized form.
231*b4c3e9b5SBjoern A. Zeeb */
qm_log10(s32 N,s16 qN,s16 * log10N,s16 * qLog10N)232*b4c3e9b5SBjoern A. Zeeb void qm_log10(s32 N, s16 qN, s16 *log10N, s16 *qLog10N)
233*b4c3e9b5SBjoern A. Zeeb {
234*b4c3e9b5SBjoern A. Zeeb s16 s16norm, s16tableIndex, s16errorApproximation;
235*b4c3e9b5SBjoern A. Zeeb u16 u16offset;
236*b4c3e9b5SBjoern A. Zeeb s32 s32log;
237*b4c3e9b5SBjoern A. Zeeb
238*b4c3e9b5SBjoern A. Zeeb /* normalize the N. */
239*b4c3e9b5SBjoern A. Zeeb s16norm = qm_norm32(N);
240*b4c3e9b5SBjoern A. Zeeb N = N << s16norm;
241*b4c3e9b5SBjoern A. Zeeb
242*b4c3e9b5SBjoern A. Zeeb /* The qformat of N after normalization.
243*b4c3e9b5SBjoern A. Zeeb * -30 is added to treat the no as between 1.0 to 2.0
244*b4c3e9b5SBjoern A. Zeeb * i.e. after adding the -30 to the qformat the decimal point will be
245*b4c3e9b5SBjoern A. Zeeb * just rigtht of the MSB. (i.e. after sign bit and 1st MSB). i.e.
246*b4c3e9b5SBjoern A. Zeeb * at the right side of 30th bit.
247*b4c3e9b5SBjoern A. Zeeb */
248*b4c3e9b5SBjoern A. Zeeb qN = qN + s16norm - 30;
249*b4c3e9b5SBjoern A. Zeeb
250*b4c3e9b5SBjoern A. Zeeb /* take the table index as the LOG2_OF_LOG_TABLE_SIZE bits right of the
251*b4c3e9b5SBjoern A. Zeeb * MSB */
252*b4c3e9b5SBjoern A. Zeeb s16tableIndex = (s16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE)));
253*b4c3e9b5SBjoern A. Zeeb
254*b4c3e9b5SBjoern A. Zeeb /* remove the MSB. the MSB is always 1 after normalization. */
255*b4c3e9b5SBjoern A. Zeeb s16tableIndex =
256*b4c3e9b5SBjoern A. Zeeb s16tableIndex & (s16) ((1 << LOG2_LOG_TABLE_SIZE) - 1);
257*b4c3e9b5SBjoern A. Zeeb
258*b4c3e9b5SBjoern A. Zeeb /* remove the (1+LOG2_OF_LOG_TABLE_SIZE) MSBs in the N. */
259*b4c3e9b5SBjoern A. Zeeb N = N & ((1 << (32 - (2 + LOG2_LOG_TABLE_SIZE))) - 1);
260*b4c3e9b5SBjoern A. Zeeb
261*b4c3e9b5SBjoern A. Zeeb /* take the offset as the 16 MSBS after table index.
262*b4c3e9b5SBjoern A. Zeeb */
263*b4c3e9b5SBjoern A. Zeeb u16offset = (u16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE + 16)));
264*b4c3e9b5SBjoern A. Zeeb
265*b4c3e9b5SBjoern A. Zeeb /* look the log value in the table. */
266*b4c3e9b5SBjoern A. Zeeb s32log = log_table[s16tableIndex]; /* q.15 format */
267*b4c3e9b5SBjoern A. Zeeb
268*b4c3e9b5SBjoern A. Zeeb /* interpolate using the offset. q.15 format. */
269*b4c3e9b5SBjoern A. Zeeb s16errorApproximation = (s16) qm_mulu16(u16offset,
270*b4c3e9b5SBjoern A. Zeeb (u16) (log_table[s16tableIndex + 1] -
271*b4c3e9b5SBjoern A. Zeeb log_table[s16tableIndex]));
272*b4c3e9b5SBjoern A. Zeeb
273*b4c3e9b5SBjoern A. Zeeb /* q.15 format */
274*b4c3e9b5SBjoern A. Zeeb s32log = qm_add16((s16) s32log, s16errorApproximation);
275*b4c3e9b5SBjoern A. Zeeb
276*b4c3e9b5SBjoern A. Zeeb /* adjust for the qformat of the N as
277*b4c3e9b5SBjoern A. Zeeb * log2(mag * 2^x) = log2(mag) + x
278*b4c3e9b5SBjoern A. Zeeb */
279*b4c3e9b5SBjoern A. Zeeb s32log = qm_add32(s32log, ((s32) -qN) << 15); /* q.15 format */
280*b4c3e9b5SBjoern A. Zeeb
281*b4c3e9b5SBjoern A. Zeeb /* normalize the result. */
282*b4c3e9b5SBjoern A. Zeeb s16norm = qm_norm32(s32log);
283*b4c3e9b5SBjoern A. Zeeb
284*b4c3e9b5SBjoern A. Zeeb /* bring all the important bits into lower 16 bits */
285*b4c3e9b5SBjoern A. Zeeb /* q.15+s16norm-16 format */
286*b4c3e9b5SBjoern A. Zeeb s32log = qm_shl32(s32log, s16norm - 16);
287*b4c3e9b5SBjoern A. Zeeb
288*b4c3e9b5SBjoern A. Zeeb /* compute the log10(N) by multiplying log2(N) with log10(2).
289*b4c3e9b5SBjoern A. Zeeb * as log10(mag * 2^x) = log2(mag * 2^x) * log10(2)
290*b4c3e9b5SBjoern A. Zeeb * log10N in q.15+s16norm-16+1 (LOG10_2 is in q.16)
291*b4c3e9b5SBjoern A. Zeeb */
292*b4c3e9b5SBjoern A. Zeeb *log10N = qm_muls16((s16) s32log, (s16) LOG10_2);
293*b4c3e9b5SBjoern A. Zeeb
294*b4c3e9b5SBjoern A. Zeeb /* write the q format of the result. */
295*b4c3e9b5SBjoern A. Zeeb *qLog10N = 15 + s16norm - 16 + 1;
296*b4c3e9b5SBjoern A. Zeeb
297*b4c3e9b5SBjoern A. Zeeb return;
298*b4c3e9b5SBjoern A. Zeeb }
299