1*25665Ssam /* fpe.c 1.1 86/01/03 */ 2*25665Ssam 3*25665Ssam #include "../tahoe/psl.h" 4*25665Ssam #include "../tahoe/reg.h" 5*25665Ssam #include "../tahoe/pte.h" 6*25665Ssam #include "../tahoe/mtpr.h" 7*25665Ssam #include "../tahoemath/Kfp.h" 8*25665Ssam 9*25665Ssam #include "param.h" 10*25665Ssam #include "systm.h" 11*25665Ssam #include "dir.h" 12*25665Ssam #include "user.h" 13*25665Ssam #include "proc.h" 14*25665Ssam #include "seg.h" 15*25665Ssam #include "acct.h" 16*25665Ssam #include "kernel.h" 17*25665Ssam 18*25665Ssam /* 19*25665Ssam * Floating point emulation support. 20*25665Ssam */ 21*25665Ssam extern float Kcvtlf(), Kaddf(), Ksubf(), Kmulf(), Kdivf(); 22*25665Ssam extern double Kcvtld(), Kaddd(), Ksubd(), Kmuld(), Kdivd(); 23*25665Ssam extern float Ksinf(), Kcosf(), Katanf(), Klogf(), Ksqrtf(), Kexpf(); 24*25665Ssam 25*25665Ssam #define OP(dop) ((dop) &~ 01) /* precision-less version of opcode */ 26*25665Ssam #define isdouble(op) ((op) & 01) /* is opcode double or float */ 27*25665Ssam 28*25665Ssam struct fpetab { 29*25665Ssam int fpe_op; /* base opcode emulating */ 30*25665Ssam float (*fpe_ffunc)(); /* float version of op */ 31*25665Ssam double (*fpe_dfunc)(); /* double version of op */ 32*25665Ssam } fpetab[] = { 33*25665Ssam { OP(CVLD), Kcvtlf, Kcvtld }, 34*25665Ssam { OP(ADDD), Kaddf, Kaddd }, 35*25665Ssam { OP(SUBD), Ksubf, Ksubd }, 36*25665Ssam { OP(MULD), Kmulf, Kmuld }, 37*25665Ssam { OP(DIVD), Kdivf, Kdivd }, 38*25665Ssam { SINF, Ksinf, 0 }, 39*25665Ssam { COSF, Kcosf, 0 }, 40*25665Ssam { ATANF, Katanf, 0 }, 41*25665Ssam { LOGF, Klogf, 0 }, 42*25665Ssam { SQRTF, Ksqrtf, 0 }, 43*25665Ssam { EXPF, Kexpf, 0 }, 44*25665Ssam }; 45*25665Ssam #define NFPETAB (sizeof (fpetab) / sizeof (fpetab[0])) 46*25665Ssam 47*25665Ssam /* 48*25665Ssam * Emulate the FP opcode. Update psl as necessary. 49*25665Ssam * If OK, set opcode to 0, else to the FP exception #. 50*25665Ssam * Not all parameter longwords are relevant, depends on opcode. 51*25665Ssam * 52*25665Ssam * The entry mask is set by locore.s so ALL registers are saved. 53*25665Ssam * This enables FP opcodes to change user registers on return. 54*25665Ssam */ 55*25665Ssam /* WARNING!!!! THIS CODE MUST NOT PRODUCE ANY FLOATING POINT EXCEPTIONS */ 56*25665Ssam /*ARGSUSED*/ 57*25665Ssam fpemulate(hfsreg, acc_most, acc_least, dbl, op_most, op_least, opcode, pc, psl) 58*25665Ssam { 59*25665Ssam int r0, r1; /* must reserve space */ 60*25665Ssam register int *locr0 = ((int *)&psl)-PS; 61*25665Ssam register struct fpetab *fp; 62*25665Ssam int hfs = 0; /* returned data about exceptions */ 63*25665Ssam int type; /* opcode type, FLOAT or DOUBLE */ 64*25665Ssam union { float ff; int fi; } f_res; 65*25665Ssam union { double dd; int di[2]; } d_res; 66*25665Ssam 67*25665Ssam #ifdef lint 68*25665Ssam r0 = 0; r0 = r0; r1 = 0; r1 = r1; 69*25665Ssam #endif 70*25665Ssam type = isdouble(opcode) ? DOUBLE : FLOAT; 71*25665Ssam for (fp = fpetab; fp < &fpetab[NFPETAB]; fp++) 72*25665Ssam if ((opcode & 0xfe) == fp->fpe_op) 73*25665Ssam break; 74*25665Ssam if (type == DOUBLE) { 75*25665Ssam if (fp->fpe_dfunc == 0) 76*25665Ssam fp = &fpetab[NFPETAB]; 77*25665Ssam else 78*25665Ssam locr0[PS] &= ~PSL_DBL; 79*25665Ssam } 80*25665Ssam if (fp >= &fpetab[NFPETAB]) { 81*25665Ssam opcode = DIV0_EXC; /* generate SIGILL - XXX */ 82*25665Ssam return; 83*25665Ssam } 84*25665Ssam switch (type) { 85*25665Ssam 86*25665Ssam case DOUBLE: 87*25665Ssam d_res.dd = (*fp->fpe_dfunc)(acc_most, acc_least, op_most, 88*25665Ssam op_least, &hfs); 89*25665Ssam if (d_res.di[0] == 0 && d_res.di[1] == 0) 90*25665Ssam locr0[PS] |= PSL_Z; 91*25665Ssam if (d_res.di[0] < 0) 92*25665Ssam locr0[PS] |= PSL_N; 93*25665Ssam break; 94*25665Ssam 95*25665Ssam case FLOAT: 96*25665Ssam f_res.ff = (*fp->fpe_ffunc)(acc_most, acc_least, op_most, 97*25665Ssam op_least, &hfs); 98*25665Ssam if (f_res.fi == 0) 99*25665Ssam locr0[PS] |= PSL_Z; 100*25665Ssam if (f_res.fi == 0) 101*25665Ssam locr0[PS] |= PSL_N; 102*25665Ssam break; 103*25665Ssam } 104*25665Ssam if (hfs & HFS_OVF) { 105*25665Ssam locr0[PS] |= PSL_V; /* turn on overflow bit */ 106*25665Ssam #ifdef notdef 107*25665Ssam if (locr0[PS] & PSL_IV) { /* overflow enabled? */ 108*25665Ssam #endif 109*25665Ssam opcode = OVF_EXC; 110*25665Ssam u.u_error = (hfs & HFS_DOM) ? EDOM : ERANGE; 111*25665Ssam return; 112*25665Ssam #ifdef notdef 113*25665Ssam } 114*25665Ssam #endif 115*25665Ssam } else if (hfs & HFS_UNDF) { 116*25665Ssam if (locr0[PS] & PSL_FU) { /* underflow enabled? */ 117*25665Ssam opcode = UNDF_EXC; 118*25665Ssam u.u_error = (hfs & HFS_DOM) ? EDOM : ERANGE; 119*25665Ssam return; 120*25665Ssam } 121*25665Ssam } else if (hfs & HFS_DIVZ) { 122*25665Ssam opcode = DIV0_EXC; 123*25665Ssam return; 124*25665Ssam } else if (hfs & HFS_DOM) 125*25665Ssam u.u_error = EDOM; 126*25665Ssam else if (hfs & HFS_RANGE) 127*25665Ssam u.u_error = ERANGE; 128*25665Ssam switch (type) { 129*25665Ssam 130*25665Ssam case DOUBLE: 131*25665Ssam if (hfs & (HFS_OVF|HFS_UNDF)) { 132*25665Ssam d_res.dd = 0.0; 133*25665Ssam locr0[PS] |= PSL_Z; 134*25665Ssam } 135*25665Ssam mvtodacc(d_res.di[0], d_res.di[1], &acc_most); 136*25665Ssam break; 137*25665Ssam 138*25665Ssam case FLOAT: 139*25665Ssam if (hfs & (HFS_OVF|HFS_UNDF)) { 140*25665Ssam f_res.ff = 0.0; 141*25665Ssam locr0[PS] |= PSL_Z; 142*25665Ssam } 143*25665Ssam mvtofacc(f_res.ff, &acc_most); 144*25665Ssam break; 145*25665Ssam } 146*25665Ssam opcode = 0; 147*25665Ssam } 148