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