|
|
1.1 ! root 1: /* FLOATING POINT OVERFLOW FAULT HANDLER. ! 2: * UNIVERSITY OF NEW MEXICO. ! 3: * This set of routines handles floating faults for most instructions ! 4: * that can generate them. Two notable exceptions are EMOD and POLY. ! 5: * These two instructions are not generated by the C compiler however. ! 6: * The routines are written generically enough that it would be easy ! 7: * to modify the code to handle all possible arithmetic exceptions on ! 8: * VAX 11/730s, 11/750s and 11/780's (after ECO #7). Before DEC's ! 9: * Engineering Change Order #7 * VAX 11/780s trapped on these errors so ! 10: * they must be handled in a TOTALLY different manner. ! 11: * ! 12: * To use these routines from Fortran: ! 13: * ! 14: * call ofault(nummsg) will initialize the fault handler and set ! 15: * the count for number of messages to be ! 16: * printed to nummsg . ! 17: * ! 18: * k = kfault(dummy) returns a count of the number of overflows ! 19: * and divisions by zero seen so far. ! 20: * ! 21: * The result of all floating point expononent overflows and ! 22: * floating point divisions by zero will be the largest possible ! 23: * floating point number, which is approximately 1.7e+38. Floating ! 24: * underflows (if you have the fault enabled) will return the smallest ! 25: * floating point number. ! 26: * ! 27: * The strategy goes like this: When VAX detects a fault some ! 28: * registers, the PC of the offending instruction and the PSL are saved on the ! 29: * user stack. When we get this we go through all the operand specifiers ! 30: * performing address calculation in a manner compatible with the machine. ! 31: * What this means is that auto-increment and its kin are performed on the ! 32: * register contents pushed on the stack. When we find the destination ! 33: * address of the offending instruction, the maximum value for the data ! 34: * type is placed there for an error return. Our working PC now points to ! 35: * the next instruction past the bad one. We load the saved PC on the stack ! 36: * with our working PC and return. Thus the instruction really never gets ! 37: * executed BUT we maintain consistency with pointers, etc in the code. ! 38: * ! 39: * One might notice that little discrepancies in the addressing modes, like ! 40: * the fact that you aren't supposed to use general mode with the PC, are ! 41: * not checked for. This is so that the code runs a bit quicker. For most ! 42: * of these VAX will give a different fault long before attempting the ! 43: * arithmetic and the others the user is warned against. ! 44: * ! 45: * Lee Ward, University of New Mexico, 7/2/83. ! 46: * Inspired by Gary Klimowicz's pre ECO #7 trap handling routines. ! 47: */ ! 48: ! 49: #include <signal.h> ! 50: #include <stdio.h> ! 51: #include "ofault.h" ! 52: ! 53: #ifndef FPE_FLTOVF_FAULT ! 54: #define FPE_FLTOVF_FAULT K_FLTOVF ! 55: #define FPE_FLTDIV_FAULT K_FLTDIV ! 56: #define FPE_FLTUND_FAULT K_FLTUND ! 57: #endif ! 58: ! 59: #define size_of(x) (x) ! 60: ! 61: /* GLOBALS */ ! 62: char *pc; /* PC to be used by the routines */ ! 63: long *regs0t6; /* Saved at interrupt time */ ! 64: long *regs7t11; /* We cause these to be pushed */ ! 65: int num_msgs; /* Maximum number of error messages */ ! 66: int kfault; /* Overflows detected */ ! 67: ! 68: /* ofault_ Set up to trap arithmetic exceptions reported by SIGFPE. ! 69: * Calling this function a second (or third or ...) time ! 70: * will cause the number of error messages to be printed ! 71: * to be reset. ! 72: */ ! 73: ofault_(nummsgs) ! 74: int *nummsgs; ! 75: { ! 76: extern fp_except(); ! 77: extern int num_msgs; ! 78: extern int kfault; ! 79: ! 80: num_msgs = *nummsgs; ! 81: kfault = 0; ! 82: signal (SIGFPE, fp_except); ! 83: } ! 84: ! 85: /* kfault_ Return the number of overflows encountered ! 86: */ ! 87: int kfault_ () ! 88: { ! 89: extern int kfault; ! 90: ! 91: return (kfault); ! 92: } ! 93: ! 94: /* fp_except Handle floating point faults ! 95: * ! 96: * A little expalnation here as this is somewhat confusing. At interrupt ! 97: * time the hardware pushes registers 0 through 6 on the users stack. These ! 98: * can be found at &signo - 8. The others we arrange to have pushed into ! 99: * the local call frame with the below register definitions. It is important ! 100: * that these are not changed. Note that fault_pc and psl are effectively ! 101: * passed by reference as the REI instruction causes them to be reloaded. ! 102: * It is possible to play with these a little. You just must be careful ! 103: * not to put the processor into an "undefined state." For reference see ! 104: * the Architecture handbook (REI instruction). ! 105: */ ! 106: fp_except (signo, f_type, myaddr, fault_pc, psl) ! 107: int f_type; ! 108: unsigned psl; ! 109: char *fault_pc; ! 110: { ! 111: long first_local[1]; /* MUST be first! */ ! 112: register int a, b, c, d, e; /* Don't change! */ ! 113: extern int num_msgs; ! 114: extern int kfault; ! 115: ! 116: /* Get info off of stack */ ! 117: regs7t11 = &first_local[0]; ! 118: regs0t6 = &signo - 8; ! 119: pc = fault_pc; ! 120: ! 121: /* Two switches here. One to print an appropriate message and one ! 122: * to handle the fault. ! 123: */ ! 124: if (kfault < num_msgs) ! 125: switch (f_type) { ! 126: case FPE_FLTOVF_FAULT: ! 127: fprintf (stderr, "Floating overflow!\n"); ! 128: break; ! 129: case FPE_FLTDIV_FAULT: ! 130: fprintf (stderr, "Floating division by zero!\n"); ! 131: break; ! 132: case FPE_FLTUND_FAULT: ! 133: fprintf (stderr, "Floating underflow!\n"); ! 134: break; ! 135: default: /* Let the handler switch deal with this */ ! 136: break; ! 137: } ! 138: ! 139: switch (f_type) { ! 140: case FPE_FLTOVF_FAULT: ! 141: case FPE_FLTDIV_FAULT: ! 142: flt_ov_fault(); ! 143: break; ! 144: case FPE_FLTUND_FAULT: /* You have to enable first */ ! 145: flt_und_fault(); ! 146: break; ! 147: default: ! 148: err ("Cannot handle fault 0X%x", f_type); ! 149: } ! 150: ++kfault; ! 151: ! 152: fault_pc = pc; ! 153: signal (SIGFPE, fp_except); ! 154: ! 155: if (kfault == num_msgs) ! 156: err ("No more overflow messages will be printed"); ! 157: ! 158: return; /* Ala REI */ ! 159: } ! 160: ! 161: /* flt_ov_fault Handle a floating overflow fault. A misnomer as we handle ! 162: * division by zero in the same manner. ! 163: */ ! 164: flt_ov_fault () ! 165: { ! 166: int opcode; ! 167: int x; ! 168: int dest; ! 169: int type; ! 170: char *addr; ! 171: extern char *pc; ! 172: extern ANYTYPE *fetch(); ! 173: extern char *addr_reg(); ! 174: extern char *opnd_addr(); ! 175: ! 176: opcode = (int )fetch()->byte; ! 177: pc += 1; ! 178: ! 179: dest = dest_opnd(opcode); ! 180: for (x = 1; x <= num_opnd(opcode); ++x) { ! 181: if ((type = get_type(opcode, x)) == GARBAGE) ! 182: err ("data type of operand? (op = 0X%x, operand %d)" ! 183: , opcode, x); ! 184: addr = opnd_addr (type); ! 185: if (x == dest) ! 186: load (addr, type, MAXFLOAT, MAXDOUBLR); ! 187: } ! 188: } ! 189: ! 190: /* flt_und_fault Handle a floating underflow fault. ! 191: */ ! 192: flt_und_fault () ! 193: { ! 194: int opcode; ! 195: int x; ! 196: int dest; ! 197: int type; ! 198: char *addr; ! 199: extern char *pc; ! 200: extern ANYTYPE *fetch(); ! 201: extern char *addr_reg(); ! 202: extern char *opnd_addr(); ! 203: ! 204: opcode = (int )fetch()->byte; ! 205: pc += 1; ! 206: ! 207: dest = dest_opnd(opcode); ! 208: for (x = 1; x <= num_opnd(opcode); ++x) { ! 209: if ((type = get_type(opcode, x)) == GARBAGE) ! 210: err ("data type of operand? (op = 0X%x, operand %d)" ! 211: , opcode, x); ! 212: addr = opnd_addr (type); ! 213: if (x == dest) ! 214: load (addr, type, MINFLOAT, MINDOUBLR); ! 215: } ! 216: } ! 217: ! 218: /* dest_opnd Given an opcode return the number of the operand specifier ! 219: * that is the destination. ! 220: */ ! 221: dest_opnd (opcode) ! 222: int opcode; ! 223: { ! 224: ! 225: switch (opcode) { ! 226: ! 227: case CVTDF: ! 228: case ADDD2: ! 229: case SUBD2: ! 230: case MULD2: ! 231: case DIVD2: ! 232: case ADDF2: ! 233: case SUBF2: ! 234: case MULF2: ! 235: case DIVF2: return (2); ! 236: case ADDF3: ! 237: case SUBF3: ! 238: case MULF3: ! 239: case DIVF3: ! 240: case ADDD3: ! 241: case SUBD3: ! 242: case MULD3: ! 243: case DIVD3: return (3); ! 244: default: ! 245: err ("cannot determine destination operand (opcode = %x)"); ! 246: return (-1); ! 247: } ! 248: } ! 249: ! 250: /* num_opnd Given an opcode return the number of operand specifiers ! 251: * associated with it. ! 252: */ ! 253: num_opnd (opcode) ! 254: int opcode; ! 255: { ! 256: ! 257: switch (opcode) { ! 258: ! 259: case CVTDF: ! 260: case ADDD2: ! 261: case SUBD2: ! 262: case MULD2: ! 263: case DIVD2: ! 264: case ADDF2: ! 265: case SUBF2: ! 266: case MULF2: ! 267: case DIVF2: return (2); ! 268: case ADDF3: ! 269: case SUBF3: ! 270: case MULF3: ! 271: case DIVF3: ! 272: case ADDD3: ! 273: case SUBD3: ! 274: case MULD3: ! 275: case DIVD3: return (3); ! 276: default: ! 277: err ("cannot determine number of operands (opcode = %x)" ! 278: , opcode); ! 279: return (-1); ! 280: } ! 281: } ! 282: ! 283: /* opnd_addr Given an operand specifier address, return the address ! 284: * of the operand. ! 285: * Note: PC is incremented dynamically here as that is the way ! 286: * the VAX goes through its operand specifiers. Also any ! 287: * increment/decrement modes cause changes according to the ! 288: * documentation. ! 289: */ ! 290: char *opnd_addr(type) ! 291: int type; ! 292: { ! 293: register unsigned temp; ! 294: register char *tptr; ! 295: register int mode; ! 296: register int reg; ! 297: extern ANYTYPE *fetch(); ! 298: extern char *addr_reg(); ! 299: extern char *pc; ! 300: ! 301: temp = (unsigned )fetch()->byte; ! 302: mode = (temp & MODE_MASK) >> 4; ! 303: reg = temp & REG_MASK; ! 304: pc += 1; ! 305: switch (mode) { ! 306: case INDEXED: ! 307: tptr = (char *)(reg_cont (reg) * size_of (type)); ! 308: return (tptr + (int )opnd_addr(LONG)); ! 309: case GENERAL: ! 310: return (addr_reg(reg)); ! 311: case REG_DEFRD: ! 312: return ((char *)reg_cont (reg)); ! 313: case AUTO_DEC: ! 314: tptr = addr_reg(reg); ! 315: *tptr -= size_of (type); ! 316: return ((char *)reg_cont(reg)); ! 317: case AUTO_INC: ! 318: tptr = addr_reg(reg); ! 319: *tptr += size_of (type); ! 320: return ((char *)(reg_cont(reg) - size_of(type))); ! 321: case AUTO_INC_DEF: ! 322: tptr = addr_reg (reg); ! 323: *tptr += size_of (LONG); ! 324: return ((char *)*(char *)(reg_cont(reg) - size_of(LONG))); ! 325: case BYTE_DISP: ! 326: tptr = (char *)fetch()->byte; ! 327: pc += 1; ! 328: return (tptr + reg_cont(reg)); ! 329: case BYTE_DISP_DEF: ! 330: tptr = (char *)fetch()->byte; ! 331: pc += 1; ! 332: return ((char *)*(long *)(tptr + reg_cont(reg))); ! 333: case WORD_DISP: ! 334: tptr = (char *)fetch()->word; ! 335: pc += 2; ! 336: return (tptr + reg_cont(reg)); ! 337: case WORD_DISP_DEF: ! 338: tptr = (char *)fetch()->word; ! 339: pc += 2; ! 340: return ((char *)*(long *)(tptr + reg_cont(reg))); ! 341: case LONG_DISP: ! 342: tptr = (char *)fetch()->llong; ! 343: pc += 4; ! 344: return (tptr + reg_cont(reg)); ! 345: case LONG_DISP_DEF: ! 346: tptr = (char *)fetch()->llong; ! 347: pc += 4; ! 348: return ((char *)*(long *)(tptr + reg_cont(reg))); ! 349: default: /* Cannot screw with literals */ ! 350: err ("cannot get address of operand for type 0X%x", type); ! 351: return (NULL); ! 352: } ! 353: } ! 354: ! 355: /* get_type: Given an opcode and the number of the operand return the data ! 356: * type of the operand. ! 357: */ ! 358: get_type (opcode, opernd_num) ! 359: int opcode; ! 360: int opernd_num; ! 361: { ! 362: ! 363: switch (opcode) { ! 364: ! 365: case CVTDF: switch (opernd_num) { ! 366: case 1: return (DOUBLE); ! 367: case 2: return (FLOAT); ! 368: default: return (GARBAGE); ! 369: } ! 370: case ADDF2: ! 371: case SUBF2: ! 372: case MULF2: ! 373: case DIVF2: switch (opernd_num) { ! 374: case 1: ! 375: case 2: return (FLOAT); ! 376: default: return (GARBAGE); ! 377: } ! 378: case ADDF3: ! 379: case SUBF3: ! 380: case MULF3: ! 381: case DIVF3: switch (opernd_num) { ! 382: case 1: ! 383: case 2: ! 384: case 3: return (FLOAT); ! 385: default: return (GARBAGE); ! 386: } ! 387: case ADDD2: ! 388: case SUBD2: ! 389: case MULD2: ! 390: case DIVD2: switch (opernd_num) { ! 391: case 1: ! 392: case 2: return (DOUBLE); ! 393: default: return (GARBAGE); ! 394: } ! 395: case ADDD3: ! 396: case SUBD3: ! 397: case MULD3: ! 398: case DIVD3: switch (opernd_num) { ! 399: case 1: ! 400: case 2: ! 401: case 3: return (DOUBLE); ! 402: default: return (GARBAGE); ! 403: } ! 404: default: return (GARBAGE); ! 405: } ! 406: } ! 407: ! 408: /* fetch: Make a fetch from users space ! 409: * Returned data is static. Any changes are reflected in the actual code. ! 410: * BEWARE ! 411: */ ! 412: ANYTYPE *fetch () ! 413: { ! 414: extern char *pc; ! 415: ! 416: return ((ANYTYPE *)pc); ! 417: } ! 418: ! 419: /* reg_cont Return the contents of the specified register ! 420: */ ! 421: reg_cont (reg) ! 422: int reg; ! 423: { ! 424: if (reg == PC) return ((int )pc); ! 425: if (reg == SP) return ((int ) ®s0t6[6]); ! 426: if (reg == FP) return (regs0t6[-2]); ! 427: if (reg == AP) return (regs0t6[-3]); ! 428: if (reg >= 0 && reg <= 6) return (regs0t6[reg]); ! 429: if (reg >= 7 && reg <= 11) return (regs7t11[reg]); ! 430: err ("Cannot deliver contents of register %d", reg); ! 431: return (NULL); ! 432: } ! 433: ! 434: /* addr_reg Return the stack address of the specified register ! 435: */ ! 436: char *addr_reg (reg) ! 437: int reg; ! 438: { ! 439: extern long *regs0t6, *regs7t11; ! 440: ! 441: if (reg < 7) ! 442: return ((char *)(regs0t6 + reg)); ! 443: return ((char *)(regs7t11 + reg - 7)); ! 444: } ! 445: ! 446: /* load Load value into the address(es) pointed to by addr. ! 447: */ ! 448: load (addr, type, valuel, valuer) ! 449: char *addr; ! 450: int type; ! 451: long valuel; ! 452: long valuer; ! 453: { ! 454: ! 455: *(long *)addr = valuel; ! 456: if (type != QUAD) ! 457: return; ! 458: /* Must fix other half */ ! 459: addr = addr == addr_reg(6) ? addr_reg(7) : addr + 4; ! 460: *(long *)addr = valuer; ! 461: } ! 462: ! 463: /* err ! 464: * The fault handler is confused. Give the user a message and continue. ! 465: * Probably to nausea, but we might have done the job. ! 466: */ ! 467: /* VARARGS 1 */ ! 468: err (fmt, a, b, c, d, e, f, g, h, i, j, k, l) ! 469: char *fmt; ! 470: { ! 471: ! 472: fprintf (stderr, "Fault handler: "); ! 473: fprintf (stderr, fmt, a, b, c, d, e, f, g, h, i, j, k, l); ! 474: putc ('\n', stderr); ! 475: fflush (stderr); /* Deliver message NOW! */ ! 476: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.