123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- /*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include "phy_qmath.h"
- /*
- * Description: This function make 16 bit unsigned multiplication.
- * To fit the output into 16 bits the 32 bit multiplication result is right
- * shifted by 16 bits.
- */
- u16 qm_mulu16(u16 op1, u16 op2)
- {
- return (u16) (((u32) op1 * (u32) op2) >> 16);
- }
- /*
- * Description: This function make 16 bit multiplication and return the result
- * in 16 bits. To fit the multiplication result into 16 bits the multiplication
- * result is right shifted by 15 bits. Right shifting 15 bits instead of 16 bits
- * is done to remove the extra sign bit formed due to the multiplication.
- * When both the 16bit inputs are 0x8000 then the output is saturated to
- * 0x7fffffff.
- */
- s16 qm_muls16(s16 op1, s16 op2)
- {
- s32 result;
- if (op1 == (s16) 0x8000 && op2 == (s16) 0x8000)
- result = 0x7fffffff;
- else
- result = ((s32) (op1) * (s32) (op2));
- return (s16) (result >> 15);
- }
- /*
- * Description: This function add two 32 bit numbers and return the 32bit
- * result. If the result overflow 32 bits, the output will be saturated to
- * 32bits.
- */
- s32 qm_add32(s32 op1, s32 op2)
- {
- s32 result;
- result = op1 + op2;
- if (op1 < 0 && op2 < 0 && result > 0)
- result = 0x80000000;
- else if (op1 > 0 && op2 > 0 && result < 0)
- result = 0x7fffffff;
- return result;
- }
- /*
- * Description: This function add two 16 bit numbers and return the 16bit
- * result. If the result overflow 16 bits, the output will be saturated to
- * 16bits.
- */
- s16 qm_add16(s16 op1, s16 op2)
- {
- s16 result;
- s32 temp = (s32) op1 + (s32) op2;
- if (temp > (s32) 0x7fff)
- result = (s16) 0x7fff;
- else if (temp < (s32) 0xffff8000)
- result = (s16) 0xffff8000;
- else
- result = (s16) temp;
- return result;
- }
- /*
- * Description: This function make 16 bit subtraction and return the 16bit
- * result. If the result overflow 16 bits, the output will be saturated to
- * 16bits.
- */
- s16 qm_sub16(s16 op1, s16 op2)
- {
- s16 result;
- s32 temp = (s32) op1 - (s32) op2;
- if (temp > (s32) 0x7fff)
- result = (s16) 0x7fff;
- else if (temp < (s32) 0xffff8000)
- result = (s16) 0xffff8000;
- else
- result = (s16) temp;
- return result;
- }
- /*
- * Description: This function make a 32 bit saturated left shift when the
- * specified shift is +ve. This function will make a 32 bit right shift when
- * the specified shift is -ve. This function return the result after shifting
- * operation.
- */
- s32 qm_shl32(s32 op, int shift)
- {
- int i;
- s32 result;
- result = op;
- if (shift > 31)
- shift = 31;
- else if (shift < -31)
- shift = -31;
- if (shift >= 0) {
- for (i = 0; i < shift; i++)
- result = qm_add32(result, result);
- } else {
- result = result >> (-shift);
- }
- return result;
- }
- /*
- * Description: This function make a 16 bit saturated left shift when the
- * specified shift is +ve. This function will make a 16 bit right shift when
- * the specified shift is -ve. This function return the result after shifting
- * operation.
- */
- s16 qm_shl16(s16 op, int shift)
- {
- int i;
- s16 result;
- result = op;
- if (shift > 15)
- shift = 15;
- else if (shift < -15)
- shift = -15;
- if (shift > 0) {
- for (i = 0; i < shift; i++)
- result = qm_add16(result, result);
- } else {
- result = result >> (-shift);
- }
- return result;
- }
- /*
- * Description: This function make a 16 bit right shift when shift is +ve.
- * This function make a 16 bit saturated left shift when shift is -ve. This
- * function return the result of the shift operation.
- */
- s16 qm_shr16(s16 op, int shift)
- {
- return qm_shl16(op, -shift);
- }
- /*
- * Description: This function return the number of redundant sign bits in a
- * 32 bit number. Example: qm_norm32(0x00000080) = 23
- */
- s16 qm_norm32(s32 op)
- {
- u16 u16extraSignBits;
- if (op == 0) {
- return 31;
- } else {
- u16extraSignBits = 0;
- while ((op >> 31) == (op >> 30)) {
- u16extraSignBits++;
- op = op << 1;
- }
- }
- return u16extraSignBits;
- }
- /* This table is log2(1+(i/32)) where i=[0:1:32], in q.15 format */
- static const s16 log_table[] = {
- 0,
- 1455,
- 2866,
- 4236,
- 5568,
- 6863,
- 8124,
- 9352,
- 10549,
- 11716,
- 12855,
- 13968,
- 15055,
- 16117,
- 17156,
- 18173,
- 19168,
- 20143,
- 21098,
- 22034,
- 22952,
- 23852,
- 24736,
- 25604,
- 26455,
- 27292,
- 28114,
- 28922,
- 29717,
- 30498,
- 31267,
- 32024,
- 32767
- };
- #define LOG_TABLE_SIZE 32 /* log_table size */
- #define LOG2_LOG_TABLE_SIZE 5 /* log2(log_table size) */
- #define Q_LOG_TABLE 15 /* qformat of log_table */
- #define LOG10_2 19728 /* log10(2) in q.16 */
- /*
- * Description:
- * This routine takes the input number N and its q format qN and compute
- * the log10(N). This routine first normalizes the input no N. Then N is in
- * mag*(2^x) format. mag is any number in the range 2^30-(2^31 - 1).
- * Then log2(mag * 2^x) = log2(mag) + x is computed. From that
- * log10(mag * 2^x) = log2(mag * 2^x) * log10(2) is computed.
- * This routine looks the log2 value in the table considering
- * LOG2_LOG_TABLE_SIZE+1 MSBs. As the MSB is always 1, only next
- * LOG2_OF_LOG_TABLE_SIZE MSBs are used for table lookup. Next 16 MSBs are used
- * for interpolation.
- * Inputs:
- * N - number to which log10 has to be found.
- * qN - q format of N
- * log10N - address where log10(N) will be written.
- * qLog10N - address where log10N qformat will be written.
- * Note/Problem:
- * For accurate results input should be in normalized or near normalized form.
- */
- void qm_log10(s32 N, s16 qN, s16 *log10N, s16 *qLog10N)
- {
- s16 s16norm, s16tableIndex, s16errorApproximation;
- u16 u16offset;
- s32 s32log;
- /* normalize the N. */
- s16norm = qm_norm32(N);
- N = N << s16norm;
- /* The qformat of N after normalization.
- * -30 is added to treat the no as between 1.0 to 2.0
- * i.e. after adding the -30 to the qformat the decimal point will be
- * just rigtht of the MSB. (i.e. after sign bit and 1st MSB). i.e.
- * at the right side of 30th bit.
- */
- qN = qN + s16norm - 30;
- /* take the table index as the LOG2_OF_LOG_TABLE_SIZE bits right of the
- * MSB */
- s16tableIndex = (s16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE)));
- /* remove the MSB. the MSB is always 1 after normalization. */
- s16tableIndex =
- s16tableIndex & (s16) ((1 << LOG2_LOG_TABLE_SIZE) - 1);
- /* remove the (1+LOG2_OF_LOG_TABLE_SIZE) MSBs in the N. */
- N = N & ((1 << (32 - (2 + LOG2_LOG_TABLE_SIZE))) - 1);
- /* take the offset as the 16 MSBS after table index.
- */
- u16offset = (u16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE + 16)));
- /* look the log value in the table. */
- s32log = log_table[s16tableIndex]; /* q.15 format */
- /* interpolate using the offset. q.15 format. */
- s16errorApproximation = (s16) qm_mulu16(u16offset,
- (u16) (log_table[s16tableIndex + 1] -
- log_table[s16tableIndex]));
- /* q.15 format */
- s32log = qm_add16((s16) s32log, s16errorApproximation);
- /* adjust for the qformat of the N as
- * log2(mag * 2^x) = log2(mag) + x
- */
- s32log = qm_add32(s32log, ((s32) -qN) << 15); /* q.15 format */
- /* normalize the result. */
- s16norm = qm_norm32(s32log);
- /* bring all the important bits into lower 16 bits */
- /* q.15+s16norm-16 format */
- s32log = qm_shl32(s32log, s16norm - 16);
- /* compute the log10(N) by multiplying log2(N) with log10(2).
- * as log10(mag * 2^x) = log2(mag * 2^x) * log10(2)
- * log10N in q.15+s16norm-16+1 (LOG10_2 is in q.16)
- */
- *log10N = qm_muls16((s16) s32log, (s16) LOG10_2);
- /* write the q format of the result. */
- *qLog10N = 15 + s16norm - 16 + 1;
- return;
- }
|