123851Sjerry /* #define OLD_BSD if you're running < 4.2 bsd */ 213576Sdlw /* 322991Skre * Copyright (c) 1980 Regents of the University of California. 422991Skre * All rights reserved. The Berkeley software License Agreement 522991Skre * specifies the terms and conditions for redistribution. 613576Sdlw * 7*39150Sbostic * @(#)trpfpe_.c 5.5 09/15/89 822991Skre * 922996Skre * 1013576Sdlw * Fortran floating-point error handler 1113576Sdlw * 1213576Sdlw * Synopsis: 1313576Sdlw * call trpfpe (n, retval) 1413576Sdlw * causes floating point faults to be trapped, with the 1513576Sdlw * first 'n' errors getting a message printed. 1613576Sdlw * 'retval' is put in place of the bad result. 1713576Sdlw * k = fpecnt() 1813576Sdlw * causes 'k' to get the number of errors since the 1913576Sdlw * last call to trpfpe(). 2013576Sdlw * 2113576Sdlw * common /fpeflt/ fpflag 2213576Sdlw * logical fpflag 2313576Sdlw * fpflag will become .true. on faults 2413576Sdlw * 2513576Sdlw * David Wasley, UCBerkeley, June 1983. 2613576Sdlw */ 2713576Sdlw 2813576Sdlw 2913576Sdlw #include <stdio.h> 30*39150Sbostic #include <sys/signal.h> 3113576Sdlw #include "../libI77/fiodefs.h" 3213576Sdlw 33*39150Sbostic #define SIG_VAL void (*)() 3413576Sdlw 3529977Smckusick #ifdef vax 3629977Smckusick #include "opcodes.h" 3729977Smckusick #include "operand.h" 3813576Sdlw 3913576Sdlw struct arglist { /* what AP points to */ 4013576Sdlw long al_numarg; /* only true in CALLS format */ 4113576Sdlw long al_arg[256]; 4213576Sdlw }; 4313576Sdlw 4413576Sdlw struct cframe { /* VAX call frame */ 4513576Sdlw long cf_handler; 4613576Sdlw unsigned short cf_psw; 4713576Sdlw unsigned short cf_mask; 4813576Sdlw struct arglist *cf_ap; 4913576Sdlw struct cframe *cf_fp; 5013576Sdlw char *cf_pc; 5113576Sdlw }; 5213576Sdlw 5313576Sdlw /* 5413576Sdlw * bits in the PSW 5513576Sdlw */ 5613576Sdlw #define PSW_V 0x2 5713576Sdlw #define PSW_FU 0x40 5813576Sdlw #define PSW_IV 0x20 5913576Sdlw 6013576Sdlw /* 6113576Sdlw * where the registers are stored as we see them in the handler 6213576Sdlw */ 6313576Sdlw struct reg0_6 { 6413576Sdlw long reg[7]; 6513576Sdlw }; 6613576Sdlw 6713576Sdlw struct reg7_11 { 6813576Sdlw long reg[5]; 6913576Sdlw }; 7013576Sdlw 7113576Sdlw #define iR0 reg0_6->reg[0] 7213576Sdlw #define iR1 reg0_6->reg[1] 7313576Sdlw #define iR2 reg0_6->reg[2] 7413576Sdlw #define iR3 reg0_6->reg[3] 7513576Sdlw #define iR4 reg0_6->reg[4] 7613576Sdlw #define iR5 reg0_6->reg[5] 7713576Sdlw #define iR6 reg0_6->reg[6] 7813576Sdlw #define iR7 reg7_11->reg[0] 7913576Sdlw #define iR8 reg7_11->reg[1] 8013576Sdlw #define iR9 reg7_11->reg[2] 8113576Sdlw #define iR10 reg7_11->reg[3] 8213576Sdlw #define iR11 reg7_11->reg[4] 8313576Sdlw 8413576Sdlw union objects { /* for load/store */ 8513576Sdlw char ua_byte; 8613576Sdlw short ua_word; 8713576Sdlw long ua_long; 8813576Sdlw float ua_float; 8913576Sdlw double ua_double; 9013576Sdlw union objects *ua_anything; 9113576Sdlw }; 9213576Sdlw 9313576Sdlw typedef union objects anything; 9413576Sdlw enum object_type { BYTE, WORD, LONG, FLOAT, QUAD, DOUBLE, UNKNOWN }; 9513576Sdlw 9613576Sdlw 9713576Sdlw /* 9813576Sdlw * assembly language assist 9913576Sdlw * There are some things you just can't do in C 10013576Sdlw */ 10113576Sdlw asm(".text"); 10213576Sdlw 10313576Sdlw struct cframe *myfp(); 10413576Sdlw asm("_myfp: .word 0x0"); 10513576Sdlw asm("movl 12(fp),r0"); 10613576Sdlw asm("ret"); 10713576Sdlw 10813576Sdlw struct arglist *myap(); 10913576Sdlw asm("_myap: .word 0x0"); 11013576Sdlw asm("movl 8(fp),r0"); 11113576Sdlw asm("ret"); 11213576Sdlw 11313576Sdlw char *mysp(); 11413576Sdlw asm("_mysp: .word 0x0"); 11513576Sdlw asm("extzv $30,$2,4(fp),r0"); 11613576Sdlw asm("addl2 ap,r0"); /* SP in caller is AP+4 here + SPA bits! */ 11713576Sdlw asm("addl2 $4,r0"); 11813576Sdlw asm("ret"); 11913576Sdlw 12013576Sdlw char *mypc(); 12113576Sdlw asm("_mypc: .word 0x0"); 12213576Sdlw asm("movl 16(fp),r0"); 12313576Sdlw asm("ret"); 12413576Sdlw 12513576Sdlw asm(".data"); 12613576Sdlw 12713576Sdlw 12813576Sdlw /* 12913576Sdlw * Where interrupted objects are 13013576Sdlw */ 13113576Sdlw static struct cframe **ifp; /* addr of saved FP */ 13213576Sdlw static struct arglist **iap; /* addr of saved AP */ 13313576Sdlw static char *isp; /* value of interrupted SP */ 13413576Sdlw static char **ipc; /* addr of saved PC */ 13513576Sdlw static struct reg0_6 *reg0_6;/* registers 0-6 are saved on the exception */ 13613576Sdlw static struct reg7_11 *reg7_11;/* we save 7-11 by our entry mask */ 13713576Sdlw static anything *result_addr; /* where the dummy result goes */ 13813576Sdlw static enum object_type result_type; /* what kind of object it is */ 13913576Sdlw 14013576Sdlw /* 14113576Sdlw * some globals 14213576Sdlw */ 14313576Sdlw static union { 14413576Sdlw long rv_long[2]; 14513576Sdlw float rv_float; 14613576Sdlw double rv_double; 14713576Sdlw } retval; /* the user specified dummy result */ 14813576Sdlw static int max_messages = 1; /* the user can tell us */ 14913576Sdlw static int fpe_count = 0; /* how bad is it ? */ 15013576Sdlw long fpeflt_ = 0; /* fortran "common /fpeflt/ flag" */ 15113576Sdlw static int (*sigfpe_dfl)() = SIG_DFL; /* if we can't fix it ... */ 15213576Sdlw 15313576Sdlw /* 15413576Sdlw * The fortran unit control table 15513576Sdlw */ 15613576Sdlw extern unit units[]; 15713576Sdlw 15813576Sdlw /* 15913576Sdlw * Fortran message table is in main 16013576Sdlw */ 16113576Sdlw struct msgtbl { 16213576Sdlw char *mesg; 16313576Sdlw int dummy; 16413576Sdlw }; 16513576Sdlw extern struct msgtbl act_fpe[]; 16613576Sdlw 16713576Sdlw 16813576Sdlw /* 16913576Sdlw * Get the address of the (saved) next operand & update saved PC. 17013576Sdlw * The major purpose of this is to determine where to store the result. 17113576Sdlw * There is one case we can't deal with: -(SP) or (SP)+ 17213576Sdlw * since we can't change the size of the stack. 17313576Sdlw * Let's just hope compilers don't generate that for results. 17413576Sdlw */ 17513576Sdlw 17613576Sdlw anything * 17713576Sdlw get_operand (oper_size) 17813576Sdlw int oper_size; /* size of operand we expect */ 17913576Sdlw { 18013576Sdlw register int regnum; 18113576Sdlw register int operand_code; 18213576Sdlw int index; 18313576Sdlw anything *oper_addr; 18413576Sdlw anything *reg_addr; 18513576Sdlw 18613576Sdlw regnum = (**ipc & 0xf); 18713576Sdlw if (regnum == PC) 18813576Sdlw operand_code = (*(*ipc)++ & 0xff); 18913576Sdlw else 19013576Sdlw operand_code = (*(*ipc)++ & 0xf0); 19113576Sdlw if (regnum <= R6) 19213576Sdlw reg_addr = (anything *)®0_6->reg[regnum]; 19313576Sdlw else if (regnum <= R11) 19413576Sdlw reg_addr = (anything *)®7_11->reg[regnum]; 19513576Sdlw else if (regnum == AP) 19613576Sdlw reg_addr = (anything *)iap; 19713576Sdlw else if (regnum == FP) 19813576Sdlw reg_addr = (anything *)ifp; 19913576Sdlw else if (regnum == SP) 20013576Sdlw reg_addr = (anything *)&isp; /* We saved this ourselves */ 20113576Sdlw else if (regnum == PC) 20213576Sdlw reg_addr = (anything *)ipc; 20313576Sdlw 20413576Sdlw 20513576Sdlw switch (operand_code) 20613576Sdlw { 20713576Sdlw case IMMEDIATE: 20813576Sdlw oper_addr = (anything *)(*ipc); 20913576Sdlw *ipc += oper_size; 21013576Sdlw return(oper_addr); 21113576Sdlw 21213576Sdlw case ABSOLUTE: 21313576Sdlw oper_addr = (anything *)(**ipc); 21413576Sdlw *ipc += sizeof (anything *); 21513576Sdlw return(oper_addr); 21613576Sdlw 21713576Sdlw case LITERAL0: 21813576Sdlw case LITERAL1: 21913576Sdlw case LITERAL2: 22013576Sdlw case LITERAL3: 22113576Sdlw /* we don't care about the address of these */ 22213576Sdlw return((anything *)0); 22313576Sdlw 22413576Sdlw case INDEXED: 22513576Sdlw index = reg_addr->ua_long * oper_size; 22613576Sdlw oper_addr = (anything *)(get_operand(sizeof (long))->ua_long + index); 22713576Sdlw return(oper_addr); 22813576Sdlw 22913576Sdlw case REGISTER: 23013576Sdlw return(reg_addr); 23113576Sdlw 23213576Sdlw case REGDEFERED: 23313576Sdlw return(reg_addr->ua_anything); 23413576Sdlw 23513576Sdlw case AUTODEC: 23613576Sdlw if (regnum == SP) 23713576Sdlw { 23813576Sdlw fprintf(stderr, "trp: can't fix -(SP) operand\n"); 23913576Sdlw exit(1); 24013576Sdlw } 24113576Sdlw reg_addr->ua_long -= oper_size; 24213576Sdlw oper_addr = reg_addr->ua_anything; 24313576Sdlw return(oper_addr); 24413576Sdlw 24513576Sdlw case AUTOINC: 24613576Sdlw if (regnum == SP) 24713576Sdlw { 24813576Sdlw fprintf(stderr, "trp: can't fix (SP)+ operand\n"); 24913576Sdlw exit(1); 25013576Sdlw } 25113576Sdlw oper_addr = reg_addr->ua_anything; 25213576Sdlw reg_addr->ua_long += oper_size; 25313576Sdlw return(oper_addr); 25413576Sdlw 25513576Sdlw case AUTOINCDEF: 25613576Sdlw if (regnum == SP) 25713576Sdlw { 25813576Sdlw fprintf(stderr, "trp: can't fix @(SP)+ operand\n"); 25913576Sdlw exit(1); 26013576Sdlw } 26113576Sdlw oper_addr = (reg_addr->ua_anything)->ua_anything; 26213576Sdlw reg_addr->ua_long += sizeof (anything *); 26313576Sdlw return(oper_addr); 26413576Sdlw 26513576Sdlw case BYTEDISP: 26613576Sdlw case BYTEREL: 26713626Sdlw index = ((anything *)(*ipc))->ua_byte; 26813626Sdlw *ipc += sizeof (char); /* do it now in case reg==PC */ 26913626Sdlw oper_addr = (anything *)(index + reg_addr->ua_long); 27013576Sdlw return(oper_addr); 27113576Sdlw 27213576Sdlw case BYTEDISPDEF: 27313576Sdlw case BYTERELDEF: 27413626Sdlw index = ((anything *)(*ipc))->ua_byte; 27513626Sdlw *ipc += sizeof (char); /* do it now in case reg==PC */ 27613626Sdlw oper_addr = (anything *)(index + reg_addr->ua_long); 27713576Sdlw oper_addr = oper_addr->ua_anything; 27813576Sdlw return(oper_addr); 27913576Sdlw 28013576Sdlw case WORDDISP: 28113576Sdlw case WORDREL: 28213626Sdlw index = ((anything *)(*ipc))->ua_word; 28313626Sdlw *ipc += sizeof (short); /* do it now in case reg==PC */ 28413626Sdlw oper_addr = (anything *)(index + reg_addr->ua_long); 28513576Sdlw return(oper_addr); 28613576Sdlw 28713576Sdlw case WORDDISPDEF: 28813576Sdlw case WORDRELDEF: 28913626Sdlw index = ((anything *)(*ipc))->ua_word; 29013626Sdlw *ipc += sizeof (short); /* do it now in case reg==PC */ 29113626Sdlw oper_addr = (anything *)(index + reg_addr->ua_long); 29213576Sdlw oper_addr = oper_addr->ua_anything; 29313576Sdlw return(oper_addr); 29413576Sdlw 29513576Sdlw case LONGDISP: 29613576Sdlw case LONGREL: 29713626Sdlw index = ((anything *)(*ipc))->ua_long; 29813626Sdlw *ipc += sizeof (long); /* do it now in case reg==PC */ 29913626Sdlw oper_addr = (anything *)(index + reg_addr->ua_long); 30013576Sdlw return(oper_addr); 30113576Sdlw 30213576Sdlw case LONGDISPDEF: 30313576Sdlw case LONGRELDEF: 30413626Sdlw index = ((anything *)(*ipc))->ua_long; 30513626Sdlw *ipc += sizeof (long); /* do it now in case reg==PC */ 30613626Sdlw oper_addr = (anything *)(index + reg_addr->ua_long); 30713576Sdlw oper_addr = oper_addr->ua_anything; 30813576Sdlw return(oper_addr); 30913576Sdlw 31013576Sdlw /* NOTREACHED */ 31113576Sdlw } 31213576Sdlw } 31313576Sdlw 31413576Sdlw /* 31513576Sdlw * Trap & repair floating exceptions so that a program may proceed. 31613576Sdlw * There is no notion of "correctness" here; just the ability to continue. 31713576Sdlw * 31813576Sdlw * The on_fpe() routine first checks the type code to see if the 31913576Sdlw * exception is repairable. If so, it checks the opcode to see if 32013576Sdlw * it is one that it knows. If this is true, it then simulates the 32113576Sdlw * VAX cpu in retrieving operands in order to increment iPC correctly. 32213576Sdlw * It notes where the result of the operation would have been stored 32313576Sdlw * and substitutes a previously supplied value. 32413576Sdlw */ 32513576Sdlw 32613576Sdlw #ifdef OLD_BSD 32713576Sdlw on_fpe(signo, code, myaddr, pc, ps) 32813576Sdlw int signo, code, ps; 32913576Sdlw char *myaddr, *pc; 33013576Sdlw #else 331*39150Sbostic void 33213576Sdlw on_fpe(signo, code, sc, grbg) 33313576Sdlw int signo, code; 33413576Sdlw struct sigcontext *sc; 33513576Sdlw #endif 33613576Sdlw { 33713576Sdlw /* 33813576Sdlw * There must be at least 5 register variables here 33913576Sdlw * so our entry mask will save R11-R7. 34013576Sdlw */ 34113576Sdlw register long *stk; 34213576Sdlw register long *sp; 34313576Sdlw register struct arglist *ap; 34413576Sdlw register struct cframe *fp; 34513576Sdlw register FILE *ef; 34613576Sdlw 34713576Sdlw ef = units[STDERR].ufd; /* fortran error stream */ 34813576Sdlw 34913576Sdlw switch (code) 35013576Sdlw { 35113576Sdlw case FPE_INTOVF_TRAP: /* integer overflow */ 35213576Sdlw case FPE_INTDIV_TRAP: /* integer divide by zero */ 35313576Sdlw case FPE_FLTOVF_TRAP: /* floating overflow */ 35413576Sdlw case FPE_FLTDIV_TRAP: /* floating/decimal divide by zero */ 35513576Sdlw case FPE_FLTUND_TRAP: /* floating underflow */ 35613576Sdlw case FPE_DECOVF_TRAP: /* decimal overflow */ 35713576Sdlw case FPE_SUBRNG_TRAP: /* subscript out of range */ 35813576Sdlw default: 35913576Sdlw cant_fix: 36013576Sdlw if (sigfpe_dfl > (SIG_VAL)7) /* user specified */ 36113576Sdlw #ifdef OLD_BSD 362*39150Sbostic (*sigfpe_dfl)(signo, code, myaddr, pc, ps); 36313576Sdlw #else 364*39150Sbostic (*sigfpe_dfl)(signo, code, sc, grbg); 36513576Sdlw #endif 36613576Sdlw else 36713576Sdlw #ifdef OLD_BSD 36813576Sdlw sigdie(signo, code, myaddr, pc, ps); 36913576Sdlw #else 37013576Sdlw sigdie(signo, code, sc, grbg); 37113576Sdlw #endif 37213576Sdlw /* NOTREACHED */ 37313576Sdlw 37413576Sdlw case FPE_FLTOVF_FAULT: /* floating overflow fault */ 37513576Sdlw case FPE_FLTDIV_FAULT: /* divide by zero floating fault */ 37613576Sdlw case FPE_FLTUND_FAULT: /* floating underflow fault */ 37713576Sdlw if (++fpe_count <= max_messages) { 37813576Sdlw fprintf(ef, "trpfpe: %s", 37913576Sdlw act_fpe[code-1].mesg); 38013576Sdlw if (fpe_count == max_messages) 38113576Sdlw fprintf(ef, ": No more messages will be printed.\n"); 38213576Sdlw else 38313576Sdlw fputc('\n', ef); 38413576Sdlw } 38513576Sdlw fpeflt_ = -1; 38613576Sdlw break; 38713576Sdlw } 38813576Sdlw 38913576Sdlw ap = myap(); /* my arglist pointer */ 39013576Sdlw fp = myfp(); /* my frame pointer */ 39113576Sdlw ifp = &(fp->cf_fp)->cf_fp; /* user's stored in next frame back */ 39213576Sdlw iap = &(fp->cf_fp)->cf_ap; 39313576Sdlw /* 39413576Sdlw * these are likely to be system dependent 39513576Sdlw */ 39613576Sdlw reg0_6 = (struct reg0_6 *)((char *)fp->cf_fp + sizeof (struct cframe)); 39713576Sdlw reg7_11 = (struct reg7_11 *)((char *)fp->cf_fp - sizeof (struct reg7_11)); 39813576Sdlw 39913576Sdlw #ifdef OLD_BSD 40013576Sdlw ipc = &pc; 40113576Sdlw isp = (char *)&ap->al_arg[ap->al_numarg + 2]; /* assumes 2 dummys */ 40213576Sdlw ps &= ~(PSW_V|PSW_FU); 40313576Sdlw #else 40413576Sdlw ipc = (char **)&sc->sc_pc; 40514635Sdlw isp = (char *)sc + sizeof (struct sigcontext); 40613576Sdlw sc->sc_ps &= ~(PSW_V|PSW_FU); 40713576Sdlw #endif 40813576Sdlw 40913576Sdlw 41013576Sdlw switch (*(*ipc)++) 41113576Sdlw { 41213576Sdlw case ADDD3: 41313576Sdlw case DIVD3: 41413576Sdlw case MULD3: 41513576Sdlw case SUBD3: 41613576Sdlw (void) get_operand(sizeof (double)); 41713576Sdlw /* intentional fall-thru */ 41813576Sdlw 41913576Sdlw case ADDD2: 42013576Sdlw case DIVD2: 42113576Sdlw case MULD2: 42213576Sdlw case SUBD2: 42313576Sdlw case MNEGD: 42413576Sdlw case MOVD: 42513576Sdlw (void) get_operand(sizeof (double)); 42613576Sdlw result_addr = get_operand(sizeof (double)); 42713576Sdlw result_type = DOUBLE; 42813576Sdlw break; 42913576Sdlw 43013576Sdlw case ADDF3: 43113576Sdlw case DIVF3: 43213576Sdlw case MULF3: 43313576Sdlw case SUBF3: 43413576Sdlw (void) get_operand(sizeof (float)); 43513576Sdlw /* intentional fall-thru */ 43613576Sdlw 43713576Sdlw case ADDF2: 43813576Sdlw case DIVF2: 43913576Sdlw case MULF2: 44013576Sdlw case SUBF2: 44113576Sdlw case MNEGF: 44213576Sdlw case MOVF: 44313576Sdlw (void) get_operand(sizeof (float)); 44413576Sdlw result_addr = get_operand(sizeof (float)); 44513576Sdlw result_type = FLOAT; 44613576Sdlw break; 44713576Sdlw 44813576Sdlw case CVTDF: 44913576Sdlw (void) get_operand(sizeof (double)); 45013576Sdlw result_addr = get_operand(sizeof (float)); 45113576Sdlw result_type = FLOAT; 45213576Sdlw break; 45313576Sdlw 45413576Sdlw case CVTFD: 45513576Sdlw (void) get_operand(sizeof (float)); 45613576Sdlw result_addr = get_operand(sizeof (double)); 45713576Sdlw result_type = DOUBLE; 45813576Sdlw break; 45913576Sdlw 46013576Sdlw case EMODF: 46113576Sdlw case EMODD: 46213576Sdlw fprintf(ef, "trpfpe: can't fix emod yet\n"); 46313576Sdlw goto cant_fix; 46413576Sdlw 46513576Sdlw case POLYF: 46613576Sdlw case POLYD: 46713576Sdlw fprintf(ef, "trpfpe: can't fix poly yet\n"); 46813576Sdlw goto cant_fix; 46913576Sdlw 47013576Sdlw case ACBD: 47113576Sdlw case ACBF: 47213576Sdlw case CMPD: 47313576Sdlw case CMPF: 47413576Sdlw case TSTD: 47513576Sdlw case TSTF: 47613576Sdlw case CVTDB: 47713576Sdlw case CVTDL: 47813576Sdlw case CVTDW: 47913576Sdlw case CVTFB: 48013576Sdlw case CVTFL: 48113576Sdlw case CVTFW: 48213576Sdlw case CVTRDL: 48313576Sdlw case CVTRFL: 48413576Sdlw /* These can generate only reserved operand faults */ 48513576Sdlw /* They are shown here for completeness */ 48613576Sdlw 48713576Sdlw default: 48813576Sdlw fprintf(stderr, "trp: opcode 0x%02x unknown\n", 48913576Sdlw *(--(*ipc)) & 0xff); 49013576Sdlw goto cant_fix; 49113576Sdlw /* NOTREACHED */ 49213576Sdlw } 49313576Sdlw 49413576Sdlw if (result_type == FLOAT) 49513576Sdlw result_addr->ua_float = retval.rv_float; 49613576Sdlw else 49713576Sdlw { 49813576Sdlw if (result_addr == (anything *)&iR6) 49913576Sdlw { /* 50013576Sdlw * special case - the R6/R7 pair is stored apart 50113576Sdlw */ 50213576Sdlw result_addr->ua_long = retval.rv_long[0]; 50313576Sdlw ((anything *)&iR7)->ua_long = retval.rv_long[1]; 50413576Sdlw } 50513576Sdlw else 50613576Sdlw result_addr->ua_double = retval.rv_double; 50713576Sdlw } 50813576Sdlw signal(SIGFPE, on_fpe); 50913576Sdlw } 51013576Sdlw 51113576Sdlw trpfpe_ (count, rval) 51213576Sdlw long *count; /* how many to announce */ 51313576Sdlw double *rval; /* dummy return value */ 51413576Sdlw { 51513576Sdlw max_messages = *count; 51613576Sdlw retval.rv_double = *rval; 51713576Sdlw sigfpe_dfl = signal(SIGFPE, on_fpe); 51813576Sdlw fpe_count = 0; 51913576Sdlw } 52013576Sdlw 52113576Sdlw long 52213576Sdlw fpecnt_ () 52313576Sdlw { 52413576Sdlw return (fpe_count); 52513576Sdlw } 52629977Smckusick #endif vax 52713576Sdlw 52829977Smckusick #ifdef tahoe 52929977Smckusick /* 53029977Smckusick * This handler just prints a message. It cannot fix anything 53129977Smckusick * on Power6 because of its fpp architecture. In any case, there 53229977Smckusick * are no arithmetic faults (only traps) around, so that no instruction 53329977Smckusick * is interrupted befor it completes, and PC points to the next floating 53429977Smckusick * point instruction (not necessarily next executable instr after the one 53529977Smckusick * that got the exception). 53629977Smckusick */ 53729977Smckusick 53829977Smckusick struct arglist { /* what AP points to */ 53929977Smckusick long al_arg[256]; 54029977Smckusick }; 54129977Smckusick 54229977Smckusick struct reg0_1 { 54329977Smckusick long reg[2]; 54429977Smckusick }; 54529977Smckusick struct reg2_12 { 54629977Smckusick long reg[11]; 54729977Smckusick }; 54829977Smckusick #include <sys/types.h> 54929977Smckusick #include <frame.h> 55029977Smckusick #include "sigframe.h" 55129977Smckusick 55229977Smckusick /* 55329977Smckusick * bits in the PSL 55429977Smckusick */ 55529977Smckusick #include <machine/psl.h> 55629977Smckusick 55729977Smckusick /* 55829977Smckusick * where the registers are stored as we see them in the handler 55929977Smckusick */ 56029977Smckusick 56129977Smckusick 56229977Smckusick #define iR0 reg0_1->reg[1] 56329977Smckusick #define iR1 reg0_1->reg[0] 56429977Smckusick 56529977Smckusick #define iR2 reg2_12->reg[0] 56629977Smckusick #define iR3 reg2_12->reg[1] 56729977Smckusick #define iR4 reg2_12->reg[2] 56829977Smckusick #define iR5 reg2_12->reg[3] 56929977Smckusick #define iR6 reg2_12->reg[4] 57029977Smckusick #define iR7 reg2_12->reg[5] 57129977Smckusick #define iR8 reg2_12->reg[6] 57229977Smckusick #define iR9 reg2_12->reg[7] 57329977Smckusick #define iR10 reg2_12->reg[8] 57429977Smckusick #define iR11 reg2_12->reg[9] 57529977Smckusick #define iR12 reg2_12->reg[10] 57629977Smckusick 57729977Smckusick union objects { /* for load/store */ 57829977Smckusick char ua_byte; 57929977Smckusick short ua_word; 58029977Smckusick long ua_long; 58129977Smckusick float ua_float; 58229977Smckusick double ua_double; 58329977Smckusick union objects *ua_anything; 58429977Smckusick }; 58529977Smckusick 58629977Smckusick typedef union objects anything; 58729977Smckusick enum object_type { BYTE, WORD, LONG, FLOAT, QUAD, DOUBLE, UNKNOWN }; 58829977Smckusick 58929977Smckusick 59029977Smckusick /* 59129977Smckusick * assembly language assist 59229977Smckusick * There are some things you just can't do in C 59329977Smckusick */ 59429977Smckusick asm(".text"); 59529977Smckusick 59629977Smckusick long *myfp(); 59729977Smckusick asm("_myfp: .word 0"); 59829977Smckusick asm("movl (fp),r0"); 59929977Smckusick asm("ret"); 60029977Smckusick 60129977Smckusick struct frame *framep(p) 60229977Smckusick long *p; 60329977Smckusick { 60429977Smckusick return((struct frame *)(p-2)); 60529977Smckusick } 60629977Smckusick 60729977Smckusick struct arglist *argp(p) 60829977Smckusick long *p; 60929977Smckusick { 61029977Smckusick return((struct arglist *)(p+1)); 61129977Smckusick } 61229977Smckusick 61329977Smckusick char *mysp(); 61429977Smckusick asm("_mysp: .word 0"); 61529977Smckusick asm("addl3 $4,fp,r0"); 61629977Smckusick asm("ret"); 61729977Smckusick 61829977Smckusick char *mypc(); 61929977Smckusick asm("_mypc: .word 0"); 62029977Smckusick asm("movl -8(fp),r0"); 62129977Smckusick asm("ret"); 62229977Smckusick 62329977Smckusick asm(".data"); 62429977Smckusick 62529977Smckusick 62629977Smckusick /* 62729977Smckusick * Where interrupted objects are 62829977Smckusick */ 62929977Smckusick static struct frame *ifp; /* addr of saved FP */ 63029977Smckusick static struct arglist *iap; /* addr of saved AP */ 63129977Smckusick static char *isp; /* value of interrupted SP */ 63229977Smckusick static char **ipc; /* addr of saved PC */ 63329977Smckusick static struct reg0_1 *reg0_1;/* registers 0-1 are saved on the exception */ 63429977Smckusick static struct reg2_12 *reg2_12;/* we save 2-12 by our entry mask */ 63529977Smckusick static anything *result_addr; /* where the dummy result goes */ 63629977Smckusick static enum object_type result_type; /* what kind of object it is */ 63729977Smckusick 63829977Smckusick /* 63929977Smckusick * some globals 64029977Smckusick */ 64129977Smckusick static union { 64229977Smckusick long rv_long[2]; 64329977Smckusick float rv_float; 64429977Smckusick double rv_double; 64529977Smckusick } retval; /* the user specified dummy result */ 64629977Smckusick static int max_messages = 1; /* the user can tell us */ 64729977Smckusick static int fpe_count = 0; /* how bad is it ? */ 64829977Smckusick long fpeflt_ = 0; /* fortran "common /fpeflt/ flag" */ 649*39150Sbostic static sig_t sigfpe_dfl = SIG_DFL; /* if we can't fix it ... */ 65029977Smckusick 65129977Smckusick /* 65229977Smckusick * The fortran unit control table 65329977Smckusick */ 65429977Smckusick extern unit units[]; 65529977Smckusick 65629977Smckusick /* 65729977Smckusick * Fortran message table is in main 65829977Smckusick */ 65929977Smckusick struct msgtbl { 66029977Smckusick char *mesg; 66129977Smckusick int dummy; 66229977Smckusick }; 66329977Smckusick extern struct msgtbl act_fpe[]; 66429977Smckusick 66529977Smckusick 66629977Smckusick /* VALID ONLY ON VAX !!! 66729977Smckusick * 66829977Smckusick * Get the address of the (saved) next operand & update saved PC. 66929977Smckusick * The major purpose of this is to determine where to store the result. 67029977Smckusick * There is one case we can't deal with: -(SP) or (SP)+ 67129977Smckusick * since we can't change the size of the stack. 67229977Smckusick * Let's just hope compilers don't generate that for results. 67329977Smckusick */ 67429977Smckusick 67529977Smckusick 67629977Smckusick /* 67729977Smckusick * Trap & repair floating exceptions so that a program may proceed. 67829977Smckusick * There is no notion of "correctness" here; just the ability to continue. 67929977Smckusick * 68029977Smckusick * The on_fpe() routine first checks the type code to see if the 68129977Smckusick * exception is repairable. If so, it checks the opcode to see if 68229977Smckusick * it is one that it knows. If this is true, it then simulates the 68329977Smckusick * VAX cpu in retrieving operands in order to increment iPC correctly. 68429977Smckusick * It notes where the result of the operation would have been stored 68529977Smckusick * and substitutes a previously supplied value. 68629977Smckusick * DOES NOT REPAIR ON TAHOE !!! 68729977Smckusick */ 688*39150Sbostic void 68929977Smckusick on_fpe(signo, code, sc) 69029977Smckusick int signo, code; 69129977Smckusick struct sigcontext *sc; 69229977Smckusick { 69329977Smckusick /* 69429977Smckusick * There must be at least 11 register variables here 69529977Smckusick * so our entry mask will save R12-R2. 69629977Smckusick */ 69729977Smckusick register long *stk; 69829977Smckusick register long *sp, *rfp; 69929977Smckusick register struct arglist *ap; 70029977Smckusick register struct frame *fp; 70129977Smckusick register FILE *ef; 70229977Smckusick register struct sigframe *sfp; 70329977Smckusick register long dmy1, dmy2, dmy3, dmy4; 70429977Smckusick 70529977Smckusick dmy1 = dmy2 = dmy3 = dmy4 = 0; 70629977Smckusick 70729977Smckusick ef = units[STDERR].ufd; /* fortran error stream */ 70829977Smckusick 70929977Smckusick switch (code) 71029977Smckusick { 71129977Smckusick case FPE_INTOVF_TRAP: /* integer overflow */ 71229977Smckusick case FPE_INTDIV_TRAP: /* integer divide by zero */ 71329977Smckusick case FPE_FLTOVF_TRAP: /* floating overflow */ 71429977Smckusick case FPE_FLTDIV_TRAP: /* floating divide by zero */ 71529977Smckusick case FPE_FLTUND_TRAP: /* floating underflow */ 71629977Smckusick default: 71729977Smckusick cant_fix: 71829977Smckusick if (sigfpe_dfl > (SIG_VAL)7) /* user specified */ 719*39150Sbostic (*sigfpe_dfl)(signo, code, sc); 72029977Smckusick else 72129977Smckusick if (++fpe_count <= max_messages) { 72229977Smckusick fprintf(ef, "trpfpe: %s", 72329977Smckusick act_fpe[code-1].mesg); 72429977Smckusick if (fpe_count == max_messages) 72529977Smckusick fprintf(ef, ": No more messages will be printed.\n"); 72629977Smckusick else 72729977Smckusick fputc('\n', ef); 72829977Smckusick } 72929977Smckusick fpeflt_ = -1; 73029977Smckusick break; 73129977Smckusick } 73229977Smckusick 73329977Smckusick /* 73429977Smckusick * Find all the registers just in case something better can be done. 73529977Smckusick */ 73629977Smckusick 73729977Smckusick rfp = myfp(); /* contents of fp register */ 73829977Smckusick ap = argp(rfp); /* my arglist pointer */ 73929977Smckusick fp = framep(rfp); /* my frame pointer */ 74029977Smckusick ifp = framep(*rfp); /* user's stored in next frame back */ 74129977Smckusick iap = argp(*rfp); 74229977Smckusick 74329977Smckusick sfp = (struct sigframe *)ap; /* sigframe contains at its bottom the 74429977Smckusick signal handler arguments */ 74529977Smckusick 74629977Smckusick reg0_1 = (struct reg0_1 *)&sfp->r1; 74729977Smckusick reg2_12 = (struct reg2_12 *)((char *)fp - sizeof (struct reg2_12)); 74829977Smckusick 74929977Smckusick ipc = (char **)&sc->sc_pc; 75029977Smckusick isp = (char *)sc + sizeof (struct sigcontext); 75129977Smckusick sc->sc_ps &= ~(PSL_V|PSL_FU); 75229977Smckusick 75329977Smckusick fprintf(ef, "Current PC = %X \n", sc->sc_pc); 75429977Smckusick 75529977Smckusick signal(SIGFPE, on_fpe); 75629977Smckusick sigdie(signo, code, sc); 75729977Smckusick } 75829977Smckusick 75929977Smckusick trpfpe_ (count, rval) 76029977Smckusick long *count; /* how many to announce */ 76129977Smckusick double *rval; /* dummy return value */ 76229977Smckusick { 76329977Smckusick max_messages = *count; 76429977Smckusick retval.rv_double = *rval; 76529977Smckusick sigfpe_dfl = signal(SIGFPE, on_fpe); 76629977Smckusick fpe_count = 0; 76729977Smckusick } 76829977Smckusick 76929977Smckusick long 77029977Smckusick fpecnt_ () 77129977Smckusick { 77229977Smckusick return (fpe_count); 77329977Smckusick } 77429977Smckusick 77529977Smckusick #endif tahoe 776