diff options
Diffstat (limited to 'os/mpc/fpipower.c')
| -rw-r--r-- | os/mpc/fpipower.c | 970 |
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) +*/ |
