1*13576Sdlw /* #define OLD_BSD if you're running < 4.2bsd */ 2*13576Sdlw /* 3*13576Sdlw char id_trpfpe[] = "@(#)trpfpe_.c 1.1"; 4*13576Sdlw * 5*13576Sdlw * Fortran floating-point error handler 6*13576Sdlw * 7*13576Sdlw * Synopsis: 8*13576Sdlw * call trpfpe (n, retval) 9*13576Sdlw * causes floating point faults to be trapped, with the 10*13576Sdlw * first 'n' errors getting a message printed. 11*13576Sdlw * 'retval' is put in place of the bad result. 12*13576Sdlw * k = fpecnt() 13*13576Sdlw * causes 'k' to get the number of errors since the 14*13576Sdlw * last call to trpfpe(). 15*13576Sdlw * 16*13576Sdlw * common /fpeflt/ fpflag 17*13576Sdlw * logical fpflag 18*13576Sdlw * fpflag will become .true. on faults 19*13576Sdlw * 20*13576Sdlw * David Wasley, UCBerkeley, June 1983. 21*13576Sdlw */ 22*13576Sdlw 23*13576Sdlw 24*13576Sdlw #include <stdio.h> 25*13576Sdlw #include <signal.h> 26*13576Sdlw #include "opcodes.h" 27*13576Sdlw #include "operand.h" 28*13576Sdlw #include "../libI77/fiodefs.h" 29*13576Sdlw 30*13576Sdlw #define SIG_VAL int (*)() 31*13576Sdlw 32*13576Sdlw #if vax /* only works on VAXen */ 33*13576Sdlw 34*13576Sdlw struct arglist { /* what AP points to */ 35*13576Sdlw long al_numarg; /* only true in CALLS format */ 36*13576Sdlw long al_arg[256]; 37*13576Sdlw }; 38*13576Sdlw 39*13576Sdlw struct cframe { /* VAX call frame */ 40*13576Sdlw long cf_handler; 41*13576Sdlw unsigned short cf_psw; 42*13576Sdlw unsigned short cf_mask; 43*13576Sdlw struct arglist *cf_ap; 44*13576Sdlw struct cframe *cf_fp; 45*13576Sdlw char *cf_pc; 46*13576Sdlw }; 47*13576Sdlw 48*13576Sdlw /* 49*13576Sdlw * bits in the PSW 50*13576Sdlw */ 51*13576Sdlw #define PSW_V 0x2 52*13576Sdlw #define PSW_FU 0x40 53*13576Sdlw #define PSW_IV 0x20 54*13576Sdlw 55*13576Sdlw /* 56*13576Sdlw * where the registers are stored as we see them in the handler 57*13576Sdlw */ 58*13576Sdlw struct reg0_6 { 59*13576Sdlw long reg[7]; 60*13576Sdlw }; 61*13576Sdlw 62*13576Sdlw struct reg7_11 { 63*13576Sdlw long reg[5]; 64*13576Sdlw }; 65*13576Sdlw 66*13576Sdlw #define iR0 reg0_6->reg[0] 67*13576Sdlw #define iR1 reg0_6->reg[1] 68*13576Sdlw #define iR2 reg0_6->reg[2] 69*13576Sdlw #define iR3 reg0_6->reg[3] 70*13576Sdlw #define iR4 reg0_6->reg[4] 71*13576Sdlw #define iR5 reg0_6->reg[5] 72*13576Sdlw #define iR6 reg0_6->reg[6] 73*13576Sdlw #define iR7 reg7_11->reg[0] 74*13576Sdlw #define iR8 reg7_11->reg[1] 75*13576Sdlw #define iR9 reg7_11->reg[2] 76*13576Sdlw #define iR10 reg7_11->reg[3] 77*13576Sdlw #define iR11 reg7_11->reg[4] 78*13576Sdlw 79*13576Sdlw union objects { /* for load/store */ 80*13576Sdlw char ua_byte; 81*13576Sdlw short ua_word; 82*13576Sdlw long ua_long; 83*13576Sdlw float ua_float; 84*13576Sdlw double ua_double; 85*13576Sdlw union objects *ua_anything; 86*13576Sdlw }; 87*13576Sdlw 88*13576Sdlw typedef union objects anything; 89*13576Sdlw enum object_type { BYTE, WORD, LONG, FLOAT, QUAD, DOUBLE, UNKNOWN }; 90*13576Sdlw 91*13576Sdlw 92*13576Sdlw /* 93*13576Sdlw * assembly language assist 94*13576Sdlw * There are some things you just can't do in C 95*13576Sdlw */ 96*13576Sdlw asm(".text"); 97*13576Sdlw 98*13576Sdlw struct cframe *myfp(); 99*13576Sdlw asm("_myfp: .word 0x0"); 100*13576Sdlw asm("movl 12(fp),r0"); 101*13576Sdlw asm("ret"); 102*13576Sdlw 103*13576Sdlw struct arglist *myap(); 104*13576Sdlw asm("_myap: .word 0x0"); 105*13576Sdlw asm("movl 8(fp),r0"); 106*13576Sdlw asm("ret"); 107*13576Sdlw 108*13576Sdlw char *mysp(); 109*13576Sdlw asm("_mysp: .word 0x0"); 110*13576Sdlw asm("extzv $30,$2,4(fp),r0"); 111*13576Sdlw asm("addl2 ap,r0"); /* SP in caller is AP+4 here + SPA bits! */ 112*13576Sdlw asm("addl2 $4,r0"); 113*13576Sdlw asm("ret"); 114*13576Sdlw 115*13576Sdlw char *mypc(); 116*13576Sdlw asm("_mypc: .word 0x0"); 117*13576Sdlw asm("movl 16(fp),r0"); 118*13576Sdlw asm("ret"); 119*13576Sdlw 120*13576Sdlw asm(".data"); 121*13576Sdlw 122*13576Sdlw 123*13576Sdlw /* 124*13576Sdlw * Where interrupted objects are 125*13576Sdlw */ 126*13576Sdlw static struct cframe **ifp; /* addr of saved FP */ 127*13576Sdlw static struct arglist **iap; /* addr of saved AP */ 128*13576Sdlw static char *isp; /* value of interrupted SP */ 129*13576Sdlw static char **ipc; /* addr of saved PC */ 130*13576Sdlw static struct reg0_6 *reg0_6;/* registers 0-6 are saved on the exception */ 131*13576Sdlw static struct reg7_11 *reg7_11;/* we save 7-11 by our entry mask */ 132*13576Sdlw static anything *result_addr; /* where the dummy result goes */ 133*13576Sdlw static enum object_type result_type; /* what kind of object it is */ 134*13576Sdlw 135*13576Sdlw /* 136*13576Sdlw * some globals 137*13576Sdlw */ 138*13576Sdlw static union { 139*13576Sdlw long rv_long[2]; 140*13576Sdlw float rv_float; 141*13576Sdlw double rv_double; 142*13576Sdlw } retval; /* the user specified dummy result */ 143*13576Sdlw static int max_messages = 1; /* the user can tell us */ 144*13576Sdlw static int fpe_count = 0; /* how bad is it ? */ 145*13576Sdlw long fpeflt_ = 0; /* fortran "common /fpeflt/ flag" */ 146*13576Sdlw static int (*sigfpe_dfl)() = SIG_DFL; /* if we can't fix it ... */ 147*13576Sdlw 148*13576Sdlw /* 149*13576Sdlw * The fortran unit control table 150*13576Sdlw */ 151*13576Sdlw extern unit units[]; 152*13576Sdlw 153*13576Sdlw /* 154*13576Sdlw * Fortran message table is in main 155*13576Sdlw */ 156*13576Sdlw struct msgtbl { 157*13576Sdlw char *mesg; 158*13576Sdlw int dummy; 159*13576Sdlw }; 160*13576Sdlw extern struct msgtbl act_fpe[]; 161*13576Sdlw 162*13576Sdlw 163*13576Sdlw /* 164*13576Sdlw * Get the address of the (saved) next operand & update saved PC. 165*13576Sdlw * The major purpose of this is to determine where to store the result. 166*13576Sdlw * There is one case we can't deal with: -(SP) or (SP)+ 167*13576Sdlw * since we can't change the size of the stack. 168*13576Sdlw * Let's just hope compilers don't generate that for results. 169*13576Sdlw */ 170*13576Sdlw 171*13576Sdlw anything * 172*13576Sdlw get_operand (oper_size) 173*13576Sdlw int oper_size; /* size of operand we expect */ 174*13576Sdlw { 175*13576Sdlw register int regnum; 176*13576Sdlw register int operand_code; 177*13576Sdlw int index; 178*13576Sdlw anything *oper_addr; 179*13576Sdlw anything *reg_addr; 180*13576Sdlw 181*13576Sdlw regnum = (**ipc & 0xf); 182*13576Sdlw if (regnum == PC) 183*13576Sdlw operand_code = (*(*ipc)++ & 0xff); 184*13576Sdlw else 185*13576Sdlw operand_code = (*(*ipc)++ & 0xf0); 186*13576Sdlw if (regnum <= R6) 187*13576Sdlw reg_addr = (anything *)®0_6->reg[regnum]; 188*13576Sdlw else if (regnum <= R11) 189*13576Sdlw reg_addr = (anything *)®7_11->reg[regnum]; 190*13576Sdlw else if (regnum == AP) 191*13576Sdlw reg_addr = (anything *)iap; 192*13576Sdlw else if (regnum == FP) 193*13576Sdlw reg_addr = (anything *)ifp; 194*13576Sdlw else if (regnum == SP) 195*13576Sdlw reg_addr = (anything *)&isp; /* We saved this ourselves */ 196*13576Sdlw else if (regnum == PC) 197*13576Sdlw reg_addr = (anything *)ipc; 198*13576Sdlw 199*13576Sdlw 200*13576Sdlw switch (operand_code) 201*13576Sdlw { 202*13576Sdlw case IMMEDIATE: 203*13576Sdlw oper_addr = (anything *)(*ipc); 204*13576Sdlw *ipc += oper_size; 205*13576Sdlw return(oper_addr); 206*13576Sdlw 207*13576Sdlw case ABSOLUTE: 208*13576Sdlw oper_addr = (anything *)(**ipc); 209*13576Sdlw *ipc += sizeof (anything *); 210*13576Sdlw return(oper_addr); 211*13576Sdlw 212*13576Sdlw case LITERAL0: 213*13576Sdlw case LITERAL1: 214*13576Sdlw case LITERAL2: 215*13576Sdlw case LITERAL3: 216*13576Sdlw /* we don't care about the address of these */ 217*13576Sdlw return((anything *)0); 218*13576Sdlw 219*13576Sdlw case INDEXED: 220*13576Sdlw index = reg_addr->ua_long * oper_size; 221*13576Sdlw oper_addr = (anything *)(get_operand(sizeof (long))->ua_long + index); 222*13576Sdlw return(oper_addr); 223*13576Sdlw 224*13576Sdlw case REGISTER: 225*13576Sdlw return(reg_addr); 226*13576Sdlw 227*13576Sdlw case REGDEFERED: 228*13576Sdlw return(reg_addr->ua_anything); 229*13576Sdlw 230*13576Sdlw case AUTODEC: 231*13576Sdlw if (regnum == SP) 232*13576Sdlw { 233*13576Sdlw fprintf(stderr, "trp: can't fix -(SP) operand\n"); 234*13576Sdlw exit(1); 235*13576Sdlw } 236*13576Sdlw reg_addr->ua_long -= oper_size; 237*13576Sdlw oper_addr = reg_addr->ua_anything; 238*13576Sdlw return(oper_addr); 239*13576Sdlw 240*13576Sdlw case AUTOINC: 241*13576Sdlw if (regnum == SP) 242*13576Sdlw { 243*13576Sdlw fprintf(stderr, "trp: can't fix (SP)+ operand\n"); 244*13576Sdlw exit(1); 245*13576Sdlw } 246*13576Sdlw oper_addr = reg_addr->ua_anything; 247*13576Sdlw reg_addr->ua_long += oper_size; 248*13576Sdlw return(oper_addr); 249*13576Sdlw 250*13576Sdlw case AUTOINCDEF: 251*13576Sdlw if (regnum == SP) 252*13576Sdlw { 253*13576Sdlw fprintf(stderr, "trp: can't fix @(SP)+ operand\n"); 254*13576Sdlw exit(1); 255*13576Sdlw } 256*13576Sdlw oper_addr = (reg_addr->ua_anything)->ua_anything; 257*13576Sdlw reg_addr->ua_long += sizeof (anything *); 258*13576Sdlw return(oper_addr); 259*13576Sdlw 260*13576Sdlw case BYTEDISP: 261*13576Sdlw case BYTEREL: 262*13576Sdlw oper_addr = (anything *)(((anything *)(*ipc))->ua_byte + reg_addr->ua_long); 263*13576Sdlw *ipc += sizeof (char); 264*13576Sdlw return(oper_addr); 265*13576Sdlw 266*13576Sdlw case BYTEDISPDEF: 267*13576Sdlw case BYTERELDEF: 268*13576Sdlw oper_addr = (anything *)(((anything *)(*ipc))->ua_byte + reg_addr->ua_long); 269*13576Sdlw oper_addr = oper_addr->ua_anything; 270*13576Sdlw *ipc += sizeof (char); 271*13576Sdlw return(oper_addr); 272*13576Sdlw 273*13576Sdlw case WORDDISP: 274*13576Sdlw case WORDREL: 275*13576Sdlw oper_addr = (anything *)(((anything *)(*ipc))->ua_word + reg_addr->ua_long); 276*13576Sdlw *ipc += sizeof (short); 277*13576Sdlw return(oper_addr); 278*13576Sdlw 279*13576Sdlw case WORDDISPDEF: 280*13576Sdlw case WORDRELDEF: 281*13576Sdlw oper_addr = (anything *)(((anything *)(*ipc))->ua_word + reg_addr->ua_long); 282*13576Sdlw oper_addr = oper_addr->ua_anything; 283*13576Sdlw *ipc += sizeof (short); 284*13576Sdlw return(oper_addr); 285*13576Sdlw 286*13576Sdlw case LONGDISP: 287*13576Sdlw case LONGREL: 288*13576Sdlw oper_addr = (anything *)(((anything *)(*ipc))->ua_long + reg_addr->ua_long); 289*13576Sdlw *ipc += sizeof (long); 290*13576Sdlw return(oper_addr); 291*13576Sdlw 292*13576Sdlw case LONGDISPDEF: 293*13576Sdlw case LONGRELDEF: 294*13576Sdlw oper_addr = (anything *)(((anything *)(*ipc))->ua_long + reg_addr->ua_long); 295*13576Sdlw oper_addr = oper_addr->ua_anything; 296*13576Sdlw *ipc += sizeof (long); 297*13576Sdlw return(oper_addr); 298*13576Sdlw 299*13576Sdlw /* NOTREACHED */ 300*13576Sdlw } 301*13576Sdlw } 302*13576Sdlw 303*13576Sdlw /* 304*13576Sdlw * Trap & repair floating exceptions so that a program may proceed. 305*13576Sdlw * There is no notion of "correctness" here; just the ability to continue. 306*13576Sdlw * 307*13576Sdlw * The on_fpe() routine first checks the type code to see if the 308*13576Sdlw * exception is repairable. If so, it checks the opcode to see if 309*13576Sdlw * it is one that it knows. If this is true, it then simulates the 310*13576Sdlw * VAX cpu in retrieving operands in order to increment iPC correctly. 311*13576Sdlw * It notes where the result of the operation would have been stored 312*13576Sdlw * and substitutes a previously supplied value. 313*13576Sdlw */ 314*13576Sdlw 315*13576Sdlw #ifdef OLD_BSD 316*13576Sdlw on_fpe(signo, code, myaddr, pc, ps) 317*13576Sdlw int signo, code, ps; 318*13576Sdlw char *myaddr, *pc; 319*13576Sdlw #else 320*13576Sdlw on_fpe(signo, code, sc, grbg) 321*13576Sdlw int signo, code; 322*13576Sdlw struct sigcontext *sc; 323*13576Sdlw #endif 324*13576Sdlw { 325*13576Sdlw /* 326*13576Sdlw * There must be at least 5 register variables here 327*13576Sdlw * so our entry mask will save R11-R7. 328*13576Sdlw */ 329*13576Sdlw register long *stk; 330*13576Sdlw register long *sp; 331*13576Sdlw register struct arglist *ap; 332*13576Sdlw register struct cframe *fp; 333*13576Sdlw register FILE *ef; 334*13576Sdlw 335*13576Sdlw ef = units[STDERR].ufd; /* fortran error stream */ 336*13576Sdlw 337*13576Sdlw switch (code) 338*13576Sdlw { 339*13576Sdlw case FPE_INTOVF_TRAP: /* integer overflow */ 340*13576Sdlw case FPE_INTDIV_TRAP: /* integer divide by zero */ 341*13576Sdlw case FPE_FLTOVF_TRAP: /* floating overflow */ 342*13576Sdlw case FPE_FLTDIV_TRAP: /* floating/decimal divide by zero */ 343*13576Sdlw case FPE_FLTUND_TRAP: /* floating underflow */ 344*13576Sdlw case FPE_DECOVF_TRAP: /* decimal overflow */ 345*13576Sdlw case FPE_SUBRNG_TRAP: /* subscript out of range */ 346*13576Sdlw default: 347*13576Sdlw cant_fix: 348*13576Sdlw if (sigfpe_dfl > (SIG_VAL)7) /* user specified */ 349*13576Sdlw #ifdef OLD_BSD 350*13576Sdlw return((*sigfpe_dfl)(signo, code, myaddr, pc, ps)); 351*13576Sdlw #else 352*13576Sdlw return((*sigfpe_dfl)(signo, code, sc, grbg)); 353*13576Sdlw #endif 354*13576Sdlw else 355*13576Sdlw #ifdef OLD_BSD 356*13576Sdlw sigdie(signo, code, myaddr, pc, ps); 357*13576Sdlw #else 358*13576Sdlw sigdie(signo, code, sc, grbg); 359*13576Sdlw #endif 360*13576Sdlw /* NOTREACHED */ 361*13576Sdlw 362*13576Sdlw case FPE_FLTOVF_FAULT: /* floating overflow fault */ 363*13576Sdlw case FPE_FLTDIV_FAULT: /* divide by zero floating fault */ 364*13576Sdlw case FPE_FLTUND_FAULT: /* floating underflow fault */ 365*13576Sdlw if (++fpe_count <= max_messages) { 366*13576Sdlw fprintf(ef, "trpfpe: %s", 367*13576Sdlw act_fpe[code-1].mesg); 368*13576Sdlw if (fpe_count == max_messages) 369*13576Sdlw fprintf(ef, ": No more messages will be printed.\n"); 370*13576Sdlw else 371*13576Sdlw fputc('\n', ef); 372*13576Sdlw } 373*13576Sdlw fpeflt_ = -1; 374*13576Sdlw break; 375*13576Sdlw } 376*13576Sdlw 377*13576Sdlw ap = myap(); /* my arglist pointer */ 378*13576Sdlw fp = myfp(); /* my frame pointer */ 379*13576Sdlw ifp = &(fp->cf_fp)->cf_fp; /* user's stored in next frame back */ 380*13576Sdlw iap = &(fp->cf_fp)->cf_ap; 381*13576Sdlw /* 382*13576Sdlw * these are likely to be system dependent 383*13576Sdlw */ 384*13576Sdlw reg0_6 = (struct reg0_6 *)((char *)fp->cf_fp + sizeof (struct cframe)); 385*13576Sdlw reg7_11 = (struct reg7_11 *)((char *)fp->cf_fp - sizeof (struct reg7_11)); 386*13576Sdlw 387*13576Sdlw #ifdef OLD_BSD 388*13576Sdlw ipc = &pc; 389*13576Sdlw isp = (char *)&ap->al_arg[ap->al_numarg + 2]; /* assumes 2 dummys */ 390*13576Sdlw ps &= ~(PSW_V|PSW_FU); 391*13576Sdlw #else 392*13576Sdlw ipc = (char **)&sc->sc_pc; 393*13576Sdlw isp = (char *)&ap->al_arg[ap->al_numarg] + sizeof (struct sigcontext); 394*13576Sdlw sc->sc_ps &= ~(PSW_V|PSW_FU); 395*13576Sdlw #endif 396*13576Sdlw 397*13576Sdlw 398*13576Sdlw switch (*(*ipc)++) 399*13576Sdlw { 400*13576Sdlw case ADDD3: 401*13576Sdlw case DIVD3: 402*13576Sdlw case MULD3: 403*13576Sdlw case SUBD3: 404*13576Sdlw (void) get_operand(sizeof (double)); 405*13576Sdlw /* intentional fall-thru */ 406*13576Sdlw 407*13576Sdlw case ADDD2: 408*13576Sdlw case DIVD2: 409*13576Sdlw case MULD2: 410*13576Sdlw case SUBD2: 411*13576Sdlw case MNEGD: 412*13576Sdlw case MOVD: 413*13576Sdlw (void) get_operand(sizeof (double)); 414*13576Sdlw result_addr = get_operand(sizeof (double)); 415*13576Sdlw result_type = DOUBLE; 416*13576Sdlw break; 417*13576Sdlw 418*13576Sdlw case ADDF3: 419*13576Sdlw case DIVF3: 420*13576Sdlw case MULF3: 421*13576Sdlw case SUBF3: 422*13576Sdlw (void) get_operand(sizeof (float)); 423*13576Sdlw /* intentional fall-thru */ 424*13576Sdlw 425*13576Sdlw case ADDF2: 426*13576Sdlw case DIVF2: 427*13576Sdlw case MULF2: 428*13576Sdlw case SUBF2: 429*13576Sdlw case MNEGF: 430*13576Sdlw case MOVF: 431*13576Sdlw (void) get_operand(sizeof (float)); 432*13576Sdlw result_addr = get_operand(sizeof (float)); 433*13576Sdlw result_type = FLOAT; 434*13576Sdlw break; 435*13576Sdlw 436*13576Sdlw case CVTDF: 437*13576Sdlw (void) get_operand(sizeof (double)); 438*13576Sdlw result_addr = get_operand(sizeof (float)); 439*13576Sdlw result_type = FLOAT; 440*13576Sdlw break; 441*13576Sdlw 442*13576Sdlw case CVTFD: 443*13576Sdlw (void) get_operand(sizeof (float)); 444*13576Sdlw result_addr = get_operand(sizeof (double)); 445*13576Sdlw result_type = DOUBLE; 446*13576Sdlw break; 447*13576Sdlw 448*13576Sdlw case EMODF: 449*13576Sdlw case EMODD: 450*13576Sdlw fprintf(ef, "trpfpe: can't fix emod yet\n"); 451*13576Sdlw goto cant_fix; 452*13576Sdlw 453*13576Sdlw case POLYF: 454*13576Sdlw case POLYD: 455*13576Sdlw fprintf(ef, "trpfpe: can't fix poly yet\n"); 456*13576Sdlw goto cant_fix; 457*13576Sdlw 458*13576Sdlw case ACBD: 459*13576Sdlw case ACBF: 460*13576Sdlw case CMPD: 461*13576Sdlw case CMPF: 462*13576Sdlw case TSTD: 463*13576Sdlw case TSTF: 464*13576Sdlw case CVTDB: 465*13576Sdlw case CVTDL: 466*13576Sdlw case CVTDW: 467*13576Sdlw case CVTFB: 468*13576Sdlw case CVTFL: 469*13576Sdlw case CVTFW: 470*13576Sdlw case CVTRDL: 471*13576Sdlw case CVTRFL: 472*13576Sdlw /* These can generate only reserved operand faults */ 473*13576Sdlw /* They are shown here for completeness */ 474*13576Sdlw 475*13576Sdlw default: 476*13576Sdlw fprintf(stderr, "trp: opcode 0x%02x unknown\n", 477*13576Sdlw *(--(*ipc)) & 0xff); 478*13576Sdlw goto cant_fix; 479*13576Sdlw /* NOTREACHED */ 480*13576Sdlw } 481*13576Sdlw 482*13576Sdlw if (result_type == FLOAT) 483*13576Sdlw result_addr->ua_float = retval.rv_float; 484*13576Sdlw else 485*13576Sdlw { 486*13576Sdlw if (result_addr == (anything *)&iR6) 487*13576Sdlw { /* 488*13576Sdlw * special case - the R6/R7 pair is stored apart 489*13576Sdlw */ 490*13576Sdlw result_addr->ua_long = retval.rv_long[0]; 491*13576Sdlw ((anything *)&iR7)->ua_long = retval.rv_long[1]; 492*13576Sdlw } 493*13576Sdlw else 494*13576Sdlw result_addr->ua_double = retval.rv_double; 495*13576Sdlw } 496*13576Sdlw signal(SIGFPE, on_fpe); 497*13576Sdlw } 498*13576Sdlw #endif vax 499*13576Sdlw 500*13576Sdlw trpfpe_ (count, rval) 501*13576Sdlw long *count; /* how many to announce */ 502*13576Sdlw double *rval; /* dummy return value */ 503*13576Sdlw { 504*13576Sdlw #if vax 505*13576Sdlw max_messages = *count; 506*13576Sdlw retval.rv_double = *rval; 507*13576Sdlw sigfpe_dfl = signal(SIGFPE, on_fpe); 508*13576Sdlw fpe_count = 0; 509*13576Sdlw #endif 510*13576Sdlw } 511*13576Sdlw 512*13576Sdlw long 513*13576Sdlw fpecnt_ () 514*13576Sdlw { 515*13576Sdlw #if vax 516*13576Sdlw return (fpe_count); 517*13576Sdlw #else 518*13576Sdlw return (0L); 519*13576Sdlw #endif 520*13576Sdlw } 521*13576Sdlw 522