17d9195a7SDavid du Colombier #include <u.h>
27d9195a7SDavid du Colombier #include <libc.h>
37d9195a7SDavid du Colombier #include <bio.h>
47d9195a7SDavid du Colombier #include <mach.h>
57d9195a7SDavid du Colombier #define Extern extern
67d9195a7SDavid du Colombier #include "power.h"
77d9195a7SDavid du Colombier
87d9195a7SDavid du Colombier ulong setfpscr(void);
97d9195a7SDavid du Colombier void setfpcc(double);
107d9195a7SDavid du Colombier void farith(ulong);
117d9195a7SDavid du Colombier void farith2(ulong);
127d9195a7SDavid du Colombier void fariths(ulong);
137d9195a7SDavid du Colombier void fcmp(ulong);
147d9195a7SDavid du Colombier void mtfsb1(ulong);
157d9195a7SDavid du Colombier void mcrfs(ulong);
167d9195a7SDavid du Colombier void mtfsb0(ulong);
177d9195a7SDavid du Colombier void mtfsf(ulong);
187d9195a7SDavid du Colombier void mtfsfi(ulong);
197d9195a7SDavid du Colombier void mffs(ulong);
207d9195a7SDavid du Colombier void mtfsf(ulong);
217d9195a7SDavid du Colombier
227d9195a7SDavid du Colombier Inst op59[] = {
237d9195a7SDavid du Colombier [18] {fariths, "fdivs", Ifloat},
247d9195a7SDavid du Colombier [20] {fariths, "fsubs", Ifloat},
257d9195a7SDavid du Colombier [21] {fariths, "fadds", Ifloat},
267d9195a7SDavid du Colombier [22] {unimp, "fsqrts", Ifloat},
277d9195a7SDavid du Colombier [24] {unimp, "fres", Ifloat},
287d9195a7SDavid du Colombier [25] {fariths, "fmuls", Ifloat},
297d9195a7SDavid du Colombier [28] {fariths, "fmsubs", Ifloat},
307d9195a7SDavid du Colombier [29] {fariths, "fmadds", Ifloat},
317d9195a7SDavid du Colombier [30] {fariths, "fnmsubs", Ifloat},
327d9195a7SDavid du Colombier [31] {fariths, "fnmadds", Ifloat},
337d9195a7SDavid du Colombier };
347d9195a7SDavid du Colombier
357d9195a7SDavid du Colombier Inset ops59 = {op59, nelem(op59)};
367d9195a7SDavid du Colombier
377d9195a7SDavid du Colombier Inst op63a[] = {
387d9195a7SDavid du Colombier [12] {farith, "frsp", Ifloat},
397d9195a7SDavid du Colombier [14] {farith, "fctiw", Ifloat},
407d9195a7SDavid du Colombier [15] {farith, "fctiwz", Ifloat},
417d9195a7SDavid du Colombier [18] {farith, "fdiv", Ifloat},
427d9195a7SDavid du Colombier [20] {farith, "fsub", Ifloat},
437d9195a7SDavid du Colombier [21] {farith, "fadd", Ifloat},
447d9195a7SDavid du Colombier [22] {unimp, "frsqrt", Ifloat},
457d9195a7SDavid du Colombier [23] {unimp, "fsel", Ifloat},
467d9195a7SDavid du Colombier [25] {farith, "fmul", Ifloat},
477d9195a7SDavid du Colombier [26] {unimp, "frsqrte", Ifloat},
487d9195a7SDavid du Colombier [28] {farith, "fmsub", Ifloat},
497d9195a7SDavid du Colombier [29] {farith, "fmadd", Ifloat},
507d9195a7SDavid du Colombier [30] {farith, "fnmsub", Ifloat},
517d9195a7SDavid du Colombier [31] {farith, "fnmadd", Ifloat},
527d9195a7SDavid du Colombier };
537d9195a7SDavid du Colombier
547d9195a7SDavid du Colombier Inset ops63a= {op63a, nelem(op63a)};
557d9195a7SDavid du Colombier
567d9195a7SDavid du Colombier Inst op63b[] = {
577d9195a7SDavid du Colombier [0] {fcmp, "fcmpu", Ifloat},
587d9195a7SDavid du Colombier [32] {fcmp, "fcmpo", Ifloat},
597d9195a7SDavid du Colombier [38] {mtfsb1, "mtfsb1", Ifloat},
607d9195a7SDavid du Colombier [40] {farith2, "fneg", Ifloat},
617d9195a7SDavid du Colombier [64] {mcrfs, "mcrfs", Ifloat},
627d9195a7SDavid du Colombier [70] {mtfsb0, "mtfsb0", Ifloat},
637d9195a7SDavid du Colombier [72] {farith2, "fmr", Ifloat},
647d9195a7SDavid du Colombier [134] {mtfsfi, "mtfsfi", Ifloat},
657d9195a7SDavid du Colombier [136] {farith2, "fnabs", Ifloat},
667d9195a7SDavid du Colombier [264] {farith2, "fabs", Ifloat},
677d9195a7SDavid du Colombier [583] {mffs, "mffs", Ifloat},
687d9195a7SDavid du Colombier [711] {mtfsf, "mtfsf", Ifloat},
697d9195a7SDavid du Colombier };
707d9195a7SDavid du Colombier
717d9195a7SDavid du Colombier Inset ops63b = {op63b, nelem(op63b)};
727d9195a7SDavid du Colombier
737d9195a7SDavid du Colombier void
fpreginit(void)74*6891d857SDavid du Colombier fpreginit(void)
75*6891d857SDavid du Colombier {
76*6891d857SDavid du Colombier int i;
77*6891d857SDavid du Colombier
78*6891d857SDavid du Colombier /* Normally initialised by the kernel */
79*6891d857SDavid du Colombier reg.fd[27] = 4503601774854144.0;
80*6891d857SDavid du Colombier reg.fd[29] = 0.5;
81*6891d857SDavid du Colombier reg.fd[28] = 0.0;
82*6891d857SDavid du Colombier reg.fd[30] = 1.0;
83*6891d857SDavid du Colombier reg.fd[31] = 2.0;
84*6891d857SDavid du Colombier for(i = 0; i < 27; i++)
85*6891d857SDavid du Colombier reg.fd[i] = reg.fd[28];
86*6891d857SDavid du Colombier }
87*6891d857SDavid du Colombier
88*6891d857SDavid du Colombier static double
v2fp(uvlong v)89*6891d857SDavid du Colombier v2fp(uvlong v)
90*6891d857SDavid du Colombier {
91*6891d857SDavid du Colombier FPdbleword f;
92*6891d857SDavid du Colombier
93*6891d857SDavid du Colombier f.hi = v>>32;
94*6891d857SDavid du Colombier f.lo = v;
95*6891d857SDavid du Colombier return f.x;
96*6891d857SDavid du Colombier }
97*6891d857SDavid du Colombier
98*6891d857SDavid du Colombier static uvlong
fp2v(double d)99*6891d857SDavid du Colombier fp2v(double d)
100*6891d857SDavid du Colombier {
101*6891d857SDavid du Colombier FPdbleword f;
102*6891d857SDavid du Colombier
103*6891d857SDavid du Colombier f.x = d;
104*6891d857SDavid du Colombier return ((uvlong)f.hi<<32) | f.lo;
105*6891d857SDavid du Colombier }
106*6891d857SDavid du Colombier
107*6891d857SDavid du Colombier void
lfs(ulong ir)1087d9195a7SDavid du Colombier lfs(ulong ir)
1097d9195a7SDavid du Colombier {
1107d9195a7SDavid du Colombier ulong ea;
1117d9195a7SDavid du Colombier int imm, ra, rd, upd;
1127d9195a7SDavid du Colombier union {
1137d9195a7SDavid du Colombier ulong i;
1147d9195a7SDavid du Colombier float f;
1157d9195a7SDavid du Colombier } u;
1167d9195a7SDavid du Colombier
1177d9195a7SDavid du Colombier getairr(ir);
1187d9195a7SDavid du Colombier ea = imm;
1197d9195a7SDavid du Colombier upd = (ir&(1L<<26))!=0;
1207d9195a7SDavid du Colombier if(ra) {
1217d9195a7SDavid du Colombier ea += reg.r[ra];
1227d9195a7SDavid du Colombier if(upd)
1237d9195a7SDavid du Colombier reg.r[ra] = ea;
1247d9195a7SDavid du Colombier } else {
1257d9195a7SDavid du Colombier if(upd)
1267d9195a7SDavid du Colombier undef(ir);
1277d9195a7SDavid du Colombier }
1287d9195a7SDavid du Colombier if(trace)
1297d9195a7SDavid du Colombier itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea);
1307d9195a7SDavid du Colombier
1317d9195a7SDavid du Colombier u.i = getmem_w(ea);
1327d9195a7SDavid du Colombier reg.fd[rd] = u.f;
1337d9195a7SDavid du Colombier }
1347d9195a7SDavid du Colombier
1357d9195a7SDavid du Colombier void
lfsx(ulong ir)1367d9195a7SDavid du Colombier lfsx(ulong ir)
1377d9195a7SDavid du Colombier {
1387d9195a7SDavid du Colombier ulong ea;
1397d9195a7SDavid du Colombier int rd, ra, rb, upd;
1407d9195a7SDavid du Colombier union {
1417d9195a7SDavid du Colombier ulong i;
1427d9195a7SDavid du Colombier float f;
1437d9195a7SDavid du Colombier } u;
1447d9195a7SDavid du Colombier
1457d9195a7SDavid du Colombier getarrr(ir);
1467d9195a7SDavid du Colombier ea = reg.r[rb];
1477d9195a7SDavid du Colombier upd = ((ir>>1)&0x3FF)==567;
1487d9195a7SDavid du Colombier if(ra){
1497d9195a7SDavid du Colombier ea += reg.r[ra];
1507d9195a7SDavid du Colombier if(upd)
1517d9195a7SDavid du Colombier reg.r[ra] = ea;
1527d9195a7SDavid du Colombier if(trace)
1537d9195a7SDavid du Colombier itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea);
1547d9195a7SDavid du Colombier } else {
1557d9195a7SDavid du Colombier if(upd)
1567d9195a7SDavid du Colombier undef(ir);
1577d9195a7SDavid du Colombier if(trace)
1587d9195a7SDavid du Colombier itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea);
1597d9195a7SDavid du Colombier }
1607d9195a7SDavid du Colombier
1617d9195a7SDavid du Colombier u.i = getmem_w(ea);
1627d9195a7SDavid du Colombier reg.fd[rd] = u.f;
1637d9195a7SDavid du Colombier }
1647d9195a7SDavid du Colombier
1657d9195a7SDavid du Colombier void
lfd(ulong ir)1667d9195a7SDavid du Colombier lfd(ulong ir)
1677d9195a7SDavid du Colombier {
1687d9195a7SDavid du Colombier ulong ea;
1697d9195a7SDavid du Colombier int imm, ra, rd, upd;
1707d9195a7SDavid du Colombier
1717d9195a7SDavid du Colombier getairr(ir);
1727d9195a7SDavid du Colombier ea = imm;
1737d9195a7SDavid du Colombier upd = (ir&(1L<<26))!=0;
1747d9195a7SDavid du Colombier if(ra) {
1757d9195a7SDavid du Colombier ea += reg.r[ra];
1767d9195a7SDavid du Colombier if(upd)
1777d9195a7SDavid du Colombier reg.r[ra] = ea;
1787d9195a7SDavid du Colombier } else {
1797d9195a7SDavid du Colombier if(upd)
1807d9195a7SDavid du Colombier undef(ir);
1817d9195a7SDavid du Colombier }
1827d9195a7SDavid du Colombier if(trace)
1837d9195a7SDavid du Colombier itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea);
1847d9195a7SDavid du Colombier
185*6891d857SDavid du Colombier reg.fd[rd] = v2fp(getmem_v(ea));
1867d9195a7SDavid du Colombier }
1877d9195a7SDavid du Colombier
1887d9195a7SDavid du Colombier void
lfdx(ulong ir)1897d9195a7SDavid du Colombier lfdx(ulong ir)
1907d9195a7SDavid du Colombier {
1917d9195a7SDavid du Colombier ulong ea;
1927d9195a7SDavid du Colombier int rd, ra, rb, upd;
1937d9195a7SDavid du Colombier
1947d9195a7SDavid du Colombier getarrr(ir);
1957d9195a7SDavid du Colombier ea = reg.r[rb];
1967d9195a7SDavid du Colombier upd = ((ir>>1)&0x3FF)==631;
1977d9195a7SDavid du Colombier if(ra){
1987d9195a7SDavid du Colombier ea += reg.r[ra];
1997d9195a7SDavid du Colombier if(upd)
2007d9195a7SDavid du Colombier reg.r[ra] = ea;
2017d9195a7SDavid du Colombier if(trace)
2027d9195a7SDavid du Colombier itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea);
2037d9195a7SDavid du Colombier } else {
2047d9195a7SDavid du Colombier if(upd)
2057d9195a7SDavid du Colombier undef(ir);
2067d9195a7SDavid du Colombier if(trace)
2077d9195a7SDavid du Colombier itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea);
2087d9195a7SDavid du Colombier }
2097d9195a7SDavid du Colombier
210*6891d857SDavid du Colombier reg.fd[rd] = v2fp(getmem_v(ea));
2117d9195a7SDavid du Colombier }
2127d9195a7SDavid du Colombier
2137d9195a7SDavid du Colombier void
stfs(ulong ir)2147d9195a7SDavid du Colombier stfs(ulong ir)
2157d9195a7SDavid du Colombier {
2167d9195a7SDavid du Colombier ulong ea;
2177d9195a7SDavid du Colombier int imm, ra, rd, upd;
2187d9195a7SDavid du Colombier union {
2197d9195a7SDavid du Colombier float f;
2207d9195a7SDavid du Colombier ulong w;
2217d9195a7SDavid du Colombier } u;
2227d9195a7SDavid du Colombier
2237d9195a7SDavid du Colombier getairr(ir);
2247d9195a7SDavid du Colombier ea = imm;
2257d9195a7SDavid du Colombier upd = (ir&(1L<<26))!=0;
2267d9195a7SDavid du Colombier if(ra) {
2277d9195a7SDavid du Colombier ea += reg.r[ra];
2287d9195a7SDavid du Colombier if(upd)
2297d9195a7SDavid du Colombier reg.r[ra] = ea;
2307d9195a7SDavid du Colombier } else {
2317d9195a7SDavid du Colombier if(upd)
2327d9195a7SDavid du Colombier undef(ir);
2337d9195a7SDavid du Colombier }
2347d9195a7SDavid du Colombier if(trace)
2357d9195a7SDavid du Colombier itrace("%s\tf%d,%ld(r%d) %lux=%g",
2367d9195a7SDavid du Colombier ci->name, rd, imm, ra, ea, reg.fd[rd]);
2377d9195a7SDavid du Colombier u.f = reg.fd[rd]; /* BUG: actual PPC conversion is more subtle than this */
2387d9195a7SDavid du Colombier putmem_w(ea, u.w);
2397d9195a7SDavid du Colombier }
2407d9195a7SDavid du Colombier
2417d9195a7SDavid du Colombier void
stfsx(ulong ir)2427d9195a7SDavid du Colombier stfsx(ulong ir)
2437d9195a7SDavid du Colombier {
2447d9195a7SDavid du Colombier ulong ea;
2457d9195a7SDavid du Colombier int rd, ra, rb, upd;
2467d9195a7SDavid du Colombier union {
2477d9195a7SDavid du Colombier float f;
2487d9195a7SDavid du Colombier ulong w;
2497d9195a7SDavid du Colombier } u;
2507d9195a7SDavid du Colombier
2517d9195a7SDavid du Colombier getarrr(ir);
2527d9195a7SDavid du Colombier ea = reg.r[rb];
2537d9195a7SDavid du Colombier upd = getxo(ir)==695;
2547d9195a7SDavid du Colombier if(ra){
2557d9195a7SDavid du Colombier ea += reg.r[ra];
2567d9195a7SDavid du Colombier if(upd)
2577d9195a7SDavid du Colombier reg.r[ra] = ea;
2587d9195a7SDavid du Colombier if(trace)
2597d9195a7SDavid du Colombier itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, (float)reg.fd[rd]);
2607d9195a7SDavid du Colombier } else {
2617d9195a7SDavid du Colombier if(upd)
2627d9195a7SDavid du Colombier undef(ir);
2637d9195a7SDavid du Colombier if(trace)
2647d9195a7SDavid du Colombier itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, (float)reg.fd[rd]);
2657d9195a7SDavid du Colombier }
2667d9195a7SDavid du Colombier
2677d9195a7SDavid du Colombier u.f = reg.fd[rd]; /* BUG: actual PPC conversion is more subtle than this */
2687d9195a7SDavid du Colombier putmem_w(ea, u.w);
2697d9195a7SDavid du Colombier }
2707d9195a7SDavid du Colombier
2717d9195a7SDavid du Colombier void
stfd(ulong ir)2727d9195a7SDavid du Colombier stfd(ulong ir)
2737d9195a7SDavid du Colombier {
2747d9195a7SDavid du Colombier ulong ea;
2757d9195a7SDavid du Colombier int imm, ra, rd, upd;
2767d9195a7SDavid du Colombier
2777d9195a7SDavid du Colombier getairr(ir);
2787d9195a7SDavid du Colombier ea = imm;
2797d9195a7SDavid du Colombier upd = (ir&(1L<<26))!=0;
2807d9195a7SDavid du Colombier if(ra) {
2817d9195a7SDavid du Colombier ea += reg.r[ra];
2827d9195a7SDavid du Colombier if(upd)
2837d9195a7SDavid du Colombier reg.r[ra] = ea;
2847d9195a7SDavid du Colombier } else {
2857d9195a7SDavid du Colombier if(upd)
2867d9195a7SDavid du Colombier undef(ir);
2877d9195a7SDavid du Colombier }
2887d9195a7SDavid du Colombier if(trace)
2897d9195a7SDavid du Colombier itrace("%s\tf%d,%ld(r%d) %lux=%g",
2907d9195a7SDavid du Colombier ci->name, rd, imm, ra, ea, reg.fd[rd]);
2917d9195a7SDavid du Colombier
292*6891d857SDavid du Colombier putmem_v(ea, fp2v(reg.fd[rd]));
2937d9195a7SDavid du Colombier }
2947d9195a7SDavid du Colombier
2957d9195a7SDavid du Colombier void
stfdx(ulong ir)2967d9195a7SDavid du Colombier stfdx(ulong ir)
2977d9195a7SDavid du Colombier {
2987d9195a7SDavid du Colombier ulong ea;
2997d9195a7SDavid du Colombier int rd, ra, rb, upd;
3007d9195a7SDavid du Colombier
3017d9195a7SDavid du Colombier getarrr(ir);
3027d9195a7SDavid du Colombier ea = reg.r[rb];
3037d9195a7SDavid du Colombier upd = ((ir>>1)&0x3FF)==759;
3047d9195a7SDavid du Colombier if(ra){
3057d9195a7SDavid du Colombier ea += reg.r[ra];
3067d9195a7SDavid du Colombier if(upd)
3077d9195a7SDavid du Colombier reg.r[ra] = ea;
3087d9195a7SDavid du Colombier if(trace)
3097d9195a7SDavid du Colombier itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, reg.fd[rd]);
3107d9195a7SDavid du Colombier } else {
3117d9195a7SDavid du Colombier if(upd)
3127d9195a7SDavid du Colombier undef(ir);
3137d9195a7SDavid du Colombier if(trace)
3147d9195a7SDavid du Colombier itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, reg.fd[rd]);
3157d9195a7SDavid du Colombier }
3167d9195a7SDavid du Colombier
317*6891d857SDavid du Colombier putmem_v(ea, fp2v(reg.fd[rd]));
3187d9195a7SDavid du Colombier }
3197d9195a7SDavid du Colombier
3207d9195a7SDavid du Colombier void
mcrfs(ulong ir)3217d9195a7SDavid du Colombier mcrfs(ulong ir)
3227d9195a7SDavid du Colombier {
3237d9195a7SDavid du Colombier ulong rd, ra, rb;
3247d9195a7SDavid du Colombier static ulong fpscr0[] ={
3257d9195a7SDavid du Colombier FPS_FX|FPS_OX,
3267d9195a7SDavid du Colombier FPS_UX|FPS_ZX|FPS_XX|FPS_VXSNAN,
3277d9195a7SDavid du Colombier FPS_VXISI|FPS_VXIDI|FPS_VXZDZ|FPS_VXIMZ,
3287d9195a7SDavid du Colombier FPS_VXVC,
3297d9195a7SDavid du Colombier 0,
3307d9195a7SDavid du Colombier FPS_VXCVI,
3317d9195a7SDavid du Colombier };
3327d9195a7SDavid du Colombier
3337d9195a7SDavid du Colombier getarrr(ir);
3347d9195a7SDavid du Colombier if(rb || ra&3 || rd&3)
3357d9195a7SDavid du Colombier undef(ir);
3367d9195a7SDavid du Colombier ra >>= 2;
3377d9195a7SDavid du Colombier rd >>= 2;
3387d9195a7SDavid du Colombier reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, reg.fpscr));
3397d9195a7SDavid du Colombier reg.fpscr &= ~fpscr0[ra];
3407d9195a7SDavid du Colombier if(trace)
3417d9195a7SDavid du Colombier itrace("mcrfs\tcrf%d,crf%d\n", rd, ra);
3427d9195a7SDavid du Colombier }
3437d9195a7SDavid du Colombier
3447d9195a7SDavid du Colombier void
mffs(ulong ir)3457d9195a7SDavid du Colombier mffs(ulong ir)
3467d9195a7SDavid du Colombier {
3477d9195a7SDavid du Colombier int rd, ra, rb;
348*6891d857SDavid du Colombier FPdbleword d;
3497d9195a7SDavid du Colombier
3507d9195a7SDavid du Colombier getarrr(ir);
3517d9195a7SDavid du Colombier if(ra || rb)
3527d9195a7SDavid du Colombier undef(ir);
353*6891d857SDavid du Colombier d.hi = 0xFFF80000UL;
354*6891d857SDavid du Colombier d.lo = reg.fpscr;
355*6891d857SDavid du Colombier reg.fd[rd] = d.x;
3567d9195a7SDavid du Colombier /* it's anyone's guess how CR1 should be set when ir&1 */
3577d9195a7SDavid du Colombier reg.cr &= ~mkCR(1, 0xE); /* leave SO, reset others */
3587d9195a7SDavid du Colombier if(trace)
3597d9195a7SDavid du Colombier itrace("mffs%s\tfr%d\n", ir&1?".":"", rd);
3607d9195a7SDavid du Colombier }
3617d9195a7SDavid du Colombier
3627d9195a7SDavid du Colombier void
mtfsb1(ulong ir)3637d9195a7SDavid du Colombier mtfsb1(ulong ir)
3647d9195a7SDavid du Colombier {
3657d9195a7SDavid du Colombier int rd, ra, rb;
3667d9195a7SDavid du Colombier
3677d9195a7SDavid du Colombier getarrr(ir);
3687d9195a7SDavid du Colombier if(ra || rb)
3697d9195a7SDavid du Colombier undef(ir);
3707d9195a7SDavid du Colombier reg.fpscr |= (1L << (31-rd));
3717d9195a7SDavid du Colombier /* BUG: should set summary bits */
3727d9195a7SDavid du Colombier if(ir & 1)
3737d9195a7SDavid du Colombier reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
3747d9195a7SDavid du Colombier if(trace)
3757d9195a7SDavid du Colombier itrace("mtfsb1%s\tfr%d\n", ir&1?".":"", rd);
3767d9195a7SDavid du Colombier }
3777d9195a7SDavid du Colombier
3787d9195a7SDavid du Colombier void
mtfsb0(ulong ir)3797d9195a7SDavid du Colombier mtfsb0(ulong ir)
3807d9195a7SDavid du Colombier {
3817d9195a7SDavid du Colombier int rd, ra, rb;
3827d9195a7SDavid du Colombier
3837d9195a7SDavid du Colombier getarrr(ir);
3847d9195a7SDavid du Colombier if(ra || rb)
3857d9195a7SDavid du Colombier undef(ir);
3867d9195a7SDavid du Colombier reg.fpscr &= ~(1L << (31-rd));
3877d9195a7SDavid du Colombier if(ir & 1)
3887d9195a7SDavid du Colombier reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
3897d9195a7SDavid du Colombier if(trace)
3907d9195a7SDavid du Colombier itrace("mtfsb0%s\tfr%d\n", ir&1?".":"", rd);
3917d9195a7SDavid du Colombier }
3927d9195a7SDavid du Colombier
3937d9195a7SDavid du Colombier void
mtfsf(ulong ir)3947d9195a7SDavid du Colombier mtfsf(ulong ir)
3957d9195a7SDavid du Colombier {
3967d9195a7SDavid du Colombier int fm, rb, i;
397*6891d857SDavid du Colombier FPdbleword d;
3987d9195a7SDavid du Colombier ulong v;
3997d9195a7SDavid du Colombier
4007d9195a7SDavid du Colombier if(ir & ((1L << 25)|(1L << 16)))
4017d9195a7SDavid du Colombier undef(ir);
4027d9195a7SDavid du Colombier rb = (ir >> 11) & 0x1F;
4037d9195a7SDavid du Colombier fm = (ir >> 17) & 0xFF;
404*6891d857SDavid du Colombier d.x = reg.fd[rb];
405*6891d857SDavid du Colombier v = d.lo;
4067d9195a7SDavid du Colombier for(i=0; i<8; i++)
4077d9195a7SDavid du Colombier if(fm & (1 << (7-i)))
4087d9195a7SDavid du Colombier reg.fpscr = (reg.fpscr & ~mkCR(i, 0xF)) | mkCR(i, getCR(i, v));
4097d9195a7SDavid du Colombier /* BUG: should set FEX and VX `according to the usual rule' */
4107d9195a7SDavid du Colombier if(ir & 1)
4117d9195a7SDavid du Colombier reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
4127d9195a7SDavid du Colombier if(trace)
4137d9195a7SDavid du Colombier itrace("mtfsf%s\t#%.2x,fr%d", ir&1?".":"", fm, rb);
4147d9195a7SDavid du Colombier }
4157d9195a7SDavid du Colombier
4167d9195a7SDavid du Colombier void
mtfsfi(ulong ir)4177d9195a7SDavid du Colombier mtfsfi(ulong ir)
4187d9195a7SDavid du Colombier {
4197d9195a7SDavid du Colombier int imm, rd;
4207d9195a7SDavid du Colombier
4217d9195a7SDavid du Colombier if(ir & ((0x7F << 16)|(1L << 11)))
4227d9195a7SDavid du Colombier undef(ir);
4237d9195a7SDavid du Colombier rd = (ir >> 23) & 0xF;
4247d9195a7SDavid du Colombier imm = (ir >> 12) & 0xF;
4257d9195a7SDavid du Colombier reg.fpscr = (reg.fpscr & ~mkCR(rd, 0xF)) | mkCR(rd, imm);
4267d9195a7SDavid du Colombier /* BUG: should set FEX and VX `according to the usual rule' */
4277d9195a7SDavid du Colombier if(ir & 1)
4287d9195a7SDavid du Colombier reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
4297d9195a7SDavid du Colombier if(trace)
4307d9195a7SDavid du Colombier itrace("mtfsfi%s\tcrf%d,#%x", ir&1?".":"", rd, imm);
4317d9195a7SDavid du Colombier }
4327d9195a7SDavid du Colombier
4337d9195a7SDavid du Colombier void
fcmp(ulong ir)4347d9195a7SDavid du Colombier fcmp(ulong ir)
4357d9195a7SDavid du Colombier {
4367d9195a7SDavid du Colombier int fc, rd, ra, rb;
4377d9195a7SDavid du Colombier
4387d9195a7SDavid du Colombier getarrr(ir);
4397d9195a7SDavid du Colombier if(rd & 3)
4407d9195a7SDavid du Colombier undef(ir);
4417d9195a7SDavid du Colombier rd >>= 2;
4427d9195a7SDavid du Colombier SET(fc);
4437d9195a7SDavid du Colombier switch(getxo(ir)) {
4447d9195a7SDavid du Colombier default:
4457d9195a7SDavid du Colombier undef(ir);
4467d9195a7SDavid du Colombier case 0:
4477d9195a7SDavid du Colombier if(trace)
4487d9195a7SDavid du Colombier itrace("fcmpu\tcr%d,f%d,f%d", rd, ra, rb);
4497d9195a7SDavid du Colombier if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) {
4507d9195a7SDavid du Colombier fc = CRFU;
4517d9195a7SDavid du Colombier break;
4527d9195a7SDavid du Colombier }
4537d9195a7SDavid du Colombier if(reg.fd[ra] == reg.fd[rb]) {
4547d9195a7SDavid du Colombier fc = CREQ;
4557d9195a7SDavid du Colombier break;
4567d9195a7SDavid du Colombier }
4577d9195a7SDavid du Colombier if(reg.fd[ra] < reg.fd[rb]) {
4587d9195a7SDavid du Colombier fc = CRLT;
4597d9195a7SDavid du Colombier break;
4607d9195a7SDavid du Colombier }
4617d9195a7SDavid du Colombier if(reg.fd[ra] > reg.fd[rb]) {
4627d9195a7SDavid du Colombier fc = CRGT;
4637d9195a7SDavid du Colombier break;
4647d9195a7SDavid du Colombier }
4657d9195a7SDavid du Colombier print("qi: fcmp error\n");
4667d9195a7SDavid du Colombier break;
4677d9195a7SDavid du Colombier case 32:
4687d9195a7SDavid du Colombier if(trace)
4697d9195a7SDavid du Colombier itrace("fcmpo\tcr%d,f%d,f%d", rd, ra, rb);
4707d9195a7SDavid du Colombier if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) { /* BUG: depends whether quiet or signalling ... */
4717d9195a7SDavid du Colombier fc = CRFU;
4727d9195a7SDavid du Colombier Bprint(bioout, "invalid_fp_register\n");
4737d9195a7SDavid du Colombier longjmp(errjmp, 0);
4747d9195a7SDavid du Colombier }
4757d9195a7SDavid du Colombier if(reg.fd[ra] == reg.fd[rb]) {
4767d9195a7SDavid du Colombier fc = CREQ;
4777d9195a7SDavid du Colombier break;
4787d9195a7SDavid du Colombier }
4797d9195a7SDavid du Colombier if(reg.fd[ra] < reg.fd[rb]) {
4807d9195a7SDavid du Colombier fc = CRLT;
4817d9195a7SDavid du Colombier break;
4827d9195a7SDavid du Colombier }
4837d9195a7SDavid du Colombier if(reg.fd[ra] > reg.fd[rb]) {
4847d9195a7SDavid du Colombier fc = CRGT;
4857d9195a7SDavid du Colombier break;
4867d9195a7SDavid du Colombier }
4877d9195a7SDavid du Colombier print("qi: fcmp error\n");
4887d9195a7SDavid du Colombier break;
4897d9195a7SDavid du Colombier
4907d9195a7SDavid du Colombier }
4917d9195a7SDavid du Colombier fc >>= 28;
4927d9195a7SDavid du Colombier reg.cr = (reg.cr & ~mkCR(rd,~0)) | mkCR(rd, fc);
4937d9195a7SDavid du Colombier reg.fpscr = (reg.fpscr & ~0xF800) | (fc<<11);
4947d9195a7SDavid du Colombier /* BUG: update FX, VXSNAN, VXVC */
4957d9195a7SDavid du Colombier }
4967d9195a7SDavid du Colombier
4977d9195a7SDavid du Colombier /*
4987d9195a7SDavid du Colombier * the farith functions probably don't produce the right results
4997d9195a7SDavid du Colombier * in the presence of NaNs, Infs, etc., esp. wrt exception handling,
5007d9195a7SDavid du Colombier */
5017d9195a7SDavid du Colombier void
fariths(ulong ir)5027d9195a7SDavid du Colombier fariths(ulong ir)
5037d9195a7SDavid du Colombier {
5047d9195a7SDavid du Colombier int rd, ra, rb, rc, fmt;
5057d9195a7SDavid du Colombier char *cc;
5067d9195a7SDavid du Colombier ulong fpscr;
5077d9195a7SDavid du Colombier
5087d9195a7SDavid du Colombier fmt = 0;
5097d9195a7SDavid du Colombier rc = (ir>>6)&0x1F;
5107d9195a7SDavid du Colombier getarrr(ir);
5117d9195a7SDavid du Colombier switch(getxo(ir)&0x1F) { /* partial XO decode */
5127d9195a7SDavid du Colombier default:
5137d9195a7SDavid du Colombier undef(ir);
5147d9195a7SDavid du Colombier case 18:
5157d9195a7SDavid du Colombier if((float)reg.fd[rb] == 0.0) {
5167d9195a7SDavid du Colombier Bprint(bioout, "fp_exception ZX\n");
5177d9195a7SDavid du Colombier reg.fpscr |= FPS_ZX | FPS_FX;
5187d9195a7SDavid du Colombier longjmp(errjmp, 0);
5197d9195a7SDavid du Colombier }
5207d9195a7SDavid du Colombier reg.fd[rd] = (float)(reg.fd[ra] / reg.fd[rb]);
5217d9195a7SDavid du Colombier break;
5227d9195a7SDavid du Colombier case 20:
5237d9195a7SDavid du Colombier reg.fd[rd] = (float)(reg.fd[ra] - reg.fd[rb]);
5247d9195a7SDavid du Colombier break;
5257d9195a7SDavid du Colombier case 21:
5267d9195a7SDavid du Colombier reg.fd[rd] = (float)(reg.fd[ra] + reg.fd[rb]);
5277d9195a7SDavid du Colombier break;
5287d9195a7SDavid du Colombier case 25:
5297d9195a7SDavid du Colombier reg.fd[rd] = (float)(reg.fd[ra] * reg.fd[rc]);
5307d9195a7SDavid du Colombier rb = rc;
5317d9195a7SDavid du Colombier break;
5327d9195a7SDavid du Colombier case 28:
5337d9195a7SDavid du Colombier reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
5347d9195a7SDavid du Colombier fmt = 2;
5357d9195a7SDavid du Colombier break;
5367d9195a7SDavid du Colombier case 29:
5377d9195a7SDavid du Colombier reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
5387d9195a7SDavid du Colombier fmt = 2;
5397d9195a7SDavid du Colombier break;
5407d9195a7SDavid du Colombier case 30:
5417d9195a7SDavid du Colombier reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
5427d9195a7SDavid du Colombier fmt = 2;
5437d9195a7SDavid du Colombier break;
5447d9195a7SDavid du Colombier case 31:
5457d9195a7SDavid du Colombier reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
5467d9195a7SDavid du Colombier fmt = 2;
5477d9195a7SDavid du Colombier break;
5487d9195a7SDavid du Colombier }
5497d9195a7SDavid du Colombier if(fmt==1 && ra)
5507d9195a7SDavid du Colombier undef(ir);
5517d9195a7SDavid du Colombier fpscr = setfpscr();
5527d9195a7SDavid du Colombier setfpcc(reg.fd[rd]);
5537d9195a7SDavid du Colombier cc = "";
5547d9195a7SDavid du Colombier if(ir & 1) {
5557d9195a7SDavid du Colombier cc = ".";
5567d9195a7SDavid du Colombier reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
5577d9195a7SDavid du Colombier }
5587d9195a7SDavid du Colombier if(trace) {
5597d9195a7SDavid du Colombier switch(fmt) {
5607d9195a7SDavid du Colombier case 0:
5617d9195a7SDavid du Colombier itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb);
5627d9195a7SDavid du Colombier break;
5637d9195a7SDavid du Colombier case 1:
5647d9195a7SDavid du Colombier itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
5657d9195a7SDavid du Colombier break;
5667d9195a7SDavid du Colombier case 2:
5677d9195a7SDavid du Colombier itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb);
5687d9195a7SDavid du Colombier break;
5697d9195a7SDavid du Colombier }
5707d9195a7SDavid du Colombier }
5717d9195a7SDavid du Colombier }
5727d9195a7SDavid du Colombier
5737d9195a7SDavid du Colombier void
farith(ulong ir)5747d9195a7SDavid du Colombier farith(ulong ir)
5757d9195a7SDavid du Colombier {
5767d9195a7SDavid du Colombier vlong vl;
5777d9195a7SDavid du Colombier int rd, ra, rb, rc, fmt;
5787d9195a7SDavid du Colombier char *cc;
5797d9195a7SDavid du Colombier ulong fpscr;
5807d9195a7SDavid du Colombier int nocc;
5817d9195a7SDavid du Colombier double d;
5827d9195a7SDavid du Colombier
5837d9195a7SDavid du Colombier fmt = 0;
5847d9195a7SDavid du Colombier nocc = 0;
5857d9195a7SDavid du Colombier rc = (ir>>6)&0x1F;
5867d9195a7SDavid du Colombier getarrr(ir);
5877d9195a7SDavid du Colombier switch(getxo(ir)&0x1F) { /* partial XO decode */
5887d9195a7SDavid du Colombier default:
5897d9195a7SDavid du Colombier undef(ir);
5907d9195a7SDavid du Colombier case 12: /* frsp */
5917d9195a7SDavid du Colombier reg.fd[rd] = (float)reg.fd[rb];
5927d9195a7SDavid du Colombier fmt = 1;
5937d9195a7SDavid du Colombier break;
5947d9195a7SDavid du Colombier case 14: /* fctiw */ /* BUG: ignores rounding mode */
5957d9195a7SDavid du Colombier case 15: /* fctiwz */
5967d9195a7SDavid du Colombier d = reg.fd[rb];
5977d9195a7SDavid du Colombier if(d >= 0x7fffffff)
5987d9195a7SDavid du Colombier vl = 0x7fffffff;
5997d9195a7SDavid du Colombier else if(d < 0x80000000)
6007d9195a7SDavid du Colombier vl = 0x80000000;
6017d9195a7SDavid du Colombier else
6027d9195a7SDavid du Colombier vl = d;
603*6891d857SDavid du Colombier reg.fd[rd] = v2fp(vl);
6047d9195a7SDavid du Colombier fmt = 1;
6057d9195a7SDavid du Colombier nocc = 1;
6067d9195a7SDavid du Colombier break;
6077d9195a7SDavid du Colombier case 18:
6087d9195a7SDavid du Colombier if(reg.fd[rb] == 0.0) {
6097d9195a7SDavid du Colombier Bprint(bioout, "fp_exception ZX\n");
6107d9195a7SDavid du Colombier reg.fpscr |= FPS_ZX | FPS_FX;
6117d9195a7SDavid du Colombier longjmp(errjmp, 0);
6127d9195a7SDavid du Colombier }
6137d9195a7SDavid du Colombier reg.fd[rd] = reg.fd[ra] / reg.fd[rb];
6147d9195a7SDavid du Colombier break;
6157d9195a7SDavid du Colombier case 20:
6167d9195a7SDavid du Colombier reg.fd[rd] = reg.fd[ra] - reg.fd[rb];
6177d9195a7SDavid du Colombier break;
6187d9195a7SDavid du Colombier case 21:
6197d9195a7SDavid du Colombier reg.fd[rd] = reg.fd[ra] + reg.fd[rb];
6207d9195a7SDavid du Colombier break;
6217d9195a7SDavid du Colombier case 25:
6227d9195a7SDavid du Colombier reg.fd[rd] = reg.fd[ra] * reg.fd[rc];
6237d9195a7SDavid du Colombier rb = rc;
6247d9195a7SDavid du Colombier break;
6257d9195a7SDavid du Colombier case 28:
6267d9195a7SDavid du Colombier reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) - reg.fd[rb];
6277d9195a7SDavid du Colombier fmt = 2;
6287d9195a7SDavid du Colombier break;
6297d9195a7SDavid du Colombier case 29:
6307d9195a7SDavid du Colombier reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) + reg.fd[rb];
6317d9195a7SDavid du Colombier fmt = 2;
6327d9195a7SDavid du Colombier break;
6337d9195a7SDavid du Colombier case 30:
6347d9195a7SDavid du Colombier reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
6357d9195a7SDavid du Colombier fmt = 2;
6367d9195a7SDavid du Colombier break;
6377d9195a7SDavid du Colombier case 31:
6387d9195a7SDavid du Colombier reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
6397d9195a7SDavid du Colombier fmt = 2;
6407d9195a7SDavid du Colombier break;
6417d9195a7SDavid du Colombier }
6427d9195a7SDavid du Colombier if(fmt==1 && ra)
6437d9195a7SDavid du Colombier undef(ir);
6447d9195a7SDavid du Colombier fpscr = setfpscr();
6457d9195a7SDavid du Colombier if(nocc == 0)
6467d9195a7SDavid du Colombier setfpcc(reg.fd[rd]);
6477d9195a7SDavid du Colombier cc = "";
6487d9195a7SDavid du Colombier if(ir & 1) {
6497d9195a7SDavid du Colombier cc = ".";
6507d9195a7SDavid du Colombier reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
6517d9195a7SDavid du Colombier }
6527d9195a7SDavid du Colombier if(trace) {
6537d9195a7SDavid du Colombier switch(fmt) {
6547d9195a7SDavid du Colombier case 0:
6557d9195a7SDavid du Colombier itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb);
6567d9195a7SDavid du Colombier break;
6577d9195a7SDavid du Colombier case 1:
6587d9195a7SDavid du Colombier itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
6597d9195a7SDavid du Colombier break;
6607d9195a7SDavid du Colombier case 2:
6617d9195a7SDavid du Colombier itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb);
6627d9195a7SDavid du Colombier break;
6637d9195a7SDavid du Colombier }
6647d9195a7SDavid du Colombier }
6657d9195a7SDavid du Colombier }
6667d9195a7SDavid du Colombier
6677d9195a7SDavid du Colombier void
farith2(ulong ir)6687d9195a7SDavid du Colombier farith2(ulong ir)
6697d9195a7SDavid du Colombier {
6707d9195a7SDavid du Colombier int rd, ra, rb;
6717d9195a7SDavid du Colombier char *cc;
6727d9195a7SDavid du Colombier ulong fpscr;
6737d9195a7SDavid du Colombier
6747d9195a7SDavid du Colombier getarrr(ir);
6757d9195a7SDavid du Colombier switch(getxo(ir)) { /* full XO decode */
6767d9195a7SDavid du Colombier default:
6777d9195a7SDavid du Colombier undef(ir);
6787d9195a7SDavid du Colombier case 40:
6797d9195a7SDavid du Colombier reg.fd[rd] = -reg.fd[rb];
6807d9195a7SDavid du Colombier break;
6817d9195a7SDavid du Colombier case 72:
6827d9195a7SDavid du Colombier reg.fd[rd] = reg.fd[rb];
6837d9195a7SDavid du Colombier break;
6847d9195a7SDavid du Colombier case 136:
6857d9195a7SDavid du Colombier reg.fd[rd] = -fabs(reg.fd[rb]);
6867d9195a7SDavid du Colombier break;
6877d9195a7SDavid du Colombier case 264:
6887d9195a7SDavid du Colombier reg.fd[rd] = fabs(reg.fd[rb]);
6897d9195a7SDavid du Colombier break;
6907d9195a7SDavid du Colombier }
6917d9195a7SDavid du Colombier if(ra)
6927d9195a7SDavid du Colombier undef(ir);
6937d9195a7SDavid du Colombier fpscr = setfpscr();
6947d9195a7SDavid du Colombier setfpcc(reg.fd[rd]);
6957d9195a7SDavid du Colombier cc = "";
6967d9195a7SDavid du Colombier if(ir & 1) {
6977d9195a7SDavid du Colombier cc = ".";
6987d9195a7SDavid du Colombier reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
6997d9195a7SDavid du Colombier }
7007d9195a7SDavid du Colombier if(trace)
7017d9195a7SDavid du Colombier itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
7027d9195a7SDavid du Colombier }
7037d9195a7SDavid du Colombier
7047d9195a7SDavid du Colombier ulong
setfpscr(void)7057d9195a7SDavid du Colombier setfpscr(void)
7067d9195a7SDavid du Colombier {
7077d9195a7SDavid du Colombier ulong fps, fpscr;
7087d9195a7SDavid du Colombier
7097d9195a7SDavid du Colombier fps = getfsr();
7107d9195a7SDavid du Colombier fpscr = reg.fpscr;
7117d9195a7SDavid du Colombier if(fps & FPAOVFL)
7127d9195a7SDavid du Colombier fpscr |= FPS_OX;
7137d9195a7SDavid du Colombier if(fps & FPAINEX)
7147d9195a7SDavid du Colombier fpscr |= FPS_XX;
7157d9195a7SDavid du Colombier if(fps & FPAUNFL)
7167d9195a7SDavid du Colombier fpscr |= FPS_UX;
7177d9195a7SDavid du Colombier if(fps & FPAZDIV)
7187d9195a7SDavid du Colombier fpscr |= FPS_ZX;
7197d9195a7SDavid du Colombier if(fpscr != reg.fpscr) {
7207d9195a7SDavid du Colombier fpscr |= FPS_FX;
7217d9195a7SDavid du Colombier reg.fpscr = fpscr;
7227d9195a7SDavid du Colombier }
7237d9195a7SDavid du Colombier return fpscr;
7247d9195a7SDavid du Colombier }
7257d9195a7SDavid du Colombier
7267d9195a7SDavid du Colombier void
setfpcc(double r)7277d9195a7SDavid du Colombier setfpcc(double r)
7287d9195a7SDavid du Colombier {
7297d9195a7SDavid du Colombier int c;
7307d9195a7SDavid du Colombier
7317d9195a7SDavid du Colombier c = 0;
7327d9195a7SDavid du Colombier if(r == 0)
7337d9195a7SDavid du Colombier c |= 2;
7347d9195a7SDavid du Colombier else if(r < 0)
7357d9195a7SDavid du Colombier c |= 4;
7367d9195a7SDavid du Colombier else
7377d9195a7SDavid du Colombier c |= 8;
7387d9195a7SDavid du Colombier if(isNaN(r))
7397d9195a7SDavid du Colombier c |= 1;
7407d9195a7SDavid du Colombier reg.fpscr = (reg.fpscr & ~0xF800) | (0<<15) | (c<<11); /* unsure about class bit */
7417d9195a7SDavid du Colombier }
742