|
|
linux 0.97
/*
* linux/kernel/math/sqrt.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* simple and stupid temporary real fsqrt() routine
*
* There are probably better ways to do this, but this should work ok.
*/
#include <linux/math_emu.h>
#include <linux/sched.h>
static void shift_right(int * c)
{
__asm__("shrl $1,12(%0) ; rcrl $1,8(%0) ; rcrl $1,4(%0) ; rcrl $1,(%0)"
::"r" ((long) c));
}
static int sqr64(unsigned long * a, unsigned long * b)
{
unsigned long tmp[4];
__asm__("movl (%0),%%eax ; mull %%eax\n\t"
"movl %%eax,(%1) ; movl %%edx,4(%1)\n\t"
"movl 4(%0),%%eax ; mull %%eax\n\t"
"movl %%eax,8(%1) ; movl %%edx,12(%1)\n\t"
"movl (%0),%%eax ; mull 4(%0)\n\t"
"addl %%eax,%%eax ; adcl %%edx,%%edx\n\t"
"adcl $0,12(%1) ; addl %%eax,4(%1)\n\t"
"adcl %%edx,8(%1) ; adcl $0,12(%1)"
::"b" ((long) a),"c" ((long) tmp)
:"ax","bx","cx","dx");
if (tmp[3] > b[3] ||
(tmp[3] == b[3] && (tmp[2] > b[2] ||
(tmp[2] == b[2] && (tmp[1] > b[1] ||
(tmp[1] == b[1] && tmp[0] > b[0]))))))
return 0;
return 1;
}
void fsqrt(const temp_real * s, temp_real * d)
{
unsigned long src[4];
unsigned long res[2];
int exponent;
unsigned long mask, *c;
int i;
exponent = s->exponent;
src[0] = src[1] = 0;
src[2] = s->a;
src[3] = s->b;
d->exponent = 0;
d->a = d->b = 0;
if (!exponent) /* fsqrt(0.0) = 0.0 */
return;
if (!src[2] && !src[3])
return;
if (exponent & 0x8000) {
send_sig(SIGFPE,current,0);
return;
}
if (exponent & 1) {
shift_right(src);
exponent++;
}
exponent >>= 1;
exponent += 0x1fff;
c = res + 2;
mask = 0;
for (i = 64 ; i > 0 ; i--) {
if (!(mask >>= 1)) {
c--;
mask = 0x80000000;
}
res[0] = d->a; res[1] = d->b;
*c |= mask;
if (sqr64(res,src)) {
d->a = res[0];
d->b = res[1];
}
}
if (!d->a && !d->b)
return;
while (!(d->b & 0x80000000)) {
__asm__("addl %%eax,%%eax ; adcl %%edx,%%edx"
:"=a" (d->a),"=d" (d->b)
:"0" (d->a),"1" (d->b));
exponent--;
}
d->exponent = exponent;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.