]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/omap/fpiarm.c
kernel: dont use atomic increment for Proc.nlocks, maintain Lock.m for lock(), use...
[plan9front.git] / sys / src / 9 / omap / fpiarm.c
1 /*
2  * this doesn't attempt to implement ARM floating-point properties
3  * that aren't visible in the Inferno environment.
4  * all arithmetic is done in double precision.
5  * the FP trap status isn't updated.
6  */
7 #include        "u.h"
8 #include        "../port/lib.h"
9 #include        "mem.h"
10 #include        "dat.h"
11 #include        "fns.h"
12
13 #include        "ureg.h"
14
15 #include        "arm.h"
16 #include        "fpi.h"
17
18 /* undef this if correct kernel r13 isn't in Ureg;
19  * check calculation in fpiarm below
20  */
21 #define REG(ur, x) (*(long*)(((char*)(ur))+roff[(x)]))
22 #define FR(ufp, x) (*(Internal*)(ufp)->regs[(x)&(Nfpctlregs - 1)])
23
24 typedef struct FP2 FP2;
25 typedef struct FP1 FP1;
26
27 struct FP2 {
28         char*   name;
29         void    (*f)(Internal, Internal, Internal*);
30 };
31
32 struct FP1 {
33         char*   name;
34         void    (*f)(Internal*, Internal*);
35 };
36
37 enum {
38         N = 1<<31,
39         Z = 1<<30,
40         C = 1<<29,
41         V = 1<<28,
42         REGPC = 15,
43 };
44
45 enum {
46         fpemudebug = 0,
47 };
48
49 #undef OFR
50 #define OFR(X)  ((ulong)&((Ureg*)0)->X)
51
52 static  int     roff[] = {
53         OFR(r0), OFR(r1), OFR(r2), OFR(r3),
54         OFR(r4), OFR(r5), OFR(r6), OFR(r7),
55         OFR(r8), OFR(r9), OFR(r10), OFR(r11),
56         OFR(r12), OFR(r13), OFR(r14), OFR(pc),
57 };
58
59 static Internal fpconst[8] = {          /* indexed by op&7 (ARM 7500 FPA) */
60         /* s, e, l, h */
61         {0, 0x1, 0x00000000, 0x00000000}, /* 0.0 */
62         {0, 0x3FF, 0x00000000, 0x08000000},     /* 1.0 */
63         {0, 0x400, 0x00000000, 0x08000000},     /* 2.0 */
64         {0, 0x400, 0x00000000, 0x0C000000},     /* 3.0 */
65         {0, 0x401, 0x00000000, 0x08000000},     /* 4.0 */
66         {0, 0x401, 0x00000000, 0x0A000000},     /* 5.0 */
67         {0, 0x3FE, 0x00000000, 0x08000000},     /* 0.5 */
68         {0, 0x402, 0x00000000, 0x0A000000},     /* 10.0 */
69 };
70
71 /*
72  * arm binary operations
73  */
74
75 static void
76 fadd(Internal m, Internal n, Internal *d)
77 {
78         (m.s == n.s? fpiadd: fpisub)(&m, &n, d);
79 }
80
81 static void
82 fsub(Internal m, Internal n, Internal *d)
83 {
84         m.s ^= 1;
85         (m.s == n.s? fpiadd: fpisub)(&m, &n, d);
86 }
87
88 static void
89 fsubr(Internal m, Internal n, Internal *d)
90 {
91         n.s ^= 1;
92         (n.s == m.s? fpiadd: fpisub)(&n, &m, d);
93 }
94
95 static void
96 fmul(Internal m, Internal n, Internal *d)
97 {
98         fpimul(&m, &n, d);
99 }
100
101 static void
102 fdiv(Internal m, Internal n, Internal *d)
103 {
104         fpidiv(&m, &n, d);
105 }
106
107 static void
108 fdivr(Internal m, Internal n, Internal *d)
109 {
110         fpidiv(&n, &m, d);
111 }
112
113 /*
114  * arm unary operations
115  */
116
117 static void
118 fmov(Internal *m, Internal *d)
119 {
120         *d = *m;
121 }
122
123 static void
124 fmovn(Internal *m, Internal *d)
125 {
126         *d = *m;
127         d->s ^= 1;
128 }
129
130 static void
131 fabsf(Internal *m, Internal *d)
132 {
133         *d = *m;
134         d->s = 0;
135 }
136
137 static void
138 frnd(Internal *m, Internal *d)
139 {
140         short e;
141
142         (m->s? fsub: fadd)(fpconst[6], *m, d);
143         if(IsWeird(d))
144                 return;
145         fpiround(d);
146         e = (d->e - ExpBias) + 1;
147         if(e <= 0)
148                 SetZero(d);
149         else if(e > FractBits){
150                 if(e < 2*FractBits)
151                         d->l &= ~((1<<(2*FractBits - e))-1);
152         }else{
153                 d->l = 0;
154                 if(e < FractBits)
155                         d->h &= ~((1<<(FractBits-e))-1);
156         }
157 }
158
159 /*
160  * ARM 7500 FPA opcodes
161  */
162
163 static  FP1     optab1[16] = {  /* Fd := OP Fm */
164 [0]     {"MOVF",        fmov},
165 [1]     {"NEGF",        fmovn},
166 [2]     {"ABSF",        fabsf},
167 [3]     {"RNDF",        frnd},
168 [4]     {"SQTF",        /*fsqt*/0},
169 /* LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN all `deprecated' */
170 /* URD and NRM aren't implemented */
171 };
172
173 static  FP2     optab2[16] = {  /* Fd := Fn OP Fm */
174 [0]     {"ADDF",        fadd},
175 [1]     {"MULF",        fmul},
176 [2]     {"SUBF",        fsub},
177 [3]     {"RSUBF",       fsubr},
178 [4]     {"DIVF",        fdiv},
179 [5]     {"RDIVF",       fdivr},
180 /* POW, RPW deprecated */
181 [8]     {"REMF",        /*frem*/0},
182 [9]     {"FMF", fmul},  /* fast multiply */
183 [10]    {"FDV", fdiv},  /* fast divide */
184 [11]    {"FRD", fdivr}, /* fast reverse divide */
185 /* POL deprecated */
186 };
187
188 /*
189  * ARM VFP opcodes
190  */
191
192 static  FP1     voptab1[32] = { /* Vd := OP Vm */
193 [0]     {"MOVF",        fmov},
194 [1]     {"ABSF",        fabsf},
195 [2]     {"NEGF",        fmovn},
196 [15]    {"CVTF",        fmov},
197 };
198
199 static  FP2     voptab2[16] = { /* Vd := Vn FOP Fm */
200 [4]     {"MULF",        fmul},
201 [6]     {"ADDF",        fadd},
202 [7]     {"SUBF",        fsub},
203 [8]     {"DIVF",        fdiv},
204 };
205
206 static ulong
207 fcmp(Internal *n, Internal *m)
208 {
209         int i;
210         Internal rm, rn;
211
212         if(IsWeird(m) || IsWeird(n)){
213                 /* BUG: should trap if not masked */
214                 return V|C;
215         }
216         rn = *n;
217         rm = *m;
218         fpiround(&rn);
219         fpiround(&rm);
220         i = fpicmp(&rn, &rm);
221         if(i > 0)
222                 return C;
223         else if(i == 0)
224                 return C|Z;
225         else
226                 return N;
227 }
228
229 static void
230 fld(void (*f)(Internal*, void*), int d, ulong ea, int n, FPsave *ufp)
231 {
232         void *mem;
233
234         mem = (void*)ea;
235         (*f)(&FR(ufp, d), mem);
236         if(fpemudebug)
237                 print("MOV%c #%lux, F%d\n", n==8? 'D': 'F', ea, d);
238 }
239
240 static void
241 fst(void (*f)(void*, Internal*), ulong ea, int s, int n, FPsave *ufp)
242 {
243         Internal tmp;
244         void *mem;
245
246         mem = (void*)ea;
247         tmp = FR(ufp, s);
248         if(fpemudebug)
249                 print("MOV%c    F%d,#%lux\n", n==8? 'D': 'F', s, ea);
250         (*f)(mem, &tmp);
251 }
252
253 static int
254 condok(int cc, int c)
255 {
256         switch(c){
257         case 0: /* Z set */
258                 return cc&Z;
259         case 1: /* Z clear */
260                 return (cc&Z) == 0;
261         case 2: /* C set */
262                 return cc&C;
263         case 3: /* C clear */
264                 return (cc&C) == 0;
265         case 4: /* N set */
266                 return cc&N;
267         case 5: /* N clear */
268                 return (cc&N) == 0;
269         case 6: /* V set */
270                 return cc&V;
271         case 7: /* V clear */
272                 return (cc&V) == 0;
273         case 8: /* C set and Z clear */
274                 return cc&C && (cc&Z) == 0;
275         case 9: /* C clear or Z set */
276                 return (cc&C) == 0 || cc&Z;
277         case 10:        /* N set and V set, or N clear and V clear */
278                 return (~cc&(N|V))==0 || (cc&(N|V)) == 0;
279         case 11:        /* N set and V clear, or N clear and V set */
280                 return (cc&(N|V))==N || (cc&(N|V))==V;
281         case 12:        /* Z clear, and either N set and V set or N clear and V clear */
282                 return (cc&Z) == 0 && ((~cc&(N|V))==0 || (cc&(N|V))==0);
283         case 13:        /* Z set, or N set and V clear or N clear and V set */
284                 return (cc&Z) || (cc&(N|V))==N || (cc&(N|V))==V;
285         case 14:        /* always */
286                 return 1;
287         case 15:        /* never (reserved) */
288                 return 0;
289         }
290         return 0;       /* not reached */
291 }
292
293 static void
294 unimp(ulong pc, ulong op)
295 {
296         char buf[60];
297
298         snprint(buf, sizeof(buf), "sys: fp: pc=%lux unimp fp 0x%.8lux", pc, op);
299         if(fpemudebug)
300                 print("FPE: %s\n", buf);
301         error(buf);
302         /* no return */
303 }
304
305 static void
306 fpaemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
307 {
308         int rn, rd, tag, o;
309         long off;
310         ulong ea;
311         Internal tmp, *fm, *fn;
312
313         /* note: would update fault status here if we noted numeric exceptions */
314
315         /*
316          * LDF, STF; 10.1.1
317          */
318         if(((op>>25)&7) == 6){
319                 if(op & (1<<22))
320                         unimp(pc, op);  /* packed or extended */
321                 rn = (op>>16)&0xF;
322                 off = (op&0xFF)<<2;
323                 if((op & (1<<23)) == 0)
324                         off = -off;
325                 ea = REG(ur, rn);
326                 if(rn == REGPC)
327                         ea += 8;
328                 if(op & (1<<24))
329                         ea += off;
330                 rd = (op>>12)&7;
331                 if(op & (1<<20)){
332                         if(op & (1<<15))
333                                 fld(fpid2i, rd, ea, 8, ufp);
334                         else
335                                 fld(fpis2i, rd, ea, 4, ufp);
336                 }else{
337                         if(op & (1<<15))
338                                 fst(fpii2d, ea, rd, 8, ufp);
339                         else
340                                 fst(fpii2s, ea, rd, 4, ufp);
341                 }
342                 if((op & (1<<24)) == 0)
343                         ea += off;
344                 if(op & (1<<21))
345                         REG(ur, rn) = ea;
346                 return;
347         }
348
349         /*
350          * CPRT/transfer, 10.3
351          */
352         if(op & (1<<4)){
353                 rd = (op>>12) & 0xF;
354
355                 /*
356                  * compare, 10.3.1
357                  */
358                 if(rd == 15 && op & (1<<20)){
359                         rn = (op>>16)&7;
360                         fn = &FR(ufp, rn);
361                         if(op & (1<<3)){
362                                 fm = &fpconst[op&7];
363                                 if(fpemudebug)
364                                         tag = 'C';
365                         }else{
366                                 fm = &FR(ufp, op&7);
367                                 if(fpemudebug)
368                                         tag = 'F';
369                         }
370                         switch((op>>21)&7){
371                         default:
372                                 unimp(pc, op);
373                         case 4: /* CMF: Fn :: Fm */
374                         case 6: /* CMFE: Fn :: Fm (with exception) */
375                                 ur->psr &= ~(N|C|Z|V);
376                                 ur->psr |= fcmp(fn, fm);
377                                 break;
378                         case 5: /* CNF: Fn :: -Fm */
379                         case 7: /* CNFE: Fn :: -Fm (with exception) */
380                                 tmp = *fm;
381                                 tmp.s ^= 1;
382                                 ur->psr &= ~(N|C|Z|V);
383                                 ur->psr |= fcmp(fn, &tmp);
384                                 break;
385                         }
386                         if(fpemudebug)
387                                 print("CMPF     %c%d,F%ld =%#lux\n",
388                                         tag, rn, op&7, ur->psr>>28);
389                         return;
390                 }
391
392                 /*
393                  * other transfer, 10.3
394                  */
395                 switch((op>>20)&0xF){
396                 default:
397                         unimp(pc, op);
398                 case 0: /* FLT */
399                         rn = (op>>16) & 7;
400                         fpiw2i(&FR(ufp, rn), &REG(ur, rd));
401                         if(fpemudebug)
402                                 print("MOVW[FD] R%d, F%d\n", rd, rn);
403                         break;
404                 case 1: /* FIX */
405                         if(op & (1<<3))
406                                 unimp(pc, op);
407                         rn = op & 7;
408                         tmp = FR(ufp, rn);
409                         fpii2w(&REG(ur, rd), &tmp);
410                         if(fpemudebug)
411                                 print("MOV[FD]W F%d, R%d =%ld\n", rn, rd, REG(ur, rd));
412                         break;
413                 case 2: /* FPSR := Rd */
414                         ufp->status = REG(ur, rd);
415                         if(fpemudebug)
416                                 print("MOVW     R%d, FPSR\n", rd);
417                         break;
418                 case 3: /* Rd := FPSR */
419                         REG(ur, rd) = ufp->status;
420                         if(fpemudebug)
421                                 print("MOVW     FPSR, R%d\n", rd);
422                         break;
423                 case 4: /* FPCR := Rd */
424                         ufp->control = REG(ur, rd);
425                         if(fpemudebug)
426                                 print("MOVW     R%d, FPCR\n", rd);
427                         break;
428                 case 5: /* Rd := FPCR */
429                         REG(ur, rd) = ufp->control;
430                         if(fpemudebug)
431                                 print("MOVW     FPCR, R%d\n", rd);
432                         break;
433                 }
434                 return;
435         }
436
437         /*
438          * arithmetic
439          */
440
441         if(op & (1<<3)){        /* constant */
442                 fm = &fpconst[op&7];
443                 if(fpemudebug)
444                         tag = 'C';
445         }else{
446                 fm = &FR(ufp, op&7);
447                 if(fpemudebug)
448                         tag = 'F';
449         }
450         rd = (op>>12)&7;
451         o = (op>>20)&0xF;
452         if(op & (1<<15)){       /* monadic */
453                 FP1 *fp;
454                 fp = &optab1[o];
455                 if(fp->f == nil)
456                         unimp(pc, op);
457                 if(fpemudebug)
458                         print("%s       %c%ld,F%d\n", fp->name, tag, op&7, rd);
459                 (*fp->f)(fm, &FR(ufp, rd));
460         } else {
461                 FP2 *fp;
462                 fp = &optab2[o];
463                 if(fp->f == nil)
464                         unimp(pc, op);
465                 rn = (op>>16)&7;
466                 if(fpemudebug)
467                         print("%s       %c%ld,F%d,F%d\n", fp->name, tag, op&7, rn, rd);
468                 (*fp->f)(*fm, FR(ufp, rn), &FR(ufp, rd));
469         }
470 }
471
472 static void
473 vfpoptoi(Internal *fm, uchar o2, uchar o4)
474 {
475         fm->s = o2>>3;
476         fm->e = ((o2>>3) | ~(o2 & 4)) - 3 + ExpBias;
477         fm->l = 0;
478         fm->h = o4 << (20+NGuardBits);
479         if(fm->e)
480                 fm->h |= HiddenBit;
481         else
482                 fm->e++;
483 }
484
485 static void
486 vfpemu(ulong pc, ulong op, Ureg *ur, FPsave *ufp)
487 {
488         int sz, vd, o1, o2, o3, o4, o, tag;
489         long off;
490         ulong ea;
491         Word w;
492         
493         Internal *fm, fc;
494
495         /* note: would update fault status here if we noted numeric exceptions */
496
497         sz = op & (1<<8);
498         o1 = (op>>20) & 0xF;
499         o2 = (op>>16) & 0xF;
500         vd = (op>>12) & 0xF;
501
502         switch((op>>24) & 0xF){
503         default:
504                 unimp(pc, op);
505         case 0xD:
506                 /* 
507                  * Extension Register load/store A7.6 
508                  */
509                 off = (op&0xFF)<<2;
510                 if((op & (1<<23)) == 0)
511                         off = -off;
512                 ea = REG(ur, o2) + off;
513                 switch(o1&0x7){ /* D(Bit 22) = 0 (5l) */
514                 default:
515                         unimp(pc, op);
516                 case 0:
517                         if(sz)
518                                 fst(fpii2d, ea, vd, sz, ufp);
519                         else
520                                 fst(fpii2s, ea, vd, sz, ufp);
521                         break;
522                 case 1:
523                         if(sz)
524                                 fld(fpid2i, vd, ea, sz, ufp);
525                         else
526                                 fld(fpis2i, vd, ea, sz, ufp);
527                         break;
528                 }
529                 break;
530         case 0xE:
531                 if(op & (1<<4)){
532                         /* 
533                          * Register transfer between Core & Extension A7.8
534                          */
535                         if(sz)  /* C(Bit 8) != 0 */
536                                 unimp(pc, op);
537                         switch(o1){
538                         default:
539                                 unimp(pc, op);
540                         case 0: /* Fn := Rt */
541                                 *((Word*)&FR(ufp, o2)) = REG(ur, vd);
542                                 if(fpemudebug)
543                                         print("MOVWF    R%d, F%d\n", vd, o2);
544                                 break;
545                         case 1: /* Rt := Fn */
546                                 REG(ur, vd) = *((Word*)&FR(ufp, o2));
547                                 if(fpemudebug)
548                                         print("MOVFW    F%d, R%d =%ld\n", o2, vd, REG(ur, vd));
549                                 break;
550                         case 0xE:       /* FPSCR := Rt */
551                                 ufp->status = REG(ur, vd);
552                                 if(fpemudebug)
553                                         print("MOVW     R%d, FPSCR\n", vd);
554                                 break;
555                         case 0xF:       /* Rt := FPSCR */
556                                 if(vd == 0xF){
557                                         ur->psr = ufp->status;
558                                         if(fpemudebug)
559                                                 print("MOVW     FPSCR, PSR\n");
560                                 }else{
561                                         REG(ur, vd) = ufp->status;
562                                         if(fpemudebug)
563                                                 print("MOVW     FPSCR, R%d\n", vd);
564                                 }
565                                 break;
566                         }
567                 }
568                 else{
569                         /*
570                          * VFP data processing instructions A7.5
571                          * Note: As per 5l we ignore (D, N, M) bits
572                          */
573                         if(fpemudebug)
574                                 tag = 'F';
575                         o3 = (op>>6) & 0x3;
576                         o4 = op & 0xF;
577                         fm = &FR(ufp, o4);
578
579                         if(o1 == 0xB){  /* A7-17 */
580                                 if(o3 & 0x1){
581                                         switch(o2){
582                                         default:
583                                                 o = (o2<<1) | (o3>>1);
584                                                 break;
585                                         case 0x8:       /* CVT int -> float/double */
586                                                 w = *((Word*)fm);
587                                                 fpiw2i(&FR(ufp, vd), &w);
588                                                 if(fpemudebug)
589                                                         print("CVTW%c   F%d, F%d\n", sz?'D':'F', o4, vd);
590                                                 return;
591                                         case 0xD:       /* CVT float/double -> int */
592                                                 fpii2w(&w, fm);
593                                                 *((Word*)&FR(ufp, vd)) = w;
594                                                 if(fpemudebug)
595                                                         print("CVT%cW   F%d, F%d\n", sz?'D':'F', o4, vd);
596                                                 return;
597                                         case 0x5:       /* CMPF(E) */
598                                                         fm = &fpconst[0];
599                                                         if(fpemudebug)
600                                                                 tag = 'C';
601                                         case 0x4:       /* CMPF(E) */
602                                                 ufp->status &= ~(N|C|Z|V);
603                                                 ufp->status |= fcmp(&FR(ufp, vd), fm);
604                                                 if(fpemudebug)
605                                                         print("CMPF     %c%d,F%d =%#lux\n",
606                                                                         tag, (o2&0x1)? 0: o4, vd, ufp->status>>28);
607                                                 return;
608                                         }
609                                 }else{  /* VMOV imm (VFPv3 & v4) (5l doesn't generate) */
610                                         vfpoptoi(&fc, o2, o4);
611                                         fm = &fc;
612                                         o = 0;
613                                         if(fpemudebug)
614                                                 tag = 'C';
615                                 }
616                                 FP1 *vfp;
617                                 vfp = &voptab1[o];
618                                 if(vfp->f == nil)
619                                         unimp(pc, op);
620                                 if(fpemudebug)
621                                         print("%s       %c%d,F%d\n", vfp->name, tag, o4, vd);
622                                 (*vfp->f)(fm, &FR(ufp, vd));
623                         }
624                         else {  /* A7-16 */
625                                 FP2 *vfp;
626                                 o = ((o1&0x3)<<1) | (o1&0x8) | (o3&0x1);
627                                 vfp = &voptab2[o];
628                                 if(vfp->f == nil)
629                                         unimp(pc, op);
630                                 if(fpemudebug)
631                                         print("%s       F%d,F%d,F%d\n", vfp->name, o4, o2, vd);
632                                 (*vfp->f)(*fm, FR(ufp, o2), &FR(ufp, vd));
633                         }
634                 }
635                 break;
636         }
637 }
638
639 void
640 casemu(ulong pc, ulong op, Ureg *ur)
641 {
642         ulong *rp, ro, rn, *rd;
643
644         USED(pc);
645
646         rp = (ulong*)ur;
647         ro = rp[op>>16 & 0x7];
648         rn = rp[op>>0 & 0x7];
649         rd = rp + (op>>12 & 0x7);
650         rp = (ulong*)*rd;
651         validaddr((uintptr)rp, 4, 1);
652         splhi();
653         if(*rd = (*rp == ro))
654                 *rp = rn;
655         spllo();
656 }
657
658 int ldrexvalid;
659
660 void
661 ldrex(ulong pc, ulong op, Ureg *ur)
662 {
663         ulong *rp, *rd, *addr;
664
665         USED(pc);
666
667         rp = (ulong*)ur;
668         rd = rp + (op>>16 & 0x7);
669         addr = (ulong*)*rd;
670         validaddr((uintptr)addr, 4, 0);
671         ldrexvalid = 1;
672         rp[op>>12 & 0x7] = *addr;
673         if(fpemudebug)
674                 print("ldrex, r%ld = [r%ld]@0x%8.8p = 0x%8.8lux",
675                         op>>12 & 0x7, op>>16 & 0x7, addr, rp[op>>12 & 0x7]);
676 }
677
678 void
679 strex(ulong pc, ulong op, Ureg *ur)
680 {
681         ulong *rp, rn, *rd, *addr;
682
683         USED(pc);
684
685         rp = (ulong*)ur;
686         rd = rp + (op>>16 & 0x7);
687         rn = rp[op>>0 & 0x7];
688         addr = (ulong*)*rd;
689         validaddr((uintptr)addr, 4, 1);
690         splhi();
691         if(ldrexvalid){
692                 if(fpemudebug)
693                         print("strex valid, [r%ld]@0x%8.8p = r%ld = 0x%8.8lux",
694                                 op>>16 & 0x7, addr, op>>0 & 0x7, rn);
695                 *addr = rn;
696                 ldrexvalid = 0;
697                 rp[op>>12 & 0x7] = 0;
698         }else{
699                 if(fpemudebug)
700                         print("strex invalid, r%ld = 1", op>>16 & 0x7);
701                 rp[op>>12 & 0x7] = 1;
702         }
703         spllo();
704 }
705
706 struct {
707         ulong   opc;
708         ulong   mask;
709         void    (*f)(ulong, ulong, Ureg*);
710 } specialopc[] = {
711         { 0x01900f9f, 0x0ff00fff, ldrex },
712         { 0x01800f90, 0x0ff00ff0, strex },
713         { 0x0ed00100, 0x0ef08100, casemu },
714         { 0x00000000, 0x00000000, nil }
715 };
716
717 /*
718  * returns the number of FP instructions emulated
719  */
720 int
721 fpiarm(Ureg *ur)
722 {
723         ulong op, o, cp;
724         FPsave *ufp;
725         int i, n;
726
727         if(up == nil)
728                 panic("fpiarm not in a process");
729         ufp = &up->fpsave;
730         /*
731          * because all the emulated fp state is in the proc structure,
732          * it need not be saved/restored
733          */
734         if(up->fpstate != FPactive){
735 //              assert(sizeof(Internal) == sizeof(ufp->regs[0]));
736                 up->fpstate = FPactive;
737                 ufp->control = 0;
738                 ufp->status = (0x01<<28)|(1<<12);       /* software emulation, alternative C flag */
739                 for(n = 0; n < Nfpctlregs; n++)
740                         FR(ufp, n) = fpconst[0];
741         }
742         for(n=0; ;n++){
743                 validaddr(ur->pc, 4, 0);
744                 op = *(ulong*)(ur->pc);
745                 if(fpemudebug)
746                         print("%#lux: %#8.8lux ", ur->pc, op);
747                 o = (op>>24) & 0xF;
748                 cp = (op>>8) & 0xF;
749                 for(i = 0; specialopc[i].f; i++)
750                         if((op & specialopc[i].mask) == specialopc[i].opc)
751                                 break;
752                 if(specialopc[i].f){
753                         if(condok(ur->psr, op>>28))
754                                 specialopc[i].f(ur->pc, op, ur);
755                 }
756                 else if(ISVFPOP(cp, o)){
757                         if(condok(ur->psr, op>>28))
758                                 vfpemu(ur->pc, op, ur, ufp);
759                 }
760                 else if(ISFPAOP(cp, o)){
761                         if(condok(ur->psr, op>>28))
762                                 fpaemu(ur->pc, op, ur, ufp);
763                 }
764                 else
765                         break;
766
767                 ur->pc += 4;            /* pretend cpu executed the instr */
768         }
769         if(fpemudebug)
770                 print("\n");
771         return n;
772 }