ref: dd16eef8365cb0b9e4805c23291aadcaa596dd87
dir: /os/mpc/fpipower.c/
/*
* 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)
*/