xref: /plan9/sys/src/9/kw/fpiarm.c (revision d11907f1310fb3aff37a1c3d604436d4028fd86f)
1154abd99SDavid du Colombier /*
2154abd99SDavid du Colombier  * this doesn't attempt to implement ARM floating-point properties
3154abd99SDavid du Colombier  * that aren't visible in the Inferno environment.
4154abd99SDavid du Colombier  * all arithmetic is done in double precision.
5154abd99SDavid du Colombier  * the FP trap status isn't updated.
6154abd99SDavid du Colombier  */
7154abd99SDavid du Colombier #include	"u.h"
8154abd99SDavid du Colombier #include	"../port/lib.h"
9154abd99SDavid du Colombier #include	"mem.h"
10154abd99SDavid du Colombier #include	"dat.h"
11154abd99SDavid du Colombier #include	"fns.h"
12154abd99SDavid du Colombier 
13154abd99SDavid du Colombier #include	"ureg.h"
14154abd99SDavid du Colombier 
15154abd99SDavid du Colombier #include	"arm.h"
16*d11907f1SDavid du Colombier #include	"../port/fpi.h"
17154abd99SDavid du Colombier 
18154abd99SDavid du Colombier /* undef this if correct kernel r13 isn't in Ureg;
19154abd99SDavid du Colombier  * check calculation in fpiarm below
20154abd99SDavid du Colombier  */
21154abd99SDavid du Colombier 
22154abd99SDavid du Colombier 
23154abd99SDavid du Colombier #define	REG(ur, x) (*(long*)(((char*)(ur))+roff[(x)]))
24154abd99SDavid du Colombier #define	FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&7])
25154abd99SDavid du Colombier 
26154abd99SDavid du Colombier typedef struct FP2 FP2;
27154abd99SDavid du Colombier typedef struct FP1 FP1;
28154abd99SDavid du Colombier 
29154abd99SDavid du Colombier struct FP2 {
30154abd99SDavid du Colombier 	char*	name;
31154abd99SDavid du Colombier 	void	(*f)(Internal, Internal, Internal*);
32154abd99SDavid du Colombier };
33154abd99SDavid du Colombier 
34154abd99SDavid du Colombier struct FP1 {
35154abd99SDavid du Colombier 	char*	name;
36154abd99SDavid du Colombier 	void	(*f)(Internal*, Internal*);
37154abd99SDavid du Colombier };
38154abd99SDavid du Colombier 
39154abd99SDavid du Colombier enum {
40154abd99SDavid du Colombier 	N = 1<<31,
41154abd99SDavid du Colombier 	Z = 1<<30,
42154abd99SDavid du Colombier 	C = 1<<29,
43154abd99SDavid du Colombier 	V = 1<<28,
44154abd99SDavid du Colombier 	REGPC = 15,
45154abd99SDavid du Colombier };
46154abd99SDavid du Colombier 
47154abd99SDavid du Colombier enum {
48154abd99SDavid du Colombier 	fpemudebug = 0,
49154abd99SDavid du Colombier };
50154abd99SDavid du Colombier 
51154abd99SDavid du Colombier #undef OFR
52154abd99SDavid du Colombier #define	OFR(X)	((ulong)&((Ureg*)0)->X)
53154abd99SDavid du Colombier 
54154abd99SDavid du Colombier static	int	roff[] = {
55154abd99SDavid du Colombier 	OFR(r0), OFR(r1), OFR(r2), OFR(r3),
56154abd99SDavid du Colombier 	OFR(r4), OFR(r5), OFR(r6), OFR(r7),
57154abd99SDavid du Colombier 	OFR(r8), OFR(r9), OFR(r10), OFR(r11),
58154abd99SDavid du Colombier 	OFR(r12), OFR(r13), OFR(r14), OFR(pc),
59154abd99SDavid du Colombier };
60154abd99SDavid du Colombier 
61154abd99SDavid du Colombier static Internal fpconst[8] = {	/* indexed by op&7 */
62154abd99SDavid du Colombier 	/* s, e, l, h */
63154abd99SDavid du Colombier 	{0, 0x1, 0x00000000, 0x00000000}, /* 0.0 */
64154abd99SDavid du Colombier 	{0, 0x3FF, 0x00000000, 0x08000000},	/* 1.0 */
65154abd99SDavid du Colombier 	{0, 0x400, 0x00000000, 0x08000000},	/* 2.0 */
66154abd99SDavid du Colombier 	{0, 0x400, 0x00000000, 0x0C000000},	/* 3.0 */
67154abd99SDavid du Colombier 	{0, 0x401, 0x00000000, 0x08000000},	/* 4.0 */
68154abd99SDavid du Colombier 	{0, 0x401, 0x00000000, 0x0A000000},	/* 5.0 */
69154abd99SDavid du Colombier 	{0, 0x3FE, 0x00000000, 0x08000000},	/* 0.5 */
70154abd99SDavid du Colombier 	{0, 0x402, 0x00000000, 0x0A000000},	/* 10.0 */
71154abd99SDavid du Colombier };
72154abd99SDavid du Colombier 
73154abd99SDavid du Colombier /*
74154abd99SDavid du Colombier  * arm binary operations
75154abd99SDavid du Colombier  */
76154abd99SDavid du Colombier 
77154abd99SDavid du Colombier static void
fadd(Internal m,Internal n,Internal * d)78154abd99SDavid du Colombier fadd(Internal m, Internal n, Internal *d)
79154abd99SDavid du Colombier {
80154abd99SDavid du Colombier 	(m.s == n.s? fpiadd: fpisub)(&m, &n, d);
81154abd99SDavid du Colombier }
82154abd99SDavid du Colombier 
83154abd99SDavid du Colombier static void
fsub(Internal m,Internal n,Internal * d)84154abd99SDavid du Colombier fsub(Internal m, Internal n, Internal *d)
85154abd99SDavid du Colombier {
86154abd99SDavid du Colombier 	m.s ^= 1;
87154abd99SDavid du Colombier 	(m.s == n.s? fpiadd: fpisub)(&m, &n, d);
88154abd99SDavid du Colombier }
89154abd99SDavid du Colombier 
90154abd99SDavid du Colombier static void
fsubr(Internal m,Internal n,Internal * d)91154abd99SDavid du Colombier fsubr(Internal m, Internal n, Internal *d)
92154abd99SDavid du Colombier {
93154abd99SDavid du Colombier 	n.s ^= 1;
94154abd99SDavid du Colombier 	(n.s == m.s? fpiadd: fpisub)(&n, &m, d);
95154abd99SDavid du Colombier }
96154abd99SDavid du Colombier 
97154abd99SDavid du Colombier static void
fmul(Internal m,Internal n,Internal * d)98154abd99SDavid du Colombier fmul(Internal m, Internal n, Internal *d)
99154abd99SDavid du Colombier {
100154abd99SDavid du Colombier 	fpimul(&m, &n, d);
101154abd99SDavid du Colombier }
102154abd99SDavid du Colombier 
103154abd99SDavid du Colombier static void
fdiv(Internal m,Internal n,Internal * d)104154abd99SDavid du Colombier fdiv(Internal m, Internal n, Internal *d)
105154abd99SDavid du Colombier {
106154abd99SDavid du Colombier 	fpidiv(&m, &n, d);
107154abd99SDavid du Colombier }
108154abd99SDavid du Colombier 
109154abd99SDavid du Colombier static void
fdivr(Internal m,Internal n,Internal * d)110154abd99SDavid du Colombier fdivr(Internal m, Internal n, Internal *d)
111154abd99SDavid du Colombier {
112154abd99SDavid du Colombier 	fpidiv(&n, &m, d);
113154abd99SDavid du Colombier }
114154abd99SDavid du Colombier 
115154abd99SDavid du Colombier /*
116154abd99SDavid du Colombier  * arm unary operations
117154abd99SDavid du Colombier  */
118154abd99SDavid du Colombier 
119154abd99SDavid du Colombier static void
fmov(Internal * m,Internal * d)120154abd99SDavid du Colombier fmov(Internal *m, Internal *d)
121154abd99SDavid du Colombier {
122154abd99SDavid du Colombier 	*d = *m;
123154abd99SDavid du Colombier }
124154abd99SDavid du Colombier 
125154abd99SDavid du Colombier static void
fmovn(Internal * m,Internal * d)126154abd99SDavid du Colombier fmovn(Internal *m, Internal *d)
127154abd99SDavid du Colombier {
128154abd99SDavid du Colombier 	*d = *m;
129154abd99SDavid du Colombier 	d->s ^= 1;
130154abd99SDavid du Colombier }
131154abd99SDavid du Colombier 
132154abd99SDavid du Colombier static void
fabsf(Internal * m,Internal * d)133154abd99SDavid du Colombier fabsf(Internal *m, Internal *d)
134154abd99SDavid du Colombier {
135154abd99SDavid du Colombier 	*d = *m;
136154abd99SDavid du Colombier 	d->s = 0;
137154abd99SDavid du Colombier }
138154abd99SDavid du Colombier 
139154abd99SDavid du Colombier static void
frnd(Internal * m,Internal * d)140154abd99SDavid du Colombier frnd(Internal *m, Internal *d)
141154abd99SDavid du Colombier {
142154abd99SDavid du Colombier 	short e;
143154abd99SDavid du Colombier 
144154abd99SDavid du Colombier 	(m->s? fsub: fadd)(fpconst[6], *m, d);
145154abd99SDavid du Colombier 	if(IsWeird(d))
146154abd99SDavid du Colombier 		return;
147154abd99SDavid du Colombier 	fpiround(d);
148154abd99SDavid du Colombier 	e = (d->e - ExpBias) + 1;
149154abd99SDavid du Colombier 	if(e <= 0)
150154abd99SDavid du Colombier 		SetZero(d);
151154abd99SDavid du Colombier 	else if(e > FractBits){
152154abd99SDavid du Colombier 		if(e < 2*FractBits)
153154abd99SDavid du Colombier 			d->l &= ~((1<<(2*FractBits - e))-1);
154154abd99SDavid du Colombier 	}else{
155154abd99SDavid du Colombier 		d->l = 0;
156154abd99SDavid du Colombier 		if(e < FractBits)
157154abd99SDavid du Colombier 			d->h &= ~((1<<(FractBits-e))-1);
158154abd99SDavid du Colombier 	}
159154abd99SDavid du Colombier }
160154abd99SDavid du Colombier 
161154abd99SDavid du Colombier static	FP1	optab1[16] = {	/* Fd := OP Fm */
162154abd99SDavid du Colombier [0]	{"MOVF",	fmov},
163154abd99SDavid du Colombier [1]	{"NEGF",	fmovn},
164154abd99SDavid du Colombier [2]	{"ABSF",	fabsf},
165154abd99SDavid du Colombier [3]	{"RNDF",	frnd},
166154abd99SDavid du Colombier [4]	{"SQTF",	/*fsqt*/0},
167154abd99SDavid du Colombier /* LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN all `deprecated' */
168154abd99SDavid du Colombier /* URD and NRM aren't implemented */
169154abd99SDavid du Colombier };
170154abd99SDavid du Colombier 
171154abd99SDavid du Colombier static	FP2	optab2[16] = {	/* Fd := Fn OP Fm */
172154abd99SDavid du Colombier [0]	{"ADDF",	fadd},
173154abd99SDavid du Colombier [1]	{"MULF",	fmul},
174154abd99SDavid du Colombier [2]	{"SUBF",	fsub},
175154abd99SDavid du Colombier [3]	{"RSUBF",	fsubr},
176154abd99SDavid du Colombier [4]	{"DIVF",	fdiv},
177154abd99SDavid du Colombier [5]	{"RDIVF",	fdivr},
178154abd99SDavid du Colombier /* POW, RPW deprecated */
179154abd99SDavid du Colombier [8]	{"REMF",	/*frem*/0},
180154abd99SDavid du Colombier [9]	{"FMF",	fmul},	/* fast multiply */
181154abd99SDavid du Colombier [10]	{"FDV",	fdiv},	/* fast divide */
182154abd99SDavid du Colombier [11]	{"FRD",	fdivr},	/* fast reverse divide */
183154abd99SDavid du Colombier /* POL deprecated */
184154abd99SDavid du Colombier };
185154abd99SDavid du Colombier 
186154abd99SDavid du Colombier static ulong
fcmp(Internal * n,Internal * m)187154abd99SDavid du Colombier fcmp(Internal *n, Internal *m)
188154abd99SDavid du Colombier {
189154abd99SDavid du Colombier 	int i;
190154abd99SDavid du Colombier 	Internal rm, rn;
191154abd99SDavid du Colombier 
192154abd99SDavid du Colombier 	if(IsWeird(m) || IsWeird(n)){
193154abd99SDavid du Colombier 		/* BUG: should trap if not masked */
194154abd99SDavid du Colombier 		return V|C;
195154abd99SDavid du Colombier 	}
196154abd99SDavid du Colombier 	rn = *n;
197154abd99SDavid du Colombier 	rm = *m;
198154abd99SDavid du Colombier 	fpiround(&rn);
199154abd99SDavid du Colombier 	fpiround(&rm);
200154abd99SDavid du Colombier 	i = fpicmp(&rn, &rm);
201154abd99SDavid du Colombier 	if(i > 0)
202154abd99SDavid du Colombier 		return C;
203154abd99SDavid du Colombier 	else if(i == 0)
204154abd99SDavid du Colombier 		return C|Z;
205154abd99SDavid du Colombier 	else
206154abd99SDavid du Colombier 		return N;
207154abd99SDavid du Colombier }
208154abd99SDavid du Colombier 
209154abd99SDavid du Colombier static void
fld(void (* f)(Internal *,void *),int d,ulong ea,int n,FPsave * ufp)21048bb54a3SDavid du Colombier fld(void (*f)(Internal*, void*), int d, ulong ea, int n, FPsave *ufp)
211154abd99SDavid du Colombier {
212154abd99SDavid du Colombier 	void *mem;
213154abd99SDavid du Colombier 
214154abd99SDavid du Colombier 	mem = (void*)ea;
215154abd99SDavid du Colombier 	(*f)(&FR(ufp, d), mem);
216154abd99SDavid du Colombier 	if(fpemudebug)
217154abd99SDavid du Colombier 		print("MOV%c #%lux, F%d\n", n==8? 'D': 'F', ea, d);
218154abd99SDavid du Colombier }
219154abd99SDavid du Colombier 
220154abd99SDavid du Colombier static void
fst(void (* f)(void *,Internal *),ulong ea,int s,int n,FPsave * ufp)22148bb54a3SDavid du Colombier fst(void (*f)(void*, Internal*), ulong ea, int s, int n, FPsave *ufp)
222154abd99SDavid du Colombier {
223154abd99SDavid du Colombier 	Internal tmp;
224154abd99SDavid du Colombier 	void *mem;
225154abd99SDavid du Colombier 
226154abd99SDavid du Colombier 	mem = (void*)ea;
227154abd99SDavid du Colombier 	tmp = FR(ufp, s);
228154abd99SDavid du Colombier 	if(fpemudebug)
229154abd99SDavid du Colombier 		print("MOV%c	F%d,#%lux\n", n==8? 'D': 'F', s, ea);
230154abd99SDavid du Colombier 	(*f)(mem, &tmp);
231154abd99SDavid du Colombier }
232154abd99SDavid du Colombier 
233154abd99SDavid du Colombier static int
condok(int cc,int c)234154abd99SDavid du Colombier condok(int cc, int c)
235154abd99SDavid du Colombier {
236154abd99SDavid du Colombier 	switch(c){
237154abd99SDavid du Colombier 	case 0:	/* Z set */
238154abd99SDavid du Colombier 		return cc&Z;
239154abd99SDavid du Colombier 	case 1:	/* Z clear */
240154abd99SDavid du Colombier 		return (cc&Z) == 0;
241154abd99SDavid du Colombier 	case 2:	/* C set */
242154abd99SDavid du Colombier 		return cc&C;
243154abd99SDavid du Colombier 	case 3:	/* C clear */
244154abd99SDavid du Colombier 		return (cc&C) == 0;
245154abd99SDavid du Colombier 	case 4:	/* N set */
246154abd99SDavid du Colombier 		return cc&N;
247154abd99SDavid du Colombier 	case 5:	/* N clear */
248154abd99SDavid du Colombier 		return (cc&N) == 0;
249154abd99SDavid du Colombier 	case 6:	/* V set */
250154abd99SDavid du Colombier 		return cc&V;
251154abd99SDavid du Colombier 	case 7:	/* V clear */
252154abd99SDavid du Colombier 		return (cc&V) == 0;
253154abd99SDavid du Colombier 	case 8:	/* C set and Z clear */
254154abd99SDavid du Colombier 		return cc&C && (cc&Z) == 0;
255154abd99SDavid du Colombier 	case 9:	/* C clear or Z set */
256154abd99SDavid du Colombier 		return (cc&C) == 0 || cc&Z;
257154abd99SDavid du Colombier 	case 10:	/* N set and V set, or N clear and V clear */
258154abd99SDavid du Colombier 		return (~cc&(N|V))==0 || (cc&(N|V)) == 0;
259154abd99SDavid du Colombier 	case 11:	/* N set and V clear, or N clear and V set */
260154abd99SDavid du Colombier 		return (cc&(N|V))==N || (cc&(N|V))==V;
261154abd99SDavid du Colombier 	case 12:	/* Z clear, and either N set and V set or N clear and V clear */
262154abd99SDavid du Colombier 		return (cc&Z) == 0 && ((~cc&(N|V))==0 || (cc&(N|V))==0);
263154abd99SDavid du Colombier 	case 13:	/* Z set, or N set and V clear or N clear and V set */
264154abd99SDavid du Colombier 		return (cc&Z) || (cc&(N|V))==N || (cc&(N|V))==V;
265154abd99SDavid du Colombier 	case 14:	/* always */
266154abd99SDavid du Colombier 		return 1;
267154abd99SDavid du Colombier 	case 15:	/* never (reserved) */
268154abd99SDavid du Colombier 		return 0;
269154abd99SDavid du Colombier 	}
270154abd99SDavid du Colombier 	return 0;	/* not reached */
271154abd99SDavid du Colombier }
272154abd99SDavid du Colombier 
273154abd99SDavid du Colombier static void
unimp(ulong pc,ulong op)274154abd99SDavid du Colombier unimp(ulong pc, ulong op)
275154abd99SDavid du Colombier {
276154abd99SDavid du Colombier 	char buf[60];
277154abd99SDavid du Colombier 
278154abd99SDavid du Colombier 	snprint(buf, sizeof(buf), "sys: fp: pc=%lux unimp fp 0x%.8lux", pc, op);
279154abd99SDavid du Colombier 	if(fpemudebug)
280154abd99SDavid du Colombier 		print("FPE: %s\n", buf);
281154abd99SDavid du Colombier 	error(buf);
282154abd99SDavid du Colombier 	/* no return */
283154abd99SDavid du Colombier }
284154abd99SDavid du Colombier 
285154abd99SDavid du Colombier static void
fpemu(ulong pc,ulong op,Ureg * ur,FPsave * ufp)28648bb54a3SDavid du Colombier fpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
287154abd99SDavid du Colombier {
288154abd99SDavid du Colombier 	int rn, rd, tag, o;
289154abd99SDavid du Colombier 	long off;
290154abd99SDavid du Colombier 	ulong ea;
291154abd99SDavid du Colombier 	Internal tmp, *fm, *fn;
292154abd99SDavid du Colombier 
293154abd99SDavid du Colombier 	/* note: would update fault status here if we noted numeric exceptions */
294154abd99SDavid du Colombier 
295154abd99SDavid du Colombier 	/*
296154abd99SDavid du Colombier 	 * LDF, STF; 10.1.1
297154abd99SDavid du Colombier 	 */
298154abd99SDavid du Colombier 	if(((op>>25)&7) == 6){
299154abd99SDavid du Colombier 		if(op & (1<<22))
300154abd99SDavid du Colombier 			unimp(pc, op);	/* packed or extended */
301154abd99SDavid du Colombier 		rn = (op>>16)&0xF;
302154abd99SDavid du Colombier 		off = (op&0xFF)<<2;
303154abd99SDavid du Colombier 		if((op & (1<<23)) == 0)
304154abd99SDavid du Colombier 			off = -off;
305154abd99SDavid du Colombier 		ea = REG(ur, rn);
306154abd99SDavid du Colombier 		if(rn == REGPC)
307154abd99SDavid du Colombier 			ea += 8;
308154abd99SDavid du Colombier 		if(op & (1<<24))
309154abd99SDavid du Colombier 			ea += off;
310154abd99SDavid du Colombier 		rd = (op>>12)&7;
311154abd99SDavid du Colombier 		if(op & (1<<20)){
312154abd99SDavid du Colombier 			if(op & (1<<15))
313154abd99SDavid du Colombier 				fld(fpid2i, rd, ea, 8, ufp);
314154abd99SDavid du Colombier 			else
315154abd99SDavid du Colombier 				fld(fpis2i, rd, ea, 4, ufp);
316154abd99SDavid du Colombier 		}else{
317154abd99SDavid du Colombier 			if(op & (1<<15))
318154abd99SDavid du Colombier 				fst(fpii2d, ea, rd, 8, ufp);
319154abd99SDavid du Colombier 			else
320154abd99SDavid du Colombier 				fst(fpii2s, ea, rd, 4, ufp);
321154abd99SDavid du Colombier 		}
322154abd99SDavid du Colombier 		if((op & (1<<24)) == 0)
323154abd99SDavid du Colombier 			ea += off;
324154abd99SDavid du Colombier 		if(op & (1<<21))
325154abd99SDavid du Colombier 			REG(ur, rn) = ea;
326154abd99SDavid du Colombier 		return;
327154abd99SDavid du Colombier 	}
328154abd99SDavid du Colombier 
329154abd99SDavid du Colombier 	/*
330154abd99SDavid du Colombier 	 * CPRT/transfer, 10.3
331154abd99SDavid du Colombier 	 */
332154abd99SDavid du Colombier 	if(op & (1<<4)){
333154abd99SDavid du Colombier 		rd = (op>>12) & 0xF;
334154abd99SDavid du Colombier 
335154abd99SDavid du Colombier 		/*
336154abd99SDavid du Colombier 		 * compare, 10.3.1
337154abd99SDavid du Colombier 		 */
338154abd99SDavid du Colombier 		if(rd == 15 && op & (1<<20)){
339154abd99SDavid du Colombier 			rn = (op>>16)&7;
340154abd99SDavid du Colombier 			fn = &FR(ufp, rn);
341154abd99SDavid du Colombier 			if(op & (1<<3)){
342154abd99SDavid du Colombier 				fm = &fpconst[op&7];
343154abd99SDavid du Colombier 				if(fpemudebug)
344154abd99SDavid du Colombier 					tag = 'C';
345154abd99SDavid du Colombier 			}else{
346154abd99SDavid du Colombier 				fm = &FR(ufp, op&7);
347154abd99SDavid du Colombier 				if(fpemudebug)
348154abd99SDavid du Colombier 					tag = 'F';
349154abd99SDavid du Colombier 			}
350154abd99SDavid du Colombier 			switch((op>>21)&7){
351154abd99SDavid du Colombier 			default:
352154abd99SDavid du Colombier 				unimp(pc, op);
353154abd99SDavid du Colombier 			case 4:	/* CMF: Fn :: Fm */
354154abd99SDavid du Colombier 			case 6:	/* CMFE: Fn :: Fm (with exception) */
355154abd99SDavid du Colombier 				ur->psr &= ~(N|C|Z|V);
356154abd99SDavid du Colombier 				ur->psr |= fcmp(fn, fm);
357154abd99SDavid du Colombier 				break;
358154abd99SDavid du Colombier 			case 5:	/* CNF: Fn :: -Fm */
359154abd99SDavid du Colombier 			case 7:	/* CNFE: Fn :: -Fm (with exception) */
360154abd99SDavid du Colombier 				tmp = *fm;
361154abd99SDavid du Colombier 				tmp.s ^= 1;
362154abd99SDavid du Colombier 				ur->psr &= ~(N|C|Z|V);
363154abd99SDavid du Colombier 				ur->psr |= fcmp(fn, &tmp);
364154abd99SDavid du Colombier 				break;
365154abd99SDavid du Colombier 			}
366154abd99SDavid du Colombier 			if(fpemudebug)
3677bb09086SDavid du Colombier 				print("CMPF	%c%d,F%ld =%#lux\n",
368154abd99SDavid du Colombier 					tag, rn, op&7, ur->psr>>28);
369154abd99SDavid du Colombier 			return;
370154abd99SDavid du Colombier 		}
371154abd99SDavid du Colombier 
372154abd99SDavid du Colombier 		/*
373154abd99SDavid du Colombier 		 * other transfer, 10.3
374154abd99SDavid du Colombier 		 */
375154abd99SDavid du Colombier 		switch((op>>20)&0xF){
376154abd99SDavid du Colombier 		default:
377154abd99SDavid du Colombier 			unimp(pc, op);
378154abd99SDavid du Colombier 		case 0:	/* FLT */
379154abd99SDavid du Colombier 			rn = (op>>16) & 7;
380154abd99SDavid du Colombier 			fpiw2i(&FR(ufp, rn), &REG(ur, rd));
381154abd99SDavid du Colombier 			if(fpemudebug)
382154abd99SDavid du Colombier 				print("MOVW[FD]	R%d, F%d\n", rd, rn);
383154abd99SDavid du Colombier 			break;
384154abd99SDavid du Colombier 		case 1:	/* FIX */
385154abd99SDavid du Colombier 			if(op & (1<<3))
386154abd99SDavid du Colombier 				unimp(pc, op);
387154abd99SDavid du Colombier 			rn = op & 7;
388154abd99SDavid du Colombier 			tmp = FR(ufp, rn);
389154abd99SDavid du Colombier 			fpii2w(&REG(ur, rd), &tmp);
390154abd99SDavid du Colombier 			if(fpemudebug)
391154abd99SDavid du Colombier 				print("MOV[FD]W	F%d, R%d =%ld\n", rn, rd, REG(ur, rd));
392154abd99SDavid du Colombier 			break;
393154abd99SDavid du Colombier 		case 2:	/* FPSR := Rd */
394154abd99SDavid du Colombier 			ufp->status = REG(ur, rd);
395154abd99SDavid du Colombier 			if(fpemudebug)
396154abd99SDavid du Colombier 				print("MOVW	R%d, FPSR\n", rd);
397154abd99SDavid du Colombier 			break;
398154abd99SDavid du Colombier 		case 3:	/* Rd := FPSR */
399154abd99SDavid du Colombier 			REG(ur, rd) = ufp->status;
400154abd99SDavid du Colombier 			if(fpemudebug)
401154abd99SDavid du Colombier 				print("MOVW	FPSR, R%d\n", rd);
402154abd99SDavid du Colombier 			break;
403154abd99SDavid du Colombier 		case 4:	/* FPCR := Rd */
404154abd99SDavid du Colombier 			ufp->control = REG(ur, rd);
405154abd99SDavid du Colombier 			if(fpemudebug)
406154abd99SDavid du Colombier 				print("MOVW	R%d, FPCR\n", rd);
407154abd99SDavid du Colombier 			break;
408154abd99SDavid du Colombier 		case 5:	/* Rd := FPCR */
409154abd99SDavid du Colombier 			REG(ur, rd) = ufp->control;
410154abd99SDavid du Colombier 			if(fpemudebug)
411154abd99SDavid du Colombier 				print("MOVW	FPCR, R%d\n", rd);
412154abd99SDavid du Colombier 			break;
413154abd99SDavid du Colombier 		}
414154abd99SDavid du Colombier 		return;
415154abd99SDavid du Colombier 	}
416154abd99SDavid du Colombier 
417154abd99SDavid du Colombier 	/*
418154abd99SDavid du Colombier 	 * arithmetic
419154abd99SDavid du Colombier 	 */
420154abd99SDavid du Colombier 
421154abd99SDavid du Colombier 	if(op & (1<<3)){	/* constant */
422154abd99SDavid du Colombier 		fm = &fpconst[op&7];
423154abd99SDavid du Colombier 		if(fpemudebug)
424154abd99SDavid du Colombier 			tag = 'C';
425154abd99SDavid du Colombier 	}else{
426154abd99SDavid du Colombier 		fm = &FR(ufp, op&7);
427154abd99SDavid du Colombier 		if(fpemudebug)
428154abd99SDavid du Colombier 			tag = 'F';
429154abd99SDavid du Colombier 	}
430154abd99SDavid du Colombier 	rd = (op>>12)&7;
431154abd99SDavid du Colombier 	o = (op>>20)&0xF;
432154abd99SDavid du Colombier 	if(op & (1<<15)){	/* monadic */
433154abd99SDavid du Colombier 		FP1 *fp;
434154abd99SDavid du Colombier 		fp = &optab1[o];
435154abd99SDavid du Colombier 		if(fp->f == nil)
436154abd99SDavid du Colombier 			unimp(pc, op);
437154abd99SDavid du Colombier 		if(fpemudebug)
438154abd99SDavid du Colombier 			print("%s	%c%ld,F%d\n", fp->name, tag, op&7, rd);
439154abd99SDavid du Colombier 		(*fp->f)(fm, &FR(ufp, rd));
440154abd99SDavid du Colombier 	} else {
441154abd99SDavid du Colombier 		FP2 *fp;
442154abd99SDavid du Colombier 		fp = &optab2[o];
443154abd99SDavid du Colombier 		if(fp->f == nil)
444154abd99SDavid du Colombier 			unimp(pc, op);
445154abd99SDavid du Colombier 		rn = (op>>16)&7;
446154abd99SDavid du Colombier 		if(fpemudebug)
447154abd99SDavid du Colombier 			print("%s	%c%ld,F%d,F%d\n", fp->name, tag, op&7, rn, rd);
448154abd99SDavid du Colombier 		(*fp->f)(*fm, FR(ufp, rn), &FR(ufp, rd));
449154abd99SDavid du Colombier 	}
450154abd99SDavid du Colombier }
451154abd99SDavid du Colombier 
452154abd99SDavid du Colombier void
casemu(ulong pc,ulong op,Ureg * ur)453154abd99SDavid du Colombier casemu(ulong pc, ulong op, Ureg *ur)
454154abd99SDavid du Colombier {
455154abd99SDavid du Colombier 	ulong *rp, ro, rn, *rd;
456154abd99SDavid du Colombier 
457154abd99SDavid du Colombier 	USED(pc);
458154abd99SDavid du Colombier 
459154abd99SDavid du Colombier 	rp = (ulong*)ur;
460154abd99SDavid du Colombier 	ro = rp[op>>16 & 0x7];
461154abd99SDavid du Colombier 	rn = rp[op>>0 & 0x7];
462154abd99SDavid du Colombier 	rd = rp + (op>>12 & 0x7);
463154abd99SDavid du Colombier 	rp = (ulong*)*rd;
464154abd99SDavid du Colombier 	validaddr((ulong)rp, 4, 1);
465154abd99SDavid du Colombier 	splhi();
466154abd99SDavid du Colombier 	if(*rd = (*rp == ro))
467154abd99SDavid du Colombier 		*rp = rn;
468154abd99SDavid du Colombier 	spllo();
469154abd99SDavid du Colombier }
470154abd99SDavid du Colombier 
471154abd99SDavid du Colombier int ldrexvalid;
472154abd99SDavid du Colombier 
473154abd99SDavid du Colombier void
ldrex(ulong pc,ulong op,Ureg * ur)474154abd99SDavid du Colombier ldrex(ulong pc, ulong op, Ureg *ur)
475154abd99SDavid du Colombier {
476154abd99SDavid du Colombier 	ulong *rp, *rd, *addr;
477154abd99SDavid du Colombier 
478154abd99SDavid du Colombier 	USED(pc);
479154abd99SDavid du Colombier 
480154abd99SDavid du Colombier 	rp = (ulong*)ur;
481154abd99SDavid du Colombier 	rd = rp + (op>>16 & 0x7);
482154abd99SDavid du Colombier 	addr = (ulong*)*rd;
483154abd99SDavid du Colombier 	validaddr((ulong)addr, 4, 0);
484154abd99SDavid du Colombier 	ldrexvalid = 1;
485154abd99SDavid du Colombier 	rp[op>>12 & 0x7] = *addr;
486154abd99SDavid du Colombier 	if(fpemudebug)
487154abd99SDavid du Colombier 		print("ldrex, r%ld = [r%ld]@0x%8.8p = 0x%8.8lux",
488154abd99SDavid du Colombier 			op>>12 & 0x7, op>>16 & 0x7, addr, rp[op>>12 & 0x7]);
489154abd99SDavid du Colombier }
490154abd99SDavid du Colombier 
491154abd99SDavid 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)500154abd99SDavid du Colombier strex(ulong pc, ulong op, Ureg *ur)
501154abd99SDavid du Colombier {
502154abd99SDavid du Colombier 	ulong *rp, rn, *rd, *addr;
503154abd99SDavid du Colombier 
504154abd99SDavid du Colombier 	USED(pc);
505154abd99SDavid du Colombier 
506154abd99SDavid du Colombier 	rp = (ulong*)ur;
507154abd99SDavid du Colombier 	rd = rp + (op>>16 & 0x7);
508154abd99SDavid du Colombier 	rn = rp[op>>0 & 0x7];
509154abd99SDavid du Colombier 	addr = (ulong*)*rd;
510154abd99SDavid du Colombier 	validaddr((ulong)addr, 4, 1);
511154abd99SDavid du Colombier 	splhi();
512154abd99SDavid du Colombier 	if(ldrexvalid){
513154abd99SDavid du Colombier 		if(fpemudebug)
514154abd99SDavid du Colombier 			print("strex valid, [r%ld]@0x%8.8p = r%ld = 0x%8.8lux",
515154abd99SDavid du Colombier 				op>>16 & 0x7, addr, op>>0 & 0x7, rn);
516154abd99SDavid du Colombier 		*addr = rn;
517154abd99SDavid du Colombier 		ldrexvalid = 0;
518154abd99SDavid du Colombier 		rp[op>>12 & 0x7] = 0;
519154abd99SDavid du Colombier 	}else{
520154abd99SDavid du Colombier 		if(fpemudebug)
521154abd99SDavid du Colombier 			print("strex invalid, r%ld = 1", op>>16 & 0x7);
522154abd99SDavid du Colombier 		rp[op>>12 & 0x7] = 1;
523154abd99SDavid du Colombier 	}
524154abd99SDavid du Colombier 	spllo();
525154abd99SDavid du Colombier }
526154abd99SDavid du Colombier 
527154abd99SDavid du Colombier struct {
528154abd99SDavid du Colombier 	ulong	opc;
529154abd99SDavid du Colombier 	ulong	mask;
530154abd99SDavid du Colombier 	void	(*f)(ulong, ulong, Ureg*);
531154abd99SDavid du Colombier } specialopc[] = {
532154abd99SDavid du Colombier 	{ 0x01900f9f, 0x0ff00fff, ldrex },
533154abd99SDavid du Colombier 	{ 0x01800f90, 0x0ff00ff0, strex },
5340f53e541SDavid du Colombier 	{ 0xf57ff01f, 0xffffffff, clrex },
535154abd99SDavid du Colombier 	{ 0x0ed00100, 0x0ef08100, casemu },
536154abd99SDavid du Colombier 	{ 0x00000000, 0x00000000, nil }
537154abd99SDavid du Colombier };
538154abd99SDavid du Colombier 
539154abd99SDavid du Colombier /*
540154abd99SDavid du Colombier  * returns the number of FP instructions emulated
541154abd99SDavid du Colombier  */
542154abd99SDavid du Colombier int
fpiarm(Ureg * ur)543154abd99SDavid du Colombier fpiarm(Ureg *ur)
544154abd99SDavid du Colombier {
545154abd99SDavid du Colombier 	ulong op, o;
54648bb54a3SDavid du Colombier 	FPsave *ufp;
547154abd99SDavid du Colombier 	int i, n;
548154abd99SDavid du Colombier 
549154abd99SDavid du Colombier 	if(up == nil)
550154abd99SDavid du Colombier 		panic("fpiarm not in a process");
55148bb54a3SDavid du Colombier 	ufp = &up->fpsave;
552154abd99SDavid du Colombier 	/* because all the state is in the proc structure,
553154abd99SDavid du Colombier 	 * it need not be saved/restored
554154abd99SDavid du Colombier 	 */
555154abd99SDavid du Colombier 	if(up->fpstate != FPactive){
556154abd99SDavid du Colombier //		assert(sizeof(Internal) == sizeof(ufp->regs[0]));
557154abd99SDavid du Colombier 		up->fpstate = FPactive;
558154abd99SDavid du Colombier 		ufp->control = 0;
559154abd99SDavid du Colombier 		ufp->status = (0x01<<28)|(1<<12);	/* software emulation, alternative C flag */
560154abd99SDavid du Colombier 		for(n = 0; n < 8; n++)
561154abd99SDavid du Colombier 			FR(ufp, n) = fpconst[0];
562154abd99SDavid du Colombier 	}
563154abd99SDavid du Colombier 	for(n=0; ;n++){
564154abd99SDavid du Colombier 		validaddr(ur->pc, 4, 0);
565154abd99SDavid du Colombier 		op = *(ulong*)(ur->pc);
566154abd99SDavid du Colombier 		if(fpemudebug)
5677bb09086SDavid du Colombier 			print("%#lux: %#8.8lux ", ur->pc, op);
568154abd99SDavid du Colombier 		o = (op>>24) & 0xF;
569154abd99SDavid du Colombier 		if(condok(ur->psr, op>>28)){
570154abd99SDavid du Colombier 			for(i = 0; specialopc[i].f; i++)
571154abd99SDavid du Colombier 				if((op & specialopc[i].mask) == specialopc[i].opc)
572154abd99SDavid du Colombier 					break;
573154abd99SDavid du Colombier 			if(specialopc[i].f)
574154abd99SDavid du Colombier 				specialopc[i].f(ur->pc, op, ur);
575154abd99SDavid du Colombier 			else if((op & 0xF00) != 0x100 || o != 0xE && (o&~1) != 0xC)
576154abd99SDavid du Colombier 				break;
577154abd99SDavid du Colombier 			else
578154abd99SDavid du Colombier 				fpemu(ur->pc, op, ur, ufp);
579154abd99SDavid du Colombier 		}else if((op & 0xF00) != 0x100 || o != 0xE && (o&~1) != 0xC)
580154abd99SDavid du Colombier 			break;
581154abd99SDavid du Colombier 		ur->pc += 4;
582154abd99SDavid du Colombier 	}
583154abd99SDavid du Colombier 	if(fpemudebug) print("\n");
584154abd99SDavid du Colombier 	return n;
585154abd99SDavid du Colombier }
586