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), ®(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(®(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