summaryrefslogtreecommitdiff
path: root/os/mpc/fpipower.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /os/mpc/fpipower.c
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'os/mpc/fpipower.c')
-rw-r--r--os/mpc/fpipower.c970
1 files changed, 970 insertions, 0 deletions
diff --git a/os/mpc/fpipower.c b/os/mpc/fpipower.c
new file mode 100644
index 00000000..ec4363b2
--- /dev/null
+++ b/os/mpc/fpipower.c
@@ -0,0 +1,970 @@
+/*
+ * this doesn't attempt to implement Power architecture floating-point properties
+ * that aren't visible in the Inferno environment.
+ * all arithmetic is done in double precision.
+ * the FP trap status isn't updated.
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include "ureg.h"
+
+#include "fpi.h"
+
+#define REG(x) (*(long*)(((char*)em->ur)+roff[(x)]))
+#define FR(x) (*(Internal*)em->fr[(x)&0x1F])
+#define REGSP 1 /* stack pointer */
+
+/* BUG: check fetch (not worthwhile in Inferno) */
+#define getulong(a) (*(ulong*)(a))
+
+enum {
+ CRLT = 1<<31,
+ CRGT = 1<<30,
+ CREQ = 1<<29,
+ CRSO = 1<<28,
+ CRFU = CRSO,
+
+ CRFX = 1<<27,
+ CRFEX = 1<<26,
+ CRVX = 1<<25,
+ CROX = 1<<24,
+};
+
+#define getCR(x,w) (((w)>>(28-(x*4)))&0xF)
+#define mkCR(x,v) (((v)&0xF)<<(28-(x*4)))
+
+#define simm(xx, ii) xx = (short)(ii&0xFFFF);
+#define getairr(i) rd = (i>>21)&0x1f; ra = (i>>16)&0x1f; simm(imm,i)
+#define getarrr(i) rd = (i>>21)&0x1f; ra = (i>>16)&0x1f; rb = (i>>11)&0x1f;
+#define getop(i) ((i>>26)&0x3F)
+#define getxo(i) ((i>>1)&0x3FF)
+
+#define FPS_FX (1<<31) /* exception summary (sticky) */
+#define FPS_EX (1<<30) /* enabled exception summary */
+#define FPS_VX (1<<29) /* invalid operation exception summary */
+#define FPS_OX (1<<28) /* overflow exception OX (sticky) */
+#define FPS_UX (1<<27) /* underflow exception UX (sticky) */
+#define FPS_ZX (1<<26) /* zero divide exception ZX (sticky) */
+#define FPS_XX (1<<25) /* inexact exception XX (sticky) */
+#define FPS_VXSNAN (1<<24) /* invalid operation exception for SNaN (sticky) */
+#define FPS_VXISI (1<<23) /* invalid operation exception for ∞-∞ (sticky) */
+#define FPS_VXIDI (1<<22) /* invalid operation exception for ∞/∞ (sticky) */
+#define FPS_VXZDZ (1<<21) /* invalid operation exception for 0/0 (sticky) */
+#define FPS_VXIMZ (1<<20) /* invalid operation exception for ∞*0 (sticky) */
+#define FPS_VXVC (1<<19) /* invalid operation exception for invalid compare (sticky) */
+#define FPS_FR (1<<18) /* fraction rounded */
+#define FPS_FI (1<<17) /* fraction inexact */
+#define FPS_FPRF (1<<16) /* floating point result class */
+#define FPS_FPCC (0xF<<12) /* <, >, =, unordered */
+#define FPS_VXCVI (1<<8) /* enable exception for invalid integer convert (sticky) */
+#define FPS_VE (1<<7) /* invalid operation exception enable */
+#define FPS_OE (1<<6) /* enable overflow exceptions */
+#define FPS_UE (1<<5) /* enable underflow */
+#define FPS_ZE (1<<4) /* enable zero divide */
+#define FPS_XE (1<<3) /* enable inexact exceptions */
+#define FPS_RN (3<<0) /* rounding mode */
+
+typedef struct Emreg Emreg;
+
+struct Emreg {
+ Ureg* ur;
+ ulong (*fr)[3];
+ FPenv* ufp;
+ ulong ir;
+ char* name;
+};
+
+int fpemudebug = 0;
+
+#undef OFR
+#define OFR(X) ((ulong)&((Ureg*)0)->X)
+
+static int roff[] = {
+ OFR(r0), OFR(r1), OFR(r2), OFR(r3),
+ OFR(r4), OFR(r5), OFR(r6), OFR(r7),
+ OFR(r8), OFR(r9), OFR(r10), OFR(r11),
+ OFR(r12), OFR(r13), OFR(r14), OFR(r15),
+ OFR(r16), OFR(r17), OFR(r18), OFR(r19),
+ OFR(r20), OFR(r21), OFR(r22), OFR(r23),
+ OFR(r24), OFR(r25), OFR(r26), OFR(r27),
+ OFR(r28), OFR(r29), OFR(r30), OFR(r31),
+};
+
+/*
+ * initial FP register values assumed by qc's code
+ */
+static Internal fpreginit[] = {
+ /* s, e, l, h */
+ {0, 0x400, 0x00000000, 0x08000000}, /* F31=2.0 */
+ {0, 0x3FF, 0x00000000, 0x08000000}, /* F30=1.0 */
+ {0, 0x3FE, 0x00000000, 0x08000000}, /* F29=0.5 */
+ {0, 0x1, 0x00000000, 0x00000000}, /* F28=0.0 */
+ {0, 0x433, 0x00000000, 0x08000040}, /* F27=FREGCVI */
+};
+
+static void
+fadd(Emreg *em, Internal *d, int ra, int rb)
+{
+ Internal a, b;
+
+ a = FR(ra);
+ b = FR(rb);
+ (a.s == b.s? fpiadd: fpisub)(&b, &a, d);
+}
+
+static void
+fsub(Emreg *em, Internal *d, int ra, int rb)
+{
+ Internal a, b;
+
+ a = FR(ra);
+ b = FR(rb);
+ b.s ^= 1;
+ (b.s == a.s? fpiadd: fpisub)(&b, &a, d);
+}
+
+static void
+fmul(Emreg *em, Internal *d, int ra, int rb)
+{
+ Internal a, b;
+
+ a = FR(ra);
+ b = FR(rb);
+ fpimul(&b, &a, d);
+}
+
+static void
+fdiv(Emreg *em, Internal *d, int ra, int rb)
+{
+ Internal a, b;
+
+ a = FR(ra);
+ b = FR(rb);
+ fpidiv(&b, &a, d);
+}
+
+static void
+fmsub(Emreg *em, Internal *d, int ra, int rc, int rb)
+{
+ Internal a, c, b, t;
+
+ a = FR(ra);
+ c = FR(rc);
+ b = FR(rb);
+ fpimul(&a, &c, &t);
+ b.s ^= 1;
+ (b.s == t.s? fpiadd: fpisub)(&b, &t, d);
+}
+
+static void
+fmadd(Emreg *em, Internal *d, int ra, int rc, int rb)
+{
+ Internal a, c, b, t;
+
+ a = FR(ra);
+ c = FR(rc);
+ b = FR(rb);
+ fpimul(&a, &c, &t);
+ (t.s == b.s? fpiadd: fpisub)(&b, &t, d);
+}
+
+static ulong setfpscr(Emreg*);
+static void setfpcc(Emreg*, int);
+
+static void
+unimp(Emreg *em, ulong op)
+{
+ char buf[60];
+
+ snprint(buf, sizeof(buf), "sys: fp: pc=%lux unimp fp 0x%.8lux", em->ur->pc, op);
+ if(fpemudebug)
+ print("FPE: %s\n", buf);
+ error(buf);
+ /* no return */
+}
+
+/*
+ * floating load/store
+ */
+
+static void
+fpeairr(Emreg *em, ulong ir, void **eap, int *rdp)
+{
+ ulong ea;
+ long imm;
+ int ra, rd, upd;
+
+ getairr(ir);
+ ea = imm;
+ upd = (ir&(1L<<26))!=0;
+ if(ra) {
+ ea += REG(ra);
+ if(upd){
+ if(ra == REGSP)
+ panic("fpemu: r1 update"); /* can't do it because we're running on the same stack */
+ REG(ra) = ea;
+ }
+ } else {
+ if(upd)
+ unimp(em, ir);
+ }
+ *rdp = rd;
+ *eap = (void*)ea;
+ if(fpemudebug)
+ print("%8.8lux %s\tf%d,%ld(r%d) ea=%lux upd=%d\n", em->ur->pc, em->name, rd, imm, ra, ea, upd);
+}
+
+static void
+fpearrr(Emreg *em, ulong ir, int upd, void **eap, int *rdp)
+{
+ ulong ea;
+ int ra, rb, rd;
+
+ getarrr(ir);
+ ea = REG(rb);
+ if(ra){
+ ea += REG(ra);
+ if(upd){
+ if(ra == REGSP)
+ panic("fpemu: r1 update");
+ REG(ra) = ea;
+ }
+ if(fpemudebug)
+ 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);
+ } else {
+ if(upd)
+ unimp(em, ir);
+ if(fpemudebug)
+ print("%8.8lux %s\tf%d,(r%d) ea=%lux\n", em->ur->pc, em->name, rd, rb, ea);
+ }
+ *eap = (void*)ea;
+ *rdp = rd;
+}
+
+static void
+lfs(Emreg *em, ulong ir)
+{
+ void *ea;
+ int rd;
+
+ em->name = "lfs";
+ fpeairr(em, ir, &ea, &rd);
+ fpis2i(&FR(rd), (void*)ea);
+}
+
+static void
+lfsx(Emreg *em, ulong ir)
+{
+ void *ea;
+ int rd;
+
+ em->name = "lfsx";
+ fpearrr(em, ir, ((ir>>1)&0x3FF)==567, &ea, &rd);
+ fpis2i(&FR(rd), (void*)ea);
+}
+
+static void
+lfd(Emreg *em, ulong ir)
+{
+ void *ea;
+ int rd;
+
+ em->name = "lfd";
+ fpeairr(em, ir, &ea, &rd);
+ fpid2i(&FR(rd), (void*)ea);
+}
+
+static void
+lfdx(Emreg *em, ulong ir)
+{
+ void *ea;
+ int rd;
+
+ em->name = "lfdx";
+ fpearrr(em, ir, ((ir>>1)&0x3FF)==631, &ea, &rd);
+ fpid2i(&FR(rd), (void*)ea);
+}
+
+static void
+stfs(Emreg *em, ulong ir)
+{
+ void *ea;
+ int rd;
+ Internal tmp;
+
+ em->name = "stfs";
+ fpeairr(em, ir, &ea, &rd);
+ tmp = FR(rd);
+ fpii2s(ea, &tmp);
+}
+
+static void
+stfsx(Emreg *em, ulong ir)
+{
+ void *ea;
+ int rd;
+ Internal tmp;
+
+ em->name = "stfsx";
+ fpearrr(em, ir, getxo(ir)==695, &ea, &rd);
+ tmp = FR(rd);
+ fpii2s(ea, &tmp);
+}
+
+static void
+stfd(Emreg *em, ulong ir)
+{
+ void *ea;
+ int rd;
+ Internal tmp;
+
+ em->name = "stfd";
+ fpeairr(em, ir, &ea, &rd);
+ tmp = FR(rd);
+ fpii2d(ea, &tmp);
+}
+
+static void
+stfdx(Emreg *em, ulong ir)
+{
+ void *ea;
+ int rd;
+ Internal tmp;
+
+ em->name = "stfdx";
+ fpearrr(em, ir, ((ir>>1)&0x3FF)==759, &ea, &rd);
+ tmp = FR(rd);
+ fpii2d(ea, &tmp);
+}
+
+static void
+mcrfs(Emreg *em, ulong ir)
+{
+ int rd, ra, rb;
+ static ulong fpscr0[] ={
+ FPS_FX|FPS_OX,
+ FPS_UX|FPS_ZX|FPS_XX|FPS_VXSNAN,
+ FPS_VXISI|FPS_VXIDI|FPS_VXZDZ|FPS_VXIMZ,
+ FPS_VXVC,
+ 0,
+ FPS_VXCVI,
+ };
+
+ getarrr(ir);
+ if(rb || ra&3 || rd&3)
+ unimp(em, ir);
+ ra >>= 2;
+ rd >>= 2;
+ em->ur->cr = (em->ur->cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, em->ufp->fpscr));
+ em->ufp->fpscr &= ~fpscr0[ra];
+ if(fpemudebug)
+ print("%8.8lux mcrfs\tcrf%d,crf%d\n", em->ur->pc, rd, ra);
+}
+
+static void
+mffs(Emreg *em, ulong ir)
+{
+ int rd, ra, rb;
+ Double dw;
+
+ getarrr(ir);
+ if(ra || rb)
+ unimp(em, ir);
+ dw.h = 0;
+ dw.l = ((uvlong)0xFFF8000L<<16)|em->ufp->fpscr;
+ fpid2i(&FR(rd), &dw);
+ /* it's anyone's guess how CR1 should be set when ir&1 */
+ em->ur->cr &= ~mkCR(1, 0xE); /* leave SO, reset others */
+ if(fpemudebug)
+ print("%8.8lux mffs%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd);
+}
+
+static void
+mtfsb1(Emreg *em, ulong ir)
+{
+ int rd, ra, rb;
+
+ getarrr(ir);
+ if(ra || rb)
+ unimp(em, ir);
+ em->ufp->fpscr |= (1L << (31-rd));
+ /* BUG: should set summary bits */
+ if(ir & 1)
+ em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
+ if(fpemudebug)
+ print("%8.8lux mtfsb1%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd);
+}
+
+static void
+mtfsb0(Emreg *em, ulong ir)
+{
+ int rd, ra, rb;
+
+ getarrr(ir);
+ if(ra || rb)
+ unimp(em, ir);
+ em->ufp->fpscr &= ~(1L << (31-rd));
+ if(ir & 1)
+ em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
+ if(fpemudebug)
+ print("%8.8lux mtfsb0%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd);
+}
+
+static void
+mtfsf(Emreg *em, ulong ir)
+{
+ int fm, rb, i;
+ ulong v;
+ Internal b;
+ Double db;
+
+ if(ir & ((1L << 25)|(1L << 16)))
+ unimp(em, ir);
+ rb = (ir >> 11) & 0x1F;
+ fm = (ir >> 17) & 0xFF;
+ b = FR(rb);
+ fpii2d(&db, &b); /* reconstruct hi/lo format to recover low word */
+ v = db.l;
+ for(i=0; i<8; i++)
+ if(fm & (1 << (7-i)))
+ em->ufp->fpscr = (em->ufp->fpscr & ~mkCR(i, 0xF)) | mkCR(i, getCR(i, v));
+ /* BUG: should set FEX and VX `according to the usual rule' */
+ if(ir & 1)
+ em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
+ if(fpemudebug)
+ print("%8.8lux mtfsf%s\t#%.2x,fr%d\n", em->ur->pc, ir&1?".":"", fm, rb);
+}
+
+static void
+mtfsfi(Emreg *em, ulong ir)
+{
+ int imm, rd;
+
+ if(ir & ((0x7F << 16)|(1L << 11)))
+ unimp(em, ir);
+ rd = (ir >> 23) & 0xF;
+ imm = (ir >> 12) & 0xF;
+ em->ufp->fpscr = (em->ufp->fpscr & ~mkCR(rd, 0xF)) | mkCR(rd, imm);
+ /* BUG: should set FEX and VX `according to the usual rule' */
+ if(ir & 1)
+ em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
+ if(fpemudebug)
+ print("%8.8lux mtfsfi%s\tcrf%d,#%x\n", em->ur->pc, ir&1?".":"", rd, imm);
+}
+
+static void
+fcmp(Emreg *em, ulong ir)
+{
+ int fc, rd, ra, rb, sig, i;
+
+ getarrr(ir);
+ if(rd & 3)
+ unimp(em, ir);
+ rd >>= 2;
+ sig = 0;
+ switch(getxo(ir)) {
+ default:
+ unimp(em, ir);
+ case 32:
+ if(fpemudebug)
+ print("%8.8lux fcmpo\tcr%d,f%d,f%d\n", em->ur->pc, rd, ra, rb);
+ sig = 1;
+ break;
+ case 0:
+ if(fpemudebug)
+ print("%8.8lux fcmpu\tcr%d,f%d,f%d\n", em->ur->pc, rd, ra, rb);
+ break;
+ }
+ if(IsWeird(&FR(ra)) || IsWeird(&FR(rb))) {
+ if(sig){
+ ; /* BUG: should trap if not masked ... */
+ }
+ fc = CRFU;
+ } else {
+ i = fpicmp(&FR(ra), &FR(rb));
+ if(i > 0)
+ fc = CRGT;
+ else if(i == 0)
+ fc = CREQ;
+ else
+ fc = CRLT;
+ }
+ fc >>= 28;
+ em->ur->cr = (em->ur->cr & ~mkCR(rd,~0)) | mkCR(rd, fc);
+ em->ufp->fpscr = (em->ufp->fpscr & ~0xF800) | (fc<<11);
+ /* BUG: update FX, VXSNAN, VXVC */
+}
+
+static void
+fariths(Emreg *em, ulong ir)
+{
+ int rd, ra, rb, rc, fmt;
+ char *cc, *n;
+ ulong fpscr;
+ Internal *d;
+
+ fmt = 0;
+ rc = (ir>>6)&0x1F;
+ getarrr(ir);
+ d = &FR(rd);
+ switch(getxo(ir)&0x1F) { /* partial XO decode */
+ case 22: /* fsqrts */
+ case 24: /* fres */
+ default:
+ unimp(em, ir);
+ return;
+ case 18:
+ if(IsZero(&FR(rb))) {
+ em->ufp->fpscr |= FPS_ZX | FPS_FX;
+ error("sys: fp: zero divide");
+ }
+ fdiv(em, d, ra, rb);
+ n = "fdivs";
+ break;
+ case 20:
+ fsub(em, d, ra, rb);
+ n = "fsubs";
+ break;
+ case 21:
+ fadd(em, d, ra, rb);
+ n = "fadds";
+ break;
+ case 25:
+ fmul(em, d, ra, rc);
+ rb = rc;
+ n = "fmuls";
+ break;
+ case 28:
+ fmsub(em, d, ra, rc, rb);
+ fmt = 2;
+ n = "fmsubs";
+ break;
+ case 29:
+ fmadd(em, d, ra, rc, rb);
+ fmt = 2;
+ n = "fmadds";
+ break;
+ case 30:
+ fmsub(em, d, ra, rc, rb);
+ d->s ^= 1;
+ fmt = 2;
+ n = "fnmsubs";
+ break;
+ case 31:
+ fmadd(em, d, ra, rc, rb);
+ d->s ^= 1;
+ fmt = 2;
+ n = "fnmadds";
+ break;
+ }
+ if(fmt==1 && ra)
+ unimp(em, ir);
+ fpscr = setfpscr(em);
+ setfpcc(em, rd);
+ cc = "";
+ if(ir & 1) {
+ cc = ".";
+ em->ur->cr = (em->ur->cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
+ }
+ if(fpemudebug) {
+ switch(fmt) {
+ case 0:
+ print("%8.8lux %s%s\tfr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rb);
+ break;
+ case 1:
+ print("%8.8lux %s%s\tfr%d,fr%d\n", em->ur->pc, n, cc, rd, rb);
+ break;
+ case 2:
+ print("%8.8lux %s%s\tfr%d,fr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rc, rb);
+ break;
+ }
+ }
+}
+
+static void
+farith(Emreg *em, ulong ir)
+{
+ Word w;
+ Double dv;
+ int rd, ra, rb, rc, fmt;
+ char *cc, *n;
+ ulong fpscr;
+ int nocc;
+ Internal *d;
+
+ fmt = 0;
+ nocc = 0;
+ rc = (ir>>6)&0x1F;
+ getarrr(ir);
+ d = &FR(rd);
+ switch(getxo(ir)&0x1F) { /* partial XO decode */
+ case 22: /* frsqrt */
+ case 23: /* fsel */
+ case 26: /* fsqrte */
+ default:
+ unimp(em, ir);
+ return;
+ case 12: /* frsp */
+ *d = FR(rb); /* BUG: doesn't round to single precision */
+ fmt = 1;
+ n = "frsp";
+ break;
+ case 14: /* fctiw */ /* BUG: ignores rounding mode */
+ case 15: /* fctiwz */
+ fpii2w(&w, &FR(rb));
+ dv.h = 0;
+ dv.l = w;
+ fpid2i(d, &dv);
+ fmt = 1;
+ nocc = 1;
+ n = "fctiw";
+ break;
+ case 18:
+ if(IsZero(&FR(rb))) {
+ em->ufp->fpscr |= FPS_ZX | FPS_FX;
+ error("sys: fp: zero divide");
+ }
+ fdiv(em, d, ra, rb);
+ n = "fdiv";
+ break;
+ case 20:
+ fsub(em, d, ra, rb);
+ n = "fsub";
+ break;
+ case 21:
+ fadd(em, d, ra, rb);
+ n = "fadd";
+ break;
+ case 25:
+ fmul(em, d, ra, rc);
+ rb = rc;
+ n = "fmul";
+ break;
+ case 28:
+ fmsub(em, d, ra, rc, rb);
+ fmt = 2;
+ n = "fmsub";
+ break;
+ case 29:
+ fmadd(em, d, ra, rc, rb);
+ fmt = 2;
+ n = "fmadd";
+ break;
+ case 30:
+ fmsub(em, d, ra, rc, rb);
+ d->s ^= 1;
+ fmt = 2;
+ n = "fnmsub";
+ break;
+ case 31:
+ fmadd(em, d, ra, rc, rb);
+ d->s ^= 1;
+ fmt = 2;
+ n = "fnmadd";
+ break;
+ }
+ if(fmt==1 && ra)
+ unimp(em, ir);
+ fpscr = setfpscr(em);
+ if(nocc == 0)
+ setfpcc(em, rd);
+ cc = "";
+ if(ir & 1) {
+ cc = ".";
+ em->ur->cr = (em->ur->cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
+ }
+ if(fpemudebug) {
+ switch(fmt) {
+ case 0:
+ print("%8.8lux %s%s\tfr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rb);
+ break;
+ case 1:
+ print("%8.8lux %s%s\tfr%d,fr%d\n", em->ur->pc, n, cc, rd, rb);
+ break;
+ case 2:
+ print("%8.8lux %s%s\tfr%d,fr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rc, rb);
+ break;
+ }
+ }
+}
+
+static void
+farith2(Emreg *em, ulong ir)
+{
+ int rd, ra, rb;
+ char *cc, *n;
+ ulong fpscr;
+ Internal *d, *b;
+
+ getarrr(ir);
+ if(ra)
+ unimp(em, ir);
+ d = &FR(rd);
+ b = &FR(rb);
+ switch(getxo(ir)) { /* full XO decode */
+ default:
+ unimp(em, ir);
+ case 40:
+ *d = *b;
+ d->s ^= 1;
+ n = "fneg";
+ break;
+ case 72:
+ *d = *b;
+ n = "fmr";
+ break;
+ case 136:
+ *d = *b;
+ d->s = 1;
+ n = "fnabs";
+ break;
+ case 264:
+ *d = *b;
+ d->s = 0;
+ n = "fabs";
+ break;
+ }
+ fpscr = setfpscr(em);
+ setfpcc(em, rd);
+ cc = "";
+ if(ir & 1) {
+ cc = ".";
+ em->ur->cr = (em->ur->cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
+ }
+ if(fpemudebug)
+ print("%8.8lux %s%s\tfr%d,fr%d\n", em->ur->pc, n, cc, rd, rb);
+}
+
+static ulong
+setfpscr(Emreg *em)
+{
+ ulong fps, fpscr;
+
+ fps = 0; /* BUG: getfsr() */
+ fpscr = em->ufp->fpscr;
+ if(fps & FPAOVFL)
+ fpscr |= FPS_OX;
+ if(fps & FPAINEX)
+ fpscr |= FPS_XX;
+ if(fps & FPAUNFL)
+ fpscr |= FPS_UX;
+ if(fps & FPAZDIV)
+ fpscr |= FPS_ZX;
+ if(fpscr != em->ufp->fpscr) {
+ fpscr |= FPS_FX;
+ em->ufp->fpscr = fpscr;
+ }
+ return fpscr;
+}
+
+static void
+setfpcc(Emreg *em, int r)
+{
+ int c;
+ Internal *d;
+
+ d = &FR(r);
+ c = 0;
+ if(IsZero(d))
+ c |= 2;
+ else if(d->s == 1)
+ c |= 4;
+ else
+ c |= 8;
+ if(IsNaN(d))
+ c |= 1;
+ em->ufp->fpscr = (em->ufp->fpscr & ~0xF800) | (0<<15) | (c<<11); /* unsure about class bit */
+}
+
+static uchar op63flag[32] = {
+[12] 1, [14] 1, [15] 1, [18] 1, [20] 1, [21] 1, [22] 1,
+[23] 1, [25] 1, [26] 1, [28] 1, [29] 1, [30] 1, [31] 1,
+};
+
+/*
+ * returns the number of FP instructions emulated
+ */
+int
+fpipower(Ureg *ur)
+{
+ ulong op;
+ int xo;
+ Emreg emreg, *em;
+ FPenv *ufp;
+ int n;
+
+ ufp = &up->env->fpu; /* because all the state is in Osenv, it need not be saved/restored */
+ em = &emreg;
+ em->ur = ur;
+ em->fr = ufp->emreg;
+ em->ufp = ufp;
+ em->name = nil;
+ if(em->ufp->fpistate != FPACTIVE) {
+ em->ufp->fpistate = FPACTIVE;
+ em->ufp->fpscr = 0; /* TO DO */
+ for(n = 0; n < nelem(fpreginit); n++)
+ FR(31-n) = fpreginit[n];
+ }
+ for(n=0;;n++){
+ op = getulong(ur->pc);
+ em->ir = op;
+ if(fpemudebug > 1)
+ print("%8.8lux %8.8lux: ", ur->pc, op);
+ switch(op>>26){
+ default:
+ return n;
+ case 48: /* lfs */
+ case 49: /* lfsu */
+ lfs(em, op);
+ break;
+ case 50: /* lfd */
+ case 51: /* lfdu */
+ lfd(em, op);
+ break;
+ case 52: /* stfs */
+ case 53: /* stfsu */
+ stfs(em, op);
+ break;
+ case 54: /* stfd */
+ case 55: /* stfdu */
+ stfd(em, op);
+ break;
+ case 31: /* indexed load/store */
+ xo = getxo(op);
+ if((xo & 0x300) != 0x200)
+ return n;
+ switch(xo){
+ default:
+ return n;
+ case 535: /* lfsx */
+ case 567: /* lfsux */
+ lfsx(em, op);
+ break;
+ case 599: /* lfdx */
+ case 631: /* lfdux */
+ lfdx(em, op);
+ break;
+ case 663: /* stfsx */
+ case 695: /* stfsux */
+ stfsx(em, op);
+ break;
+ case 727: /* stfdx */
+ case 759: /* stfdux */
+ stfdx(em, op);
+ break;
+ }
+ break;
+ case 63: /* double precision */
+ xo = getxo(op);
+ if(op63flag[xo & 0x1F]){
+ farith(em, op);
+ break;
+ }
+ switch(xo){
+ default:
+ return n;
+ case 0: /* fcmpu */
+ case 32: /* fcmpo */
+ fcmp(em, op);
+ break;
+ case 40: /* fneg */
+ case 72: /* fmr */
+ case 136: /* fnabs */
+ case 264: /* fabs */
+ farith2(em, op);
+ break;
+ case 38:
+ mtfsb1(em, op);
+ break;
+ case 64:
+ mcrfs(em, op);
+ break;
+ case 70:
+ mtfsb0(em, op);
+ break;
+ case 134:
+ mtfsfi(em, op);
+ break;
+ case 583:
+ mffs(em, op);
+ break;
+ case 711:
+ mtfsf(em, op);
+ break;
+ }
+ break;
+ case 59: /* single precision */
+ fariths(em, op);
+ break;
+ }
+ ur->pc += 4;
+ if(anyhigher())
+ sched();
+ }
+ return n;
+}
+
+/*
+50: lfd frD,d(rA)
+51: lfdu frD,d(rA)
+31,631: lfdux frD,rA,rB
+31,599: lfdx frD,rA,rB
+48: lfs frD,d(rA)
+49: lfsu frD,d(rA)
+31,567: lfsux frD,rA,rB
+31,535: lfsx frD,rA,rB
+
+54: stfd frS,d(rA)
+55: stfdu frS,d(rA)
+31,759: stfdux frS,rA,rB
+31,727: stfdx frS,rA,rB
+52: stfs frS,d(rA)
+53: stfsu frS,d(rA)
+31,695: stfsux frS,rA,rB
+31,663: stfsx frS,rA,rB
+
+63,64: mcrfs crfD,crfS
+63,583: mffs[.] frD
+63,70: mtfsb0[.] crbD
+63,38: mtfsb1[.] crbD
+63,711: mtfsf[.] FM,frB
+63,134: mtfsfi[.] crfD,IMM
+*/
+
+/*
+float to int:
+ FMOVD g+0(SB),F1
+ FCTIWZ F1,F4
+ FMOVD F4,.rathole+0(SB)
+ MOVW .rathole+4(SB),R7
+ MOVW R7,l+0(SB)
+*/
+
+/*
+int to float:
+ MOVW $1127219200,R9
+ MOVW l+0(SB),R7
+ MOVW R9,.rathole+0(SB)
+ XOR $-2147483648,R7,R6
+ MOVW R6,.rathole+4(SB)
+ FMOVD .rathole+0(SB),F0
+ FSUB F27,F0
+
+unsigned to float:
+ MOVW ul+0(SB),R5
+ MOVW R9,.rathole+0(SB)
+ XOR $-2147483648,R5,R4
+ MOVW R4,.rathole+4(SB)
+ FMOVD .rathole+0(SB),F3
+ FSUB F27,F3
+ FCMPU F3,F28
+ BGE ,3(PC)
+ FMOVD $4.29496729600000000e+09,F2
+ FADD F2,F3
+ FMOVD F3,g+0(SB)
+*/