* linux/kernel/math/math_emulate.c
* (C) 1991 Linus Torvalds
* [expediant "port" of linux 8087 emulator to 386BSD, with apologies -wfj]
* Limited emulation 27.12.91 - mostly loads/stores, which gcc wants
* even for soft-float, unless you use bruce evans' patches. The patches
* are great, but they have to be re-applied for every version, and the
* library is different for soft-float and 80387. So emulation is more
* practical, even though it's slower.
* 28.12.91 - loads/stores work, even BCD. I'll have to start thinking
* about add/sub/mul/div. Urgel. I should find some good source, but I'll
* just fake up something.
* 30.12.91 - add/sub/mul/div/com seem to work mostly. I should really
* test every possible combination.
* This file is full of ugly macros etc: one problem was that gcc simply
* didn't want to make the structures as they should be: it has to try to
* align them. Sickening code, but at least I've hidden the ugly things
* in this one file: the other files don't need to know about these things.
* The other files also don't care about ST(x) etc - they just get addresses
* to 80-bit temporary reals, and do with them as they please. I wanted to
* hide most of the 387-specific things here.
#define __ALIGNED_TEMP_REAL 1
#include "i386/i386/math_emu.h"
#define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
#define ST(x) (*__st((x)))
#define PST(x) ((const temp_real *) __st((x)))
#define math_abort(tfp, signo) tfp->tf_eip = oldeip; return (signo);
* We don't want these inlined - it gets too messy in the machine-code.
static void fxchg(temp_real_unaligned
* a
, temp_real_unaligned
* b
);
static temp_real_unaligned
* __st(int i
);
unsigned char get_fs_byte(char *adr
) { return(fubyte(adr
)); }
unsigned short get_fs_word(unsigned short *adr
) { return(fuword(adr
)); }
unsigned long get_fs_long(unsigned long *adr
) { return(fuword(adr
)); }
put_fs_byte(unsigned char val
, char *adr
) { (void)subyte(adr
,val
); }
put_fs_word(unsigned short val
, short *adr
) { (void)susword(adr
,val
); }
put_fs_long(unsigned long val
, unsigned long *adr
) { (void)suword(adr
,val
); }
math_emulate(struct trapframe
* info
)
if ((((struct pcb
*)curproc
->p_addr
)->pcb_flags
& FP_SOFTFP
) == 0) {
((struct pcb
*)curproc
->p_addr
)->pcb_flags
|= FP_SOFTFP
;
if (I387
.cwd
& I387
.swd
& 0x3f)
/* 0x001f means user code space */
if ((u_short
)info
->tf_cs
!= 0x001F) {
printf("math_emulate: %04x:%08x\n\r", (u_short
)info
->tf_cs
,
panic("?Math emulation needed in kernel?");
code
= get_fs_word((unsigned short *) oldeip
);
*(unsigned short *) &I387
.fcs
= (u_short
) info
->tf_cs
;
*(1+(unsigned short *) &I387
.fcs
) = code
;
case 0x1d1: case 0x1d2: case 0x1d3:
case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
ST(0).exponent
^= 0x8000;
ST(0).exponent
&= 0x7fff;
printf("fxam not implemented\n\r");
case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3:
case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7:
case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb:
"math_emulate: instruction %04x not implemented\n",
/* incomplete and totally inadequate -wfj */
Fscale(PST(0), PST(1), &tmp
);
real_to_real(&tmp
,&ST(0));
return(0); /* 19 Sep 92*/
real_to_real(&tmp
,&ST(0));
*(short *) &info
->tf_eax
= I387
.swd
;
fadd(PST(0),PST(code
& 7),&tmp
);
real_to_real(&tmp
,&ST(0));
fmul(PST(0),PST(code
& 7),&tmp
);
real_to_real(&tmp
,&ST(0));
fcom(PST(code
& 7),&tmp
);
real_to_real(&tmp
,&ST(0));
fcom(PST(code
& 7),&tmp
);
real_to_real(&tmp
,&ST(0));
real_to_real(&ST(code
& 7),&tmp
);
real_to_real(&tmp
,&ST(0));
ST(0).exponent
^= 0x8000;
fadd(PST(0),PST(code
& 7),&tmp
);
real_to_real(&tmp
,&ST(0));
fdiv(PST(0),PST(code
& 7),&tmp
);
real_to_real(&tmp
,&ST(0));
fdiv(PST(code
& 7),PST(0),&tmp
);
real_to_real(&tmp
,&ST(0));
ST(0) = ST((code
& 7)+1);
fxchg(&ST(0),&ST(code
& 7));
fadd(PST(0),PST(code
& 7),&tmp
);
real_to_real(&tmp
,&ST(code
& 7));
fmul(PST(0),PST(code
& 7),&tmp
);
real_to_real(&tmp
,&ST(code
& 7));
fcom(PST(code
& 7),PST(0));
fcom(PST(code
& 7),PST(0));
ST(code
& 7).exponent
^= 0x8000;
fadd(PST(0),PST(code
& 7),&tmp
);
real_to_real(&tmp
,&ST(code
& 7));
real_to_real(&ST(0),&tmp
);
fadd(PST(code
& 7),&tmp
,&tmp
);
real_to_real(&tmp
,&ST(code
& 7));
fdiv(PST(0),PST(code
& 7),&tmp
);
real_to_real(&tmp
,&ST(code
& 7));
fdiv(PST(code
& 7),PST(0),&tmp
);
real_to_real(&tmp
,&ST(code
& 7));
printf("ffree not implemented\n\r");
fxchg(&ST(0),&ST(code
& 7));
fucom(PST(code
& 7),PST(0));
fucom(PST(code
& 7),PST(0));
fadd(PST(code
& 7),PST(0),&tmp
);
real_to_real(&tmp
,&ST(code
& 7));
fmul(PST(code
& 7),PST(0),&tmp
);
real_to_real(&tmp
,&ST(code
& 7));
fcom(PST(code
& 7),PST(0));
ST(code
& 7).exponent
^= 0x8000;
fadd(PST(0),PST(code
& 7),&tmp
);
real_to_real(&tmp
,&ST(code
& 7));
real_to_real(&ST(0),&tmp
);
fadd(PST(code
& 7),&tmp
,&tmp
);
real_to_real(&tmp
,&ST(code
& 7));
fdiv(PST(0),PST(code
& 7),&tmp
);
real_to_real(&tmp
,&ST(code
& 7));
fdiv(PST(code
& 7),PST(0),&tmp
);
real_to_real(&tmp
,&ST(code
& 7));
printf("ffree not implemented\n\r");
fxchg(&ST(0),&ST(code
& 7));
switch ((code
>>3) & 0xe7) {
put_short_real(PST(0),info
,code
);
put_short_real(PST(0),info
,code
);
for (code
= 0 ; code
< 7 ; code
++) {
((long *) & I387
)[code
] =
get_fs_long((unsigned long *) address
);
*(unsigned short *) &I387
.cwd
=
get_fs_word((unsigned short *) address
);
/*verify_area(address,28);*/
for (code
= 0 ; code
< 7 ; code
++) {
put_fs_long( ((long *) & I387
)[code
],
(unsigned long *) address
);
/*verify_area(address,2);*/
put_fs_word(I387
.cwd
,(short *) address
);
put_long_int(PST(0),info
,code
);
put_long_int(PST(0),info
,code
);
get_temp_real(&tmp
,info
,code
);
real_to_real(&tmp
,&ST(0));
put_temp_real(PST(0),info
,code
);
put_long_real(PST(0),info
,code
);
put_long_real(PST(0),info
,code
);
for (code
= 0 ; code
< 27 ; code
++) {
((long *) & I387
)[code
] =
get_fs_long((unsigned long *) address
);
/*verify_area(address,108);*/
for (code
= 0 ; code
< 27 ; code
++) {
put_fs_long( ((long *) & I387
)[code
],
(unsigned long *) address
);
/*verify_area(address,2);*/
put_fs_word(I387
.swd
,(short *) address
);
put_short_int(PST(0),info
,code
);
put_short_int(PST(0),info
,code
);
real_to_real(&tmp
,&ST(0));
get_longlong_int(&tmp
,info
,code
);
real_to_real(&tmp
,&ST(0));
put_BCD(PST(0),info
,code
);
put_longlong_int(PST(0),info
,code
);
get_short_real(&tmp
,info
,code
);
get_long_int(&tmp
,info
,code
);
get_long_real(&tmp
,info
,code
);
get_short_int(&tmp
,info
,code
);
switch ((code
>>3) & 0x27) {
real_to_real(&tmp
,&ST(0));
real_to_real(&tmp
,&ST(0));
real_to_real(&tmp
,&ST(0));
ST(0).exponent
^= 0x8000;
real_to_real(&tmp
,&ST(0));
real_to_real(&tmp
,&ST(0));
real_to_real(&tmp
,&ST(0));
if ((code
& 0x138) == 0x100) {
real_to_real(&tmp
,&ST(0));
printf("Unknown math-insns: %04x:%08x %04x\n\r",(u_short
)info
->tf_cs
,
tmp
= I387
.swd
& 0xffffc7ff;
tmp
= I387
.swd
& 0xffffc7ff;
static void fxchg(temp_real_unaligned
* a
, temp_real_unaligned
* b
)
static temp_real_unaligned
* __st(int i
)
return (temp_real_unaligned
*) (i
*10 + (char *)(I387
.st_space
));
* (C) 1991 Linus Torvalds
* Calculate the effective address.
static int __regoffset
[] = {
tEAX
, tECX
, tEDX
, tEBX
, tESP
, tEBP
, tESI
, tEDI
#define REG(x) (curproc->p_regs[__regoffset[(x)]])
static char * sib(struct trapframe
* info
, int mod
)
unsigned char ss
,index
,base
;
base
= get_fs_byte((char *) info
->tf_eip
);
offset
+= (signed char) get_fs_byte((char *) info
->tf_eip
);
} else if (mod
== 2 || base
== 5) {
offset
+= (signed) get_fs_long((unsigned long *) info
->tf_eip
);
char * ea(struct trapframe
* info
, unsigned short code
)
offset
= get_fs_long((unsigned long *) info
->tf_eip
);
case 0: offset
= 0; break;
offset
= (signed char) get_fs_byte((char *) info
->tf_eip
);
offset
= (signed) get_fs_long((unsigned long *) info
->tf_eip
);
math_abort(info
,1<<(SIGILL
-1));
return offset
+ (char *) *tmp
;
* linux/kernel/math/get_put.c
* (C) 1991 Linus Torvalds
* This file handles all accesses to user memory: getting and putting
* ints/reals/BCD etc. This is the only part that concerns itself with
* other than temporary real format. All other cals are strictly temp_real.
void get_short_real(temp_real
* tmp
,
struct trapframe
* info
, unsigned short code
)
sr
= get_fs_long((unsigned long *) addr
);
void get_long_real(temp_real
* tmp
,
struct trapframe
* info
, unsigned short code
)
lr
.a
= get_fs_long((unsigned long *) addr
);
lr
.b
= get_fs_long(1 + (unsigned long *) addr
);
void get_temp_real(temp_real
* tmp
,
struct trapframe
* info
, unsigned short code
)
tmp
->a
= get_fs_long((unsigned long *) addr
);
tmp
->b
= get_fs_long(1 + (unsigned long *) addr
);
tmp
->exponent
= get_fs_word(4 + (unsigned short *) addr
);
void get_short_int(temp_real
* tmp
,
struct trapframe
* info
, unsigned short code
)
ti
.a
= (signed short) get_fs_word((unsigned short *) addr
);
if (ti
.sign
= (ti
.a
< 0))
void get_long_int(temp_real
* tmp
,
struct trapframe
* info
, unsigned short code
)
ti
.a
= get_fs_long((unsigned long *) addr
);
if (ti
.sign
= (ti
.a
< 0))
void get_longlong_int(temp_real
* tmp
,
struct trapframe
* info
, unsigned short code
)
ti
.a
= get_fs_long((unsigned long *) addr
);
ti
.b
= get_fs_long(1 + (unsigned long *) addr
);
if (ti
.sign
= (ti
.b
< 0))
__asm__("notl %0 ; notl %1\n\t"
"addl $1,%0 ; adcl $0,%1"
#define MUL10(low,high) \
__asm__("addl %0,%0 ; adcl %1,%1\n\t" \
"movl %0,%%ecx ; movl %1,%%ebx\n\t" \
"addl %0,%0 ; adcl %1,%1\n\t" \
"addl %0,%0 ; adcl %1,%1\n\t" \
"addl %%ecx,%0 ; adcl %%ebx,%1" \
:"=a" (low),"=d" (high) \
:"0" (low),"1" (high):"cx","bx")
#define ADD64(val,low,high) \
__asm__("addl %4,%0 ; adcl $0,%1":"=r" (low),"=r" (high) \
:"0" (low),"1" (high),"r" ((unsigned long) (val)))
void get_BCD(temp_real
* tmp
, struct trapframe
* info
, unsigned short code
)
i
.sign
= 0x80 & get_fs_byte(addr
--);
for (k
= 0; k
< 9; k
++) {
ADD64((c
&0xf), i
.a
, i
.b
);
void put_short_real(const temp_real
* tmp
,
struct trapframe
* info
, unsigned short code
)
put_fs_long(sr
,(unsigned long *) addr
);
void put_long_real(const temp_real
* tmp
,
struct trapframe
* info
, unsigned short code
)
put_fs_long(lr
.a
, (unsigned long *) addr
);
put_fs_long(lr
.b
, 1 + (unsigned long *) addr
);
void put_temp_real(const temp_real
* tmp
,
struct trapframe
* info
, unsigned short code
)
/*verify_area(addr,10);*/
put_fs_long(tmp
->a
, (unsigned long *) addr
);
put_fs_long(tmp
->b
, 1 + (unsigned long *) addr
);
put_fs_word(tmp
->exponent
, 4 + (short *) addr
);
void put_short_int(const temp_real
* tmp
,
struct trapframe
* info
, unsigned short code
)
put_fs_word(ti
.a
,(short *) addr
);
void put_long_int(const temp_real
* tmp
,
struct trapframe
* info
, unsigned short code
)
put_fs_long(ti
.a
,(unsigned long *) addr
);
void put_longlong_int(const temp_real
* tmp
,
struct trapframe
* info
, unsigned short code
)
__asm__("notl %0 ; notl %1\n\t"
"addl $1,%0 ; adcl $0,%1"
put_fs_long(ti
.a
,(unsigned long *) addr
);
put_fs_long(ti
.b
,1 + (unsigned long *) addr
);
#define DIV10(low,high,rem) \
__asm__("divl %6 ; xchgl %1,%2 ; divl %6" \
:"=d" (rem),"=a" (low),"=r" (high) \
:"0" (0),"1" (high),"2" (low),"c" (10))
void put_BCD(const temp_real
* tmp
,struct trapframe
* info
, unsigned short code
)
/*verify_area(addr,10);*/
put_fs_byte(0x80, addr
+9);
for (k
= 0; k
< 9; k
++) {
* linux/kernel/math/mul.c
* (C) 1991 Linus Torvalds
* temporary real multiplication routine.
static void shift(int * c
)
__asm__("movl (%0),%%eax ; addl %%eax,(%0)\n\t"
"movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t"
"movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t"
"movl 12(%0),%%eax ; adcl %%eax,12(%0)"
static void mul64(const temp_real
* a
, const temp_real
* b
, int * c
)
__asm__("movl (%0),%%eax\n\t"
::"S" ((long) a
),"c" ((long) b
),"D" ((long) c
)
void fmul(const temp_real
* src1
, const temp_real
* src2
, temp_real
* result
)
sign
= (src1
->exponent
^ src2
->exponent
) & 0x8000;
i
= (src1
->exponent
& 0x7fff) + (src2
->exponent
& 0x7fff) - 16383 + 1;
result
->a
= result
->b
= 0;
if (tmp
[0] || tmp
[1] || tmp
[2] || tmp
[3])
while (i
&& tmp
[3] >= 0) {
result
->exponent
= i
| sign
;
* linux/kernel/math/div.c
* (C) 1991 Linus Torvalds
* temporary real division routine.
static void shift_left(int * c
)
__asm__
__volatile__("movl (%0),%%eax ; addl %%eax,(%0)\n\t"
"movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t"
"movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t"
"movl 12(%0),%%eax ; adcl %%eax,12(%0)"
static void shift_right(int * c
)
__asm__("shrl $1,12(%0) ; rcrl $1,8(%0) ; rcrl $1,4(%0) ; rcrl $1,(%0)"
static int try_sub(int * a
, int * b
)
__asm__
__volatile__("movl (%1),%%eax ; subl %%eax,(%2)\n\t"
"movl 4(%1),%%eax ; sbbl %%eax,4(%2)\n\t"
"movl 8(%1),%%eax ; sbbl %%eax,8(%2)\n\t"
"movl 12(%1),%%eax ; sbbl %%eax,12(%2)\n\t"
"setae %%al":"=a" (ok
):"c" ((long) a
),"d" ((long) b
));
static void div64(int * a
, int * b
, int * c
)
for (i
= 0 ; i
<64 ; i
++) {
tmp
[0] = a
[0]; tmp
[1] = a
[1];
tmp
[2] = a
[2]; tmp
[3] = a
[3];
a
[0] = tmp
[0]; a
[1] = tmp
[1];
a
[2] = tmp
[2]; a
[3] = tmp
[3];
void fdiv(const temp_real
* src1
, const temp_real
* src2
, temp_real
* result
)
int a
[4],b
[4],tmp
[4] = {0,0,0,0};
sign
= (src1
->exponent
^ src2
->exponent
) & 0x8000;
if (!(src2
->a
|| src2
->b
)) {
i
= (src1
->exponent
& 0x7fff) - (src2
->exponent
& 0x7fff) + 16383;
result
->a
= result
->b
= 0;
if (tmp
[0] || tmp
[1] || tmp
[2] || tmp
[3]) {
while (i
&& tmp
[3] >= 0) {
result
->exponent
= i
| sign
;
* linux/kernel/math/add.c
* (C) 1991 Linus Torvalds
* temporary real addition routine.
* NOTE! These aren't exact: they are only 62 bits wide, and don't do
* correct rounding. Fast hack. The reason is that we shift right the
* values by two, in order not to have overflow (1 bit), and to be able
* to move the sign into the mantissa (1 bit). Much simpler algorithms,
* and 62 bits (61 really - no rounding) accuracy is usually enough. The
* only time you should notice anything weird is when adding 64-bit
* integers together. When using doubles (52 bits accuracy), the
* 61-bit accuracy never shows at all.
__asm__("notl %0 ; notl %1 ; addl $1,%0 ; adcl $0,%1" \
:"=r" (a->a),"=r" (a->b) \
static void signify(temp_real
* a
)
__asm__("shrdl $2,%1,%0 ; shrl $2,%1"
static void unsignify(temp_real
* a
)
__asm__("addl %0,%0 ; adcl %1,%1"
void fadd(const temp_real
* src1
, const temp_real
* src2
, temp_real
* result
)
x1
= src1
->exponent
& 0x7fff;
x2
= src2
->exponent
& 0x7fff;
__asm__("shrdl %4,%1,%0 ; shrl %4,%1"
:"0" (b
.a
),"1" (b
.b
),"c" ((char) shift
));
__asm__("addl %4,%0 ; adcl %5,%1"
:"0" (a
.a
),"1" (a
.b
),"g" (b
.a
),"g" (b
.b
));
* linux/kernel/math/compare.c
* (C) 1991 Linus Torvalds
* temporary real comparison routines
#define clear_Cx() (I387.swd &= ~0x4500)
static void normalize(temp_real
* a
)
int i
= a
->exponent
& 0x7fff;
int sign
= a
->exponent
& 0x8000;
__asm__("addl %0,%0 ; adcl %1,%1"
void ftst(const temp_real
* a
)
if (b
.a
|| b
.b
|| b
.exponent
) {
void fcom(const temp_real
* src1
, const temp_real
* src2
)
void fucom(const temp_real
* src1
, const temp_real
* src2
)
* linux/kernel/math/convert.c
* (C) 1991 Linus Torvalds
* NOTE!!! There is some "non-obvious" optimisations in the temp_to_long
* and temp_to_short conversion routines: don't touch them if you don't
* know what's going on. They are the adding of one in the rounding: the
* overflow bit is also used for adding one into the exponent. Thus it
* looks like the overflow would be incorrectly handled, but due to the
* way the IEEE numbers work, things are correct.
* There is no checking for total overflow in the conversions, though (ie
* if the temp-real number simply won't fit in a short- or long-real.)
void short_to_temp(const short_real
* a
, temp_real
* b
)
if (!(*a
& 0x7fffffff)) {
b
->exponent
= ((*a
>>23) & 0xff)-127+16383;
b
->b
= (*a
<<8) | 0x80000000;
void long_to_temp(const long_real
* a
, temp_real
* b
)
if (!a
->a
&& !(a
->b
& 0x7fffffff)) {
b
->exponent
= ((a
->b
>> 20) & 0x7ff)-1023+16383;
b
->b
= 0x80000000 | (a
->b
<<11) | (((unsigned long)a
->a
)>>21);
void temp_to_short(const temp_real
* a
, short_real
* b
)
if (!(a
->exponent
& 0x7fff)) {
*b
= (a
->exponent
)?0x80000000:0;
*b
= ((((long) a
->exponent
)-16383+127) << 23) & 0x7f800000;
*b
|= (a
->b
>> 8) & 0x007fffff;
if ((a
->b
& 0xff) > 0x80)
if ((a
->exponent
& 0x8000) && (a
->b
& 0xff))
if (!(a
->exponent
& 0x8000) && (a
->b
& 0xff))
void temp_to_long(const temp_real
* a
, long_real
* b
)
if (!(a
->exponent
& 0x7fff)) {
b
->b
= (a
->exponent
)?0x80000000:0;
b
->b
= (((0x7fff & (long) a
->exponent
)-16383+1023) << 20) & 0x7ff00000;
b
->b
|= (a
->b
>> 11) & 0x000fffff;
b
->a
|= (a
->a
>> 11) & 0x001fffff;
if ((a
->a
& 0x7ff) > 0x400)
__asm__("addl $1,%0 ; adcl $0,%1"
if ((a
->exponent
& 0x8000) && (a
->b
& 0xff))
__asm__("addl $1,%0 ; adcl $0,%1"
if (!(a
->exponent
& 0x8000) && (a
->b
& 0xff))
__asm__("addl $1,%0 ; adcl $0,%1"
void frndint(const temp_real
* a
, temp_real
* b
)
int shift
= 16383 + 63 - (a
->exponent
& 0x7fff);
if ((shift
< 0) || (shift
== 16383+63)) {
b
->a
= b
->b
= underflow
= 0;
b
->exponent
= a
->exponent
;
b
->b
= a
->b
; b
->a
= a
->a
;
b
->a
= a
->b
; underflow
= a
->a
;
:"=r" (underflow
),"=r" (b
->a
)
:"c" ((char) shift
),"0" (underflow
),"1" (b
->a
));
:"c" ((char) shift
),"0" (b
->a
),"1" (b
->b
));
:"c" ((char) shift
),"0" (b
->b
));
__asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
,"r" (0x7fffffff + (b
->a
& 1))
if ((b
->exponent
>= 0) && underflow
)
__asm__("addl $1,%0 ; adcl $0,%1"
if ((b
->exponent
< 0) && underflow
)
__asm__("addl $1,%0 ; adcl $0,%1"
__asm__("addl %0,%0 ; adcl %1,%1"
void Fscale(const temp_real
*a
, const temp_real
*b
, temp_real
*c
)
if(!c
->a
&& !c
->b
) { /* 19 Sep 92*/
void real_to_int(const temp_real
* a
, temp_int
* b
)
int shift
= 16383 + 63 - (a
->exponent
& 0x7fff);
b
->a
= b
->b
= underflow
= 0;
b
->sign
= (a
->exponent
< 0);
b
->b
= a
->b
; b
->a
= a
->a
;
b
->a
= a
->b
; underflow
= a
->a
;
:"=r" (underflow
),"=r" (b
->a
)
:"c" ((char) shift
),"0" (underflow
),"1" (b
->a
));
:"c" ((char) shift
),"0" (b
->a
),"1" (b
->b
));
:"c" ((char) shift
),"0" (b
->b
));
__asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
,"r" (0x7fffffff + (b
->a
& 1))
if (!b
->sign
&& underflow
)
__asm__("addl $1,%0 ; adcl $0,%1"
if (b
->sign
&& underflow
)
__asm__("addl $1,%0 ; adcl $0,%1"
void int_to_real(const temp_int
* a
, temp_real
* b
)
b
->exponent
= 16383 + 63 + (a
->sign
? 0x8000:0);
__asm__("addl %0,%0 ; adcl %1,%1"