xref: /plan9/sys/src/ape/lib/ap/power/vlrt.c (revision 6891d8578618fb7ccda4a131c122d4d0e6580c4b)
17dd7cddfSDavid du Colombier typedef	unsigned long	ulong;
27dd7cddfSDavid du Colombier typedef	unsigned int	uint;
37dd7cddfSDavid du Colombier typedef	unsigned short	ushort;
47dd7cddfSDavid du Colombier typedef	unsigned char	uchar;
57dd7cddfSDavid du Colombier typedef	signed char	schar;
67dd7cddfSDavid du Colombier 
77dd7cddfSDavid du Colombier #define	SIGN(n)	(1UL<<(n-1))
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier typedef	struct	Vlong	Vlong;
107dd7cddfSDavid du Colombier struct	Vlong
117dd7cddfSDavid du Colombier {
127dd7cddfSDavid du Colombier 	ulong	hi;
137dd7cddfSDavid du Colombier 	ulong	lo;
147dd7cddfSDavid du Colombier };
157dd7cddfSDavid du Colombier 
167dd7cddfSDavid du Colombier void	abort(void);
17*6891d857SDavid du Colombier void	_divu64(Vlong, Vlong, Vlong*, Vlong*);
187dd7cddfSDavid du Colombier 
197dd7cddfSDavid du Colombier void
_d2v(Vlong * y,double d)207dd7cddfSDavid du Colombier _d2v(Vlong *y, double d)
217dd7cddfSDavid du Colombier {
22*6891d857SDavid du Colombier 	union { double d; Vlong; } x;
237dd7cddfSDavid du Colombier 	ulong xhi, xlo, ylo, yhi;
247dd7cddfSDavid du Colombier 	int sh;
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier 	x.d = d;
277dd7cddfSDavid du Colombier 
287dd7cddfSDavid du Colombier 	xhi = (x.hi & 0xfffff) | 0x100000;
297dd7cddfSDavid du Colombier 	xlo = x.lo;
307dd7cddfSDavid du Colombier 	sh = 1075 - ((x.hi >> 20) & 0x7ff);
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier 	ylo = 0;
337dd7cddfSDavid du Colombier 	yhi = 0;
347dd7cddfSDavid du Colombier 	if(sh >= 0) {
357dd7cddfSDavid du Colombier 		/* v = (hi||lo) >> sh */
367dd7cddfSDavid du Colombier 		if(sh < 32) {
377dd7cddfSDavid du Colombier 			if(sh == 0) {
387dd7cddfSDavid du Colombier 				ylo = xlo;
397dd7cddfSDavid du Colombier 				yhi = xhi;
407dd7cddfSDavid du Colombier 			} else {
417dd7cddfSDavid du Colombier 				ylo = (xlo >> sh) | (xhi << (32-sh));
427dd7cddfSDavid du Colombier 				yhi = xhi >> sh;
437dd7cddfSDavid du Colombier 			}
447dd7cddfSDavid du Colombier 		} else {
457dd7cddfSDavid du Colombier 			if(sh == 32) {
467dd7cddfSDavid du Colombier 				ylo = xhi;
477dd7cddfSDavid du Colombier 			} else
487dd7cddfSDavid du Colombier 			if(sh < 64) {
497dd7cddfSDavid du Colombier 				ylo = xhi >> (sh-32);
507dd7cddfSDavid du Colombier 			}
517dd7cddfSDavid du Colombier 		}
527dd7cddfSDavid du Colombier 	} else {
537dd7cddfSDavid du Colombier 		/* v = (hi||lo) << -sh */
547dd7cddfSDavid du Colombier 		sh = -sh;
557dd7cddfSDavid du Colombier 		if(sh <= 10) {
567dd7cddfSDavid du Colombier 			ylo = xlo << sh;
577dd7cddfSDavid du Colombier 			yhi = (xhi << sh) | (xlo >> (32-sh));
587dd7cddfSDavid du Colombier 		} else {
597dd7cddfSDavid du Colombier 			/* overflow */
607dd7cddfSDavid du Colombier 			yhi = d;	/* causes something awful */
617dd7cddfSDavid du Colombier 		}
627dd7cddfSDavid du Colombier 	}
637dd7cddfSDavid du Colombier 	if(x.hi & SIGN(32)) {
647dd7cddfSDavid du Colombier 		if(ylo != 0) {
657dd7cddfSDavid du Colombier 			ylo = -ylo;
667dd7cddfSDavid du Colombier 			yhi = ~yhi;
677dd7cddfSDavid du Colombier 		} else
687dd7cddfSDavid du Colombier 			yhi = -yhi;
697dd7cddfSDavid du Colombier 	}
707dd7cddfSDavid du Colombier 
717dd7cddfSDavid du Colombier 	y->hi = yhi;
727dd7cddfSDavid du Colombier 	y->lo = ylo;
737dd7cddfSDavid du Colombier }
747dd7cddfSDavid du Colombier 
757dd7cddfSDavid du Colombier void
_f2v(Vlong * y,float f)767dd7cddfSDavid du Colombier _f2v(Vlong *y, float f)
777dd7cddfSDavid du Colombier {
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier 	_d2v(y, f);
807dd7cddfSDavid du Colombier }
817dd7cddfSDavid du Colombier 
827dd7cddfSDavid du Colombier double
_v2d(Vlong x)837dd7cddfSDavid du Colombier _v2d(Vlong x)
847dd7cddfSDavid du Colombier {
857dd7cddfSDavid du Colombier 	if(x.hi & SIGN(32)) {
867dd7cddfSDavid du Colombier 		if(x.lo) {
877dd7cddfSDavid du Colombier 			x.lo = -x.lo;
887dd7cddfSDavid du Colombier 			x.hi = ~x.hi;
897dd7cddfSDavid du Colombier 		} else
907dd7cddfSDavid du Colombier 			x.hi = -x.hi;
917dd7cddfSDavid du Colombier 		return -((long)x.hi*4294967296. + x.lo);
927dd7cddfSDavid du Colombier 	}
937dd7cddfSDavid du Colombier 	return (long)x.hi*4294967296. + x.lo;
947dd7cddfSDavid du Colombier }
957dd7cddfSDavid du Colombier 
967dd7cddfSDavid du Colombier float
_v2f(Vlong x)977dd7cddfSDavid du Colombier _v2f(Vlong x)
987dd7cddfSDavid du Colombier {
997dd7cddfSDavid du Colombier 	return _v2d(x);
1007dd7cddfSDavid du Colombier }
1017dd7cddfSDavid du Colombier 
1027dd7cddfSDavid du Colombier void
_divvu(Vlong * q,Vlong n,Vlong d)1037dd7cddfSDavid du Colombier _divvu(Vlong *q, Vlong n, Vlong d)
1047dd7cddfSDavid du Colombier {
1057dd7cddfSDavid du Colombier 
1067dd7cddfSDavid du Colombier 	if(n.hi == 0 && d.hi == 0) {
1077dd7cddfSDavid du Colombier 		q->hi = 0;
1087dd7cddfSDavid du Colombier 		q->lo = n.lo / d.lo;
1097dd7cddfSDavid du Colombier 		return;
1107dd7cddfSDavid du Colombier 	}
111*6891d857SDavid du Colombier 	_divu64(n, d, q, 0);
1127dd7cddfSDavid du Colombier }
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier void
_modvu(Vlong * r,Vlong n,Vlong d)1157dd7cddfSDavid du Colombier _modvu(Vlong *r, Vlong n, Vlong d)
1167dd7cddfSDavid du Colombier {
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier 	if(n.hi == 0 && d.hi == 0) {
1197dd7cddfSDavid du Colombier 		r->hi = 0;
1207dd7cddfSDavid du Colombier 		r->lo = n.lo % d.lo;
1217dd7cddfSDavid du Colombier 		return;
1227dd7cddfSDavid du Colombier 	}
123*6891d857SDavid du Colombier 	_divu64(n, d, 0, r);
1247dd7cddfSDavid du Colombier }
1257dd7cddfSDavid du Colombier 
1267dd7cddfSDavid du Colombier static void
vneg(Vlong * v)1277dd7cddfSDavid du Colombier vneg(Vlong *v)
1287dd7cddfSDavid du Colombier {
1297dd7cddfSDavid du Colombier 
1307dd7cddfSDavid du Colombier 	if(v->lo == 0) {
1317dd7cddfSDavid du Colombier 		v->hi = -v->hi;
1327dd7cddfSDavid du Colombier 		return;
1337dd7cddfSDavid du Colombier 	}
1347dd7cddfSDavid du Colombier 	v->lo = -v->lo;
1357dd7cddfSDavid du Colombier 	v->hi = ~v->hi;
1367dd7cddfSDavid du Colombier }
1377dd7cddfSDavid du Colombier 
1387dd7cddfSDavid du Colombier void
_divv(Vlong * q,Vlong n,Vlong d)1397dd7cddfSDavid du Colombier _divv(Vlong *q, Vlong n, Vlong d)
1407dd7cddfSDavid du Colombier {
1417dd7cddfSDavid du Colombier 	long nneg, dneg;
1427dd7cddfSDavid du Colombier 
1437dd7cddfSDavid du Colombier 	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
1447dd7cddfSDavid du Colombier 		q->lo = (long)n.lo / (long)d.lo;
1457dd7cddfSDavid du Colombier 		q->hi = ((long)q->lo) >> 31;
1467dd7cddfSDavid du Colombier 		return;
1477dd7cddfSDavid du Colombier 	}
1487dd7cddfSDavid du Colombier 	nneg = n.hi >> 31;
1497dd7cddfSDavid du Colombier 	if(nneg)
1507dd7cddfSDavid du Colombier 		vneg(&n);
1517dd7cddfSDavid du Colombier 	dneg = d.hi >> 31;
1527dd7cddfSDavid du Colombier 	if(dneg)
1537dd7cddfSDavid du Colombier 		vneg(&d);
154*6891d857SDavid du Colombier 	_divu64(n, d, q, 0);
1557dd7cddfSDavid du Colombier 	if(nneg != dneg)
1567dd7cddfSDavid du Colombier 		vneg(q);
1577dd7cddfSDavid du Colombier }
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier void
_modv(Vlong * r,Vlong n,Vlong d)1607dd7cddfSDavid du Colombier _modv(Vlong *r, Vlong n, Vlong d)
1617dd7cddfSDavid du Colombier {
1627dd7cddfSDavid du Colombier 	long nneg, dneg;
1637dd7cddfSDavid du Colombier 
1647dd7cddfSDavid du Colombier 	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
1657dd7cddfSDavid du Colombier 		r->lo = (long)n.lo % (long)d.lo;
1667dd7cddfSDavid du Colombier 		r->hi = ((long)r->lo) >> 31;
1677dd7cddfSDavid du Colombier 		return;
1687dd7cddfSDavid du Colombier 	}
1697dd7cddfSDavid du Colombier 	nneg = n.hi >> 31;
1707dd7cddfSDavid du Colombier 	if(nneg)
1717dd7cddfSDavid du Colombier 		vneg(&n);
1727dd7cddfSDavid du Colombier 	dneg = d.hi >> 31;
1737dd7cddfSDavid du Colombier 	if(dneg)
1747dd7cddfSDavid du Colombier 		vneg(&d);
175*6891d857SDavid du Colombier 	_divu64(n, d, 0, r);
1767dd7cddfSDavid du Colombier 	if(nneg)
1777dd7cddfSDavid du Colombier 		vneg(r);
1787dd7cddfSDavid du Colombier }
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier void
_vasop(Vlong * ret,void * lv,void fn (Vlong *,Vlong,Vlong),int type,Vlong rv)1817dd7cddfSDavid du Colombier _vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
1827dd7cddfSDavid du Colombier {
1837dd7cddfSDavid du Colombier 	Vlong t, u;
1847dd7cddfSDavid du Colombier 
1857dd7cddfSDavid du Colombier 	u = *ret;
1867dd7cddfSDavid du Colombier 	switch(type) {
1877dd7cddfSDavid du Colombier 	default:
1887dd7cddfSDavid du Colombier 		abort();
1897dd7cddfSDavid du Colombier 		break;
1907dd7cddfSDavid du Colombier 
1917dd7cddfSDavid du Colombier 	case 1:	/* schar */
1927dd7cddfSDavid du Colombier 		t.lo = *(schar*)lv;
1937dd7cddfSDavid du Colombier 		t.hi = t.lo >> 31;
1947dd7cddfSDavid du Colombier 		fn(&u, t, rv);
1957dd7cddfSDavid du Colombier 		*(schar*)lv = u.lo;
1967dd7cddfSDavid du Colombier 		break;
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier 	case 2:	/* uchar */
1997dd7cddfSDavid du Colombier 		t.lo = *(uchar*)lv;
2007dd7cddfSDavid du Colombier 		t.hi = 0;
2017dd7cddfSDavid du Colombier 		fn(&u, t, rv);
2027dd7cddfSDavid du Colombier 		*(uchar*)lv = u.lo;
2037dd7cddfSDavid du Colombier 		break;
2047dd7cddfSDavid du Colombier 
2057dd7cddfSDavid du Colombier 	case 3:	/* short */
2067dd7cddfSDavid du Colombier 		t.lo = *(short*)lv;
2077dd7cddfSDavid du Colombier 		t.hi = t.lo >> 31;
2087dd7cddfSDavid du Colombier 		fn(&u, t, rv);
2097dd7cddfSDavid du Colombier 		*(short*)lv = u.lo;
2107dd7cddfSDavid du Colombier 		break;
2117dd7cddfSDavid du Colombier 
2127dd7cddfSDavid du Colombier 	case 4:	/* ushort */
2137dd7cddfSDavid du Colombier 		t.lo = *(ushort*)lv;
2147dd7cddfSDavid du Colombier 		t.hi = 0;
2157dd7cddfSDavid du Colombier 		fn(&u, t, rv);
2167dd7cddfSDavid du Colombier 		*(ushort*)lv = u.lo;
2177dd7cddfSDavid du Colombier 		break;
2187dd7cddfSDavid du Colombier 
2197dd7cddfSDavid du Colombier 	case 9:	/* int */
2207dd7cddfSDavid du Colombier 		t.lo = *(int*)lv;
2217dd7cddfSDavid du Colombier 		t.hi = t.lo >> 31;
2227dd7cddfSDavid du Colombier 		fn(&u, t, rv);
2237dd7cddfSDavid du Colombier 		*(int*)lv = u.lo;
2247dd7cddfSDavid du Colombier 		break;
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier 	case 10:	/* uint */
2277dd7cddfSDavid du Colombier 		t.lo = *(uint*)lv;
2287dd7cddfSDavid du Colombier 		t.hi = 0;
2297dd7cddfSDavid du Colombier 		fn(&u, t, rv);
2307dd7cddfSDavid du Colombier 		*(uint*)lv = u.lo;
2317dd7cddfSDavid du Colombier 		break;
2327dd7cddfSDavid du Colombier 
2337dd7cddfSDavid du Colombier 	case 5:	/* long */
2347dd7cddfSDavid du Colombier 		t.lo = *(long*)lv;
2357dd7cddfSDavid du Colombier 		t.hi = t.lo >> 31;
2367dd7cddfSDavid du Colombier 		fn(&u, t, rv);
2377dd7cddfSDavid du Colombier 		*(long*)lv = u.lo;
2387dd7cddfSDavid du Colombier 		break;
2397dd7cddfSDavid du Colombier 
2407dd7cddfSDavid du Colombier 	case 6:	/* ulong */
2417dd7cddfSDavid du Colombier 		t.lo = *(ulong*)lv;
2427dd7cddfSDavid du Colombier 		t.hi = 0;
2437dd7cddfSDavid du Colombier 		fn(&u, t, rv);
2447dd7cddfSDavid du Colombier 		*(ulong*)lv = u.lo;
2457dd7cddfSDavid du Colombier 		break;
2467dd7cddfSDavid du Colombier 
2477dd7cddfSDavid du Colombier 	case 7:	/* vlong */
2487dd7cddfSDavid du Colombier 	case 8:	/* uvlong */
2497dd7cddfSDavid du Colombier 		fn(&u, *(Vlong*)lv, rv);
2507dd7cddfSDavid du Colombier 		*(Vlong*)lv = u;
2517dd7cddfSDavid du Colombier 		break;
2527dd7cddfSDavid du Colombier 	}
2537dd7cddfSDavid du Colombier 	*ret = u;
2547dd7cddfSDavid du Colombier }
255