Charles.Forsyth20060303644188019 years agoHistory
970 lines · 18.2 KB · C
RawDownload
/* * this doesn't attempt to implement Power architecture floating-point properties * that aren't visible in the Inferno environment. * all arithmetic is done in double precision. * the FP trap status isn't updated. */#include "u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"io.h" #include	"ureg.h" #include	"fpi.h" #define	REG(x) (*(long*)(((char*)em->ur)+roff[(x)]))#define	FR(x) (*(Internal*)em->fr[(x)&0x1F])#define	REGSP	1	/* stack pointer */ /* BUG: check fetch (not worthwhile in Inferno) */#define	getulong(a) (*(ulong*)(a)) enum {	CRLT = 1<<31,	CRGT = 1<<30,	CREQ = 1<<29,	CRSO = 1<<28,	CRFU = CRSO, 	CRFX = 1<<27,	CRFEX = 1<<26,	CRVX = 1<<25,	CROX = 1<<24,}; #define getCR(x,w) (((w)>>(28-(x*4)))&0xF)#define mkCR(x,v) (((v)&0xF)<<(28-(x*4))) #define simm(xx, ii)	xx = (short)(ii&0xFFFF);#define getairr(i)	rd = (i>>21)&0x1f; ra = (i>>16)&0x1f; simm(imm,i)#define getarrr(i)	rd = (i>>21)&0x1f; ra = (i>>16)&0x1f; rb = (i>>11)&0x1f;#define getop(i) ((i>>26)&0x3F)#define getxo(i) ((i>>1)&0x3FF) #define	FPS_FX	(1<<31)	/* exception summary (sticky) */#define	FPS_EX	(1<<30)	/* enabled exception summary */#define	FPS_VX	(1<<29)	/* invalid operation exception summary */#define	FPS_OX	(1<<28)	/* overflow exception OX (sticky) */#define	FPS_UX	(1<<27)	/* underflow exception UX (sticky) */#define	FPS_ZX	(1<<26)	/* zero divide exception ZX (sticky) */#define	FPS_XX	(1<<25)	/* inexact exception XX (sticky) */#define	FPS_VXSNAN (1<<24)	/* invalid operation exception for SNaN (sticky) */#define	FPS_VXISI	(1<<23)	/* invalid operation exception for ∞-∞ (sticky) */#define	FPS_VXIDI	(1<<22)	/* invalid operation exception for ∞/∞ (sticky) */#define	FPS_VXZDZ (1<<21)	/* invalid operation exception for 0/0 (sticky) */#define	FPS_VXIMZ	(1<<20)	/* invalid operation exception for ∞*0 (sticky) */#define	FPS_VXVC	(1<<19)	/* invalid operation exception for invalid compare (sticky) */#define	FPS_FR	(1<<18)	/* fraction rounded */#define	FPS_FI	(1<<17)	/* fraction inexact */#define	FPS_FPRF	(1<<16)	/* floating point result class */#define	FPS_FPCC	(0xF<<12)	/* <, >, =, unordered */#define	FPS_VXCVI	(1<<8)	/* enable exception for invalid integer convert (sticky) */#define	FPS_VE	(1<<7)	/* invalid operation exception enable */#define	FPS_OE	(1<<6)	/* enable overflow exceptions */#define	FPS_UE	(1<<5)	/* enable underflow */#define	FPS_ZE	(1<<4)	/* enable zero divide */#define	FPS_XE	(1<<3)	/* enable inexact exceptions */#define	FPS_RN	(3<<0)	/* rounding mode */ typedef struct Emreg Emreg; struct Emreg {	Ureg*	ur;	ulong	(*fr)[3];	FPenv*	ufp;	ulong	ir;	char*	name;}; int	fpemudebug = 0; #undef OFR#define	OFR(X)	((ulong)&((Ureg*)0)->X) static	int	roff[] = {	OFR(r0), OFR(r1), OFR(r2), OFR(r3),	OFR(r4), OFR(r5), OFR(r6), OFR(r7),	OFR(r8), OFR(r9), OFR(r10), OFR(r11),	OFR(r12), OFR(r13), OFR(r14), OFR(r15),	OFR(r16), OFR(r17), OFR(r18), OFR(r19),	OFR(r20), OFR(r21), OFR(r22), OFR(r23),	OFR(r24), OFR(r25), OFR(r26), OFR(r27),	OFR(r28), OFR(r29), OFR(r30), OFR(r31),}; /* * initial FP register values assumed by qc's code */static Internal fpreginit[] = {	/* s, e, l, h */	{0, 0x400, 0x00000000, 0x08000000},	/* F31=2.0 */	{0, 0x3FF, 0x00000000, 0x08000000},	/* F30=1.0 */	{0, 0x3FE, 0x00000000, 0x08000000},	/* F29=0.5 */	{0, 0x1, 0x00000000, 0x00000000}, /* F28=0.0 */	{0, 0x433, 0x00000000, 0x08000040},	/* F27=FREGCVI */}; static voidfadd(Emreg *em, Internal *d, int ra, int rb){	Internal a, b; 	a = FR(ra);	b = FR(rb);	(a.s == b.s? fpiadd: fpisub)(&b, &a, d);} static voidfsub(Emreg *em, Internal *d, int ra, int rb){	Internal a, b; 	a = FR(ra);	b = FR(rb);	b.s ^= 1;	(b.s == a.s? fpiadd: fpisub)(&b, &a, d);} static voidfmul(Emreg *em, Internal *d, int ra, int rb){	Internal a, b; 	a = FR(ra);	b = FR(rb);	fpimul(&b, &a, d);} static voidfdiv(Emreg *em, Internal *d, int ra, int rb){	Internal a, b; 	a = FR(ra);	b = FR(rb);	fpidiv(&b, &a, d);} static voidfmsub(Emreg *em, Internal *d, int ra, int rc, int rb){	Internal a, c, b, t; 	a = FR(ra);	c = FR(rc);	b = FR(rb);	fpimul(&a, &c, &t);	b.s ^= 1;	(b.s == t.s? fpiadd: fpisub)(&b, &t, d);} static voidfmadd(Emreg *em, Internal *d, int ra, int rc, int rb){	Internal a, c, b, t; 	a = FR(ra);	c = FR(rc);	b = FR(rb);	fpimul(&a, &c, &t);	(t.s == b.s? fpiadd: fpisub)(&b, &t, d);} static ulong	setfpscr(Emreg*);static void	setfpcc(Emreg*, int); static voidunimp(Emreg *em, ulong op){	char buf[60]; 	snprint(buf, sizeof(buf), "sys: fp: pc=%lux unimp fp 0x%.8lux", em->ur->pc, op);	if(fpemudebug)		print("FPE: %s\n", buf);	error(buf);	/* no return */} /* * floating load/store */ static voidfpeairr(Emreg *em, ulong ir, void **eap, int *rdp){	ulong ea;	long imm;	int ra, rd, upd; 	getairr(ir);	ea = imm;	upd = (ir&(1L<<26))!=0;	if(ra) {		ea += REG(ra);		if(upd){			if(ra == REGSP)				panic("fpemu: r1 update");	/* can't do it because we're running on the same stack */			REG(ra) = ea;		}	} else {		if(upd)			unimp(em, ir);	}	*rdp = rd;	*eap = (void*)ea;	if(fpemudebug)		print("%8.8lux %s\tf%d,%ld(r%d) ea=%lux upd=%d\n", em->ur->pc, em->name, rd, imm, ra, ea, upd);} static voidfpearrr(Emreg *em, ulong ir, int upd, void **eap, int *rdp){	ulong ea;	int ra, rb, rd; 	getarrr(ir);	ea = REG(rb);	if(ra){		ea += REG(ra);		if(upd){			if(ra == REGSP)				panic("fpemu: r1 update");			REG(ra) = ea;		}		if(fpemudebug)			print("%8.8lux %s\tf%d,(r%d+r%d) ea=%lux upd=%d\n", em->ur->pc, em->name, rd, ra, rb, ea, upd);	} else {		if(upd)			unimp(em, ir);		if(fpemudebug)			print("%8.8lux %s\tf%d,(r%d) ea=%lux\n", em->ur->pc, em->name, rd, rb, ea);	}	*eap = (void*)ea;	*rdp = rd;} static voidlfs(Emreg *em, ulong ir){	void *ea;	int rd; 	em->name = "lfs";	fpeairr(em, ir, &ea, &rd);	fpis2i(&FR(rd), (void*)ea);} static voidlfsx(Emreg *em, ulong ir){	void *ea;	int rd; 	em->name = "lfsx";	fpearrr(em, ir, ((ir>>1)&0x3FF)==567, &ea, &rd);	fpis2i(&FR(rd), (void*)ea);} static voidlfd(Emreg *em, ulong ir){	void *ea;	int rd; 	em->name = "lfd";	fpeairr(em, ir, &ea, &rd);	fpid2i(&FR(rd), (void*)ea);} static voidlfdx(Emreg *em, ulong ir){	void *ea;	int rd; 	em->name = "lfdx";	fpearrr(em, ir, ((ir>>1)&0x3FF)==631, &ea, &rd);	fpid2i(&FR(rd), (void*)ea);} static voidstfs(Emreg *em, ulong ir){	void *ea;	int rd;	Internal tmp; 	em->name = "stfs";	fpeairr(em, ir, &ea, &rd);	tmp = FR(rd);	fpii2s(ea, &tmp);} static voidstfsx(Emreg *em, ulong ir){	void *ea;	int rd;	Internal tmp; 	em->name = "stfsx";	fpearrr(em, ir, getxo(ir)==695, &ea, &rd);	tmp = FR(rd);	fpii2s(ea, &tmp);} static voidstfd(Emreg *em, ulong ir){	void *ea;	int rd;	Internal tmp; 	em->name = "stfd";	fpeairr(em, ir, &ea, &rd);	tmp = FR(rd);	fpii2d(ea, &tmp);} static voidstfdx(Emreg *em, ulong ir){	void *ea;	int rd;	Internal tmp; 	em->name = "stfdx";	fpearrr(em, ir, ((ir>>1)&0x3FF)==759, &ea, &rd);	tmp = FR(rd);	fpii2d(ea, &tmp);} static voidmcrfs(Emreg *em, ulong ir){	int rd, ra, rb;	static ulong fpscr0[] ={		FPS_FX|FPS_OX,		FPS_UX|FPS_ZX|FPS_XX|FPS_VXSNAN,		FPS_VXISI|FPS_VXIDI|FPS_VXZDZ|FPS_VXIMZ,		FPS_VXVC,		0,		FPS_VXCVI,	}; 	getarrr(ir);	if(rb || ra&3 || rd&3)		unimp(em, ir);	ra >>= 2;	rd >>= 2;	em->ur->cr = (em->ur->cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, em->ufp->fpscr));	em->ufp->fpscr &= ~fpscr0[ra];	if(fpemudebug)		print("%8.8lux mcrfs\tcrf%d,crf%d\n", em->ur->pc, rd, ra);} static voidmffs(Emreg *em, ulong ir){	int rd, ra, rb;	Double dw; 	getarrr(ir);	if(ra || rb)		unimp(em, ir);	dw.h = 0;	dw.l = ((uvlong)0xFFF8000L<<16)|em->ufp->fpscr;	fpid2i(&FR(rd), &dw);	/* it's anyone's guess how CR1 should be set when ir&1 */	em->ur->cr &= ~mkCR(1, 0xE);	/* leave SO, reset others */	if(fpemudebug)		print("%8.8lux mffs%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd);} static voidmtfsb1(Emreg *em, ulong ir){	int rd, ra, rb; 	getarrr(ir);	if(ra || rb)		unimp(em, ir);	em->ufp->fpscr |= (1L << (31-rd));	/* BUG: should set summary bits */	if(ir & 1)		em->ur->cr &= ~mkCR(1, 0xE);	/* BUG: manual unclear: leave SO, reset others? */	if(fpemudebug)		print("%8.8lux mtfsb1%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd);} static voidmtfsb0(Emreg *em, ulong ir){	int rd, ra, rb; 	getarrr(ir);	if(ra || rb)		unimp(em, ir);	em->ufp->fpscr &= ~(1L << (31-rd));	if(ir & 1)		em->ur->cr &= ~mkCR(1, 0xE);		/* BUG: manual unclear: leave SO, reset others? */	if(fpemudebug)		print("%8.8lux mtfsb0%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd);} static voidmtfsf(Emreg *em, ulong ir){	int fm, rb, i;	ulong v;	Internal b;	Double db; 	if(ir & ((1L << 25)|(1L << 16)))		unimp(em, ir);	rb = (ir >> 11) & 0x1F;	fm = (ir >> 17) & 0xFF;	b = FR(rb);	fpii2d(&db, &b);	/* reconstruct hi/lo format to recover low word */	v = db.l;	for(i=0; i<8; i++)		if(fm & (1 << (7-i)))			em->ufp->fpscr = (em->ufp->fpscr & ~mkCR(i, 0xF)) | mkCR(i, getCR(i, v));	/* BUG: should set FEX and VX `according to the usual rule' */	if(ir & 1)		em->ur->cr &= ~mkCR(1, 0xE);		/* BUG: manual unclear: leave SO, reset others? */	if(fpemudebug)		print("%8.8lux mtfsf%s\t#%.2x,fr%d\n", em->ur->pc, ir&1?".":"", fm, rb);} static voidmtfsfi(Emreg *em, ulong ir){	int imm, rd; 	if(ir & ((0x7F << 16)|(1L << 11)))		unimp(em, ir);	rd = (ir >> 23) & 0xF;	imm = (ir >> 12) & 0xF;	em->ufp->fpscr = (em->ufp->fpscr & ~mkCR(rd, 0xF)) | mkCR(rd, imm);	/* BUG: should set FEX and VX `according to the usual rule' */	if(ir & 1)		em->ur->cr &= ~mkCR(1, 0xE);		/* BUG: manual unclear: leave SO, reset others? */	if(fpemudebug)		print("%8.8lux mtfsfi%s\tcrf%d,#%x\n", em->ur->pc, ir&1?".":"", rd, imm);} static voidfcmp(Emreg *em, ulong ir){	int fc, rd, ra, rb, sig, i; 	getarrr(ir);	if(rd & 3)		unimp(em, ir);	rd >>= 2;	sig = 0;	switch(getxo(ir)) {	default:		unimp(em, ir);	case 32:		if(fpemudebug)			print("%8.8lux fcmpo\tcr%d,f%d,f%d\n", em->ur->pc, rd, ra, rb);		sig = 1;		break;	case 0:		if(fpemudebug)			print("%8.8lux fcmpu\tcr%d,f%d,f%d\n", em->ur->pc, rd, ra, rb);		break;	}	if(IsWeird(&FR(ra)) || IsWeird(&FR(rb))) {		if(sig){			;	/* BUG: should trap if not masked ... */		}		fc = CRFU;	} else {		i = fpicmp(&FR(ra), &FR(rb));		if(i > 0)			fc = CRGT;		else if(i == 0)			fc = CREQ;		else			fc = CRLT;	}	fc >>= 28;	em->ur->cr = (em->ur->cr & ~mkCR(rd,~0)) | mkCR(rd, fc);	em->ufp->fpscr = (em->ufp->fpscr & ~0xF800) | (fc<<11);	/* BUG: update FX, VXSNAN, VXVC */

Lines 1–500 of 970.