## diffname ss/fptrap.c 1992/0726
## diff -e /dev/null /n/bootesdump/1992/0726/sys/src/9/slc/fptrap.c
0a
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "ureg.h"
#include "io.h"
#include "../port/error.h"
static int unfinished(FPsave*);
static int fixq(FPsave*, int);
extern void* bbmalloc(int);
int
fptrap(void)
{
int n, ret;
ulong fsr;
n = getfpq(&u->fpsave.q[0].a);
if(n > NFPQ)
panic("FPQ %d\n", n);
again:
fsr = getfsr();
savefpregs(&u->fpsave);
u->fpsave.fsr = fsr;
ret = 0;
switch((fsr>>14) & 7){
case 2:
ret = unfinished(&u->fpsave);
break;
}
if(ret){
enabfp(); /* savefpregs disables it */
clearftt(fsr & ~0x1F); /* clear ftt and cexc */
restfpregs(&u->fpsave);
enabfp(); /* restfpregs disables it */
n = fixq(&u->fpsave, n);
if(n > 0)
goto again;
}
return ret;
}
static void
unpack(FPsave *f, int size, int reg, int *sign, int *exp)
{
*sign = 1;
if(f->fpreg[reg] & 0x80000000)
*sign = -1;
switch(size){
case 1:
*exp = ((f->fpreg[reg]>>23)&0xFF) - ((1<<7)-2);
break;
case 2:
if(reg & 1){
pprint("unaligned double fp register\n");
reg &= ~1;
}
*exp = ((f->fpreg[reg]>>20)&0x7FF) - ((1<<10)-2);
break;
case 3:
if(reg & 3){
pprint("unaligned quad fp register\n");
reg &= ~3;
}
*exp = ((f->fpreg[reg]>>16)&0x7FFF) - ((1<<14)-2);
break;
}
}
static void
zeroreg(FPsave *f, int size, int reg, int sign)
{
switch(size){
case 1:
size = 4;
break;
case 2:
if(reg & 1)
reg &= ~1;
size = 8;
break;
case 3:
if(reg & 3)
reg &= ~3;
size = 16;
break;
}
memset(&f->fpreg[reg], 0, size);
if(sign < 0)
f->fpreg[reg] |= 0x80000000;
}
static int
unfinished(FPsave *f)
{
ulong instr;
int size, maxe, maxm, op, rd, rs1, rs2;
int sd, ss1, ss2;
int ed, es1, es2;
instr = f->q[0].i;
if((instr&0xC1F80000) != 0x81A00000){
bad:
pprint("unknown unfinished instruction %lux\n", instr);
return 0;
}
size = (instr>>5) & 0x3;
if(size == 0)
goto bad;
maxe = 0;
maxm = 0;
switch(size){
case 1:
maxe = 1<<7;
maxm = 24;
break;
case 2:
maxe = 1<<10;
maxm = 53;
break;
case 3:
maxe = 1<<14;
maxm = 113;
break;
}
rd = (instr>>25) & 0x1F;
rs1 = (instr>>14) & 0x1F;
rs2 = (instr>>0) & 0x1F;
unpack(f, size, rs1, &ss1, &es1);
unpack(f, size, rs2, &ss2, &es2);
op = (instr>>7) & 0x7F;
ed = 0;
switch(op){
case 0x11: /* FSUB */
ss2 = -ss2;
case 0x10: /* FADD */
if(es1<-(maxe-maxm) && es2<-(maxe-maxm))
ed = -maxe;
if(es1 > es2)
sd = es1;
else
sd = es2;
break;
case 0x13: /* FDIV */
es2 = -es2;
case 0x12: /* FMUL */
sd = 1;
if(ss1 != ss2)
sd = -1;
ed = es1 + es2;
break;
case 0x31: /* F?TOS */
case 0x32: /* F?TOD */
case 0x33: /* F?TOQ */
if(es2 == maxe) /* NaN or Inf */
return 0;
sd = ss2;
ed = es2; /* if underflow, this will do the trick */
break;
default:
goto bad;
}
if(ed <= -(maxe-4)){ /* guess: underflow */
zeroreg(f, size, rd, sd);
return 1;
}
return 0;
}
static int
fixq(FPsave *f, int n)
{
ulong instr, fsr;
ulong *ip;
while(n > 1){
memmove(&f->q[0], &f->q[1], (n-1)*sizeof f->q[0]);
instr = f->q[0].i;
ip = bbmalloc(3*sizeof(ulong));
ip[0] = instr;
ip[1] = 0x81c3e008; /* JMPL #8(R15), R0 [RETURN] */
ip[2] = 0x01000000; /* SETHI #0, R0 [NOP] */
(*(void(*)(void))ip)();
/*
* WARNING: This code is wrong (and I don't know how
* to fix it without emulating the entire FPU in
* software--please let me knw) if the queued
* instruction gets an exception: the getfsr() generates
* a trap and the staggeringly inept SPARC design
* translates that to a reset, as you can't have
* nested exceptions. So here's the fairly solid but
* not fail-safe solution: jump out NOW if there's
* nothing else pending. If this last instruction
* causes an exception, it will fire when the *user*
* executes the next FP instruction. The system
* avoids executing any FP on the way out. The
* user will trap and we'll be back but will have
* made progress. The FQ will point to kernel space
* but the trap will happen in user space, and that's
* what matters.
*
* This same botch may cause the system to reset
* if a trap is pending when we call savefpregs() in
* trap.c. I don't know; the documentation is unclear.
*/
if(n == 1)
return 0;
for(;;){
fsr = getfsr();
if((fsr & (1<<13)) == 0) /* qne */
break;
if(fsr & 0x1F) /* cexc */
return n;
}
--n;
}
return 0;
}
.
## diffname ss/fptrap.c 1992/0802
## diff -e /n/bootesdump/1992/0726/sys/src/9/slc/fptrap.c /n/bootesdump/1992/0802/sys/src/9/slc/fptrap.c
222c
m->fpunsafe = 0;
u->p->fpstate = FPactive;
return notrap;
.
220c
if((fsr&(1<<13)) == 0)
break;
if(++i > 1000){
print("fp not quiescent\n");
break;
}
.
211,218c
(*(void(*)(void))ip)();
if(!fpquiet())
break;
}
}
/*
* Must only be called splhi() when it is safe to spllo(). Because the FP unit
* traps if you touch it when an exception is pending, and because if you
* trap with ET==0 you halt, this routine sets some global flags to enable
* the rest of the system to handle the trap that might occur here without
* upsetting the kernel.
*/
int
fpquiet(void)
{
int i, notrap;
ulong fsr;
char buf[128];
i = 0;
notrap = 1;
m->fpunsafe = 1;
u->p->fpstate = FPinactive;
for(;;){
m->fptrap = 0;
spllo();
fsr = getfsr();
splhi();
if(m->fptrap){
/* trap occurred and u->fpsave contains state */
spllo();
sprint(buf, "sys: %s", excname(8));
postnote(u->p, 1, buf, NDebug);
notrap = 0;
break;
.
190,209c
* You can always pump one instruction without immediate trap.
* Therefore run one and wait for it to complete or trap.
* If it traps, we'll recurse but we won't overwrite
* our own data structures because there will be only
* one instruction uncompleted in the FPU.
* If that instruction generates an unfixable trap,
* stop the processing, which means a buglet: if the user
* process is attempting to resolve FP errors, it must
* find and extract the uncompleted instructions behind
* the trap by examining the non-zero members of the FPQ.
* Tough.
.
188d
183a
/*
* Sparc says you have to emulate. To hell with that.
* Let's compile!
*/
.
182c
--n;
memmove(&f->q[0], &f->q[1], n*sizeof f->q[0]);
memset(&f->q[n], 0, (NFPQ-n)*sizeof f->q[0]);
.
175c
static void
.
38,40c
fixq(&u->fpsave, n);
.
11c
static void fixq(FPsave*, int);
.
## diffname ss/fptrap.c 1992/0803
## diff -e /n/bootesdump/1992/0802/sys/src/9/slc/fptrap.c /n/bootesdump/1992/0803/sys/src/9/slc/fptrap.c
176c
ulong instr;
.
## diffname ss/fptrap.c 1992/0804
## diff -e /n/bootesdump/1992/0803/sys/src/9/slc/fptrap.c /n/bootesdump/1992/0804/sys/src/9/slc/fptrap.c
205a
f->fppc = 0;
.
204a
f->fppc = f->q[0].a;
.
36c
restfpregs(&u->fpsave, fsr);
.
23c
/*
* If faulted during restart, recover PC for debugging
*/
if(u->fpsave.fppc)
u->fpsave.q[0].a = u->fpsave.fppc;
.
## diffname ss/fptrap.c 1992/0805
## diff -e /n/bootesdump/1992/0804/sys/src/9/slc/fptrap.c /n/bootesdump/1992/0805/sys/src/9/slc/fptrap.c
210c
(*(void(*)(void))ip)(); /* You are expected to understand this cast */
.
208a
ip = bbmalloc(3*sizeof(ulong));
ip[0] = instr;
ip[1] = 0x81c3e008; /* JMPL #8(R15), R0 [RETURN] */
ip[2] = 0x01000000; /* SETHI #0, R0 [NOP] */
.
190,198c
* We can compile on the fly instead.
* Run one instruction and wait for it to complete or trap.
.
## diffname ss/fptrap.c 1992/0811
## diff -e /n/bootesdump/1992/0807/sys/src/9/slc/fptrap.c /n/bootesdump/1992/0811/sys/src/9/ss/fptrap.c
239d
236d
234d
219c
* upsetting the kernel. Shouldn't be necessary, but safety first.
.
## diffname ss/fptrap.c 1993/0319
## diff -e /n/bootesdump/1992/0811/sys/src/9/ss/fptrap.c /n/bootesdump/1993/0319/sys/src/9/ss/fptrap.c
170c
if(ed <= -(maxe-5)){ /* guess: underflow */
.
## diffname ss/fptrap.c 1993/0501 # deleted
## diff -e /n/bootesdump/1993/0319/sys/src/9/ss/fptrap.c /n/fornaxdump/1993/0501/sys/src/brazil/ss/fptrap.c
1,252d
|