| /* |
| * linux/kernel/math/sqrt.c |
| * |
| * (C) 1991 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; |
| } |