## diffname power/fptrap.c 1992/0802
## diff -e /dev/null /n/bootesdump/1992/0802/sys/src/9/power/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"
typedef struct FPinstr FPinstr;
struct FPinstr
{
ulong op;
ulong load;
ulong store;
ulong branch;
ulong fmt;
ulong fs;
ulong fd;
ulong ft;
ulong cft;
};
enum /* op */
{
ABS = 5,
ADD = 0,
CVTD = 65,
CVTS = 64,
CVTW = 68,
DIV = 3,
MOV = 6,
MUL = 2,
NEG = 7,
SUB = 1,
};
static int fpunimp(Ureg*, ulong, ulong);
static ulong branch(Ureg*, ulong);
int
fptrap(Ureg *ur, ulong fcr31)
{
ulong iw, x, npc;
int i, ret;
savefpregs(&u->fpsave);
if(ur->cause & (1<<31))
iw = *(ulong*)(ur->pc+4);
else
iw = *(ulong*)ur->pc;
ret = 0;
x = fcr31>>12;
fcr31 &= ~(0x3F<<12);
for(i=0; i<6; i++,x>>=1)
if(x & 1)
switch(i){
case 0: /* inexact */
pprint("inexact\n");
return 0;
case 1: /* underflow */
pprint("underflow\n");
return 0;
case 2: /* overflow */
pprint("overflow\n");
return 0;
case 3: /* division by zero */
return 0;
case 4: /* invalid operation */
pprint("invalid op\n");
return 0;
case 5: /* unimplemented operation */
ret = fpunimp(ur, fcr31, iw);
}
if(ret){
if(ur->cause & (1<<31)){
npc = branch(ur, fcr31);
if(npc)
ur->pc = npc;
else
return 0;
}else
ur->pc += 4;
restfpregs(&u->fpsave, fcr31);
}
return ret;
}
static int
fpdas(ulong iw, FPinstr *fp)
{
memset(fp, ~0, sizeof(*fp));
if((iw>>25) == 0x23){
fp->op = iw & ((1<<5)-1);
fp->fmt = (iw>>21) & ((1<<4)-1);
fp->ft = (iw>>16) & ((1<<5)-1);
fp->fs = (iw>>11) & ((1<<5)-1);
fp->fd = (iw>>6) & ((1<<5)-1);
fp->cft = (iw>>21) & ((1<<5)-1);
return 1;
}
return 0;
}
static void
unpack(FPsave *f, int fmt, int reg, int *sign, int *exp)
{
*sign = 1;
if(f->fpreg[reg] & 0x80000000)
*sign = -1;
switch(fmt){
case 0:
*exp = ((f->fpreg[reg]>>23)&0xFF) - ((1<<7)-2);
break;
case 1:
if(reg & 1){
pprint("unaligned double fp register\n");
reg &= ~1;
}
pprint("%lux %lux\n", f->fpreg[reg], f->fpreg[reg+1]);
*exp = ((f->fpreg[reg]>>20)&0x7FF) - ((1<<10)-2);
break;
}
}
static void
zeroreg(FPsave *f, int fmt, int reg, int sign)
{
int size;
size = 0;
switch(fmt){
case 0:
size = 4;
break;
case 1:
if(reg & 1)
reg &= ~1;
size = 8;
break;
}
memset(&f->fpreg[reg], 0, size);
if(sign < 0)
f->fpreg[reg] |= 0x80000000;
}
static int
fpunimp(Ureg *ur, ulong fcr31, ulong iw)
{
FPinstr instr;
int ss, st, sd;
int es, et, ed;
int maxe, maxm;
pprint("fpunimp %lux %lux\n", iw, iw>>25);
if(!fpdas(iw, &instr))
return 0;
pprint("%d\n", instr.op);
if(instr.op == ~0)
return 0;
unpack(&u->fpsave, instr.fmt, instr.fs, &ss, &es);
unpack(&u->fpsave, instr.fmt, instr.ft, &st, &et);
ed = 0;
maxe = 0;
maxm = 0;
switch(instr.fmt){
case 0:
maxe = 1<<7;
maxm = 24;
break;
case 1:
maxe = 1<<10;
maxm = 53;
break;
}
switch(instr.op){
case SUB:
st = -st;
case ADD:
if(es<-(maxe-maxm) && et<-(maxe-maxm))
ed = -maxe;
if(es > et)
sd = es;
else
sd = et;
break;
case DIV:
et = -et;
case MUL:
sd = 1;
if(ss != st)
sd = -1;
ed = es + et;
break;
default:
pprint("unknown unimplemented fp op\n");
return 0;
}
if(ed <= -(maxe-4)){ /* guess: underflow */
pprint("guess underflow\n");
zeroreg(&u->fpsave, instr.fmt, instr.fd, sd);
return 1;
}
return 0;
}
static ulong*
reg(Ureg *ur, int regno)
{
/* regs go from R31 down in ureg, R29 is missing */
if(regno == 31)
return &ur->r31;
if(regno == 30)
return &ur->r30;
if(regno == 29)
return &ur->sp;
return (&ur->r28) + (28-regno);
}
static ulong
branch(Ureg *ur, ulong fcr31)
{
ulong iw, npc, rs, rt, rd, offset;
iw = *(ulong*)ur->pc;
rs = (iw>>21) & 0x1F;
if(rs)
rs = *reg(ur, rs);
rt = (iw>>16) & 0x1F;
if(rt)
rt = *reg(ur, rt);
offset = iw & ((1<<16)-1);
if(offset & (1<<15)) /* sign extend */
offset |= ~((1<<16)-1);
offset <<= 2;
/*
* Integer unit jumps first
*/
switch(iw>>26){
case 0: /* SPECIAL: JR or JALR */
switch(iw&0x3F){
case 0x09: /* JALR */
rd = (iw>>11) & 0x1F;
if(rd)
*reg(ur, rd) = ur->pc+8;
/* fall through */
case 0x08: /* JR */
return rs;
default:
return 0;
}
case 1: /* BCOND */
switch((iw>>16) & 0x1F){
case 0x10: /* BLTZAL */
ur->r31 = ur->pc + 8;
/* fall through */
case 0x00: /* BLTZ */
if((long)rs < 0)
return ur->pc+4 + offset;
return ur->pc + 8;
case 0x11: /* BGEZAL */
ur->r31 = ur->pc + 8;
/* fall through */
case 0x01: /* BGEZ */
if((long)rs >= 0)
return ur->pc+4 + offset;
return ur->pc + 8;
default:
return 0;
}
case 3: /* JAL */
ur->r31 = ur->pc+8;
/* fall through */
case 2: /* JMP */
npc = iw & ((1<<26)-1);
npc <<= 2;
return npc | (ur->pc&0xF0000000);
case 4: /* BEQ */
if(rs == rt)
return ur->pc+4 + offset;
return ur->pc + 8;
case 5: /* BNE */
if(rs != rt)
return ur->pc+4 + offset;
return ur->pc + 8;
case 6: /* BLEZ */
if((long)rs <= 0)
return ur->pc+4 + offset;
return ur->pc + 8;
case 7: /* BGTZ */
if((long)rs > 0)
return ur->pc+4 + offset;
return ur->pc + 8;
}
/*
* Floating point unit jumps
*/
if((iw>>26) == 0x11) /* COP1 */
switch((iw>>16) & 0x3C1){
case 0x101: /* BCT */
case 0x181: /* BCT */
if(fcr31 & (1<<23))
return ur->pc+4 + offset;
return ur->pc + 8;
case 0x100: /* BCF */
case 0x180: /* BCF */
if(!(fcr31 & (1<<23)))
return ur->pc+4 + offset;
return ur->pc + 8;
}
pprint("fptrap: can't do jump %lux\n", iw);
return 0;
}
.
## diffname power/fptrap.c 1992/0803
## diff -e /n/bootesdump/1992/0802/sys/src/9/power/fptrap.c /n/bootesdump/1992/0803/sys/src/9/power/fptrap.c
314d
312c
/* shouldn't get here */
.
201,202c
zeroreg(&u->fpsave, fmt, fd, sd);
.
197c
/* shouldn't get here */
.
195a
case CVTS:
if(fmt != 1)
return 0;
fmt = 0; /* convert FROM double TO single */
maxe = 1<<7;
ed = es;
sd = ss;
break;
.
176c
switch(op){
case ABS:
u->fpsave.fpreg[fd] &= ~0x80000000;
return 1;
case NEG:
u->fpsave.fpreg[fd] ^= 0x80000000;
return 1;
.
166c
switch(fmt){
.
158,162c
op = iw & ((1<<6)-1);
fmt = (iw>>21) & ((1<<4)-1);
ft = (iw>>16) & ((1<<5)-1);
fs = (iw>>11) & ((1<<5)-1);
fd = (iw>>6) & ((1<<5)-1);
unpack(&u->fpsave, fmt, fs, &ss, &es);
unpack(&u->fpsave, fmt, ft, &st, &et);
.
155,156c
if((iw>>25) != 0x23)
.
153a
ulong op, fmt, ft, fs, fd;
.
150d
148c
fpunimp(ulong iw)
.
119,120d
116,117c
if(reg & 1) /* shouldn't happen */
.
89,104d
86c
return 1;
.
52,75c
if(fpunimp(iw)){
.
47a
if((fcr31&(1<<17)) == 0)
return 0;
.
44,45c
ulong iw, npc;
.
38c
static int fpunimp(ulong);
.
28,30c
CVTD = 33,
CVTS = 32,
CVTW = 36,
.
10,23d
## diffname power/fptrap.c 1992/0806
## diff -e /n/bootesdump/1992/0803/sys/src/9/power/fptrap.c /n/bootesdump/1992/0806/sys/src/9/power/fptrap.c
48c
u->fpsave.fpstatus = fcr31 & ~(1<<17);
.
32a
u->p->fpstate = FPinactive; /* will get turned on again in trap() */
.
## diffname power/fptrap.c 1992/0822
## diff -e /n/bootesdump/1992/0806/sys/src/9/power/fptrap.c /n/bootesdump/1992/0822/sys/src/9/power/fptrap.c
161,162c
default: /* probably a compare */
.
51c
return 0;
.
49a
return 1;
.
## diffname power/fptrap.c 1992/1128
## diff -e /n/bootesdump/1992/0822/sys/src/9/power/fptrap.c /n/bootesdump/1992/1128/sys/src/9/power/fptrap.c
32,33d
## diffname power/fptrap.c 1992/1129
## diff -e /n/bootesdump/1992/1128/sys/src/9/power/fptrap.c /n/bootesdump/1992/1129/sys/src/9/power/fptrap.c
164a
/* Set underflow exception and sticky */
u->fpsave.fpstatus |= (1<<3)|(1<<13);
.
58a
.
50c
else
ur->pc += 4;
u->fpsave.fpstatus = u->fpsave.fpstatus & ~(1<<17);
.
38,48c
if(fpunimp(iw) == 0)
return;
if(ur->cause & (1<<31)){
npc = branch(ur, u->fpsave.fpstatus);
if(npc == 0)
return;
ur->pc = npc;
.
32,33c
if((u->fpsave.fpstatus&(1<<17)) == 0)
return;
.
27,28c
void
fptrap(Ureg *ur)
.
## diffname power/fptrap.c 1993/0107
## diff -e /n/bootesdump/1992/1129/sys/src/9/power/fptrap.c /n/bootesdump/1993/0107/sys/src/9/power/fptrap.c
34a
print("fpt: %d %s %lux\n", u->p->pid, u->p->text, u->fpsave.fpstatus);
.
## diffname power/fptrap.c 1993/0319
## diff -e /n/bootesdump/1993/0107/sys/src/9/power/fptrap.c /n/bootesdump/1993/0319/sys/src/9/power/fptrap.c
168c
if(ed <= -(maxe-5)){ /* guess: underflow */
.
## diffname power/fptrap.c 1993/0403
## diff -e /n/bootesdump/1993/0319/sys/src/9/power/fptrap.c /n/bootesdump/1993/0403/sys/src/9/power/fptrap.c
195d
193c
ulong npc, rs, rt, rd, offset;
.
191c
branch(Ureg *ur, ulong iw, ulong fcr31)
.
54c
u->fpsave.fpstatus &= ~(1<<17);
.
46c
npc = branch(ur, iw_4, u->fpsave.fpstatus);
.
39,40c
}
.
37c
if(tlbp(ur->pc) == 0)
panic("not in tlb %lux\n", ur->pc);
iw = *(ulong*)ur->pc;
iw_4 = iw;
if(ur->cause & (1<<31)){
if(tlbp(ur->pc+4) == 0)
panic("not in tlb %lux\n", ur->pc+4);
.
35c
print("fpt: %d %s %lux %lux\n", u->p->pid, u->p->text, u->fpsave.fpstatus, ur->pc);
.
30c
ulong iw, iw_4, npc;
.
25c
static ulong branch(Ureg*, ulong, ulong);
.
## diffname power/fptrap.c 1993/0416
## diff -e /n/bootesdump/1993/0403/sys/src/9/power/fptrap.c /n/bootesdump/1993/0416/sys/src/9/power/fptrap.c
34a
if((counter&0xff) == 0)
.
30a
static int counter;
.
## diffname power/fptrap.c 1993/0417
## diff -e /n/bootesdump/1993/0416/sys/src/9/power/fptrap.c /n/bootesdump/1993/0417/sys/src/9/power/fptrap.c
37d
## diffname power/fptrap.c 1993/0501
## diff -e /n/bootesdump/1993/0417/sys/src/9/power/fptrap.c /n/fornaxdump/1993/0501/sys/src/brazil/power/fptrap.c
200a
iw = *(ulong*)ur->pc;
.
199c
ulong iw, npc, rs, rt, rd, offset;
.
197c
branch(Ureg *ur, ulong fcr31)
.
177c
up->fpsave.fpstatus |= (1<<3)|(1<<13);
.
174,175c
if(ed <= -(maxe-4)){ /* guess: underflow */
zeroreg(&up->fpsave, fmt, fd, sd);
.
139c
up->fpsave.fpreg[fd] ^= 0x80000000;
.
135c
up->fpsave.fpreg[fd] &= ~0x80000000;
.
118,119c
unpack(&up->fpsave, fmt, fs, &ss, &es);
unpack(&up->fpsave, fmt, ft, &st, &et);
.
60c
up->fpsave.fpstatus = up->fpsave.fpstatus & ~(1<<17);
.
52c
npc = branch(ur, up->fpsave.fpstatus);
.
46c
else
iw = *(ulong*)ur->pc;
.
38,44c
if(ur->cause & (1<<31))
.
36c
print("fpt: %d %s %lux\n", up->pid, up->text, up->fpsave.fpstatus);
.
33c
if((up->fpsave.fpstatus&(1<<17)) == 0)
.
30,31c
ulong iw, npc;
.
25c
static ulong branch(Ureg*, ulong);
.
## diffname power/fptrap.c 1997/0327 # deleted
## diff -e /n/fornaxdump/1993/0501/sys/src/brazil/power/fptrap.c /n/emeliedump/1997/0327/sys/src/brazil/power/fptrap.c
1,283d
|