xref: /csrg-svn/usr.bin/f77/libF77/trpfpe_.c (revision 47940)
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 *)&reg0_6->reg[regnum];
19813576Sdlw 	else if (regnum <= R11)
19913576Sdlw 		reg_addr = (anything *)&reg7_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