Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c
178701 views
// SPDX-License-Identifier: ISC1/*2* Copyright (c) 2010 Broadcom Corporation3*/45#include "phy_qmath.h"67/*8* Description: This function make 16 bit unsigned multiplication.9* To fit the output into 16 bits the 32 bit multiplication result is right10* shifted by 16 bits.11*/12u16 qm_mulu16(u16 op1, u16 op2)13{14return (u16) (((u32) op1 * (u32) op2) >> 16);15}1617/*18* Description: This function make 16 bit multiplication and return the result19* in 16 bits. To fit the multiplication result into 16 bits the multiplication20* result is right shifted by 15 bits. Right shifting 15 bits instead of 16 bits21* is done to remove the extra sign bit formed due to the multiplication.22* When both the 16bit inputs are 0x8000 then the output is saturated to23* 0x7fffffff.24*/25s16 qm_muls16(s16 op1, s16 op2)26{27s32 result;28if (op1 == (s16) 0x8000 && op2 == (s16) 0x8000)29result = 0x7fffffff;30else31result = ((s32) (op1) * (s32) (op2));3233return (s16) (result >> 15);34}3536/*37* Description: This function add two 32 bit numbers and return the 32bit38* result. If the result overflow 32 bits, the output will be saturated to39* 32bits.40*/41s32 qm_add32(s32 op1, s32 op2)42{43s32 result;44result = op1 + op2;45if (op1 < 0 && op2 < 0 && result > 0)46result = 0x80000000;47else if (op1 > 0 && op2 > 0 && result < 0)48result = 0x7fffffff;4950return result;51}5253/*54* Description: This function add two 16 bit numbers and return the 16bit55* result. If the result overflow 16 bits, the output will be saturated to56* 16bits.57*/58s16 qm_add16(s16 op1, s16 op2)59{60s16 result;61s32 temp = (s32) op1 + (s32) op2;62if (temp > (s32) 0x7fff)63result = (s16) 0x7fff;64else if (temp < (s32) 0xffff8000)65result = (s16) 0xffff8000;66else67result = (s16) temp;6869return result;70}7172/*73* Description: This function make 16 bit subtraction and return the 16bit74* result. If the result overflow 16 bits, the output will be saturated to75* 16bits.76*/77s16 qm_sub16(s16 op1, s16 op2)78{79s16 result;80s32 temp = (s32) op1 - (s32) op2;81if (temp > (s32) 0x7fff)82result = (s16) 0x7fff;83else if (temp < (s32) 0xffff8000)84result = (s16) 0xffff8000;85else86result = (s16) temp;8788return result;89}9091/*92* Description: This function make a 32 bit saturated left shift when the93* specified shift is +ve. This function will make a 32 bit right shift when94* the specified shift is -ve. This function return the result after shifting95* operation.96*/97s32 qm_shl32(s32 op, int shift)98{99int i;100s32 result;101result = op;102if (shift > 31)103shift = 31;104else if (shift < -31)105shift = -31;106if (shift >= 0) {107for (i = 0; i < shift; i++)108result = qm_add32(result, result);109} else {110result = result >> (-shift);111}112113return result;114}115116/*117* Description: This function make a 16 bit saturated left shift when the118* specified shift is +ve. This function will make a 16 bit right shift when119* the specified shift is -ve. This function return the result after shifting120* operation.121*/122s16 qm_shl16(s16 op, int shift)123{124int i;125s16 result;126result = op;127if (shift > 15)128shift = 15;129else if (shift < -15)130shift = -15;131if (shift > 0) {132for (i = 0; i < shift; i++)133result = qm_add16(result, result);134} else {135result = result >> (-shift);136}137138return result;139}140141/*142* Description: This function make a 16 bit right shift when shift is +ve.143* This function make a 16 bit saturated left shift when shift is -ve. This144* function return the result of the shift operation.145*/146s16 qm_shr16(s16 op, int shift)147{148return qm_shl16(op, -shift);149}150151/*152* Description: This function return the number of redundant sign bits in a153* 32 bit number. Example: qm_norm32(0x00000080) = 23154*/155s16 qm_norm32(s32 op)156{157u16 u16extraSignBits;158if (op == 0) {159return 31;160} else {161u16extraSignBits = 0;162while ((op >> 31) == (op >> 30)) {163u16extraSignBits++;164op = op << 1;165}166}167return u16extraSignBits;168}169170/* This table is log2(1+(i/32)) where i=[0:1:32], in q.15 format */171static const s16 log_table[] = {1720,1731455,1742866,1754236,1765568,1776863,1788124,1799352,18010549,18111716,18212855,18313968,18415055,18516117,18617156,18718173,18819168,18920143,19021098,19122034,19222952,19323852,19424736,19525604,19626455,19727292,19828114,19928922,20029717,20130498,20231267,20332024,20432767205};206207#define LOG_TABLE_SIZE 32 /* log_table size */208#define LOG2_LOG_TABLE_SIZE 5 /* log2(log_table size) */209#define Q_LOG_TABLE 15 /* qformat of log_table */210#define LOG10_2 19728 /* log10(2) in q.16 */211212/*213* Description:214* This routine takes the input number N and its q format qN and compute215* the log10(N). This routine first normalizes the input no N. Then N is in216* mag*(2^x) format. mag is any number in the range 2^30-(2^31 - 1).217* Then log2(mag * 2^x) = log2(mag) + x is computed. From that218* log10(mag * 2^x) = log2(mag * 2^x) * log10(2) is computed.219* This routine looks the log2 value in the table considering220* LOG2_LOG_TABLE_SIZE+1 MSBs. As the MSB is always 1, only next221* LOG2_OF_LOG_TABLE_SIZE MSBs are used for table lookup. Next 16 MSBs are used222* for interpolation.223* Inputs:224* N - number to which log10 has to be found.225* qN - q format of N226* log10N - address where log10(N) will be written.227* qLog10N - address where log10N qformat will be written.228* Note/Problem:229* For accurate results input should be in normalized or near normalized form.230*/231void qm_log10(s32 N, s16 qN, s16 *log10N, s16 *qLog10N)232{233s16 s16norm, s16tableIndex, s16errorApproximation;234u16 u16offset;235s32 s32log;236237/* normalize the N. */238s16norm = qm_norm32(N);239N = N << s16norm;240241/* The qformat of N after normalization.242* -30 is added to treat the no as between 1.0 to 2.0243* i.e. after adding the -30 to the qformat the decimal point will be244* just rigtht of the MSB. (i.e. after sign bit and 1st MSB). i.e.245* at the right side of 30th bit.246*/247qN = qN + s16norm - 30;248249/* take the table index as the LOG2_OF_LOG_TABLE_SIZE bits right of the250* MSB */251s16tableIndex = (s16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE)));252253/* remove the MSB. the MSB is always 1 after normalization. */254s16tableIndex =255s16tableIndex & (s16) ((1 << LOG2_LOG_TABLE_SIZE) - 1);256257/* remove the (1+LOG2_OF_LOG_TABLE_SIZE) MSBs in the N. */258N = N & ((1 << (32 - (2 + LOG2_LOG_TABLE_SIZE))) - 1);259260/* take the offset as the 16 MSBS after table index.261*/262u16offset = (u16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE + 16)));263264/* look the log value in the table. */265s32log = log_table[s16tableIndex]; /* q.15 format */266267/* interpolate using the offset. q.15 format. */268s16errorApproximation = (s16) qm_mulu16(u16offset,269(u16) (log_table[s16tableIndex + 1] -270log_table[s16tableIndex]));271272/* q.15 format */273s32log = qm_add16((s16) s32log, s16errorApproximation);274275/* adjust for the qformat of the N as276* log2(mag * 2^x) = log2(mag) + x277*/278s32log = qm_add32(s32log, ((s32) -qN) << 15); /* q.15 format */279280/* normalize the result. */281s16norm = qm_norm32(s32log);282283/* bring all the important bits into lower 16 bits */284/* q.15+s16norm-16 format */285s32log = qm_shl32(s32log, s16norm - 16);286287/* compute the log10(N) by multiplying log2(N) with log10(2).288* as log10(mag * 2^x) = log2(mag * 2^x) * log10(2)289* log10N in q.15+s16norm-16+1 (LOG10_2 is in q.16)290*/291*log10N = qm_muls16((s16) s32log, (s16) LOG10_2);292293/* write the q format of the result. */294*qLog10N = 15 + s16norm - 16 + 1;295296return;297}298299300