xref: /plan9/sys/src/9/omap/fpiarm.c (revision d11907f1310fb3aff37a1c3d604436d4028fd86f)
17bb09086SDavid du Colombier /*
27bb09086SDavid du Colombier  * this doesn't attempt to implement ARM floating-point properties
37bb09086SDavid du Colombier  * that aren't visible in the Inferno environment.
47bb09086SDavid du Colombier  * all arithmetic is done in double precision.
57bb09086SDavid du Colombier  * the FP trap status isn't updated.
67bb09086SDavid du Colombier  */
77bb09086SDavid du Colombier #include	"u.h"
87bb09086SDavid du Colombier #include	"../port/lib.h"
97bb09086SDavid du Colombier #include	"mem.h"
107bb09086SDavid du Colombier #include	"dat.h"
117bb09086SDavid du Colombier #include	"fns.h"
127bb09086SDavid du Colombier 
137bb09086SDavid du Colombier #include	"ureg.h"
147bb09086SDavid du Colombier 
157bb09086SDavid du Colombier #include	"arm.h"
16*d11907f1SDavid du Colombier #include	"../port/fpi.h"
177bb09086SDavid du Colombier 
187bb09086SDavid du Colombier /* undef this if correct kernel r13 isn't in Ureg;
197bb09086SDavid du Colombier  * check calculation in fpiarm below
207bb09086SDavid du Colombier  */
217bb09086SDavid du Colombier 
227bb09086SDavid du Colombier 
237bb09086SDavid du Colombier #define	REG(ur, x) (*(long*)(((char*)(ur))+roff[(x)]))
247bb09086SDavid du Colombier #define	FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&7])
257bb09086SDavid du Colombier 
267bb09086SDavid du Colombier typedef struct FP2 FP2;
277bb09086SDavid du Colombier typedef struct FP1 FP1;
287bb09086SDavid du Colombier 
297bb09086SDavid du Colombier struct FP2 {
307bb09086SDavid du Colombier 	char*	name;
317bb09086SDavid du Colombier 	void	(*f)(Internal, Internal, Internal*);
327bb09086SDavid du Colombier };
337bb09086SDavid du Colombier 
347bb09086SDavid du Colombier struct FP1 {
357bb09086SDavid du Colombier 	char*	name;
367bb09086SDavid du Colombier 	void	(*f)(Internal*, Internal*);
377bb09086SDavid du Colombier };
387bb09086SDavid du Colombier 
397bb09086SDavid du Colombier enum {
407bb09086SDavid du Colombier 	N = 1<<31,
417bb09086SDavid du Colombier 	Z = 1<<30,
427bb09086SDavid du Colombier 	C = 1<<29,
437bb09086SDavid du Colombier 	V = 1<<28,
447bb09086SDavid du Colombier 	REGPC = 15,
457bb09086SDavid du Colombier };
467bb09086SDavid du Colombier 
477bb09086SDavid du Colombier enum {
487bb09086SDavid du Colombier 	fpemudebug = 0,
497bb09086SDavid du Colombier };
507bb09086SDavid du Colombier 
517bb09086SDavid du Colombier #undef OFR
527bb09086SDavid du Colombier #define	OFR(X)	((ulong)&((Ureg*)0)->X)
537bb09086SDavid du Colombier 
547bb09086SDavid du Colombier static	int	roff[] = {
557bb09086SDavid du Colombier 	OFR(r0), OFR(r1), OFR(r2), OFR(r3),
567bb09086SDavid du Colombier 	OFR(r4), OFR(r5), OFR(r6), OFR(r7),
577bb09086SDavid du Colombier 	OFR(r8), OFR(r9), OFR(r10), OFR(r11),
587bb09086SDavid du Colombier 	OFR(r12), OFR(r13), OFR(r14), OFR(pc),
597bb09086SDavid du Colombier };
607bb09086SDavid du Colombier 
617bb09086SDavid du Colombier static Internal fpconst[8] = {	/* indexed by op&7 */
627bb09086SDavid du Colombier 	/* s, e, l, h */
637bb09086SDavid du Colombier 	{0, 0x1, 0x00000000, 0x00000000}, /* 0.0 */
647bb09086SDavid du Colombier 	{0, 0x3FF, 0x00000000, 0x08000000},	/* 1.0 */
657bb09086SDavid du Colombier 	{0, 0x400, 0x00000000, 0x08000000},	/* 2.0 */
667bb09086SDavid du Colombier 	{0, 0x400, 0x00000000, 0x0C000000},	/* 3.0 */
677bb09086SDavid du Colombier 	{0, 0x401, 0x00000000, 0x08000000},	/* 4.0 */
687bb09086SDavid du Colombier 	{0, 0x401, 0x00000000, 0x0A000000},	/* 5.0 */
697bb09086SDavid du Colombier 	{0, 0x3FE, 0x00000000, 0x08000000},	/* 0.5 */
707bb09086SDavid du Colombier 	{0, 0x402, 0x00000000, 0x0A000000},	/* 10.0 */
717bb09086SDavid du Colombier };
727bb09086SDavid du Colombier 
737bb09086SDavid du Colombier /*
747bb09086SDavid du Colombier  * arm binary operations
757bb09086SDavid du Colombier  */
767bb09086SDavid du Colombier 
777bb09086SDavid du Colombier static void
fadd(Internal m,Internal n,Internal * d)787bb09086SDavid du Colombier fadd(Internal m, Internal n, Internal *d)
797bb09086SDavid du Colombier {
807bb09086SDavid du Colombier 	(m.s == n.s? fpiadd: fpisub)(&m, &n, d);
817bb09086SDavid du Colombier }
827bb09086SDavid du Colombier 
837bb09086SDavid du Colombier static void
fsub(Internal m,Internal n,Internal * d)847bb09086SDavid du Colombier fsub(Internal m, Internal n, Internal *d)
857bb09086SDavid du Colombier {
867bb09086SDavid du Colombier 	m.s ^= 1;
877bb09086SDavid du Colombier 	(m.s == n.s? fpiadd: fpisub)(&m, &n, d);
887bb09086SDavid du Colombier }
897bb09086SDavid du Colombier 
907bb09086SDavid du Colombier static void
fsubr(Internal m,Internal n,Internal * d)917bb09086SDavid du Colombier fsubr(Internal m, Internal n, Internal *d)
927bb09086SDavid du Colombier {
937bb09086SDavid du Colombier 	n.s ^= 1;
947bb09086SDavid du Colombier 	(n.s == m.s? fpiadd: fpisub)(&n, &m, d);
957bb09086SDavid du Colombier }
967bb09086SDavid du Colombier 
977bb09086SDavid du Colombier static void
fmul(Internal m,Internal n,Internal * d)987bb09086SDavid du Colombier fmul(Internal m, Internal n, Internal *d)
997bb09086SDavid du Colombier {
1007bb09086SDavid du Colombier 	fpimul(&m, &n, d);
1017bb09086SDavid du Colombier }
1027bb09086SDavid du Colombier 
1037bb09086SDavid du Colombier static void
fdiv(Internal m,Internal n,Internal * d)1047bb09086SDavid du Colombier fdiv(Internal m, Internal n, Internal *d)
1057bb09086SDavid du Colombier {
1067bb09086SDavid du Colombier 	fpidiv(&m, &n, d);
1077bb09086SDavid du Colombier }
1087bb09086SDavid du Colombier 
1097bb09086SDavid du Colombier static void
fdivr(Internal m,Internal n,Internal * d)1107bb09086SDavid du Colombier fdivr(Internal m, Internal n, Internal *d)
1117bb09086SDavid du Colombier {
1127bb09086SDavid du Colombier 	fpidiv(&n, &m, d);
1137bb09086SDavid du Colombier }
1147bb09086SDavid du Colombier 
1157bb09086SDavid du Colombier /*
1167bb09086SDavid du Colombier  * arm unary operations
1177bb09086SDavid du Colombier  */
1187bb09086SDavid du Colombier 
1197bb09086SDavid du Colombier static void
fmov(Internal * m,Internal * d)1207bb09086SDavid du Colombier fmov(Internal *m, Internal *d)
1217bb09086SDavid du Colombier {
1227bb09086SDavid du Colombier 	*d = *m;
1237bb09086SDavid du Colombier }
1247bb09086SDavid du Colombier 
1257bb09086SDavid du Colombier static void
fmovn(Internal * m,Internal * d)1267bb09086SDavid du Colombier fmovn(Internal *m, Internal *d)
1277bb09086SDavid du Colombier {
1287bb09086SDavid du Colombier 	*d = *m;
1297bb09086SDavid du Colombier 	d->s ^= 1;
1307bb09086SDavid du Colombier }
1317bb09086SDavid du Colombier 
1327bb09086SDavid du Colombier static void
fabsf(Internal * m,Internal * d)1337bb09086SDavid du Colombier fabsf(Internal *m, Internal *d)
1347bb09086SDavid du Colombier {
1357bb09086SDavid du Colombier 	*d = *m;
1367bb09086SDavid du Colombier 	d->s = 0;
1377bb09086SDavid du Colombier }
1387bb09086SDavid du Colombier 
1397bb09086SDavid du Colombier static void
frnd(Internal * m,Internal * d)1407bb09086SDavid du Colombier frnd(Internal *m, Internal *d)
1417bb09086SDavid du Colombier {
1427bb09086SDavid du Colombier 	short e;
1437bb09086SDavid du Colombier 
1447bb09086SDavid du Colombier 	(m->s? fsub: fadd)(fpconst[6], *m, d);
1457bb09086SDavid du Colombier 	if(IsWeird(d))
1467bb09086SDavid du Colombier 		return;
1477bb09086SDavid du Colombier 	fpiround(d);
1487bb09086SDavid du Colombier 	e = (d->e - ExpBias) + 1;
1497bb09086SDavid du Colombier 	if(e <= 0)
1507bb09086SDavid du Colombier 		SetZero(d);
1517bb09086SDavid du Colombier 	else if(e > FractBits){
1527bb09086SDavid du Colombier 		if(e < 2*FractBits)
1537bb09086SDavid du Colombier 			d->l &= ~((1<<(2*FractBits - e))-1);
1547bb09086SDavid du Colombier 	}else{
1557bb09086SDavid du Colombier 		d->l = 0;
1567bb09086SDavid du Colombier 		if(e < FractBits)
1577bb09086SDavid du Colombier 			d->h &= ~((1<<(FractBits-e))-1);
1587bb09086SDavid du Colombier 	}
1597bb09086SDavid du Colombier }
1607bb09086SDavid du Colombier 
1617bb09086SDavid du Colombier static	FP1	optab1[16] = {	/* Fd := OP Fm */
1627bb09086SDavid du Colombier [0]	{"MOVF",	fmov},
1637bb09086SDavid du Colombier [1]	{"NEGF",	fmovn},
1647bb09086SDavid du Colombier [2]	{"ABSF",	fabsf},
1657bb09086SDavid du Colombier [3]	{"RNDF",	frnd},
1667bb09086SDavid du Colombier [4]	{"SQTF",	/*fsqt*/0},
1677bb09086SDavid du Colombier /* LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN all `deprecated' */
1687bb09086SDavid du Colombier /* URD and NRM aren't implemented */
1697bb09086SDavid du Colombier };
1707bb09086SDavid du Colombier 
1717bb09086SDavid du Colombier static	FP2	optab2[16] = {	/* Fd := Fn OP Fm */
1727bb09086SDavid du Colombier [0]	{"ADDF",	fadd},
1737bb09086SDavid du Colombier [1]	{"MULF",	fmul},
1747bb09086SDavid du Colombier [2]	{"SUBF",	fsub},
1757bb09086SDavid du Colombier [3]	{"RSUBF",	fsubr},
1767bb09086SDavid du Colombier [4]	{"DIVF",	fdiv},
1777bb09086SDavid du Colombier [5]	{"RDIVF",	fdivr},
1787bb09086SDavid du Colombier /* POW, RPW deprecated */
1797bb09086SDavid du Colombier [8]	{"REMF",	/*frem*/0},
1807bb09086SDavid du Colombier [9]	{"FMF",	fmul},	/* fast multiply */
1817bb09086SDavid du Colombier [10]	{"FDV",	fdiv},	/* fast divide */
1827bb09086SDavid du Colombier [11]	{"FRD",	fdivr},	/* fast reverse divide */
1837bb09086SDavid du Colombier /* POL deprecated */
1847bb09086SDavid du Colombier };
1857bb09086SDavid du Colombier 
1867bb09086SDavid du Colombier static ulong
fcmp(Internal * n,Internal * m)1877bb09086SDavid du Colombier fcmp(Internal *n, Internal *m)
1887bb09086SDavid du Colombier {
1897bb09086SDavid du Colombier 	int i;
1907bb09086SDavid du Colombier 	Internal rm, rn;
1917bb09086SDavid du Colombier 
1927bb09086SDavid du Colombier 	if(IsWeird(m) || IsWeird(n)){
1937bb09086SDavid du Colombier 		/* BUG: should trap if not masked */
1947bb09086SDavid du Colombier 		return V|C;
1957bb09086SDavid du Colombier 	}
1967bb09086SDavid du Colombier 	rn = *n;
1977bb09086SDavid du Colombier 	rm = *m;
1987bb09086SDavid du Colombier 	fpiround(&rn);
1997bb09086SDavid du Colombier 	fpiround(&rm);
2007bb09086SDavid du Colombier 	i = fpicmp(&rn, &rm);
2017bb09086SDavid du Colombier 	if(i > 0)
2027bb09086SDavid du Colombier 		return C;
2037bb09086SDavid du Colombier 	else if(i == 0)
2047bb09086SDavid du Colombier 		return C|Z;
2057bb09086SDavid du Colombier 	else
2067bb09086SDavid du Colombier 		return N;
2077bb09086SDavid du Colombier }
2087bb09086SDavid du Colombier 
2097bb09086SDavid du Colombier static void
fld(void (* f)(Internal *,void *),int d,ulong ea,int n,FPsave * ufp)2107bb09086SDavid du Colombier fld(void (*f)(Internal*, void*), int d, ulong ea, int n, FPsave *ufp)
2117bb09086SDavid du Colombier {
2127bb09086SDavid du Colombier 	void *mem;
2137bb09086SDavid du Colombier 
2147bb09086SDavid du Colombier 	mem = (void*)ea;
2157bb09086SDavid du Colombier 	(*f)(&FR(ufp, d), mem);
2167bb09086SDavid du Colombier 	if(fpemudebug)
2177bb09086SDavid du Colombier 		print("MOV%c #%lux, F%d\n", n==8? 'D': 'F', ea, d);
2187bb09086SDavid du Colombier }
2197bb09086SDavid du Colombier 
2207bb09086SDavid du Colombier static void
fst(void (* f)(void *,Internal *),ulong ea,int s,int n,FPsave * ufp)2217bb09086SDavid du Colombier fst(void (*f)(void*, Internal*), ulong ea, int s, int n, FPsave *ufp)
2227bb09086SDavid du Colombier {
2237bb09086SDavid du Colombier 	Internal tmp;
2247bb09086SDavid du Colombier 	void *mem;
2257bb09086SDavid du Colombier 
2267bb09086SDavid du Colombier 	mem = (void*)ea;
2277bb09086SDavid du Colombier 	tmp = FR(ufp, s);
2287bb09086SDavid du Colombier 	if(fpemudebug)
2297bb09086SDavid du Colombier 		print("MOV%c	F%d,#%lux\n", n==8? 'D': 'F', s, ea);
2307bb09086SDavid du Colombier 	(*f)(mem, &tmp);
2317bb09086SDavid du Colombier }
2327bb09086SDavid du Colombier 
2337bb09086SDavid du Colombier static int
condok(int cc,int c)2347bb09086SDavid du Colombier condok(int cc, int c)
2357bb09086SDavid du Colombier {
2367bb09086SDavid du Colombier 	switch(c){
2377bb09086SDavid du Colombier 	case 0:	/* Z set */
2387bb09086SDavid du Colombier 		return cc&Z;
2397bb09086SDavid du Colombier 	case 1:	/* Z clear */
2407bb09086SDavid du Colombier 		return (cc&Z) == 0;
2417bb09086SDavid du Colombier 	case 2:	/* C set */
2427bb09086SDavid du Colombier 		return cc&C;
2437bb09086SDavid du Colombier 	case 3:	/* C clear */
2447bb09086SDavid du Colombier 		return (cc&C) == 0;
2457bb09086SDavid du Colombier 	case 4:	/* N set */
2467bb09086SDavid du Colombier 		return cc&N;
2477bb09086SDavid du Colombier 	case 5:	/* N clear */
2487bb09086SDavid du Colombier 		return (cc&N) == 0;
2497bb09086SDavid du Colombier 	case 6:	/* V set */
2507bb09086SDavid du Colombier 		return cc&V;
2517bb09086SDavid du Colombier 	case 7:	/* V clear */
2527bb09086SDavid du Colombier 		return (cc&V) == 0;
2537bb09086SDavid du Colombier 	case 8:	/* C set and Z clear */
2547bb09086SDavid du Colombier 		return cc&C && (cc&Z) == 0;
2557bb09086SDavid du Colombier 	case 9:	/* C clear or Z set */
2567bb09086SDavid du Colombier 		return (cc&C) == 0 || cc&Z;
2577bb09086SDavid du Colombier 	case 10:	/* N set and V set, or N clear and V clear */
2587bb09086SDavid du Colombier 		return (~cc&(N|V))==0 || (cc&(N|V)) == 0;
2597bb09086SDavid du Colombier 	case 11:	/* N set and V clear, or N clear and V set */
2607bb09086SDavid du Colombier 		return (cc&(N|V))==N || (cc&(N|V))==V;
2617bb09086SDavid du Colombier 	case 12:	/* Z clear, and either N set and V set or N clear and V clear */
2627bb09086SDavid du Colombier 		return (cc&Z) == 0 && ((~cc&(N|V))==0 || (cc&(N|V))==0);
2637bb09086SDavid du Colombier 	case 13:	/* Z set, or N set and V clear or N clear and V set */
2647bb09086SDavid du Colombier 		return (cc&Z) || (cc&(N|V))==N || (cc&(N|V))==V;
2657bb09086SDavid du Colombier 	case 14:	/* always */
2667bb09086SDavid du Colombier 		return 1;
2677bb09086SDavid du Colombier 	case 15:	/* never (reserved) */
2687bb09086SDavid du Colombier 		return 0;
2697bb09086SDavid du Colombier 	}
2707bb09086SDavid du Colombier 	return 0;	/* not reached */
2717bb09086SDavid du Colombier }
2727bb09086SDavid du Colombier 
2737bb09086SDavid du Colombier static void
unimp(ulong pc,ulong op)2747bb09086SDavid du Colombier unimp(ulong pc, ulong op)
2757bb09086SDavid du Colombier {
2767bb09086SDavid du Colombier 	char buf[60];
2777bb09086SDavid du Colombier 
2787bb09086SDavid du Colombier 	snprint(buf, sizeof(buf), "sys: fp: pc=%lux unimp fp 0x%.8lux", pc, op);
2797bb09086SDavid du Colombier 	if(fpemudebug)
2807bb09086SDavid du Colombier 		print("FPE: %s\n", buf);
2817bb09086SDavid du Colombier 	error(buf);
2827bb09086SDavid du Colombier 	/* no return */
2837bb09086SDavid du Colombier }
2847bb09086SDavid du Colombier 
2857bb09086SDavid du Colombier static void
fpemu(ulong pc,ulong op,Ureg * ur,FPsave * ufp)2867bb09086SDavid du Colombier fpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
2877bb09086SDavid du Colombier {
2887bb09086SDavid du Colombier 	int rn, rd, tag, o;
2897bb09086SDavid du Colombier 	long off;
2907bb09086SDavid du Colombier 	ulong ea;
2917bb09086SDavid du Colombier 	Internal tmp, *fm, *fn;
2927bb09086SDavid du Colombier 
2937bb09086SDavid du Colombier 	/* note: would update fault status here if we noted numeric exceptions */
2947bb09086SDavid du Colombier 
2957bb09086SDavid du Colombier 	/*
2967bb09086SDavid du Colombier 	 * LDF, STF; 10.1.1
2977bb09086SDavid du Colombier 	 */
2987bb09086SDavid du Colombier 	if(((op>>25)&7) == 6){
2997bb09086SDavid du Colombier 		if(op & (1<<22))
3007bb09086SDavid du Colombier 			unimp(pc, op);	/* packed or extended */
3017bb09086SDavid du Colombier 		rn = (op>>16)&0xF;
3027bb09086SDavid du Colombier 		off = (op&0xFF)<<2;
3037bb09086SDavid du Colombier 		if((op & (1<<23)) == 0)
3047bb09086SDavid du Colombier 			off = -off;
3057bb09086SDavid du Colombier 		ea = REG(ur, rn);
3067bb09086SDavid du Colombier 		if(rn == REGPC)
3077bb09086SDavid du Colombier 			ea += 8;
3087bb09086SDavid du Colombier 		if(op & (1<<24))
3097bb09086SDavid du Colombier 			ea += off;
3107bb09086SDavid du Colombier 		rd = (op>>12)&7;
3117bb09086SDavid du Colombier 		if(op & (1<<20)){
3127bb09086SDavid du Colombier 			if(op & (1<<15))
3137bb09086SDavid du Colombier 				fld(fpid2i, rd, ea, 8, ufp);
3147bb09086SDavid du Colombier 			else
3157bb09086SDavid du Colombier 				fld(fpis2i, rd, ea, 4, ufp);
3167bb09086SDavid du Colombier 		}else{
3177bb09086SDavid du Colombier 			if(op & (1<<15))
3187bb09086SDavid du Colombier 				fst(fpii2d, ea, rd, 8, ufp);
3197bb09086SDavid du Colombier 			else
3207bb09086SDavid du Colombier 				fst(fpii2s, ea, rd, 4, ufp);
3217bb09086SDavid du Colombier 		}
3227bb09086SDavid du Colombier 		if((op & (1<<24)) == 0)
3237bb09086SDavid du Colombier 			ea += off;
3247bb09086SDavid du Colombier 		if(op & (1<<21))
3257bb09086SDavid du Colombier 			REG(ur, rn) = ea;
3267bb09086SDavid du Colombier 		return;
3277bb09086SDavid du Colombier 	}
3287bb09086SDavid du Colombier 
3297bb09086SDavid du Colombier 	/*
3307bb09086SDavid du Colombier 	 * CPRT/transfer, 10.3
3317bb09086SDavid du Colombier 	 */
3327bb09086SDavid du Colombier 	if(op & (1<<4)){
3337bb09086SDavid du Colombier 		rd = (op>>12) & 0xF;
3347bb09086SDavid du Colombier 
3357bb09086SDavid du Colombier 		/*
3367bb09086SDavid du Colombier 		 * compare, 10.3.1
3377bb09086SDavid du Colombier 		 */
3387bb09086SDavid du Colombier 		if(rd == 15 && op & (1<<20)){
3397bb09086SDavid du Colombier 			rn = (op>>16)&7;
3407bb09086SDavid du Colombier 			fn = &FR(ufp, rn);
3417bb09086SDavid du Colombier 			if(op & (1<<3)){
3427bb09086SDavid du Colombier 				fm = &fpconst[op&7];
3437bb09086SDavid du Colombier 				if(fpemudebug)
3447bb09086SDavid du Colombier 					tag = 'C';
3457bb09086SDavid du Colombier 			}else{
3467bb09086SDavid du Colombier 				fm = &FR(ufp, op&7);
3477bb09086SDavid du Colombier 				if(fpemudebug)
3487bb09086SDavid du Colombier 					tag = 'F';
3497bb09086SDavid du Colombier 			}
3507bb09086SDavid du Colombier 			switch((op>>21)&7){
3517bb09086SDavid du Colombier 			default:
3527bb09086SDavid du Colombier 				unimp(pc, op);
3537bb09086SDavid du Colombier 			case 4:	/* CMF: Fn :: Fm */
3547bb09086SDavid du Colombier 			case 6:	/* CMFE: Fn :: Fm (with exception) */
3557bb09086SDavid du Colombier 				ur->psr &= ~(N|C|Z|V);
3567bb09086SDavid du Colombier 				ur->psr |= fcmp(fn, fm);
3577bb09086SDavid du Colombier 				break;
3587bb09086SDavid du Colombier 			case 5:	/* CNF: Fn :: -Fm */
3597bb09086SDavid du Colombier 			case 7:	/* CNFE: Fn :: -Fm (with exception) */
3607bb09086SDavid du Colombier 				tmp = *fm;
3617bb09086SDavid du Colombier 				tmp.s ^= 1;
3627bb09086SDavid du Colombier 				ur->psr &= ~(N|C|Z|V);
3637bb09086SDavid du Colombier 				ur->psr |= fcmp(fn, &tmp);
3647bb09086SDavid du Colombier 				break;
3657bb09086SDavid du Colombier 			}
3667bb09086SDavid du Colombier 			if(fpemudebug)
3677bb09086SDavid du Colombier 				print("CMPF	%c%d,F%ld =%#lux\n",
3687bb09086SDavid du Colombier 					tag, rn, op&7, ur->psr>>28);
3697bb09086SDavid du Colombier 			return;
3707bb09086SDavid du Colombier 		}
3717bb09086SDavid du Colombier 
3727bb09086SDavid du Colombier 		/*
3737bb09086SDavid du Colombier 		 * other transfer, 10.3
3747bb09086SDavid du Colombier 		 */
3757bb09086SDavid du Colombier 		switch((op>>20)&0xF){
3767bb09086SDavid du Colombier 		default:
3777bb09086SDavid du Colombier 			unimp(pc, op);
3787bb09086SDavid du Colombier 		case 0:	/* FLT */
3797bb09086SDavid du Colombier 			rn = (op>>16) & 7;
3807bb09086SDavid du Colombier 			fpiw2i(&FR(ufp, rn), &REG(ur, rd));
3817bb09086SDavid du Colombier 			if(fpemudebug)
3827bb09086SDavid du Colombier 				print("MOVW[FD]	R%d, F%d\n", rd, rn);
3837bb09086SDavid du Colombier 			break;
3847bb09086SDavid du Colombier 		case 1:	/* FIX */
3857bb09086SDavid du Colombier 			if(op & (1<<3))
3867bb09086SDavid du Colombier 				unimp(pc, op);
3877bb09086SDavid du Colombier 			rn = op & 7;
3887bb09086SDavid du Colombier 			tmp = FR(ufp, rn);
3897bb09086SDavid du Colombier 			fpii2w(&REG(ur, rd), &tmp);
3907bb09086SDavid du Colombier 			if(fpemudebug)
3917bb09086SDavid du Colombier 				print("MOV[FD]W	F%d, R%d =%ld\n", rn, rd, REG(ur, rd));
3927bb09086SDavid du Colombier 			break;
3937bb09086SDavid du Colombier 		case 2:	/* FPSR := Rd */
3947bb09086SDavid du Colombier 			ufp->status = REG(ur, rd);
3957bb09086SDavid du Colombier 			if(fpemudebug)
3967bb09086SDavid du Colombier 				print("MOVW	R%d, FPSR\n", rd);
3977bb09086SDavid du Colombier 			break;
3987bb09086SDavid du Colombier 		case 3:	/* Rd := FPSR */
3997bb09086SDavid du Colombier 			REG(ur, rd) = ufp->status;
4007bb09086SDavid du Colombier 			if(fpemudebug)
4017bb09086SDavid du Colombier 				print("MOVW	FPSR, R%d\n", rd);
4027bb09086SDavid du Colombier 			break;
4037bb09086SDavid du Colombier 		case 4:	/* FPCR := Rd */
4047bb09086SDavid du Colombier 			ufp->control = REG(ur, rd);
4057bb09086SDavid du Colombier 			if(fpemudebug)
4067bb09086SDavid du Colombier 				print("MOVW	R%d, FPCR\n", rd);
4077bb09086SDavid du Colombier 			break;
4087bb09086SDavid du Colombier 		case 5:	/* Rd := FPCR */
4097bb09086SDavid du Colombier 			REG(ur, rd) = ufp->control;
4107bb09086SDavid du Colombier 			if(fpemudebug)
4117bb09086SDavid du Colombier 				print("MOVW	FPCR, R%d\n", rd);
4127bb09086SDavid du Colombier 			break;
4137bb09086SDavid du Colombier 		}
4147bb09086SDavid du Colombier 		return;
4157bb09086SDavid du Colombier 	}
4167bb09086SDavid du Colombier 
4177bb09086SDavid du Colombier 	/*
4187bb09086SDavid du Colombier 	 * arithmetic
4197bb09086SDavid du Colombier 	 */
4207bb09086SDavid du Colombier 
4217bb09086SDavid du Colombier 	if(op & (1<<3)){	/* constant */
4227bb09086SDavid du Colombier 		fm = &fpconst[op&7];
4237bb09086SDavid du Colombier 		if(fpemudebug)
4247bb09086SDavid du Colombier 			tag = 'C';
4257bb09086SDavid du Colombier 	}else{
4267bb09086SDavid du Colombier 		fm = &FR(ufp, op&7);
4277bb09086SDavid du Colombier 		if(fpemudebug)
4287bb09086SDavid du Colombier 			tag = 'F';
4297bb09086SDavid du Colombier 	}
4307bb09086SDavid du Colombier 	rd = (op>>12)&7;
4317bb09086SDavid du Colombier 	o = (op>>20)&0xF;
4327bb09086SDavid du Colombier 	if(op & (1<<15)){	/* monadic */
4337bb09086SDavid du Colombier 		FP1 *fp;
4347bb09086SDavid du Colombier 		fp = &optab1[o];
4357bb09086SDavid du Colombier 		if(fp->f == nil)
4367bb09086SDavid du Colombier 			unimp(pc, op);
4377bb09086SDavid du Colombier 		if(fpemudebug)
4387bb09086SDavid du Colombier 			print("%s	%c%ld,F%d\n", fp->name, tag, op&7, rd);
4397bb09086SDavid du Colombier 		(*fp->f)(fm, &FR(ufp, rd));
4407bb09086SDavid du Colombier 	} else {
4417bb09086SDavid du Colombier 		FP2 *fp;
4427bb09086SDavid du Colombier 		fp = &optab2[o];
4437bb09086SDavid du Colombier 		if(fp->f == nil)
4447bb09086SDavid du Colombier 			unimp(pc, op);
4457bb09086SDavid du Colombier 		rn = (op>>16)&7;
4467bb09086SDavid du Colombier 		if(fpemudebug)
4477bb09086SDavid du Colombier 			print("%s	%c%ld,F%d,F%d\n", fp->name, tag, op&7, rn, rd);
4487bb09086SDavid du Colombier 		(*fp->f)(*fm, FR(ufp, rn), &FR(ufp, rd));
4497bb09086SDavid du Colombier 	}
4507bb09086SDavid du Colombier }
4517bb09086SDavid du Colombier 
4527bb09086SDavid du Colombier void
casemu(ulong pc,ulong op,Ureg * ur)4537bb09086SDavid du Colombier casemu(ulong pc, ulong op, Ureg *ur)
4547bb09086SDavid du Colombier {
4557bb09086SDavid du Colombier 	ulong *rp, ro, rn, *rd;
4567bb09086SDavid du Colombier 
4577bb09086SDavid du Colombier 	USED(pc);
4587bb09086SDavid du Colombier 
4597bb09086SDavid du Colombier 	rp = (ulong*)ur;
4607bb09086SDavid du Colombier 	ro = rp[op>>16 & 0x7];
4617bb09086SDavid du Colombier 	rn = rp[op>>0 & 0x7];
4627bb09086SDavid du Colombier 	rd = rp + (op>>12 & 0x7);
4637bb09086SDavid du Colombier 	rp = (ulong*)*rd;
4647bb09086SDavid du Colombier 	validaddr((ulong)rp, 4, 1);
4657bb09086SDavid du Colombier 	splhi();
4667bb09086SDavid du Colombier 	if(*rd = (*rp == ro))
4677bb09086SDavid du Colombier 		*rp = rn;
4687bb09086SDavid du Colombier 	spllo();
4697bb09086SDavid du Colombier }
4707bb09086SDavid du Colombier 
4717bb09086SDavid du Colombier int ldrexvalid;
4727bb09086SDavid du Colombier 
4737bb09086SDavid du Colombier void
ldrex(ulong pc,ulong op,Ureg * ur)4747bb09086SDavid du Colombier ldrex(ulong pc, ulong op, Ureg *ur)
4757bb09086SDavid du Colombier {
4767bb09086SDavid du Colombier 	ulong *rp, *rd, *addr;
4777bb09086SDavid du Colombier 
4787bb09086SDavid du Colombier 	USED(pc);
4797bb09086SDavid du Colombier 
4807bb09086SDavid du Colombier 	rp = (ulong*)ur;
4817bb09086SDavid du Colombier 	rd = rp + (op>>16 & 0x7);
4827bb09086SDavid du Colombier 	addr = (ulong*)*rd;
4837bb09086SDavid du Colombier 	validaddr((ulong)addr, 4, 0);
4847bb09086SDavid du Colombier 	ldrexvalid = 1;
4857bb09086SDavid du Colombier 	rp[op>>12 & 0x7] = *addr;
4867bb09086SDavid du Colombier 	if(fpemudebug)
4877bb09086SDavid du Colombier 		print("ldrex, r%ld = [r%ld]@0x%8.8p = 0x%8.8lux",
4887bb09086SDavid du Colombier 			op>>12 & 0x7, op>>16 & 0x7, addr, rp[op>>12 & 0x7]);
4897bb09086SDavid du Colombier }
4907bb09086SDavid du Colombier 
4917bb09086SDavid du Colombier void
clrex(ulong,ulong,Ureg *)4920f53e541SDavid du Colombier clrex(ulong, ulong, Ureg *)
4930f53e541SDavid du Colombier {
4940f53e541SDavid du Colombier 	ldrexvalid = 0;
4950f53e541SDavid du Colombier 	if(fpemudebug)
4960f53e541SDavid du Colombier 		print("clrex");
4970f53e541SDavid du Colombier }
4980f53e541SDavid du Colombier 
4990f53e541SDavid du Colombier void
strex(ulong pc,ulong op,Ureg * ur)5007bb09086SDavid du Colombier strex(ulong pc, ulong op, Ureg *ur)
5017bb09086SDavid du Colombier {
5027bb09086SDavid du Colombier 	ulong *rp, rn, *rd, *addr;
5037bb09086SDavid du Colombier 
5047bb09086SDavid du Colombier 	USED(pc);
5057bb09086SDavid du Colombier 
5067bb09086SDavid du Colombier 	rp = (ulong*)ur;
5077bb09086SDavid du Colombier 	rd = rp + (op>>16 & 0x7);
5087bb09086SDavid du Colombier 	rn = rp[op>>0 & 0x7];
5097bb09086SDavid du Colombier 	addr = (ulong*)*rd;
5107bb09086SDavid du Colombier 	validaddr((ulong)addr, 4, 1);
5117bb09086SDavid du Colombier 	splhi();
5127bb09086SDavid du Colombier 	if(ldrexvalid){
5137bb09086SDavid du Colombier 		if(fpemudebug)
5147bb09086SDavid du Colombier 			print("strex valid, [r%ld]@0x%8.8p = r%ld = 0x%8.8lux",
5157bb09086SDavid du Colombier 				op>>16 & 0x7, addr, op>>0 & 0x7, rn);
5167bb09086SDavid du Colombier 		*addr = rn;
5177bb09086SDavid du Colombier 		ldrexvalid = 0;
5187bb09086SDavid du Colombier 		rp[op>>12 & 0x7] = 0;
5197bb09086SDavid du Colombier 	}else{
5207bb09086SDavid du Colombier 		if(fpemudebug)
5217bb09086SDavid du Colombier 			print("strex invalid, r%ld = 1", op>>16 & 0x7);
5227bb09086SDavid du Colombier 		rp[op>>12 & 0x7] = 1;
5237bb09086SDavid du Colombier 	}
5247bb09086SDavid du Colombier 	spllo();
5257bb09086SDavid du Colombier }
5267bb09086SDavid du Colombier 
5277bb09086SDavid du Colombier struct {
5287bb09086SDavid du Colombier 	ulong	opc;
5297bb09086SDavid du Colombier 	ulong	mask;
5307bb09086SDavid du Colombier 	void	(*f)(ulong, ulong, Ureg*);
5317bb09086SDavid du Colombier } specialopc[] = {
5327bb09086SDavid du Colombier 	{ 0x01900f9f, 0x0ff00fff, ldrex },
5337bb09086SDavid du Colombier 	{ 0x01800f90, 0x0ff00ff0, strex },
5340f53e541SDavid du Colombier 	{ 0xf57ff01f, 0xffffffff, clrex },
5357bb09086SDavid du Colombier 	{ 0x0ed00100, 0x0ef08100, casemu },
5367bb09086SDavid du Colombier 	{ 0x00000000, 0x00000000, nil }
5377bb09086SDavid du Colombier };
5387bb09086SDavid du Colombier 
5397bb09086SDavid du Colombier /*
5407bb09086SDavid du Colombier  * returns the number of FP instructions emulated
5417bb09086SDavid du Colombier  */
5427bb09086SDavid du Colombier int
fpiarm(Ureg * ur)5437bb09086SDavid du Colombier fpiarm(Ureg *ur)
5447bb09086SDavid du Colombier {
5457bb09086SDavid du Colombier 	ulong op, o;
5467bb09086SDavid du Colombier 	FPsave *ufp;
5477bb09086SDavid du Colombier 	int i, n;
5487bb09086SDavid du Colombier 
5497bb09086SDavid du Colombier 	if(up == nil)
5507bb09086SDavid du Colombier 		panic("fpiarm not in a process");
5517bb09086SDavid du Colombier 	ufp = &up->fpsave;
5527bb09086SDavid du Colombier 	/* because all the state is in the proc structure,
5537bb09086SDavid du Colombier 	 * it need not be saved/restored
5547bb09086SDavid du Colombier 	 */
5557bb09086SDavid du Colombier 	if(up->fpstate != FPactive){
5567bb09086SDavid du Colombier //		assert(sizeof(Internal) == sizeof(ufp->regs[0]));
5577bb09086SDavid du Colombier 		up->fpstate = FPactive;
5587bb09086SDavid du Colombier 		ufp->control = 0;
5597bb09086SDavid du Colombier 		ufp->status = (0x01<<28)|(1<<12);	/* software emulation, alternative C flag */
5607bb09086SDavid du Colombier 		for(n = 0; n < 8; n++)
5617bb09086SDavid du Colombier 			FR(ufp, n) = fpconst[0];
5627bb09086SDavid du Colombier 	}
5637bb09086SDavid du Colombier 	for(n=0; ;n++){
5647bb09086SDavid du Colombier 		validaddr(ur->pc, 4, 0);
5657bb09086SDavid du Colombier 		op = *(ulong*)(ur->pc);
5667bb09086SDavid du Colombier 		if(fpemudebug)
5677bb09086SDavid du Colombier 			print("%#lux: %#8.8lux ", ur->pc, op);
5687bb09086SDavid du Colombier 		o = (op>>24) & 0xF;
5697bb09086SDavid du Colombier 		if(condok(ur->psr, op>>28)){
5707bb09086SDavid du Colombier 			for(i = 0; specialopc[i].f; i++)
5717bb09086SDavid du Colombier 				if((op & specialopc[i].mask) == specialopc[i].opc)
5727bb09086SDavid du Colombier 					break;
5737bb09086SDavid du Colombier 			if(specialopc[i].f)
5747bb09086SDavid du Colombier 				specialopc[i].f(ur->pc, op, ur);
5757bb09086SDavid du Colombier 			else if((op & 0xF00) != 0x100 || o != 0xE && (o&~1) != 0xC)
5767bb09086SDavid du Colombier 				break;
5777bb09086SDavid du Colombier 			else
5787bb09086SDavid du Colombier 				fpemu(ur->pc, op, ur, ufp);
5797bb09086SDavid du Colombier 		}else if((op & 0xF00) != 0x100 || o != 0xE && (o&~1) != 0xC)
5807bb09086SDavid du Colombier 			break;
5817bb09086SDavid du Colombier 		ur->pc += 4;
5827bb09086SDavid du Colombier 	}
5837bb09086SDavid du Colombier 	if(fpemudebug) print("\n");
5847bb09086SDavid du Colombier 	return n;
5857bb09086SDavid du Colombier }
586