initial version
This commit is contained in:
83
Book-Lite/linux-0.12/kernel/math/Makefile
Normal file
83
Book-Lite/linux-0.12/kernel/math/Makefile
Normal file
@@ -0,0 +1,83 @@
|
||||
#
|
||||
# Makefile for the FREAX-kernel character device drivers.
|
||||
#
|
||||
# Note! Dependencies are done automagically by 'make dep', which also
|
||||
# removes any old dependencies. DON'T put your own dependencies here
|
||||
# unless it's something special (ie not a .c file).
|
||||
#
|
||||
|
||||
AR =gar
|
||||
AS =gas
|
||||
LD =gld
|
||||
LDFLAGS =-s -x
|
||||
CC =gcc
|
||||
CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \
|
||||
-finline-functions -mstring-insns -nostdinc -I../../include
|
||||
CPP =gcc -E -nostdinc -I../../include
|
||||
|
||||
.c.s:
|
||||
$(CC) $(CFLAGS) \
|
||||
-S -o $*.s $<
|
||||
.s.o:
|
||||
$(AS) -c -o $*.o $<
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) \
|
||||
-c -o $*.o $<
|
||||
|
||||
OBJS = math_emulate.o error.o convert.o ea.o get_put.o \
|
||||
add.o mul.o div.o compare.o
|
||||
|
||||
math.a: $(OBJS)
|
||||
$(AR) rcs math.a $(OBJS)
|
||||
sync
|
||||
|
||||
clean:
|
||||
rm -f core *.o *.a tmp_make
|
||||
for i in *.c;do rm -f `basename $$i .c`.s;done
|
||||
|
||||
dep:
|
||||
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
|
||||
(for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \
|
||||
$(CPP) -M $$i;done) >> tmp_make
|
||||
cp tmp_make Makefile
|
||||
|
||||
### Dependencies:
|
||||
add.s add.o : add.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h
|
||||
compare.s compare.o : compare.c ../../include/linux/math_emu.h \
|
||||
../../include/linux/sched.h ../../include/linux/head.h \
|
||||
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h
|
||||
convert.s convert.o : convert.c ../../include/linux/math_emu.h \
|
||||
../../include/linux/sched.h ../../include/linux/head.h \
|
||||
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h
|
||||
div.s div.o : div.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h
|
||||
ea.s ea.o : ea.c ../../include/stddef.h ../../include/linux/math_emu.h \
|
||||
../../include/linux/sched.h ../../include/linux/head.h \
|
||||
../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h \
|
||||
../../include/asm/segment.h
|
||||
error.s error.o : error.c ../../include/signal.h ../../include/sys/types.h \
|
||||
../../include/linux/sched.h ../../include/linux/head.h \
|
||||
../../include/linux/fs.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h
|
||||
get_put.s get_put.o : get_put.c ../../include/signal.h ../../include/sys/types.h \
|
||||
../../include/linux/math_emu.h ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/linux/mm.h ../../include/linux/kernel.h \
|
||||
../../include/asm/segment.h
|
||||
math_emulate.s math_emulate.o : math_emulate.c ../../include/signal.h \
|
||||
../../include/sys/types.h ../../include/linux/math_emu.h \
|
||||
../../include/linux/sched.h ../../include/linux/head.h \
|
||||
../../include/linux/fs.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/asm/segment.h
|
||||
mul.s mul.o : mul.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
|
||||
../../include/linux/head.h ../../include/linux/fs.h \
|
||||
../../include/sys/types.h ../../include/linux/mm.h \
|
||||
../../include/linux/kernel.h ../../include/signal.h
|
||||
92
Book-Lite/linux-0.12/kernel/math/add.c
Normal file
92
Book-Lite/linux-0.12/kernel/math/add.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
|
||||
#define NEGINT(a) \
|
||||
__asm__("notl %0 ; notl %1 ; addl $1,%0 ; adcl $0,%1" \
|
||||
:"=r" (a->a),"=r" (a->b) \
|
||||
:"0" (a->a),"1" (a->b))
|
||||
|
||||
static void signify(temp_real * a)
|
||||
{
|
||||
a->exponent += 2;
|
||||
__asm__("shrdl $2,%1,%0 ; shrl $2,%1"
|
||||
:"=r" (a->a),"=r" (a->b)
|
||||
:"0" (a->a),"1" (a->b));
|
||||
if (a->exponent < 0)
|
||||
NEGINT(a);
|
||||
a->exponent &= 0x7fff;
|
||||
}
|
||||
|
||||
static void unsignify(temp_real * a)
|
||||
{
|
||||
if (!(a->a || a->b)) {
|
||||
a->exponent = 0;
|
||||
return;
|
||||
}
|
||||
a->exponent &= 0x7fff;
|
||||
if (a->b < 0) {
|
||||
NEGINT(a);
|
||||
a->exponent |= 0x8000;
|
||||
}
|
||||
while (a->b >= 0) {
|
||||
a->exponent--;
|
||||
__asm__("addl %0,%0 ; adcl %1,%1"
|
||||
:"=r" (a->a),"=r" (a->b)
|
||||
:"0" (a->a),"1" (a->b));
|
||||
}
|
||||
}
|
||||
|
||||
void fadd(const temp_real * src1, const temp_real * src2, temp_real * result)
|
||||
{
|
||||
temp_real a,b;
|
||||
int x1,x2,shift;
|
||||
|
||||
x1 = src1->exponent & 0x7fff;
|
||||
x2 = src2->exponent & 0x7fff;
|
||||
if (x1 > x2) {
|
||||
a = *src1;
|
||||
b = *src2;
|
||||
shift = x1-x2;
|
||||
} else {
|
||||
a = *src2;
|
||||
b = *src1;
|
||||
shift = x2-x1;
|
||||
}
|
||||
if (shift >= 64) {
|
||||
*result = a;
|
||||
return;
|
||||
}
|
||||
if (shift >= 32) {
|
||||
b.a = b.b;
|
||||
b.b = 0;
|
||||
shift -= 32;
|
||||
}
|
||||
__asm__("shrdl %4,%1,%0 ; shrl %4,%1"
|
||||
:"=r" (b.a),"=r" (b.b)
|
||||
:"0" (b.a),"1" (b.b),"c" ((char) shift));
|
||||
signify(&a);
|
||||
signify(&b);
|
||||
__asm__("addl %4,%0 ; adcl %5,%1"
|
||||
:"=r" (a.a),"=r" (a.b)
|
||||
:"0" (a.a),"1" (a.b),"g" (b.a),"g" (b.b));
|
||||
unsignify(&a);
|
||||
*result = a;
|
||||
}
|
||||
60
Book-Lite/linux-0.12/kernel/math/compare.c
Normal file
60
Book-Lite/linux-0.12/kernel/math/compare.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* linux/kernel/math/compare.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* temporary real comparison routines
|
||||
*/
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
|
||||
#define clear_Cx() (I387.swd &= ~0x4500)
|
||||
|
||||
static void normalize(temp_real * a)
|
||||
{
|
||||
int i = a->exponent & 0x7fff;
|
||||
int sign = a->exponent & 0x8000;
|
||||
|
||||
if (!(a->a || a->b)) {
|
||||
a->exponent = 0;
|
||||
return;
|
||||
}
|
||||
while (i && a->b >= 0) {
|
||||
i--;
|
||||
__asm__("addl %0,%0 ; adcl %1,%1"
|
||||
:"=r" (a->a),"=r" (a->b)
|
||||
:"0" (a->a),"1" (a->b));
|
||||
}
|
||||
a->exponent = i | sign;
|
||||
}
|
||||
|
||||
void ftst(const temp_real * a)
|
||||
{
|
||||
temp_real b;
|
||||
|
||||
clear_Cx();
|
||||
b = *a;
|
||||
normalize(&b);
|
||||
if (b.a || b.b || b.exponent) {
|
||||
if (b.exponent < 0)
|
||||
set_C0();
|
||||
} else
|
||||
set_C3();
|
||||
}
|
||||
|
||||
void fcom(const temp_real * src1, const temp_real * src2)
|
||||
{
|
||||
temp_real a;
|
||||
|
||||
a = *src1;
|
||||
a.exponent ^= 0x8000;
|
||||
fadd(&a,src2,&a);
|
||||
ftst(&a);
|
||||
}
|
||||
|
||||
void fucom(const temp_real * src1, const temp_real * src2)
|
||||
{
|
||||
fcom(src1,src2);
|
||||
}
|
||||
185
Book-Lite/linux-0.12/kernel/math/convert.c
Normal file
185
Book-Lite/linux-0.12/kernel/math/convert.c
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* linux/kernel/math/convert.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
|
||||
/*
|
||||
* 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->a = b->b = 0;
|
||||
if (*a)
|
||||
b->exponent = 0x8000;
|
||||
else
|
||||
b->exponent = 0;
|
||||
return;
|
||||
}
|
||||
b->exponent = ((*a>>23) & 0xff)-127+16383;
|
||||
if (*a<0)
|
||||
b->exponent |= 0x8000;
|
||||
b->b = (*a<<8) | 0x80000000;
|
||||
b->a = 0;
|
||||
}
|
||||
|
||||
void long_to_temp(const long_real * a, temp_real * b)
|
||||
{
|
||||
if (!a->a && !(a->b & 0x7fffffff)) {
|
||||
b->a = b->b = 0;
|
||||
if (a->b)
|
||||
b->exponent = 0x8000;
|
||||
else
|
||||
b->exponent = 0;
|
||||
return;
|
||||
}
|
||||
b->exponent = ((a->b >> 20) & 0x7ff)-1023+16383;
|
||||
if (a->b<0)
|
||||
b->exponent |= 0x8000;
|
||||
b->b = 0x80000000 | (a->b<<11) | (((unsigned long)a->a)>>21);
|
||||
b->a = a->a<<11;
|
||||
}
|
||||
|
||||
void temp_to_short(const temp_real * a, short_real * b)
|
||||
{
|
||||
if (!(a->exponent & 0x7fff)) {
|
||||
*b = (a->exponent)?0x80000000:0;
|
||||
return;
|
||||
}
|
||||
*b = ((((long) a->exponent)-16383+127) << 23) & 0x7f800000;
|
||||
if (a->exponent < 0)
|
||||
*b |= 0x80000000;
|
||||
*b |= (a->b >> 8) & 0x007fffff;
|
||||
switch (ROUNDING) {
|
||||
case ROUND_NEAREST:
|
||||
if ((a->b & 0xff) > 0x80)
|
||||
++*b;
|
||||
break;
|
||||
case ROUND_DOWN:
|
||||
if ((a->exponent & 0x8000) && (a->b & 0xff))
|
||||
++*b;
|
||||
break;
|
||||
case ROUND_UP:
|
||||
if (!(a->exponent & 0x8000) && (a->b & 0xff))
|
||||
++*b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void temp_to_long(const temp_real * a, long_real * b)
|
||||
{
|
||||
if (!(a->exponent & 0x7fff)) {
|
||||
b->a = 0;
|
||||
b->b = (a->exponent)?0x80000000:0;
|
||||
return;
|
||||
}
|
||||
b->b = (((0x7fff & (long) a->exponent)-16383+1023) << 20) & 0x7ff00000;
|
||||
if (a->exponent < 0)
|
||||
b->b |= 0x80000000;
|
||||
b->b |= (a->b >> 11) & 0x000fffff;
|
||||
b->a = a->b << 21;
|
||||
b->a |= (a->a >> 11) & 0x001fffff;
|
||||
switch (ROUNDING) {
|
||||
case ROUND_NEAREST:
|
||||
if ((a->a & 0x7ff) > 0x400)
|
||||
__asm__("addl $1,%0 ; adcl $0,%1"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"0" (b->a),"1" (b->b));
|
||||
break;
|
||||
case ROUND_DOWN:
|
||||
if ((a->exponent & 0x8000) && (a->b & 0xff))
|
||||
__asm__("addl $1,%0 ; adcl $0,%1"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"0" (b->a),"1" (b->b));
|
||||
break;
|
||||
case ROUND_UP:
|
||||
if (!(a->exponent & 0x8000) && (a->b & 0xff))
|
||||
__asm__("addl $1,%0 ; adcl $0,%1"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"0" (b->a),"1" (b->b));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void real_to_int(const temp_real * a, temp_int * b)
|
||||
{
|
||||
int shift = 16383 + 63 - (a->exponent & 0x7fff);
|
||||
unsigned long underflow;
|
||||
|
||||
b->a = b->b = underflow = 0;
|
||||
b->sign = (a->exponent < 0);
|
||||
if (shift < 0) {
|
||||
set_OE();
|
||||
return;
|
||||
}
|
||||
if (shift < 32) {
|
||||
b->b = a->b; b->a = a->a;
|
||||
} else if (shift < 64) {
|
||||
b->a = a->b; underflow = a->a;
|
||||
shift -= 32;
|
||||
} else if (shift < 96) {
|
||||
underflow = a->b;
|
||||
shift -= 64;
|
||||
} else
|
||||
return;
|
||||
__asm__("shrdl %2,%1,%0"
|
||||
:"=r" (underflow),"=r" (b->a)
|
||||
:"c" ((char) shift),"0" (underflow),"1" (b->a));
|
||||
__asm__("shrdl %2,%1,%0"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"c" ((char) shift),"0" (b->a),"1" (b->b));
|
||||
__asm__("shrl %1,%0"
|
||||
:"=r" (b->b)
|
||||
:"c" ((char) shift),"0" (b->b));
|
||||
switch (ROUNDING) {
|
||||
case ROUND_NEAREST:
|
||||
__asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"0" (b->a),"1" (b->b)
|
||||
,"r" (0x7fffffff + (b->a & 1))
|
||||
,"m" (*&underflow));
|
||||
break;
|
||||
case ROUND_UP:
|
||||
if (!b->sign && underflow)
|
||||
__asm__("addl $1,%0 ; adcl $0,%1"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"0" (b->a),"1" (b->b));
|
||||
break;
|
||||
case ROUND_DOWN:
|
||||
if (b->sign && underflow)
|
||||
__asm__("addl $1,%0 ; adcl $0,%1"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"0" (b->a),"1" (b->b));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void int_to_real(const temp_int * a, temp_real * b)
|
||||
{
|
||||
b->a = a->a;
|
||||
b->b = a->b;
|
||||
if (b->a || b->b)
|
||||
b->exponent = 16383 + 63 + (a->sign? 0x8000:0);
|
||||
else {
|
||||
b->exponent = 0;
|
||||
return;
|
||||
}
|
||||
while (b->b >= 0) {
|
||||
b->exponent--;
|
||||
__asm__("addl %0,%0 ; adcl %1,%1"
|
||||
:"=r" (b->a),"=r" (b->b)
|
||||
:"0" (b->a),"1" (b->b));
|
||||
}
|
||||
}
|
||||
109
Book-Lite/linux-0.12/kernel/math/div.c
Normal file
109
Book-Lite/linux-0.12/kernel/math/div.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* linux/kernel/math/div.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* temporary real division routine.
|
||||
*/
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
|
||||
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)"
|
||||
::"r" ((long) c):"ax");
|
||||
}
|
||||
|
||||
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 try_sub(int * a, int * b)
|
||||
{
|
||||
char ok;
|
||||
|
||||
__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));
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void div64(int * a, int * b, int * c)
|
||||
{
|
||||
int tmp[4];
|
||||
int i;
|
||||
unsigned int mask = 0;
|
||||
|
||||
c += 4;
|
||||
for (i = 0 ; i<64 ; i++) {
|
||||
if (!(mask >>= 1)) {
|
||||
c--;
|
||||
mask = 0x80000000;
|
||||
}
|
||||
tmp[0] = a[0]; tmp[1] = a[1];
|
||||
tmp[2] = a[2]; tmp[3] = a[3];
|
||||
if (try_sub(b,tmp)) {
|
||||
*c |= mask;
|
||||
a[0] = tmp[0]; a[1] = tmp[1];
|
||||
a[2] = tmp[2]; a[3] = tmp[3];
|
||||
}
|
||||
shift_right(b);
|
||||
}
|
||||
}
|
||||
|
||||
void fdiv(const temp_real * src1, const temp_real * src2, temp_real * result)
|
||||
{
|
||||
int i,sign;
|
||||
int a[4],b[4],tmp[4] = {0,0,0,0};
|
||||
|
||||
sign = (src1->exponent ^ src2->exponent) & 0x8000;
|
||||
if (!(src2->a || src2->b)) {
|
||||
set_ZE();
|
||||
return;
|
||||
}
|
||||
i = (src1->exponent & 0x7fff) - (src2->exponent & 0x7fff) + 16383;
|
||||
if (i<0) {
|
||||
set_UE();
|
||||
result->exponent = sign;
|
||||
result->a = result->b = 0;
|
||||
return;
|
||||
}
|
||||
a[0] = a[1] = 0;
|
||||
a[2] = src1->a;
|
||||
a[3] = src1->b;
|
||||
b[0] = b[1] = 0;
|
||||
b[2] = src2->a;
|
||||
b[3] = src2->b;
|
||||
while (b[3] >= 0) {
|
||||
i++;
|
||||
shift_left(b);
|
||||
}
|
||||
div64(a,b,tmp);
|
||||
if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) {
|
||||
while (i && tmp[3] >= 0) {
|
||||
i--;
|
||||
shift_left(tmp);
|
||||
}
|
||||
if (tmp[3] >= 0)
|
||||
set_DE();
|
||||
} else
|
||||
i = 0;
|
||||
if (i>0x7fff) {
|
||||
set_OE();
|
||||
return;
|
||||
}
|
||||
if (tmp[0] || tmp[1])
|
||||
set_PE();
|
||||
result->exponent = i | sign;
|
||||
result->a = tmp[2];
|
||||
result->b = tmp[3];
|
||||
}
|
||||
92
Book-Lite/linux-0.12/kernel/math/ea.c
Normal file
92
Book-Lite/linux-0.12/kernel/math/ea.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* linux/kernel/math/ea.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* Calculate the effective address.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
static int __regoffset[] = {
|
||||
offsetof(struct info,___eax),
|
||||
offsetof(struct info,___ecx),
|
||||
offsetof(struct info,___edx),
|
||||
offsetof(struct info,___ebx),
|
||||
offsetof(struct info,___esp),
|
||||
offsetof(struct info,___ebp),
|
||||
offsetof(struct info,___esi),
|
||||
offsetof(struct info,___edi)
|
||||
};
|
||||
|
||||
#define REG(x) (*(long *)(__regoffset[(x)]+(char *) info))
|
||||
|
||||
static char * sib(struct info * info, int mod)
|
||||
{
|
||||
unsigned char ss,index,base;
|
||||
long offset = 0;
|
||||
|
||||
base = get_fs_byte((char *) EIP);
|
||||
EIP++;
|
||||
ss = base >> 6;
|
||||
index = (base >> 3) & 7;
|
||||
base &= 7;
|
||||
if (index == 4)
|
||||
offset = 0;
|
||||
else
|
||||
offset = REG(index);
|
||||
offset <<= ss;
|
||||
if (mod || base != 5)
|
||||
offset += REG(base);
|
||||
if (mod == 1) {
|
||||
offset += (signed char) get_fs_byte((char *) EIP);
|
||||
EIP++;
|
||||
} else if (mod == 2 || base == 5) {
|
||||
offset += (signed) get_fs_long((unsigned long *) EIP);
|
||||
EIP += 4;
|
||||
}
|
||||
I387.foo = offset;
|
||||
I387.fos = 0x17;
|
||||
return (char *) offset;
|
||||
}
|
||||
|
||||
char * ea(struct info * info, unsigned short code)
|
||||
{
|
||||
unsigned char mod,rm;
|
||||
long * tmp = &EAX;
|
||||
int offset = 0;
|
||||
|
||||
mod = (code >> 6) & 3;
|
||||
rm = code & 7;
|
||||
if (rm == 4 && mod != 3)
|
||||
return sib(info,mod);
|
||||
if (rm == 5 && !mod) {
|
||||
offset = get_fs_long((unsigned long *) EIP);
|
||||
EIP += 4;
|
||||
I387.foo = offset;
|
||||
I387.fos = 0x17;
|
||||
return (char *) offset;
|
||||
}
|
||||
tmp = & REG(rm);
|
||||
switch (mod) {
|
||||
case 0: offset = 0; break;
|
||||
case 1:
|
||||
offset = (signed char) get_fs_byte((char *) EIP);
|
||||
EIP++;
|
||||
break;
|
||||
case 2:
|
||||
offset = (signed) get_fs_long((unsigned long *) EIP);
|
||||
EIP += 4;
|
||||
break;
|
||||
case 3:
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
}
|
||||
I387.foo = offset;
|
||||
I387.fos = 0x17;
|
||||
return offset + (char *) *tmp;
|
||||
}
|
||||
16
Book-Lite/linux-0.12/kernel/math/error.c
Normal file
16
Book-Lite/linux-0.12/kernel/math/error.c
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* linux/kernel/math/error.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
void math_error(void)
|
||||
{
|
||||
__asm__("fnclex");
|
||||
if (last_task_used_math)
|
||||
last_task_used_math->signal |= 1<<(SIGFPE-1);
|
||||
}
|
||||
240
Book-Lite/linux-0.12/kernel/math/get_put.c
Normal file
240
Book-Lite/linux-0.12/kernel/math/get_put.c
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#include <signal.h>
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
void get_short_real(temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
short_real sr;
|
||||
|
||||
addr = ea(info,code);
|
||||
sr = get_fs_long((unsigned long *) addr);
|
||||
short_to_temp(&sr,tmp);
|
||||
}
|
||||
|
||||
void get_long_real(temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
long_real lr;
|
||||
|
||||
addr = ea(info,code);
|
||||
lr.a = get_fs_long((unsigned long *) addr);
|
||||
lr.b = get_fs_long(1 + (unsigned long *) addr);
|
||||
long_to_temp(&lr,tmp);
|
||||
}
|
||||
|
||||
void get_temp_real(temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
|
||||
addr = ea(info,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 info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
temp_int ti;
|
||||
|
||||
addr = ea(info,code);
|
||||
ti.a = (signed short) get_fs_word((unsigned short *) addr);
|
||||
ti.b = 0;
|
||||
if (ti.sign = (ti.a < 0))
|
||||
ti.a = - ti.a;
|
||||
int_to_real(&ti,tmp);
|
||||
}
|
||||
|
||||
void get_long_int(temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
temp_int ti;
|
||||
|
||||
addr = ea(info,code);
|
||||
ti.a = get_fs_long((unsigned long *) addr);
|
||||
ti.b = 0;
|
||||
if (ti.sign = (ti.a < 0))
|
||||
ti.a = - ti.a;
|
||||
int_to_real(&ti,tmp);
|
||||
}
|
||||
|
||||
void get_longlong_int(temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
temp_int ti;
|
||||
|
||||
addr = ea(info,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"
|
||||
:"=r" (ti.a),"=r" (ti.b)
|
||||
:"0" (ti.a),"1" (ti.b));
|
||||
int_to_real(&ti,tmp);
|
||||
}
|
||||
|
||||
#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 info * info, unsigned short code)
|
||||
{
|
||||
int k;
|
||||
char * addr;
|
||||
temp_int i;
|
||||
unsigned char c;
|
||||
|
||||
addr = ea(info,code);
|
||||
addr += 9;
|
||||
i.sign = 0x80 & get_fs_byte(addr--);
|
||||
i.a = i.b = 0;
|
||||
for (k = 0; k < 9; k++) {
|
||||
c = get_fs_byte(addr--);
|
||||
MUL10(i.a, i.b);
|
||||
ADD64((c>>4), i.a, i.b);
|
||||
MUL10(i.a, i.b);
|
||||
ADD64((c&0xf), i.a, i.b);
|
||||
}
|
||||
int_to_real(&i,tmp);
|
||||
}
|
||||
|
||||
void put_short_real(const temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
short_real sr;
|
||||
|
||||
addr = ea(info,code);
|
||||
verify_area(addr,4);
|
||||
temp_to_short(tmp,&sr);
|
||||
put_fs_long(sr,(unsigned long *) addr);
|
||||
}
|
||||
|
||||
void put_long_real(const temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
long_real lr;
|
||||
|
||||
addr = ea(info,code);
|
||||
verify_area(addr,8);
|
||||
temp_to_long(tmp,&lr);
|
||||
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 info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
|
||||
addr = ea(info,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 info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
temp_int ti;
|
||||
|
||||
addr = ea(info,code);
|
||||
real_to_int(tmp,&ti);
|
||||
verify_area(addr,2);
|
||||
if (ti.sign)
|
||||
ti.a = -ti.a;
|
||||
put_fs_word(ti.a,(short *) addr);
|
||||
}
|
||||
|
||||
void put_long_int(const temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
temp_int ti;
|
||||
|
||||
addr = ea(info,code);
|
||||
real_to_int(tmp,&ti);
|
||||
verify_area(addr,4);
|
||||
if (ti.sign)
|
||||
ti.a = -ti.a;
|
||||
put_fs_long(ti.a,(unsigned long *) addr);
|
||||
}
|
||||
|
||||
void put_longlong_int(const temp_real * tmp,
|
||||
struct info * info, unsigned short code)
|
||||
{
|
||||
char * addr;
|
||||
temp_int ti;
|
||||
|
||||
addr = ea(info,code);
|
||||
real_to_int(tmp,&ti);
|
||||
verify_area(addr,8);
|
||||
if (ti.sign)
|
||||
__asm__("notl %0 ; notl %1\n\t"
|
||||
"addl $1,%0 ; adcl $0,%1"
|
||||
:"=r" (ti.a),"=r" (ti.b)
|
||||
:"0" (ti.a),"1" (ti.b));
|
||||
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),"=b" (high) \
|
||||
:"0" (0),"1" (high),"2" (low),"c" (10))
|
||||
|
||||
void put_BCD(const temp_real * tmp,struct info * info, unsigned short code)
|
||||
{
|
||||
int k,rem;
|
||||
char * addr;
|
||||
temp_int i;
|
||||
unsigned char c;
|
||||
|
||||
addr = ea(info,code);
|
||||
verify_area(addr,10);
|
||||
real_to_int(tmp,&i);
|
||||
if (i.sign)
|
||||
put_fs_byte(0x80, addr+9);
|
||||
else
|
||||
put_fs_byte(0, addr+9);
|
||||
for (k = 0; k < 9; k++) {
|
||||
DIV10(i.a,i.b,rem);
|
||||
c = rem;
|
||||
DIV10(i.a,i.b,rem);
|
||||
c += rem<<4;
|
||||
put_fs_byte(c,addr++);
|
||||
}
|
||||
}
|
||||
529
Book-Lite/linux-0.12/kernel/math/math_emulate.c
Normal file
529
Book-Lite/linux-0.12/kernel/math/math_emulate.c
Normal file
@@ -0,0 +1,529 @@
|
||||
/*
|
||||
* linux/kernel/math/math_emulate.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#define __ALIGNED_TEMP_REAL 1
|
||||
#include <linux/math_emu.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/segment.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)))
|
||||
|
||||
/*
|
||||
* We don't want these inlined - it gets too messy in the machine-code.
|
||||
*/
|
||||
static void fpop(void);
|
||||
static void fpush(void);
|
||||
static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b);
|
||||
static temp_real_unaligned * __st(int i);
|
||||
|
||||
static void do_emu(struct info * info)
|
||||
{
|
||||
unsigned short code;
|
||||
temp_real tmp;
|
||||
char * address;
|
||||
|
||||
if (I387.cwd & I387.swd & 0x3f)
|
||||
I387.swd |= 0x8000;
|
||||
else
|
||||
I387.swd &= 0x7fff;
|
||||
ORIG_EIP = EIP;
|
||||
/* 0x0007 means user code space */
|
||||
if (CS != 0x000F) {
|
||||
printk("math_emulate: %04x:%08x\n\r",CS,EIP);
|
||||
panic("Math emulation needed in kernel");
|
||||
}
|
||||
code = get_fs_word((unsigned short *) EIP);
|
||||
bswapw(code);
|
||||
code &= 0x7ff;
|
||||
I387.fip = EIP;
|
||||
*(unsigned short *) &I387.fcs = CS;
|
||||
*(1+(unsigned short *) &I387.fcs) = code;
|
||||
EIP += 2;
|
||||
switch (code) {
|
||||
case 0x1d0: /* fnop */
|
||||
return;
|
||||
case 0x1d1: case 0x1d2: case 0x1d3:
|
||||
case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
case 0x1e0:
|
||||
ST(0).exponent ^= 0x8000;
|
||||
return;
|
||||
case 0x1e1:
|
||||
ST(0).exponent &= 0x7fff;
|
||||
return;
|
||||
case 0x1e2: case 0x1e3:
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
case 0x1e4:
|
||||
ftst(PST(0));
|
||||
return;
|
||||
case 0x1e5:
|
||||
printk("fxam not implemented\n\r");
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
case 0x1e6: case 0x1e7:
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
case 0x1e8:
|
||||
fpush();
|
||||
ST(0) = CONST1;
|
||||
return;
|
||||
case 0x1e9:
|
||||
fpush();
|
||||
ST(0) = CONSTL2T;
|
||||
return;
|
||||
case 0x1ea:
|
||||
fpush();
|
||||
ST(0) = CONSTL2E;
|
||||
return;
|
||||
case 0x1eb:
|
||||
fpush();
|
||||
ST(0) = CONSTPI;
|
||||
return;
|
||||
case 0x1ec:
|
||||
fpush();
|
||||
ST(0) = CONSTLG2;
|
||||
return;
|
||||
case 0x1ed:
|
||||
fpush();
|
||||
ST(0) = CONSTLN2;
|
||||
return;
|
||||
case 0x1ee:
|
||||
fpush();
|
||||
ST(0) = CONSTZ;
|
||||
return;
|
||||
case 0x1ef:
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3:
|
||||
case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7:
|
||||
case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb:
|
||||
case 0x1fc: case 0x1fd: case 0x1fe: case 0x1ff:
|
||||
printk("%04x fxxx not implemented\n\r",code + 0xc800);
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
case 0x2e9:
|
||||
fucom(PST(1),PST(0));
|
||||
fpop(); fpop();
|
||||
return;
|
||||
case 0x3d0: case 0x3d1:
|
||||
return;
|
||||
case 0x3e2:
|
||||
I387.swd &= 0x7f00;
|
||||
return;
|
||||
case 0x3e3:
|
||||
I387.cwd = 0x037f;
|
||||
I387.swd = 0x0000;
|
||||
I387.twd = 0x0000;
|
||||
return;
|
||||
case 0x3e4:
|
||||
return;
|
||||
case 0x6d9:
|
||||
fcom(PST(1),PST(0));
|
||||
fpop(); fpop();
|
||||
return;
|
||||
case 0x7e0:
|
||||
*(short *) &EAX = I387.swd;
|
||||
return;
|
||||
}
|
||||
switch (code >> 3) {
|
||||
case 0x18:
|
||||
fadd(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x19:
|
||||
fmul(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x1a:
|
||||
fcom(PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x1b:
|
||||
fcom(PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
fpop();
|
||||
return;
|
||||
case 0x1c:
|
||||
real_to_real(&ST(code & 7),&tmp);
|
||||
tmp.exponent ^= 0x8000;
|
||||
fadd(PST(0),&tmp,&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x1d:
|
||||
ST(0).exponent ^= 0x8000;
|
||||
fadd(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x1e:
|
||||
fdiv(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x1f:
|
||||
fdiv(PST(code & 7),PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x38:
|
||||
fpush();
|
||||
ST(0) = ST((code & 7)+1);
|
||||
return;
|
||||
case 0x39:
|
||||
fxchg(&ST(0),&ST(code & 7));
|
||||
return;
|
||||
case 0x3b:
|
||||
ST(code & 7) = ST(0);
|
||||
fpop();
|
||||
return;
|
||||
case 0x98:
|
||||
fadd(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
return;
|
||||
case 0x99:
|
||||
fmul(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
return;
|
||||
case 0x9a:
|
||||
fcom(PST(code & 7),PST(0));
|
||||
return;
|
||||
case 0x9b:
|
||||
fcom(PST(code & 7),PST(0));
|
||||
fpop();
|
||||
return;
|
||||
case 0x9c:
|
||||
ST(code & 7).exponent ^= 0x8000;
|
||||
fadd(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
return;
|
||||
case 0x9d:
|
||||
real_to_real(&ST(0),&tmp);
|
||||
tmp.exponent ^= 0x8000;
|
||||
fadd(PST(code & 7),&tmp,&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
return;
|
||||
case 0x9e:
|
||||
fdiv(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
return;
|
||||
case 0x9f:
|
||||
fdiv(PST(code & 7),PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
return;
|
||||
case 0xb8:
|
||||
printk("ffree not implemented\n\r");
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
case 0xb9:
|
||||
fxchg(&ST(0),&ST(code & 7));
|
||||
return;
|
||||
case 0xba:
|
||||
ST(code & 7) = ST(0);
|
||||
return;
|
||||
case 0xbb:
|
||||
ST(code & 7) = ST(0);
|
||||
fpop();
|
||||
return;
|
||||
case 0xbc:
|
||||
fucom(PST(code & 7),PST(0));
|
||||
return;
|
||||
case 0xbd:
|
||||
fucom(PST(code & 7),PST(0));
|
||||
fpop();
|
||||
return;
|
||||
case 0xd8:
|
||||
fadd(PST(code & 7),PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
fpop();
|
||||
return;
|
||||
case 0xd9:
|
||||
fmul(PST(code & 7),PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
fpop();
|
||||
return;
|
||||
case 0xda:
|
||||
fcom(PST(code & 7),PST(0));
|
||||
fpop();
|
||||
return;
|
||||
case 0xdc:
|
||||
ST(code & 7).exponent ^= 0x8000;
|
||||
fadd(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
fpop();
|
||||
return;
|
||||
case 0xdd:
|
||||
real_to_real(&ST(0),&tmp);
|
||||
tmp.exponent ^= 0x8000;
|
||||
fadd(PST(code & 7),&tmp,&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
fpop();
|
||||
return;
|
||||
case 0xde:
|
||||
fdiv(PST(0),PST(code & 7),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
fpop();
|
||||
return;
|
||||
case 0xdf:
|
||||
fdiv(PST(code & 7),PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(code & 7));
|
||||
fpop();
|
||||
return;
|
||||
case 0xf8:
|
||||
printk("ffree not implemented\n\r");
|
||||
math_abort(info,1<<(SIGILL-1));
|
||||
fpop();
|
||||
return;
|
||||
case 0xf9:
|
||||
fxchg(&ST(0),&ST(code & 7));
|
||||
return;
|
||||
case 0xfa:
|
||||
case 0xfb:
|
||||
ST(code & 7) = ST(0);
|
||||
fpop();
|
||||
return;
|
||||
}
|
||||
switch ((code>>3) & 0xe7) {
|
||||
case 0x22:
|
||||
put_short_real(PST(0),info,code);
|
||||
return;
|
||||
case 0x23:
|
||||
put_short_real(PST(0),info,code);
|
||||
fpop();
|
||||
return;
|
||||
case 0x24:
|
||||
address = ea(info,code);
|
||||
for (code = 0 ; code < 7 ; code++) {
|
||||
((long *) & I387)[code] =
|
||||
get_fs_long((unsigned long *) address);
|
||||
address += 4;
|
||||
}
|
||||
return;
|
||||
case 0x25:
|
||||
address = ea(info,code);
|
||||
*(unsigned short *) &I387.cwd =
|
||||
get_fs_word((unsigned short *) address);
|
||||
return;
|
||||
case 0x26:
|
||||
address = ea(info,code);
|
||||
verify_area(address,28);
|
||||
for (code = 0 ; code < 7 ; code++) {
|
||||
put_fs_long( ((long *) & I387)[code],
|
||||
(unsigned long *) address);
|
||||
address += 4;
|
||||
}
|
||||
return;
|
||||
case 0x27:
|
||||
address = ea(info,code);
|
||||
verify_area(address,2);
|
||||
put_fs_word(I387.cwd,(short *) address);
|
||||
return;
|
||||
case 0x62:
|
||||
put_long_int(PST(0),info,code);
|
||||
return;
|
||||
case 0x63:
|
||||
put_long_int(PST(0),info,code);
|
||||
fpop();
|
||||
return;
|
||||
case 0x65:
|
||||
fpush();
|
||||
get_temp_real(&tmp,info,code);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0x67:
|
||||
put_temp_real(PST(0),info,code);
|
||||
fpop();
|
||||
return;
|
||||
case 0xa2:
|
||||
put_long_real(PST(0),info,code);
|
||||
return;
|
||||
case 0xa3:
|
||||
put_long_real(PST(0),info,code);
|
||||
fpop();
|
||||
return;
|
||||
case 0xa4:
|
||||
address = ea(info,code);
|
||||
for (code = 0 ; code < 27 ; code++) {
|
||||
((long *) & I387)[code] =
|
||||
get_fs_long((unsigned long *) address);
|
||||
address += 4;
|
||||
}
|
||||
return;
|
||||
case 0xa6:
|
||||
address = ea(info,code);
|
||||
verify_area(address,108);
|
||||
for (code = 0 ; code < 27 ; code++) {
|
||||
put_fs_long( ((long *) & I387)[code],
|
||||
(unsigned long *) address);
|
||||
address += 4;
|
||||
}
|
||||
I387.cwd = 0x037f;
|
||||
I387.swd = 0x0000;
|
||||
I387.twd = 0x0000;
|
||||
return;
|
||||
case 0xa7:
|
||||
address = ea(info,code);
|
||||
verify_area(address,2);
|
||||
put_fs_word(I387.swd,(short *) address);
|
||||
return;
|
||||
case 0xe2:
|
||||
put_short_int(PST(0),info,code);
|
||||
return;
|
||||
case 0xe3:
|
||||
put_short_int(PST(0),info,code);
|
||||
fpop();
|
||||
return;
|
||||
case 0xe4:
|
||||
fpush();
|
||||
get_BCD(&tmp,info,code);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0xe5:
|
||||
fpush();
|
||||
get_longlong_int(&tmp,info,code);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 0xe6:
|
||||
put_BCD(PST(0),info,code);
|
||||
fpop();
|
||||
return;
|
||||
case 0xe7:
|
||||
put_longlong_int(PST(0),info,code);
|
||||
fpop();
|
||||
return;
|
||||
}
|
||||
switch (code >> 9) {
|
||||
case 0:
|
||||
get_short_real(&tmp,info,code);
|
||||
break;
|
||||
case 1:
|
||||
get_long_int(&tmp,info,code);
|
||||
break;
|
||||
case 2:
|
||||
get_long_real(&tmp,info,code);
|
||||
break;
|
||||
case 4:
|
||||
get_short_int(&tmp,info,code);
|
||||
}
|
||||
switch ((code>>3) & 0x27) {
|
||||
case 0:
|
||||
fadd(&tmp,PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 1:
|
||||
fmul(&tmp,PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 2:
|
||||
fcom(&tmp,PST(0));
|
||||
return;
|
||||
case 3:
|
||||
fcom(&tmp,PST(0));
|
||||
fpop();
|
||||
return;
|
||||
case 4:
|
||||
tmp.exponent ^= 0x8000;
|
||||
fadd(&tmp,PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 5:
|
||||
ST(0).exponent ^= 0x8000;
|
||||
fadd(&tmp,PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 6:
|
||||
fdiv(PST(0),&tmp,&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
case 7:
|
||||
fdiv(&tmp,PST(0),&tmp);
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
}
|
||||
if ((code & 0x138) == 0x100) {
|
||||
fpush();
|
||||
real_to_real(&tmp,&ST(0));
|
||||
return;
|
||||
}
|
||||
printk("Unknown math-insns: %04x:%08x %04x\n\r",CS,EIP,code);
|
||||
math_abort(info,1<<(SIGFPE-1));
|
||||
}
|
||||
|
||||
void math_emulate(long ___false)
|
||||
{
|
||||
if (!current->used_math) {
|
||||
current->used_math = 1;
|
||||
I387.cwd = 0x037f;
|
||||
I387.swd = 0x0000;
|
||||
I387.twd = 0x0000;
|
||||
}
|
||||
/* &___false points to info->___orig_eip, so subtract 1 to get info */
|
||||
do_emu((struct info *) ((&___false) - 1));
|
||||
}
|
||||
|
||||
void __math_abort(struct info * info, unsigned int signal)
|
||||
{
|
||||
EIP = ORIG_EIP;
|
||||
current->signal |= signal;
|
||||
__asm__("movl %0,%%esp ; ret"::"g" ((long) info));
|
||||
}
|
||||
|
||||
static void fpop(void)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
||||
tmp = I387.swd & 0xffffc7ff;
|
||||
I387.swd += 0x00000800;
|
||||
I387.swd &= 0x00003800;
|
||||
I387.swd |= tmp;
|
||||
}
|
||||
|
||||
static void fpush(void)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
||||
tmp = I387.swd & 0xffffc7ff;
|
||||
I387.swd += 0x00003800;
|
||||
I387.swd &= 0x00003800;
|
||||
I387.swd |= tmp;
|
||||
}
|
||||
|
||||
static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b)
|
||||
{
|
||||
temp_real_unaligned c;
|
||||
|
||||
c = *a;
|
||||
*a = *b;
|
||||
*b = c;
|
||||
}
|
||||
|
||||
static temp_real_unaligned * __st(int i)
|
||||
{
|
||||
i += I387.swd >> 11;
|
||||
i &= 7;
|
||||
return (temp_real_unaligned *) (i*10 + (char *)(I387.st_space));
|
||||
}
|
||||
73
Book-Lite/linux-0.12/kernel/math/mul.c
Normal file
73
Book-Lite/linux-0.12/kernel/math/mul.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* linux/kernel/math/mul.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* temporary real multiplication routine.
|
||||
*/
|
||||
|
||||
#include <linux/math_emu.h>
|
||||
|
||||
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)"
|
||||
::"r" ((long) c):"ax");
|
||||
}
|
||||
|
||||
static void mul64(const temp_real * a, const temp_real * b, int * c)
|
||||
{
|
||||
__asm__("movl (%0),%%eax\n\t"
|
||||
"mull (%1)\n\t"
|
||||
"movl %%eax,(%2)\n\t"
|
||||
"movl %%edx,4(%2)\n\t"
|
||||
"movl 4(%0),%%eax\n\t"
|
||||
"mull 4(%1)\n\t"
|
||||
"movl %%eax,8(%2)\n\t"
|
||||
"movl %%edx,12(%2)\n\t"
|
||||
"movl (%0),%%eax\n\t"
|
||||
"mull 4(%1)\n\t"
|
||||
"addl %%eax,4(%2)\n\t"
|
||||
"adcl %%edx,8(%2)\n\t"
|
||||
"adcl $0,12(%2)\n\t"
|
||||
"movl 4(%0),%%eax\n\t"
|
||||
"mull (%1)\n\t"
|
||||
"addl %%eax,4(%2)\n\t"
|
||||
"adcl %%edx,8(%2)\n\t"
|
||||
"adcl $0,12(%2)"
|
||||
::"b" ((long) a),"c" ((long) b),"D" ((long) c)
|
||||
:"ax","dx");
|
||||
}
|
||||
|
||||
void fmul(const temp_real * src1, const temp_real * src2, temp_real * result)
|
||||
{
|
||||
int i,sign;
|
||||
int tmp[4] = {0,0,0,0};
|
||||
|
||||
sign = (src1->exponent ^ src2->exponent) & 0x8000;
|
||||
i = (src1->exponent & 0x7fff) + (src2->exponent & 0x7fff) - 16383 + 1;
|
||||
if (i<0) {
|
||||
result->exponent = sign;
|
||||
result->a = result->b = 0;
|
||||
return;
|
||||
}
|
||||
if (i>0x7fff) {
|
||||
set_OE();
|
||||
return;
|
||||
}
|
||||
mul64(src1,src2,tmp);
|
||||
if (tmp[0] || tmp[1] || tmp[2] || tmp[3])
|
||||
while (i && tmp[3] >= 0) {
|
||||
i--;
|
||||
shift(tmp);
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
result->exponent = i | sign;
|
||||
result->a = tmp[2];
|
||||
result->b = tmp[3];
|
||||
}
|
||||
Reference in New Issue
Block a user