Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/power/fptrap.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## 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

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].