1 /*
2 * this doesn't attempt to implement Power architecture 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 "fpi.h"
16
17 #define REG(x) (*(long*)(((char*)em->ur)+roff[(x)]))
18 #define FR(x) (*(Internal*)em->fr[(x)&0x1F])
19 #define REGSP 0 /* in Plan 9, the user and kernel stacks are different */
20
21 #define getulong(a) (*(ulong*)(a))
22
23 enum {
24 CRLT = 1<<31,
25 CRGT = 1<<30,
26 CREQ = 1<<29,
27 CRSO = 1<<28,
28 CRFU = CRSO,
29
30 CRFX = 1<<27,
31 CRFEX = 1<<26,
32 CRVX = 1<<25,
33 CROX = 1<<24,
34 };
35
36 #define getCR(x,w) (((w)>>(28-(x*4)))&0xF)
37 #define mkCR(x,v) (((v)&0xF)<<(28-(x*4)))
38
39 #define simm(xx, ii) xx = (short)(ii&0xFFFF);
40 #define getairr(i) rd = (i>>21)&0x1f; ra = (i>>16)&0x1f; simm(imm,i)
41 #define getarrr(i) rd = (i>>21)&0x1f; ra = (i>>16)&0x1f; rb = (i>>11)&0x1f;
42 #define getop(i) ((i>>26)&0x3F)
43 #define getxo(i) ((i>>1)&0x3FF)
44
45 #define FPS_FX (1<<31) /* exception summary (sticky) */
46 #define FPS_EX (1<<30) /* enabled exception summary */
47 #define FPS_VX (1<<29) /* invalid operation exception summary */
48 #define FPS_OX (1<<28) /* overflow exception OX (sticky) */
49 #define FPS_UX (1<<27) /* underflow exception UX (sticky) */
50 #define FPS_ZX (1<<26) /* zero divide exception ZX (sticky) */
51 #define FPS_XX (1<<25) /* inexact exception XX (sticky) */
52 #define FPS_VXSNAN (1<<24) /* invalid operation exception for SNaN (sticky) */
53 #define FPS_VXISI (1<<23) /* invalid operation exception for ∞-∞ (sticky) */
54 #define FPS_VXIDI (1<<22) /* invalid operation exception for ∞/∞ (sticky) */
55 #define FPS_VXZDZ (1<<21) /* invalid operation exception for 0/0 (sticky) */
56 #define FPS_VXIMZ (1<<20) /* invalid operation exception for ∞*0 (sticky) */
57 #define FPS_VXVC (1<<19) /* invalid operation exception for invalid compare (sticky) */
58 #define FPS_FR (1<<18) /* fraction rounded */
59 #define FPS_FI (1<<17) /* fraction inexact */
60 #define FPS_FPRF (1<<16) /* floating point result class */
61 #define FPS_FPCC (0xF<<12) /* <, >, =, unordered */
62 #define FPS_VXCVI (1<<8) /* enable exception for invalid integer convert (sticky) */
63 #define FPS_VE (1<<7) /* invalid operation exception enable */
64 #define FPS_OE (1<<6) /* enable overflow exceptions */
65 #define FPS_UE (1<<5) /* enable underflow */
66 #define FPS_ZE (1<<4) /* enable zero divide */
67 #define FPS_XE (1<<3) /* enable inexact exceptions */
68 #define FPS_RN (3<<0) /* rounding mode */
69
70 typedef struct Emreg Emreg;
71
72 struct Emreg {
73 Ureg* ur;
74 ulong (*fr)[3];
75 FPsave* ufp;
76 ulong ir;
77 char* name;
78 };
79
80 int fpemudebug = 0;
81
82 #undef OFR
83 #define OFR(X) ((ulong)&((Ureg*)0)->X)
84
85 static int roff[] = {
86 OFR(r0), OFR(r1), OFR(r2), OFR(r3),
87 OFR(r4), OFR(r5), OFR(r6), OFR(r7),
88 OFR(r8), OFR(r9), OFR(r10), OFR(r11),
89 OFR(r12), OFR(r13), OFR(r14), OFR(r15),
90 OFR(r16), OFR(r17), OFR(r18), OFR(r19),
91 OFR(r20), OFR(r21), OFR(r22), OFR(r23),
92 OFR(r24), OFR(r25), OFR(r26), OFR(r27),
93 OFR(r28), OFR(r29), OFR(r30), OFR(r31),
94 };
95
96 /*
97 * initial FP register values assumed by qc's code
98 */
99 static Internal fpreginit[] = {
100 /* s, e, l, h */
101 {0, 0x400, 0x00000000, 0x08000000}, /* F31=2.0 */
102 {0, 0x3FF, 0x00000000, 0x08000000}, /* F30=1.0 */
103 {0, 0x3FE, 0x00000000, 0x08000000}, /* F29=0.5 */
104 {0, 0x1, 0x00000000, 0x00000000}, /* F28=0.0 */
105 {0, 0x433, 0x00000000, 0x08000040}, /* F27=FREGCVI */
106 };
107
108 static void
fadd(Emreg * em,Internal * d,int ra,int rb)109 fadd(Emreg *em, Internal *d, int ra, int rb)
110 {
111 Internal a, b;
112
113 a = FR(ra);
114 b = FR(rb);
115 (a.s == b.s? fpiadd: fpisub)(&b, &a, d);
116 }
117
118 static void
fsub(Emreg * em,Internal * d,int ra,int rb)119 fsub(Emreg *em, Internal *d, int ra, int rb)
120 {
121 Internal a, b;
122
123 a = FR(ra);
124 b = FR(rb);
125 b.s ^= 1;
126 (b.s == a.s? fpiadd: fpisub)(&b, &a, d);
127 }
128
129 static void
fmul(Emreg * em,Internal * d,int ra,int rb)130 fmul(Emreg *em, Internal *d, int ra, int rb)
131 {
132 Internal a, b;
133
134 a = FR(ra);
135 b = FR(rb);
136 fpimul(&b, &a, d);
137 }
138
139 static void
fdiv(Emreg * em,Internal * d,int ra,int rb)140 fdiv(Emreg *em, Internal *d, int ra, int rb)
141 {
142 Internal a, b;
143
144 a = FR(ra);
145 b = FR(rb);
146 fpidiv(&b, &a, d);
147 }
148
149 static void
fmsub(Emreg * em,Internal * d,int ra,int rc,int rb)150 fmsub(Emreg *em, Internal *d, int ra, int rc, int rb)
151 {
152 Internal a, c, b, t;
153
154 a = FR(ra);
155 c = FR(rc);
156 b = FR(rb);
157 fpimul(&a, &c, &t);
158 b.s ^= 1;
159 (b.s == t.s? fpiadd: fpisub)(&b, &t, d);
160 }
161
162 static void
fmadd(Emreg * em,Internal * d,int ra,int rc,int rb)163 fmadd(Emreg *em, Internal *d, int ra, int rc, int rb)
164 {
165 Internal a, c, b, t;
166
167 a = FR(ra);
168 c = FR(rc);
169 b = FR(rb);
170 fpimul(&a, &c, &t);
171 (t.s == b.s? fpiadd: fpisub)(&b, &t, d);
172 }
173
174 static ulong setfpscr(Emreg*);
175 static void setfpcc(Emreg*, int);
176
177 static void
unimp(Emreg * em,ulong op)178 unimp(Emreg *em, ulong op)
179 {
180 char buf[60];
181
182 snprint(buf, sizeof(buf), "sys: fp: pc=%lux unimp fp 0x%.8lux", em->ur->pc, op);
183 if(fpemudebug)
184 print("FPE: %s\n", buf);
185 error(buf);
186 /* no return */
187 }
188
189 /*
190 * floating load/store
191 */
192
193 static void
fpeairr(Emreg * em,ulong ir,void ** eap,int * rdp)194 fpeairr(Emreg *em, ulong ir, void **eap, int *rdp)
195 {
196 ulong ea;
197 long imm;
198 int ra, rd, upd;
199
200 getairr(ir);
201 ea = imm;
202 upd = (ir&(1L<<26))!=0;
203 if(ra) {
204 ea += REG(ra);
205 if(upd){
206 if(REGSP && ra == REGSP)
207 panic("fpemu: r1 update"); /* can't do it because we're running on the same stack */
208 REG(ra) = ea;
209 }
210 } else {
211 if(upd)
212 unimp(em, ir);
213 }
214 *rdp = rd;
215 *eap = (void*)ea;
216 if(fpemudebug)
217 print("%8.8lux %s\tf%d,%ld(r%d) ea=%lux upd=%d\n", em->ur->pc, em->name, rd, imm, ra, ea, upd);
218 }
219
220 static void
fpearrr(Emreg * em,ulong ir,int upd,void ** eap,int * rdp)221 fpearrr(Emreg *em, ulong ir, int upd, void **eap, int *rdp)
222 {
223 ulong ea;
224 int ra, rb, rd;
225
226 getarrr(ir);
227 ea = REG(rb);
228 if(ra){
229 ea += REG(ra);
230 if(upd){
231 if(REGSP && ra == REGSP)
232 panic("fpemu: r1 update");
233 REG(ra) = ea;
234 }
235 if(fpemudebug)
236 print("%8.8lux %s\tf%d,(r%d+r%d) ea=%lux upd=%d\n", em->ur->pc, em->name, rd, ra, rb, ea, upd);
237 } else {
238 if(upd)
239 unimp(em, ir);
240 if(fpemudebug)
241 print("%8.8lux %s\tf%d,(r%d) ea=%lux\n", em->ur->pc, em->name, rd, rb, ea);
242 }
243 *eap = (void*)ea;
244 *rdp = rd;
245 }
246
247 static void
lfs(Emreg * em,ulong ir)248 lfs(Emreg *em, ulong ir)
249 {
250 void *ea;
251 int rd;
252
253 em->name = "lfs";
254 fpeairr(em, ir, &ea, &rd);
255 fpis2i(&FR(rd), (void*)ea);
256 }
257
258 static void
lfsx(Emreg * em,ulong ir)259 lfsx(Emreg *em, ulong ir)
260 {
261 void *ea;
262 int rd;
263
264 em->name = "lfsx";
265 fpearrr(em, ir, ((ir>>1)&0x3FF)==567, &ea, &rd);
266 fpis2i(&FR(rd), (void*)ea);
267 }
268
269 static void
lfd(Emreg * em,ulong ir)270 lfd(Emreg *em, ulong ir)
271 {
272 void *ea;
273 int rd;
274
275 em->name = "lfd";
276 fpeairr(em, ir, &ea, &rd);
277 fpid2i(&FR(rd), (void*)ea);
278 }
279
280 static void
lfdx(Emreg * em,ulong ir)281 lfdx(Emreg *em, ulong ir)
282 {
283 void *ea;
284 int rd;
285
286 em->name = "lfdx";
287 fpearrr(em, ir, ((ir>>1)&0x3FF)==631, &ea, &rd);
288 fpid2i(&FR(rd), (void*)ea);
289 }
290
291 static void
stfs(Emreg * em,ulong ir)292 stfs(Emreg *em, ulong ir)
293 {
294 void *ea;
295 int rd;
296 Internal tmp;
297
298 em->name = "stfs";
299 fpeairr(em, ir, &ea, &rd);
300 tmp = FR(rd);
301 fpii2s(ea, &tmp);
302 }
303
304 static void
stfsx(Emreg * em,ulong ir)305 stfsx(Emreg *em, ulong ir)
306 {
307 void *ea;
308 int rd;
309 Internal tmp;
310
311 em->name = "stfsx";
312 fpearrr(em, ir, getxo(ir)==695, &ea, &rd);
313 tmp = FR(rd);
314 fpii2s(ea, &tmp);
315 }
316
317 static void
stfd(Emreg * em,ulong ir)318 stfd(Emreg *em, ulong ir)
319 {
320 void *ea;
321 int rd;
322 Internal tmp;
323
324 em->name = "stfd";
325 fpeairr(em, ir, &ea, &rd);
326 tmp = FR(rd);
327 fpii2d(ea, &tmp);
328 }
329
330 static void
stfdx(Emreg * em,ulong ir)331 stfdx(Emreg *em, ulong ir)
332 {
333 void *ea;
334 int rd;
335 Internal tmp;
336
337 em->name = "stfdx";
338 fpearrr(em, ir, ((ir>>1)&0x3FF)==759, &ea, &rd);
339 tmp = FR(rd);
340 fpii2d(ea, &tmp);
341 }
342
343 static void
mcrfs(Emreg * em,ulong ir)344 mcrfs(Emreg *em, ulong ir)
345 {
346 int rd, ra, rb;
347 static ulong fpscr0[] ={
348 FPS_FX|FPS_OX,
349 FPS_UX|FPS_ZX|FPS_XX|FPS_VXSNAN,
350 FPS_VXISI|FPS_VXIDI|FPS_VXZDZ|FPS_VXIMZ,
351 FPS_VXVC,
352 0,
353 FPS_VXCVI,
354 };
355
356 getarrr(ir);
357 if(rb || ra&3 || rd&3)
358 unimp(em, ir);
359 ra >>= 2;
360 rd >>= 2;
361 em->ur->cr = (em->ur->cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, em->ufp->fpscr));
362 em->ufp->fpscr &= ~fpscr0[ra];
363 if(fpemudebug)
364 print("%8.8lux mcrfs\tcrf%d,crf%d\n", em->ur->pc, rd, ra);
365 }
366
367 static void
mffs(Emreg * em,ulong ir)368 mffs(Emreg *em, ulong ir)
369 {
370 int rd, ra, rb;
371 Double dw;
372
373 getarrr(ir);
374 if(ra || rb)
375 unimp(em, ir);
376 dw.h = 0;
377 dw.l = ((uvlong)0xFFF8000L<<16)|em->ufp->fpscr;
378 fpid2i(&FR(rd), &dw);
379 /* it's anyone's guess how CR1 should be set when ir&1 */
380 em->ur->cr &= ~mkCR(1, 0xE); /* leave SO, reset others */
381 if(fpemudebug)
382 print("%8.8lux mffs%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd);
383 }
384
385 static void
mtfsb1(Emreg * em,ulong ir)386 mtfsb1(Emreg *em, ulong ir)
387 {
388 int rd, ra, rb;
389
390 getarrr(ir);
391 if(ra || rb)
392 unimp(em, ir);
393 em->ufp->fpscr |= (1L << (31-rd));
394 /* BUG: should set summary bits */
395 if(ir & 1)
396 em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
397 if(fpemudebug)
398 print("%8.8lux mtfsb1%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd);
399 }
400
401 static void
mtfsb0(Emreg * em,ulong ir)402 mtfsb0(Emreg *em, ulong ir)
403 {
404 int rd, ra, rb;
405
406 getarrr(ir);
407 if(ra || rb)
408 unimp(em, ir);
409 em->ufp->fpscr &= ~(1L << (31-rd));
410 if(ir & 1)
411 em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
412 if(fpemudebug)
413 print("%8.8lux mtfsb0%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd);
414 }
415
416 static void
mtfsf(Emreg * em,ulong ir)417 mtfsf(Emreg *em, ulong ir)
418 {
419 int fm, rb, i;
420 ulong v;
421 Internal b;
422 Double db;
423
424 if(ir & ((1L << 25)|(1L << 16)))
425 unimp(em, ir);
426 rb = (ir >> 11) & 0x1F;
427 fm = (ir >> 17) & 0xFF;
428 b = FR(rb);
429 fpii2d(&db, &b); /* reconstruct hi/lo format to recover low word */
430 v = db.l;
431 for(i=0; i<8; i++)
432 if(fm & (1 << (7-i)))
433 em->ufp->fpscr = (em->ufp->fpscr & ~mkCR(i, 0xF)) | mkCR(i, getCR(i, v));
434 /* BUG: should set FEX and VX `according to the usual rule' */
435 if(ir & 1)
436 em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
437 if(fpemudebug)
438 print("%8.8lux mtfsf%s\t#%.2x,fr%d\n", em->ur->pc, ir&1?".":"", fm, rb);
439 }
440
441 static void
mtfsfi(Emreg * em,ulong ir)442 mtfsfi(Emreg *em, ulong ir)
443 {
444 int imm, rd;
445
446 if(ir & ((0x7F << 16)|(1L << 11)))
447 unimp(em, ir);
448 rd = (ir >> 23) & 0xF;
449 imm = (ir >> 12) & 0xF;
450 em->ufp->fpscr = (em->ufp->fpscr & ~mkCR(rd, 0xF)) | mkCR(rd, imm);
451 /* BUG: should set FEX and VX `according to the usual rule' */
452 if(ir & 1)
453 em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
454 if(fpemudebug)
455 print("%8.8lux mtfsfi%s\tcrf%d,#%x\n", em->ur->pc, ir&1?".":"", rd, imm);
456 }
457
458 static void
fcmp(Emreg * em,ulong ir)459 fcmp(Emreg *em, ulong ir)
460 {
461 int fc, rd, ra, rb, sig, i;
462 Internal a, b;
463
464 getarrr(ir);
465 if(rd & 3)
466 unimp(em, ir);
467 rd >>= 2;
468 sig = 0;
469 switch(getxo(ir)) {
470 default:
471 unimp(em, ir);
472 case 32:
473 if(fpemudebug)
474 print("%8.8lux fcmpo\tcr%d,f%d,f%d\n", em->ur->pc, rd, ra, rb);
475 sig = 1;
476 break;
477 case 0:
478 if(fpemudebug)
479 print("%8.8lux fcmpu\tcr%d,f%d,f%d\n", em->ur->pc, rd, ra, rb);
480 break;
481 }
482 if(IsWeird(&FR(ra)) || IsWeird(&FR(rb))) {
483 if(sig){
484 ; /* BUG: should trap if not masked ... */
485 }
486 fc = CRFU;
487 } else {
488 a = FR(ra);
489 b = FR(rb);
490 fpiround(&a);
491 fpiround(&b);
492 i = fpicmp(&a, &b);
493 if(i > 0)
494 fc = CRGT;
495 else if(i == 0)
496 fc = CREQ;
497 else
498 fc = CRLT;
499 }
500 fc >>= 28;
501 em->ur->cr = (em->ur->cr & ~mkCR(rd,~0)) | mkCR(rd, fc);
502 em->ufp->fpscr = (em->ufp->fpscr & ~0xF800) | (fc<<11);
503 /* BUG: update FX, VXSNAN, VXVC */
504 }
505
506 static void
fariths(Emreg * em,ulong ir)507 fariths(Emreg *em, ulong ir)
508 {
509 int rd, ra, rb, rc, fmt;
510 char *cc, *n;
511 ulong fpscr;
512 Internal *d;
513
514 fmt = 0;
515 rc = (ir>>6)&0x1F;
516 getarrr(ir);
517 d = &FR(rd);
518 switch(getxo(ir)&0x1F) { /* partial XO decode */
519 case 22: /* fsqrts */
520 case 24: /* fres */
521 default:
522 unimp(em, ir);
523 return;
524 case 18:
525 if(IsZero(&FR(rb))) {
526 em->ufp->fpscr |= FPS_ZX | FPS_FX;
527 error("sys: fp: zero divide");
528 }
529 fdiv(em, d, ra, rb);
530 n = "fdivs";
531 break;
532 case 20:
533 fsub(em, d, ra, rb);
534 n = "fsubs";
535 break;
536 case 21:
537 fadd(em, d, ra, rb);
538 n = "fadds";
539 break;
540 case 25:
541 fmul(em, d, ra, rc);
542 rb = rc;
543 n = "fmuls";
544 break;
545 case 28:
546 fmsub(em, d, ra, rc, rb);
547 fmt = 2;
548 n = "fmsubs";
549 break;
550 case 29:
551 fmadd(em, d, ra, rc, rb);
552 fmt = 2;
553 n = "fmadds";
554 break;
555 case 30:
556 fmsub(em, d, ra, rc, rb);
557 d->s ^= 1;
558 fmt = 2;
559 n = "fnmsubs";
560 break;
561 case 31:
562 fmadd(em, d, ra, rc, rb);
563 d->s ^= 1;
564 fmt = 2;
565 n = "fnmadds";
566 break;
567 }
568 if(fmt==1 && ra)
569 unimp(em, ir);
570 fpscr = setfpscr(em);
571 setfpcc(em, rd);
572 cc = "";
573 if(ir & 1) {
574 cc = ".";
575 em->ur->cr = (em->ur->cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
576 }
577 if(fpemudebug) {
578 switch(fmt) {
579 case 0:
580 print("%8.8lux %s%s\tfr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rb);
581 break;
582 case 1:
583 print("%8.8lux %s%s\tfr%d,fr%d\n", em->ur->pc, n, cc, rd, rb);
584 break;
585 case 2:
586 print("%8.8lux %s%s\tfr%d,fr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rc, rb);
587 break;
588 }
589 }
590 }
591
592 static void
farith(Emreg * em,ulong ir)593 farith(Emreg *em, ulong ir)
594 {
595 Word w;
596 Double dv;
597 int rd, ra, rb, rc, fmt;
598 char *cc, *n;
599 ulong fpscr;
600 int nocc;
601 Internal *d;
602
603 fmt = 0;
604 nocc = 0;
605 rc = (ir>>6)&0x1F;
606 getarrr(ir);
607 d = &FR(rd);
608 switch(getxo(ir)&0x1F) { /* partial XO decode */
609 case 22: /* frsqrt */
610 case 23: /* fsel */
611 case 26: /* fsqrte */
612 default:
613 unimp(em, ir);
614 return;
615 case 12: /* frsp */
616 *d = FR(rb); /* BUG: doesn't round to single precision */
617 fmt = 1;
618 n = "frsp";
619 break;
620 case 14: /* fctiw */ /* BUG: ignores rounding mode */
621 case 15: /* fctiwz */
622 fpii2w(&w, &FR(rb));
623 dv.h = 0;
624 dv.l = w;
625 fpid2i(d, &dv);
626 fmt = 1;
627 nocc = 1;
628 n = "fctiw";
629 break;
630 case 18:
631 if(IsZero(&FR(rb))) {
632 em->ufp->fpscr |= FPS_ZX | FPS_FX;
633 error("sys: fp: zero divide");
634 }
635 fdiv(em, d, ra, rb);
636 n = "fdiv";
637 break;
638 case 20:
639 fsub(em, d, ra, rb);
640 n = "fsub";
641 break;
642 case 21:
643 fadd(em, d, ra, rb);
644 n = "fadd";
645 break;
646 case 25:
647 fmul(em, d, ra, rc);
648 rb = rc;
649 n = "fmul";
650 break;
651 case 28:
652 fmsub(em, d, ra, rc, rb);
653 fmt = 2;
654 n = "fmsub";
655 break;
656 case 29:
657 fmadd(em, d, ra, rc, rb);
658 fmt = 2;
659 n = "fmadd";
660 break;
661 case 30:
662 fmsub(em, d, ra, rc, rb);
663 d->s ^= 1;
664 fmt = 2;
665 n = "fnmsub";
666 break;
667 case 31:
668 fmadd(em, d, ra, rc, rb);
669 d->s ^= 1;
670 fmt = 2;
671 n = "fnmadd";
672 break;
673 }
674 if(fmt==1 && ra)
675 unimp(em, ir);
676 fpscr = setfpscr(em);
677 if(nocc == 0)
678 setfpcc(em, rd);
679 cc = "";
680 if(ir & 1) {
681 cc = ".";
682 em->ur->cr = (em->ur->cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
683 }
684 if(fpemudebug) {
685 switch(fmt) {
686 case 0:
687 print("%8.8lux %s%s\tfr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rb);
688 break;
689 case 1:
690 print("%8.8lux %s%s\tfr%d,fr%d\n", em->ur->pc, n, cc, rd, rb);
691 break;
692 case 2:
693 print("%8.8lux %s%s\tfr%d,fr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rc, rb);
694 break;
695 }
696 }
697 }
698
699 static void
farith2(Emreg * em,ulong ir)700 farith2(Emreg *em, ulong ir)
701 {
702 int rd, ra, rb;
703 char *cc, *n;
704 ulong fpscr;
705 Internal *d, *b;
706
707 getarrr(ir);
708 if(ra)
709 unimp(em, ir);
710 d = &FR(rd);
711 b = &FR(rb);
712 switch(getxo(ir)) { /* full XO decode */
713 default:
714 unimp(em, ir);
715 case 40:
716 *d = *b;
717 d->s ^= 1;
718 n = "fneg";
719 break;
720 case 72:
721 *d = *b;
722 n = "fmr";
723 break;
724 case 136:
725 *d = *b;
726 d->s = 1;
727 n = "fnabs";
728 break;
729 case 264:
730 *d = *b;
731 d->s = 0;
732 n = "fabs";
733 break;
734 }
735 fpscr = setfpscr(em);
736 setfpcc(em, rd);
737 cc = "";
738 if(ir & 1) {
739 cc = ".";
740 em->ur->cr = (em->ur->cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
741 }
742 if(fpemudebug)
743 print("%8.8lux %s%s\tfr%d,fr%d\n", em->ur->pc, n, cc, rd, rb);
744 }
745
746 static ulong
setfpscr(Emreg * em)747 setfpscr(Emreg *em)
748 {
749 ulong fps, fpscr;
750
751 fps = 0; /* BUG: getfsr() */
752 fpscr = em->ufp->fpscr;
753 if(fps & FPAOVFL)
754 fpscr |= FPS_OX;
755 if(fps & FPAINEX)
756 fpscr |= FPS_XX;
757 if(fps & FPAUNFL)
758 fpscr |= FPS_UX;
759 if(fps & FPAZDIV)
760 fpscr |= FPS_ZX;
761 if(fpscr != em->ufp->fpscr) {
762 fpscr |= FPS_FX;
763 em->ufp->fpscr = fpscr;
764 }
765 return fpscr;
766 }
767
768 static void
setfpcc(Emreg * em,int r)769 setfpcc(Emreg *em, int r)
770 {
771 int c;
772 Internal *d;
773
774 d = &FR(r);
775 c = 0;
776 if(IsZero(d))
777 c |= 2;
778 else if(d->s == 1)
779 c |= 4;
780 else
781 c |= 8;
782 if(IsNaN(d))
783 c |= 1;
784 em->ufp->fpscr = (em->ufp->fpscr & ~0xF800) | (0<<15) | (c<<11); /* unsure about class bit */
785 }
786
787 static uchar op63flag[32] = {
788 [12] 1, [14] 1, [15] 1, [18] 1, [20] 1, [21] 1, [22] 1,
789 [23] 1, [25] 1, [26] 1, [28] 1, [29] 1, [30] 1, [31] 1,
790 };
791
792 /*
793 * returns the number of FP instructions emulated
794 */
795 int
fpipower(Ureg * ur)796 fpipower(Ureg *ur)
797 {
798 ulong op;
799 int xo;
800 Emreg emreg, *em;
801 FPsave *ufp;
802 int n;
803
804 ufp = &up->fpsave; /* because all the state is in FPsave, it need not be saved/restored */
805 em = &emreg;
806 em->ur = ur;
807 em->fr = ufp->emreg;
808 em->ufp = ufp;
809 em->name = nil;
810 if(em->ufp->fpistate != FPactive) {
811 em->ufp->fpistate = FPactive;
812 em->ufp->fpscr = 0; /* TO DO */
813 for(n = 0; n < nelem(fpreginit); n++)
814 FR(31-n) = fpreginit[n];
815 }
816 for(n=0;;n++){
817 validaddr(ur->pc, 4, 0);
818 op = getulong(ur->pc);
819 em->ir = op;
820 if(fpemudebug > 1)
821 print("%8.8lux %8.8lux: ", ur->pc, op);
822 switch(op>>26){
823 default:
824 return n;
825 case 48: /* lfs */
826 case 49: /* lfsu */
827 lfs(em, op);
828 break;
829 case 50: /* lfd */
830 case 51: /* lfdu */
831 lfd(em, op);
832 break;
833 case 52: /* stfs */
834 case 53: /* stfsu */
835 stfs(em, op);
836 break;
837 case 54: /* stfd */
838 case 55: /* stfdu */
839 stfd(em, op);
840 break;
841 case 31: /* indexed load/store */
842 xo = getxo(op);
843 if((xo & 0x300) != 0x200)
844 return n;
845 switch(xo){
846 default:
847 return n;
848 case 535: /* lfsx */
849 case 567: /* lfsux */
850 lfsx(em, op);
851 break;
852 case 599: /* lfdx */
853 case 631: /* lfdux */
854 lfdx(em, op);
855 break;
856 case 663: /* stfsx */
857 case 695: /* stfsux */
858 stfsx(em, op);
859 break;
860 case 727: /* stfdx */
861 case 759: /* stfdux */
862 stfdx(em, op);
863 break;
864 }
865 break;
866 case 63: /* double precision */
867 xo = getxo(op);
868 if(op63flag[xo & 0x1F]){
869 farith(em, op);
870 break;
871 }
872 switch(xo){
873 default:
874 return n;
875 case 0: /* fcmpu */
876 case 32: /* fcmpo */
877 fcmp(em, op);
878 break;
879 case 40: /* fneg */
880 case 72: /* fmr */
881 case 136: /* fnabs */
882 case 264: /* fabs */
883 farith2(em, op);
884 break;
885 case 38:
886 mtfsb1(em, op);
887 break;
888 case 64:
889 mcrfs(em, op);
890 break;
891 case 70:
892 mtfsb0(em, op);
893 break;
894 case 134:
895 mtfsfi(em, op);
896 break;
897 case 583:
898 mffs(em, op);
899 break;
900 case 711:
901 mtfsf(em, op);
902 break;
903 }
904 break;
905 case 59: /* single precision */
906 fariths(em, op);
907 break;
908 }
909 ur->pc += 4;
910 if(anyhigher())
911 sched();
912 }
913 }
914
915 /*
916 50: lfd frD,d(rA)
917 51: lfdu frD,d(rA)
918 31,631: lfdux frD,rA,rB
919 31,599: lfdx frD,rA,rB
920 48: lfs frD,d(rA)
921 49: lfsu frD,d(rA)
922 31,567: lfsux frD,rA,rB
923 31,535: lfsx frD,rA,rB
924
925 54: stfd frS,d(rA)
926 55: stfdu frS,d(rA)
927 31,759: stfdux frS,rA,rB
928 31,727: stfdx frS,rA,rB
929 52: stfs frS,d(rA)
930 53: stfsu frS,d(rA)
931 31,695: stfsux frS,rA,rB
932 31,663: stfsx frS,rA,rB
933
934 63,64: mcrfs crfD,crfS
935 63,583: mffs[.] frD
936 63,70: mtfsb0[.] crbD
937 63,38: mtfsb1[.] crbD
938 63,711: mtfsf[.] FM,frB
939 63,134: mtfsfi[.] crfD,IMM
940 */
941
942 /*
943 float to int:
944 FMOVD g+0(SB),F1
945 FCTIWZ F1,F4
946 FMOVD F4,.rathole+0(SB)
947 MOVW .rathole+4(SB),R7
948 MOVW R7,l+0(SB)
949 */
950
951 /*
952 int to float:
953 MOVW $1127219200,R9
954 MOVW l+0(SB),R7
955 MOVW R9,.rathole+0(SB)
956 XOR $-2147483648,R7,R6
957 MOVW R6,.rathole+4(SB)
958 FMOVD .rathole+0(SB),F0
959 FSUB F27,F0
960
961 unsigned to float:
962 MOVW ul+0(SB),R5
963 MOVW R9,.rathole+0(SB)
964 XOR $-2147483648,R5,R4
965 MOVW R4,.rathole+4(SB)
966 FMOVD .rathole+0(SB),F3
967 FSUB F27,F3
968 FCMPU F3,F28
969 BGE ,3(PC)
970 FMOVD $4.29496729600000000e+09,F2
971 FADD F2,F3
972 FMOVD F3,g+0(SB)
973 */
974