742 lines
13 KiB
C
742 lines
13 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <bio.h>
|
|
#include <mach.h>
|
|
#define Extern extern
|
|
#include "power.h"
|
|
|
|
ulong setfpscr(void);
|
|
void setfpcc(double);
|
|
void farith(ulong);
|
|
void farith2(ulong);
|
|
void fariths(ulong);
|
|
void fcmp(ulong);
|
|
void mtfsb1(ulong);
|
|
void mcrfs(ulong);
|
|
void mtfsb0(ulong);
|
|
void mtfsf(ulong);
|
|
void mtfsfi(ulong);
|
|
void mffs(ulong);
|
|
void mtfsf(ulong);
|
|
|
|
Inst op59[] = {
|
|
[18] {fariths, "fdivs", Ifloat},
|
|
[20] {fariths, "fsubs", Ifloat},
|
|
[21] {fariths, "fadds", Ifloat},
|
|
[22] {unimp, "fsqrts", Ifloat},
|
|
[24] {unimp, "fres", Ifloat},
|
|
[25] {fariths, "fmuls", Ifloat},
|
|
[28] {fariths, "fmsubs", Ifloat},
|
|
[29] {fariths, "fmadds", Ifloat},
|
|
[30] {fariths, "fnmsubs", Ifloat},
|
|
[31] {fariths, "fnmadds", Ifloat},
|
|
};
|
|
|
|
Inset ops59 = {op59, nelem(op59)};
|
|
|
|
Inst op63a[] = {
|
|
[12] {farith, "frsp", Ifloat},
|
|
[14] {farith, "fctiw", Ifloat},
|
|
[15] {farith, "fctiwz", Ifloat},
|
|
[18] {farith, "fdiv", Ifloat},
|
|
[20] {farith, "fsub", Ifloat},
|
|
[21] {farith, "fadd", Ifloat},
|
|
[22] {unimp, "frsqrt", Ifloat},
|
|
[23] {unimp, "fsel", Ifloat},
|
|
[25] {farith, "fmul", Ifloat},
|
|
[26] {unimp, "frsqrte", Ifloat},
|
|
[28] {farith, "fmsub", Ifloat},
|
|
[29] {farith, "fmadd", Ifloat},
|
|
[30] {farith, "fnmsub", Ifloat},
|
|
[31] {farith, "fnmadd", Ifloat},
|
|
};
|
|
|
|
Inset ops63a= {op63a, nelem(op63a)};
|
|
|
|
Inst op63b[] = {
|
|
[0] {fcmp, "fcmpu", Ifloat},
|
|
[32] {fcmp, "fcmpo", Ifloat},
|
|
[38] {mtfsb1, "mtfsb1", Ifloat},
|
|
[40] {farith2, "fneg", Ifloat},
|
|
[64] {mcrfs, "mcrfs", Ifloat},
|
|
[70] {mtfsb0, "mtfsb0", Ifloat},
|
|
[72] {farith2, "fmr", Ifloat},
|
|
[134] {mtfsfi, "mtfsfi", Ifloat},
|
|
[136] {farith2, "fnabs", Ifloat},
|
|
[264] {farith2, "fabs", Ifloat},
|
|
[583] {mffs, "mffs", Ifloat},
|
|
[711] {mtfsf, "mtfsf", Ifloat},
|
|
};
|
|
|
|
Inset ops63b = {op63b, nelem(op63b)};
|
|
|
|
void
|
|
fpreginit(void)
|
|
{
|
|
int i;
|
|
|
|
/* Normally initialised by the kernel */
|
|
reg.fd[27] = 4503601774854144.0;
|
|
reg.fd[29] = 0.5;
|
|
reg.fd[28] = 0.0;
|
|
reg.fd[30] = 1.0;
|
|
reg.fd[31] = 2.0;
|
|
for(i = 0; i < 27; i++)
|
|
reg.fd[i] = reg.fd[28];
|
|
}
|
|
|
|
static double
|
|
v2fp(uvlong v)
|
|
{
|
|
FPdbleword f;
|
|
|
|
f.hi = v>>32;
|
|
f.lo = v;
|
|
return f.x;
|
|
}
|
|
|
|
static uvlong
|
|
fp2v(double d)
|
|
{
|
|
FPdbleword f;
|
|
|
|
f.x = d;
|
|
return ((uvlong)f.hi<<32) | f.lo;
|
|
}
|
|
|
|
void
|
|
lfs(ulong ir)
|
|
{
|
|
ulong ea;
|
|
int imm, ra, rd, upd;
|
|
union {
|
|
ulong i;
|
|
float f;
|
|
} u;
|
|
|
|
getairr(ir);
|
|
ea = imm;
|
|
upd = (ir&(1L<<26))!=0;
|
|
if(ra) {
|
|
ea += reg.r[ra];
|
|
if(upd)
|
|
reg.r[ra] = ea;
|
|
} else {
|
|
if(upd)
|
|
undef(ir);
|
|
}
|
|
if(trace)
|
|
itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea);
|
|
|
|
u.i = getmem_w(ea);
|
|
reg.fd[rd] = u.f;
|
|
}
|
|
|
|
void
|
|
lfsx(ulong ir)
|
|
{
|
|
ulong ea;
|
|
int rd, ra, rb, upd;
|
|
union {
|
|
ulong i;
|
|
float f;
|
|
} u;
|
|
|
|
getarrr(ir);
|
|
ea = reg.r[rb];
|
|
upd = ((ir>>1)&0x3FF)==567;
|
|
if(ra){
|
|
ea += reg.r[ra];
|
|
if(upd)
|
|
reg.r[ra] = ea;
|
|
if(trace)
|
|
itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea);
|
|
} else {
|
|
if(upd)
|
|
undef(ir);
|
|
if(trace)
|
|
itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea);
|
|
}
|
|
|
|
u.i = getmem_w(ea);
|
|
reg.fd[rd] = u.f;
|
|
}
|
|
|
|
void
|
|
lfd(ulong ir)
|
|
{
|
|
ulong ea;
|
|
int imm, ra, rd, upd;
|
|
|
|
getairr(ir);
|
|
ea = imm;
|
|
upd = (ir&(1L<<26))!=0;
|
|
if(ra) {
|
|
ea += reg.r[ra];
|
|
if(upd)
|
|
reg.r[ra] = ea;
|
|
} else {
|
|
if(upd)
|
|
undef(ir);
|
|
}
|
|
if(trace)
|
|
itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea);
|
|
|
|
reg.fd[rd] = v2fp(getmem_v(ea));
|
|
}
|
|
|
|
void
|
|
lfdx(ulong ir)
|
|
{
|
|
ulong ea;
|
|
int rd, ra, rb, upd;
|
|
|
|
getarrr(ir);
|
|
ea = reg.r[rb];
|
|
upd = ((ir>>1)&0x3FF)==631;
|
|
if(ra){
|
|
ea += reg.r[ra];
|
|
if(upd)
|
|
reg.r[ra] = ea;
|
|
if(trace)
|
|
itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea);
|
|
} else {
|
|
if(upd)
|
|
undef(ir);
|
|
if(trace)
|
|
itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea);
|
|
}
|
|
|
|
reg.fd[rd] = v2fp(getmem_v(ea));
|
|
}
|
|
|
|
void
|
|
stfs(ulong ir)
|
|
{
|
|
ulong ea;
|
|
int imm, ra, rd, upd;
|
|
union {
|
|
float f;
|
|
ulong w;
|
|
} u;
|
|
|
|
getairr(ir);
|
|
ea = imm;
|
|
upd = (ir&(1L<<26))!=0;
|
|
if(ra) {
|
|
ea += reg.r[ra];
|
|
if(upd)
|
|
reg.r[ra] = ea;
|
|
} else {
|
|
if(upd)
|
|
undef(ir);
|
|
}
|
|
if(trace)
|
|
itrace("%s\tf%d,%ld(r%d) %lux=%g",
|
|
ci->name, rd, imm, ra, ea, reg.fd[rd]);
|
|
u.f = reg.fd[rd]; /* BUG: actual PPC conversion is more subtle than this */
|
|
putmem_w(ea, u.w);
|
|
}
|
|
|
|
void
|
|
stfsx(ulong ir)
|
|
{
|
|
ulong ea;
|
|
int rd, ra, rb, upd;
|
|
union {
|
|
float f;
|
|
ulong w;
|
|
} u;
|
|
|
|
getarrr(ir);
|
|
ea = reg.r[rb];
|
|
upd = getxo(ir)==695;
|
|
if(ra){
|
|
ea += reg.r[ra];
|
|
if(upd)
|
|
reg.r[ra] = ea;
|
|
if(trace)
|
|
itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, (float)reg.fd[rd]);
|
|
} else {
|
|
if(upd)
|
|
undef(ir);
|
|
if(trace)
|
|
itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, (float)reg.fd[rd]);
|
|
}
|
|
|
|
u.f = reg.fd[rd]; /* BUG: actual PPC conversion is more subtle than this */
|
|
putmem_w(ea, u.w);
|
|
}
|
|
|
|
void
|
|
stfd(ulong ir)
|
|
{
|
|
ulong ea;
|
|
int imm, ra, rd, upd;
|
|
|
|
getairr(ir);
|
|
ea = imm;
|
|
upd = (ir&(1L<<26))!=0;
|
|
if(ra) {
|
|
ea += reg.r[ra];
|
|
if(upd)
|
|
reg.r[ra] = ea;
|
|
} else {
|
|
if(upd)
|
|
undef(ir);
|
|
}
|
|
if(trace)
|
|
itrace("%s\tf%d,%ld(r%d) %lux=%g",
|
|
ci->name, rd, imm, ra, ea, reg.fd[rd]);
|
|
|
|
putmem_v(ea, fp2v(reg.fd[rd]));
|
|
}
|
|
|
|
void
|
|
stfdx(ulong ir)
|
|
{
|
|
ulong ea;
|
|
int rd, ra, rb, upd;
|
|
|
|
getarrr(ir);
|
|
ea = reg.r[rb];
|
|
upd = ((ir>>1)&0x3FF)==759;
|
|
if(ra){
|
|
ea += reg.r[ra];
|
|
if(upd)
|
|
reg.r[ra] = ea;
|
|
if(trace)
|
|
itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, reg.fd[rd]);
|
|
} else {
|
|
if(upd)
|
|
undef(ir);
|
|
if(trace)
|
|
itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, reg.fd[rd]);
|
|
}
|
|
|
|
putmem_v(ea, fp2v(reg.fd[rd]));
|
|
}
|
|
|
|
void
|
|
mcrfs(ulong ir)
|
|
{
|
|
ulong 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)
|
|
undef(ir);
|
|
ra >>= 2;
|
|
rd >>= 2;
|
|
reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, reg.fpscr));
|
|
reg.fpscr &= ~fpscr0[ra];
|
|
if(trace)
|
|
itrace("mcrfs\tcrf%d,crf%d\n", rd, ra);
|
|
}
|
|
|
|
void
|
|
mffs(ulong ir)
|
|
{
|
|
int rd, ra, rb;
|
|
FPdbleword d;
|
|
|
|
getarrr(ir);
|
|
if(ra || rb)
|
|
undef(ir);
|
|
d.hi = 0xFFF80000UL;
|
|
d.lo = reg.fpscr;
|
|
reg.fd[rd] = d.x;
|
|
/* it's anyone's guess how CR1 should be set when ir&1 */
|
|
reg.cr &= ~mkCR(1, 0xE); /* leave SO, reset others */
|
|
if(trace)
|
|
itrace("mffs%s\tfr%d\n", ir&1?".":"", rd);
|
|
}
|
|
|
|
void
|
|
mtfsb1(ulong ir)
|
|
{
|
|
int rd, ra, rb;
|
|
|
|
getarrr(ir);
|
|
if(ra || rb)
|
|
undef(ir);
|
|
reg.fpscr |= (1L << (31-rd));
|
|
/* BUG: should set summary bits */
|
|
if(ir & 1)
|
|
reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
|
|
if(trace)
|
|
itrace("mtfsb1%s\tfr%d\n", ir&1?".":"", rd);
|
|
}
|
|
|
|
void
|
|
mtfsb0(ulong ir)
|
|
{
|
|
int rd, ra, rb;
|
|
|
|
getarrr(ir);
|
|
if(ra || rb)
|
|
undef(ir);
|
|
reg.fpscr &= ~(1L << (31-rd));
|
|
if(ir & 1)
|
|
reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
|
|
if(trace)
|
|
itrace("mtfsb0%s\tfr%d\n", ir&1?".":"", rd);
|
|
}
|
|
|
|
void
|
|
mtfsf(ulong ir)
|
|
{
|
|
int fm, rb, i;
|
|
FPdbleword d;
|
|
ulong v;
|
|
|
|
if(ir & ((1L << 25)|(1L << 16)))
|
|
undef(ir);
|
|
rb = (ir >> 11) & 0x1F;
|
|
fm = (ir >> 17) & 0xFF;
|
|
d.x = reg.fd[rb];
|
|
v = d.lo;
|
|
for(i=0; i<8; i++)
|
|
if(fm & (1 << (7-i)))
|
|
reg.fpscr = (reg.fpscr & ~mkCR(i, 0xF)) | mkCR(i, getCR(i, v));
|
|
/* BUG: should set FEX and VX `according to the usual rule' */
|
|
if(ir & 1)
|
|
reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
|
|
if(trace)
|
|
itrace("mtfsf%s\t#%.2x,fr%d", ir&1?".":"", fm, rb);
|
|
}
|
|
|
|
void
|
|
mtfsfi(ulong ir)
|
|
{
|
|
int imm, rd;
|
|
|
|
if(ir & ((0x7F << 16)|(1L << 11)))
|
|
undef(ir);
|
|
rd = (ir >> 23) & 0xF;
|
|
imm = (ir >> 12) & 0xF;
|
|
reg.fpscr = (reg.fpscr & ~mkCR(rd, 0xF)) | mkCR(rd, imm);
|
|
/* BUG: should set FEX and VX `according to the usual rule' */
|
|
if(ir & 1)
|
|
reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
|
|
if(trace)
|
|
itrace("mtfsfi%s\tcrf%d,#%x", ir&1?".":"", rd, imm);
|
|
}
|
|
|
|
void
|
|
fcmp(ulong ir)
|
|
{
|
|
int fc, rd, ra, rb;
|
|
|
|
getarrr(ir);
|
|
if(rd & 3)
|
|
undef(ir);
|
|
rd >>= 2;
|
|
SET(fc);
|
|
switch(getxo(ir)) {
|
|
default:
|
|
undef(ir);
|
|
case 0:
|
|
if(trace)
|
|
itrace("fcmpu\tcr%d,f%d,f%d", rd, ra, rb);
|
|
if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) {
|
|
fc = CRFU;
|
|
break;
|
|
}
|
|
if(reg.fd[ra] == reg.fd[rb]) {
|
|
fc = CREQ;
|
|
break;
|
|
}
|
|
if(reg.fd[ra] < reg.fd[rb]) {
|
|
fc = CRLT;
|
|
break;
|
|
}
|
|
if(reg.fd[ra] > reg.fd[rb]) {
|
|
fc = CRGT;
|
|
break;
|
|
}
|
|
print("qi: fcmp error\n");
|
|
break;
|
|
case 32:
|
|
if(trace)
|
|
itrace("fcmpo\tcr%d,f%d,f%d", rd, ra, rb);
|
|
if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) { /* BUG: depends whether quiet or signalling ... */
|
|
fc = CRFU;
|
|
Bprint(bioout, "invalid_fp_register\n");
|
|
longjmp(errjmp, 0);
|
|
}
|
|
if(reg.fd[ra] == reg.fd[rb]) {
|
|
fc = CREQ;
|
|
break;
|
|
}
|
|
if(reg.fd[ra] < reg.fd[rb]) {
|
|
fc = CRLT;
|
|
break;
|
|
}
|
|
if(reg.fd[ra] > reg.fd[rb]) {
|
|
fc = CRGT;
|
|
break;
|
|
}
|
|
print("qi: fcmp error\n");
|
|
break;
|
|
|
|
}
|
|
fc >>= 28;
|
|
reg.cr = (reg.cr & ~mkCR(rd,~0)) | mkCR(rd, fc);
|
|
reg.fpscr = (reg.fpscr & ~0xF800) | (fc<<11);
|
|
/* BUG: update FX, VXSNAN, VXVC */
|
|
}
|
|
|
|
/*
|
|
* the farith functions probably don't produce the right results
|
|
* in the presence of NaNs, Infs, etc., esp. wrt exception handling,
|
|
*/
|
|
void
|
|
fariths(ulong ir)
|
|
{
|
|
int rd, ra, rb, rc, fmt;
|
|
char *cc;
|
|
ulong fpscr;
|
|
|
|
fmt = 0;
|
|
rc = (ir>>6)&0x1F;
|
|
getarrr(ir);
|
|
switch(getxo(ir)&0x1F) { /* partial XO decode */
|
|
default:
|
|
undef(ir);
|
|
case 18:
|
|
if((float)reg.fd[rb] == 0.0) {
|
|
Bprint(bioout, "fp_exception ZX\n");
|
|
reg.fpscr |= FPS_ZX | FPS_FX;
|
|
longjmp(errjmp, 0);
|
|
}
|
|
reg.fd[rd] = (float)(reg.fd[ra] / reg.fd[rb]);
|
|
break;
|
|
case 20:
|
|
reg.fd[rd] = (float)(reg.fd[ra] - reg.fd[rb]);
|
|
break;
|
|
case 21:
|
|
reg.fd[rd] = (float)(reg.fd[ra] + reg.fd[rb]);
|
|
break;
|
|
case 25:
|
|
reg.fd[rd] = (float)(reg.fd[ra] * reg.fd[rc]);
|
|
rb = rc;
|
|
break;
|
|
case 28:
|
|
reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
|
|
fmt = 2;
|
|
break;
|
|
case 29:
|
|
reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
|
|
fmt = 2;
|
|
break;
|
|
case 30:
|
|
reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
|
|
fmt = 2;
|
|
break;
|
|
case 31:
|
|
reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
|
|
fmt = 2;
|
|
break;
|
|
}
|
|
if(fmt==1 && ra)
|
|
undef(ir);
|
|
fpscr = setfpscr();
|
|
setfpcc(reg.fd[rd]);
|
|
cc = "";
|
|
if(ir & 1) {
|
|
cc = ".";
|
|
reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
|
|
}
|
|
if(trace) {
|
|
switch(fmt) {
|
|
case 0:
|
|
itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb);
|
|
break;
|
|
case 1:
|
|
itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
|
|
break;
|
|
case 2:
|
|
itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
farith(ulong ir)
|
|
{
|
|
vlong vl;
|
|
int rd, ra, rb, rc, fmt;
|
|
char *cc;
|
|
ulong fpscr;
|
|
int nocc;
|
|
double d;
|
|
|
|
fmt = 0;
|
|
nocc = 0;
|
|
rc = (ir>>6)&0x1F;
|
|
getarrr(ir);
|
|
switch(getxo(ir)&0x1F) { /* partial XO decode */
|
|
default:
|
|
undef(ir);
|
|
case 12: /* frsp */
|
|
reg.fd[rd] = (float)reg.fd[rb];
|
|
fmt = 1;
|
|
break;
|
|
case 14: /* fctiw */ /* BUG: ignores rounding mode */
|
|
case 15: /* fctiwz */
|
|
d = reg.fd[rb];
|
|
if(d >= 0x7fffffff)
|
|
vl = 0x7fffffff;
|
|
else if(d < 0x80000000)
|
|
vl = 0x80000000;
|
|
else
|
|
vl = d;
|
|
reg.fd[rd] = v2fp(vl);
|
|
fmt = 1;
|
|
nocc = 1;
|
|
break;
|
|
case 18:
|
|
if(reg.fd[rb] == 0.0) {
|
|
Bprint(bioout, "fp_exception ZX\n");
|
|
reg.fpscr |= FPS_ZX | FPS_FX;
|
|
longjmp(errjmp, 0);
|
|
}
|
|
reg.fd[rd] = reg.fd[ra] / reg.fd[rb];
|
|
break;
|
|
case 20:
|
|
reg.fd[rd] = reg.fd[ra] - reg.fd[rb];
|
|
break;
|
|
case 21:
|
|
reg.fd[rd] = reg.fd[ra] + reg.fd[rb];
|
|
break;
|
|
case 25:
|
|
reg.fd[rd] = reg.fd[ra] * reg.fd[rc];
|
|
rb = rc;
|
|
break;
|
|
case 28:
|
|
reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) - reg.fd[rb];
|
|
fmt = 2;
|
|
break;
|
|
case 29:
|
|
reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) + reg.fd[rb];
|
|
fmt = 2;
|
|
break;
|
|
case 30:
|
|
reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
|
|
fmt = 2;
|
|
break;
|
|
case 31:
|
|
reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
|
|
fmt = 2;
|
|
break;
|
|
}
|
|
if(fmt==1 && ra)
|
|
undef(ir);
|
|
fpscr = setfpscr();
|
|
if(nocc == 0)
|
|
setfpcc(reg.fd[rd]);
|
|
cc = "";
|
|
if(ir & 1) {
|
|
cc = ".";
|
|
reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
|
|
}
|
|
if(trace) {
|
|
switch(fmt) {
|
|
case 0:
|
|
itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb);
|
|
break;
|
|
case 1:
|
|
itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
|
|
break;
|
|
case 2:
|
|
itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
farith2(ulong ir)
|
|
{
|
|
int rd, ra, rb;
|
|
char *cc;
|
|
ulong fpscr;
|
|
|
|
getarrr(ir);
|
|
switch(getxo(ir)) { /* full XO decode */
|
|
default:
|
|
undef(ir);
|
|
case 40:
|
|
reg.fd[rd] = -reg.fd[rb];
|
|
break;
|
|
case 72:
|
|
reg.fd[rd] = reg.fd[rb];
|
|
break;
|
|
case 136:
|
|
reg.fd[rd] = -fabs(reg.fd[rb]);
|
|
break;
|
|
case 264:
|
|
reg.fd[rd] = fabs(reg.fd[rb]);
|
|
break;
|
|
}
|
|
if(ra)
|
|
undef(ir);
|
|
fpscr = setfpscr();
|
|
setfpcc(reg.fd[rd]);
|
|
cc = "";
|
|
if(ir & 1) {
|
|
cc = ".";
|
|
reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
|
|
}
|
|
if(trace)
|
|
itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
|
|
}
|
|
|
|
ulong
|
|
setfpscr(void)
|
|
{
|
|
ulong fps, fpscr;
|
|
|
|
fps = getfsr();
|
|
fpscr = reg.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 != reg.fpscr) {
|
|
fpscr |= FPS_FX;
|
|
reg.fpscr = fpscr;
|
|
}
|
|
return fpscr;
|
|
}
|
|
|
|
void
|
|
setfpcc(double r)
|
|
{
|
|
int c;
|
|
|
|
c = 0;
|
|
if(r == 0)
|
|
c |= 2;
|
|
else if(r < 0)
|
|
c |= 4;
|
|
else
|
|
c |= 8;
|
|
if(isNaN(r))
|
|
c |= 1;
|
|
reg.fpscr = (reg.fpscr & ~0xF800) | (0<<15) | (c<<11); /* unsure about class bit */
|
|
}
|