diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /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-x | sys/src/cmd/qi/float.c | 741 |
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 */ +} |