Annotation of researchv10dc/cmd/matlab/src/ofault.c, revision 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.