123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <mach.h>
- #define Extern extern
- #include "power.h"
- uint32_t setfpscr(void);
- void setfpcc(double);
- void farith(uint32_t);
- void farith2(uint32_t);
- void fariths(uint32_t);
- void fcmp(uint32_t);
- void mtfsb1(uint32_t);
- void mcrfs(uint32_t);
- void mtfsb0(uint32_t);
- void mtfsf(uint32_t);
- void mtfsfi(uint32_t);
- void mffs(uint32_t);
- void mtfsf(uint32_t);
- 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(uint64_t v)
- {
- FPdbleword f;
- f.hi = v>>32;
- f.lo = v;
- return f.x;
- }
- static uint64_t
- fp2v(double d)
- {
- FPdbleword f;
- f.x = d;
- return ((uint64_t)f.hi<<32) | f.lo;
- }
- void
- lfs(uint32_t ir)
- {
- uint32_t ea;
- int imm, ra, rd, upd;
- union {
- uint32_t 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(uint32_t ir)
- {
- uint32_t ea;
- int rd, ra, rb, upd;
- union {
- uint32_t 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(uint32_t ir)
- {
- uint32_t 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(uint32_t ir)
- {
- uint32_t 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(uint32_t ir)
- {
- uint32_t ea;
- int imm, ra, rd, upd;
- union {
- float f;
- uint32_t 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(uint32_t ir)
- {
- uint32_t ea;
- int rd, ra, rb, upd;
- union {
- float f;
- uint32_t 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(uint32_t ir)
- {
- uint32_t 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(uint32_t ir)
- {
- uint32_t 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(uint32_t ir)
- {
- uint32_t rd, ra, rb;
- static uint32_t 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(uint32_t 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(uint32_t 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(uint32_t 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(uint32_t ir)
- {
- int fm, rb, i;
- FPdbleword d;
- uint32_t 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(uint32_t 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(uint32_t 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(uint32_t ir)
- {
- int rd, ra, rb, rc, fmt;
- char *cc;
- uint32_t 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(uint32_t ir)
- {
- int64_t vl;
- int rd, ra, rb, rc, fmt;
- char *cc;
- uint32_t 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(uint32_t ir)
- {
- int rd, ra, rb;
- char *cc;
- uint32_t 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);
- }
- uint32_t
- setfpscr(void)
- {
- uint32_t 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 */
- }
|