Annotation of researchv10dc/cmd/matlab/src/ofault.c, revision 1.1.1.1

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 ) &regs0t6[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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.