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