/* * 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 voidfadd(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 voidfsub(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 voidfmul(Emreg *em, Internal *d, int ra, int rb){ Internal a, b; a = FR(ra); b = FR(rb); fpimul(&b, &a, d);} static voidfdiv(Emreg *em, Internal *d, int ra, int rb){ Internal a, b; a = FR(ra); b = FR(rb); fpidiv(&b, &a, d);} static voidfmsub(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 voidfmadd(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 voidunimp(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 voidfpeairr(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 voidfpearrr(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 voidlfs(Emreg *em, ulong ir){ void *ea; int rd; em->name = "lfs"; fpeairr(em, ir, &ea, &rd); fpis2i(&FR(rd), (void*)ea);} static voidlfsx(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 voidlfd(Emreg *em, ulong ir){ void *ea; int rd; em->name = "lfd"; fpeairr(em, ir, &ea, &rd); fpid2i(&FR(rd), (void*)ea);} static voidlfdx(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 voidstfs(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 voidstfsx(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 voidstfd(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 voidstfdx(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 voidmcrfs(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 voidmffs(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 voidmtfsb1(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 voidmtfsb0(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 voidmtfsf(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 voidmtfsfi(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 voidfcmp(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 */Lines 1–500 of 970. Load more
/* * 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 */