summaryrefslogtreecommitdiff
path: root/sys/src/cmd/qi/float.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/qi/float.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/qi/float.c')
-rwxr-xr-xsys/src/cmd/qi/float.c741
1 files changed, 741 insertions, 0 deletions
diff --git a/sys/src/cmd/qi/float.c b/sys/src/cmd/qi/float.c
new file mode 100755
index 000000000..2602adc33
--- /dev/null
+++ b/sys/src/cmd/qi/float.c
@@ -0,0 +1,741 @@
+#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 */
+}