/* Returns the number of remaining events that can occur on this freq counter * while respecting <freq> events per period, and taking into account that * <pend> events are already known to be pending. Returns 0 if limit was reached. */ unsigned int freq_ctr_remain_period(struct freq_ctr_period *ctr, unsigned int period, unsigned int freq, unsigned int pend) { unsigned int curr, past; unsigned int remain; curr = ctr->curr_ctr; past = ctr->prev_ctr; remain = ctr->curr_tick + period - now_ms; if (likely((int)remain < 0)) { /* We're past the first period, check if we can still report a * part of last period or if we're too far away. */ past = curr; curr = 0; remain += period; if ((int)remain < 0) past = 0; } if (likely(past)) curr += div64_32((unsigned long long)past * remain, period); curr += pend; freq -= curr; if ((int)freq < 0) freq = 0; return freq; }
/* Reads a frequency counter taking history into account for missing time in * current period. The period has to be passed in number of ticks and must * match the one used to feed the counter. The counter value is reported for * current date (now_ms). The return value has the same precision as one input * data sample, so low rates over the period will be inaccurate but still * appropriate for max checking. One trick we use for low values is to specially * handle the case where the rate is between 0 and 1 in order to avoid flapping * while waiting for the next event. * * For immediate limit checking, it's recommended to use freq_ctr_period_remain() * instead which does not have the flapping correction, so that even frequencies * as low as one event/period are properly handled. * * For measures over a 1-second period, it's better to use the implicit functions * above. */ unsigned int read_freq_ctr_period(struct freq_ctr_period *ctr, unsigned int period) { unsigned int curr, past; unsigned int remain; curr = ctr->curr_ctr; past = ctr->prev_ctr; remain = ctr->curr_tick + period - now_ms; if (unlikely((int)remain < 0)) { /* We're past the first period, check if we can still report a * part of last period or if we're too far away. */ remain += period; if ((int)remain < 0) return 0; past = curr; curr = 0; } if (past <= 1 && !curr) return past; /* very low rate, avoid flapping */ curr += div64_32((unsigned long long)past * remain, period); return curr; }
static cell AMX_NATIVE_CALL n_fmuldiv(AMX *amx,const cell *params) { #if !USE_ANSI_C #if defined __WATCOMC__ && defined __386__ cell __fmuldiv(void); cell a=params[1]; cell b=params[2]; cell c=params[3]; if (c==0) { amx_RaiseError(amx,AMX_ERR_DIVIDE); return 0; } /* if */ #pragma aux __fmuldiv = \ "mov eax, [a]" \ "mov ecx, [c]" \ "imul [b]" \ "mov ebx, ecx" \ "shr ecx, 1" \ "add eax, ecx" \ "adc edx, 0" \ "idiv ebx" \ "mov [a], eax" \ modify [eax ebx ecx edx]; __fmuldiv(); return a; #elif _MSC_VER>=9 && defined _WIN32 __int64 a; cell divisor=params[3]; if (divisor==0) { amx_RaiseError(amx,AMX_ERR_DIVIDE); return 0; } /* if */ a=((__int64)params[1] * (__int64)params[2] + (__int64)(divisor/2)) / (__int64)divisor; return (cell)a; #elif defined __BORLANDC__ && __BORLANDC__ >= 0x500 && (defined __32BIT__ || defined __WIN32__) __int64 a; cell divisor=params[3]; if (divisor==0) { amx_RaiseError(amx,AMX_ERR_DIVIDE); return 0; } /* if */ a=((__int64)params[1] * (__int64)params[2] + (__int64)(divisor/2)) / (__int64)divisor; return (cell)a; #elif defined __GNUC__ long long a; cell divisor=params[3]; if (divisor==0) { amx_RaiseError(amx,AMX_ERR_DIVIDE); return 0; } /* if */ a=((long long)params[1] * (long long)params[2] + (long long)(divisor/2)) / (long long)divisor; return (cell)a; #else #error Unsupported compiler configuration, but USE_ANSI_C is false #endif #else // USE_ANSI_C ucell a,b,c,d; ucell v[2]; cell sign=1; cell divisor=params[3]; assert(MULTIPLIER<=(1L<<16)); if (divisor==0) { amx_RaiseError(amx,AMX_ERR_DIVIDE); return 0; } /* if */ /* make all three operands positive values, but keep the sign of the result */ if (params[1]<0) { ((cell*)params)[1]=-params[1]; sign=-sign; /* negate result */ } /* if */ if (params[2]<0) { ((cell*)params)[2]=-params[2]; sign=-sign; /* negate result */ } /* if */ if (divisor<0) { divisor=-divisor; sign=-sign; /* negate result */ } /* if */ a = HIWORD(params[1]); b = LOWORD(params[1]); c = HIWORD(params[2]); d = LOWORD(params[2]); /* store the intermediate into a 64-bit/128-bit number */ v[1]=c*a; v[0]=d*b; ADD_WRAP(v[0],v[1],d*a << WORDSHIFT); ADD_WRAP(v[0],v[1],c*b << WORDSHIFT); /* add half of the divisor, to round the data */ ADD_WRAP(v[0],v[1],(ucell)divisor/2); /* if the divisor is smaller than v[1], the result will not fit in a cell */ if ((ucell)divisor<v[1]) { amx_RaiseError(amx,AMX_ERR_DOMAIN); return 0; } /* if */ return (cell)div64_32(v,(ucell)divisor) * sign; #endif }
static cell AMX_NATIVE_CALL n_fdiv(AMX *amx,const cell *params) { #if !USE_ANSI_C #if defined __WATCOMC__ && defined __386__ cell __fdiv(void); cell a=params[1]; cell b=params[2]; #if MULTIPLIER != 1000 #error Assembler chunks must be modified for a different base #endif if (b==0) { amx_RaiseError(amx,AMX_ERR_DIVIDE); return 0; } /* if */ #pragma aux __fdiv = \ "mov eax, [a]" \ "mov ecx, [b]" \ "cdq" \ "mov ebx, 1000" \ "imul ebx" \ "mov ebx, ecx" \ "shr ecx, 1" \ "add eax, ecx" \ "adc edx, 0" \ "idiv ebx" \ "mov [a], eax" \ modify [eax ebx ecx edx]; __fdiv(); return a; #elif _MSC_VER>=9 && defined _WIN32 __int64 a; cell divisor=params[2]; if (divisor==0) { amx_RaiseError(amx,AMX_ERR_DIVIDE); return 0; } /* if */ a=((__int64)params[1] * (__int64)MULTIPLIER + (__int64)(divisor/2)) / (__int64)divisor; return (cell)a; #elif defined __BORLANDC__ && __BORLANDC__ >= 0x500 && (defined __32BIT__ || defined __WIN32__) __int64 a; cell divisor=params[2]; if (divisor==0) { amx_RaiseError(amx,AMX_ERR_DIVIDE); return 0; } /* if */ a=((__int64)params[1] * (__int64)MULTIPLIER + (__int64)(divisor/2)) / (__int64)divisor; return (cell)a; #elif defined __GNUC__ long long a; cell divisor=params[2]; if (divisor==0) { amx_RaiseError(amx,AMX_ERR_DIVIDE); return 0; } /* if */ a=((long long)params[1] * (long long)MULTIPLIER + (long long)(divisor/2)) / (long long)divisor; return (cell)a; #else #error Unsupported compiler configuration, but USE_ANSI_C is false #endif #else // USE_ANSI_C /* The dividend must be scaled prior to division. The dividend * is a 32-bit number, however, so when shifted, it will become * a value that no longer fits in a 32-bit variable. This routine * does the division by using only 16-bit and 32-bit values, but * with considerable effort. * If your compiler supports 64-bit integers, modify this routine * to use them. If your processor can do a simple 64-bit by 32-bit * division in assembler, write assembler chunks. * In other words: the straight C routine that follows is correct * and portable, but use it only as a last resort. * * This function was adapted from source code that appeared in * Dr. Dobb's Journal, August 1992, page 117. */ cell dividend=params[1]; cell divisor=params[2]; cell sign=1; ucell b[2]; if (divisor==0) { amx_RaiseError(amx,AMX_ERR_NATIVE); return 0; } /* if */ /* make both operands positive values, but keep the sign of the result */ if (dividend<0) { dividend=-dividend; sign=-sign; /* negate result */ } /* if */ if (divisor<0) { divisor=-divisor; sign=-sign; /* negate result */ } /* if */ /* pre-scale the dividend into a 64-bit/128-bit number */ b[0]=dividend*MULTIPLIER; b[1]=(HIWORD(dividend)*MULTIPLIER) >> WORDSHIFT; /* add half of the divisor, to round the data */ b[0]+=(ucell)divisor/2; if (b[0]<(ucell)divisor/2) b[1]+=1; /* wrap-around ocurred */ /* if the divisor is smaller than b[1], the result will not fit in a cell */ if ((ucell)divisor<b[1]) { amx_RaiseError(amx,AMX_ERR_DOMAIN); return 0; } /* if */ return (cell)div64_32(b,(ucell)divisor) * sign; #endif }
static cell AMX_NATIVE_CALL n_fmul(AMX *amx,const cell *params) { #if !USE_ANSI_C #if defined __WATCOMC__ && defined __386__ cell __fmul(void); cell a=params[1]; cell b=params[2]; #if MULTIPLIER != 1000 #error Assembler chunks must be modified for a different base #endif #pragma aux __fmul = \ "mov eax, [a]" \ "mov ebx, 1000" \ "imul [b]" \ "add eax, 500" \ "adc edx, 0" \ "idiv ebx" \ "mov [a], eax" \ modify [eax ebx edx]; __fmul(); (void)amx; return a; #elif _MSC_VER>=9 && defined _WIN32 __int64 a=(__int64)params[1] * (__int64)params[2]; a=(a+MULTIPLIER/2) / MULTIPLIER; (void)amx; return (cell)a; #elif defined __BORLANDC__ && __BORLANDC__ >= 0x500 && (defined __32BIT__ || defined __WIN32__) __int64 a=(__int64)params[1] * (__int64)params[2]; a=(a+MULTIPLIER/2) / MULTIPLIER; (void)amx; return (cell)a; #elif defined __GNUC__ long long a=(long long)params[1] * (long long)params[2]; a=(a+MULTIPLIER/2) / MULTIPLIER; (void)amx; return (cell)a; #else #error Unsupported compiler configuration, but USE_ANSI_C is false #endif #else // USE_ANSI_C /* (Xs * Ys) == (X*Y)ss, where "s" stands for scaled. * The desired result is (X*Y)s, so we must unscale once. * but we cannot do this before multiplication, because of loss * of precision, and we cannot do it after the multiplication * because of the possible overflow. * The technique used here is to cut the multiplicands into * components and to multiply these components separately: * * Assume Xs == (A << 16) + B and Ys == (C << 16) + D, where A, B, * C and D are 16 bit numbers. * * A B * C D * --- * * D*B + (D*A << 16) + (C*B << 16) + (C*A << (16+16)) * * Thus we have built a 64-bit number, which can now be scaled back * to 32-bit by dividing by the scale factor. */ #define ADD_WRAP(var,carry,expr) (((var)+=(expr)), ((carry)+=((var)<(expr)) ? 1 : 0)) ucell a,b,c,d; ucell v[2]; cell sign=1; (void)amx; assert(MULTIPLIER<=(1L<<WORDSHIFT)); /* make both operands positive values, but keep the sign of the result */ if (params[1]<0) { ((cell*)params)[1]=-params[1]; sign=-sign; /* negate result */ } /* if */ if (params[2]<0) { ((cell*)params)[2]=-params[2]; sign=-sign; /* negate result */ } /* if */ a = HIWORD(params[1]); b = LOWORD(params[1]); c = HIWORD(params[2]); d = LOWORD(params[2]); /* store the intermediate into a 64-bit/128-bit number */ v[1]=c*a; v[0]=d*b; ADD_WRAP(v[0],v[1],d*a << WORDSHIFT); ADD_WRAP(v[0],v[1],c*b << WORDSHIFT); /* add half of the divisor, to round the data */ ADD_WRAP(v[0],v[1],MULTIPLIER/2); /* if the divisor is smaller than v[1], the result will not fit in a cell */ if (MULTIPLIER<v[1]) { amx_RaiseError(amx,AMX_ERR_DOMAIN); return 0; } /* if */ return (cell)div64_32(v,MULTIPLIER) * sign; #endif }
static unsigned long do_fast_gettimeoffset(void) { #ifdef CONFIG_PM unsigned long pc0; unsigned long offset; pc0 = au_readl(SYS_TOYREAD); if (pc0 < last_pc0) { offset = 0xffffffff - last_pc0 + pc0; printk("offset over: %x\n", (unsigned)offset); } else { offset = (unsigned long)(((pc0 - last_pc0) * 305) / 10); } if ((pc0-last_pc0) > 2*MATCH20_INC) { printk("huge offset %x, last_pc0 %x last_match20 %x pc0 %x\n", (unsigned)offset, (unsigned)last_pc0, (unsigned)last_match20, (unsigned)pc0); } au_sync(); return offset; #else u32 count; unsigned long res, tmp; unsigned long r0; /* Last jiffy when do_fast_gettimeoffset() was called. */ static unsigned long last_jiffies=0; unsigned long quotient; /* * Cached "1/(clocks per usec)*2^32" value. * It has to be recalculated once each jiffy. */ static unsigned long cached_quotient=0; tmp = jiffies; quotient = cached_quotient; if (tmp && last_jiffies != tmp) { last_jiffies = tmp; if (last_jiffies != 0) { r0 = div64_32(timerhi, timerlo, tmp); quotient = div64_32(USECS_PER_JIFFY, USECS_PER_JIFFY_FRAC, r0); cached_quotient = quotient; } } /* Get last timer tick in absolute kernel time */ count = read_c0_count(); /* .. relative to previous jiffy (32 bits is enough) */ count -= timerlo; __asm__("multu\t%1,%2\n\t" "mfhi\t%0" :"=r" (res) :"r" (count), "r" (quotient)); /* * Due to possible jiffies inconsistencies, we need to check * the result so that we'll get a timer that is monotonic. */ if (res >= USECS_PER_JIFFY) res = USECS_PER_JIFFY-1; return res; #endif }
UINT_32 __umoddi3(UINT_64 n, UINT_32 base) { return div64_32(n, base); }