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