xref: /original-bsd/usr.bin/f77/libF77/trapov_.c (revision 8d528b7a)
1*8d528b7aSbostic /*-
2*8d528b7aSbostic  * Copyright (c) 1980 The Regents of the University of California.
3*8d528b7aSbostic  * All rights reserved.
4*8d528b7aSbostic  *
5*8d528b7aSbostic  * %sccs.include.proprietary.c%
6*8d528b7aSbostic  */
7*8d528b7aSbostic 
8*8d528b7aSbostic #ifndef lint
9*8d528b7aSbostic static char sccsid[] = "@(#)trapov_.c	5.6 (Berkeley) 04/12/91";
10*8d528b7aSbostic #endif /* not lint */
11*8d528b7aSbostic 
124b4fc830Sdlw /*
134b4fc830Sdlw  *	Fortran/C floating-point overflow handler
144b4fc830Sdlw  *
154b4fc830Sdlw  *	The idea of these routines is to catch floating-point overflows
164b4fc830Sdlw  *	and print an eror message.  When we then get a reserved operand
174b4fc830Sdlw  *	exception, we then fix up the value to the highest possible
184b4fc830Sdlw  *	number.  Keen, no?
194b4fc830Sdlw  *	Messy, yes!
204b4fc830Sdlw  *
214b4fc830Sdlw  *	Synopsis:
224b4fc830Sdlw  *		call trapov(n)
234b4fc830Sdlw  *			causes overflows to be trapped, with the first 'n'
244b4fc830Sdlw  *			overflows getting an "Overflow!" message printed.
254b4fc830Sdlw  *		k = ovcnt(0)
264b4fc830Sdlw  *			causes 'k' to get the number of overflows since the
274b4fc830Sdlw  *			last call to trapov().
284b4fc830Sdlw  *
294b4fc830Sdlw  *	Gary Klimowicz, April 17, 1981
304b4fc830Sdlw  *	Integerated with libF77: David Wasley, UCB, July 1981.
314b4fc830Sdlw  */
324b4fc830Sdlw 
334b4fc830Sdlw # include <stdio.h>
34a0d0269cSbostic # include <sys/signal.h>
354b4fc830Sdlw # include "opcodes.h"
364b4fc830Sdlw # include "../libI77/fiodefs.h"
37a0d0269cSbostic # define SIG_VAL	void (*)()
384b4fc830Sdlw 
394b4fc830Sdlw /*
40c891893aSmckusick  *	Potential operand values
41c891893aSmckusick  */
42c891893aSmckusick typedef	union operand_types {
43c891893aSmckusick 		char	o_byte;
44c891893aSmckusick 		short	o_word;
45c891893aSmckusick 		long	o_long;
46c891893aSmckusick 		float	o_float;
47c891893aSmckusick 		long	o_quad[2];
48c891893aSmckusick 		double	o_double;
49c891893aSmckusick 	} anyval;
50c891893aSmckusick 
51c891893aSmckusick /*
52c891893aSmckusick  *	the fortran unit control table
53c891893aSmckusick  */
54c891893aSmckusick extern unit units[];
55c891893aSmckusick 
56c891893aSmckusick /*
57c891893aSmckusick  * Fortran message table is in main
58c891893aSmckusick  */
59c891893aSmckusick struct msgtbl {
60c891893aSmckusick 	char	*mesg;
61c891893aSmckusick 	int	dummy;
62c891893aSmckusick };
63c891893aSmckusick extern struct msgtbl	act_fpe[];
64c891893aSmckusick 
65c891893aSmckusick anyval *get_operand_address(), *addr_of_reg();
66c891893aSmckusick char *opcode_name();
67c891893aSmckusick 
68c891893aSmckusick /*
69c891893aSmckusick  * trap type codes
70c891893aSmckusick  */
71c891893aSmckusick # define INT_OVF_T	1
72c891893aSmckusick # define INT_DIV_T	2
73c891893aSmckusick # define FLT_OVF_T	3
74c891893aSmckusick # define FLT_DIV_T	4
75c891893aSmckusick # define FLT_UND_T	5
76c891893aSmckusick # define DEC_OVF_T	6
77c891893aSmckusick # define SUB_RNG_T	7
78c891893aSmckusick # define FLT_OVF_F	8
79c891893aSmckusick # define FLT_DIV_F	9
80c891893aSmckusick # define FLT_UND_F	10
81c891893aSmckusick 
82c891893aSmckusick # define RES_ADR_F	0
83c891893aSmckusick # define RES_OPC_F	1
84c891893aSmckusick # define RES_OPR_F	2
85c891893aSmckusick 
86c891893aSmckusick #ifdef vax
87c891893aSmckusick /*
884b4fc830Sdlw  *	Operand modes
894b4fc830Sdlw  */
904b4fc830Sdlw # define LITERAL0	0x0
914b4fc830Sdlw # define LITERAL1	0x1
924b4fc830Sdlw # define LITERAL2	0x2
934b4fc830Sdlw # define LITERAL3	0x3
944b4fc830Sdlw # define INDEXED	0x4
954b4fc830Sdlw # define REGISTER	0x5
964b4fc830Sdlw # define REG_DEF	0x6
974b4fc830Sdlw # define AUTO_DEC	0x7
984b4fc830Sdlw # define AUTO_INC	0x8
994b4fc830Sdlw # define AUTO_INC_DEF	0x9
1004b4fc830Sdlw # define BYTE_DISP	0xa
1014b4fc830Sdlw # define BYTE_DISP_DEF	0xb
1024b4fc830Sdlw # define WORD_DISP	0xc
1034b4fc830Sdlw # define WORD_DISP_DEF	0xd
1044b4fc830Sdlw # define LONG_DISP	0xe
1054b4fc830Sdlw # define LONG_DISP_DEF	0xf
1064b4fc830Sdlw 
1074b4fc830Sdlw /*
1084b4fc830Sdlw  *	Operand value types
1094b4fc830Sdlw  */
1104b4fc830Sdlw # define F		1
1114b4fc830Sdlw # define D		2
1124b4fc830Sdlw # define IDUNNO		3
1134b4fc830Sdlw 
1144b4fc830Sdlw # define PC	0xf
1154b4fc830Sdlw # define SP	0xe
1164b4fc830Sdlw # define FP	0xd
1174b4fc830Sdlw # define AP	0xc
1184b4fc830Sdlw 
1194b4fc830Sdlw /*
1204b4fc830Sdlw  *	GLOBAL VARIABLES (we need a few)
1214b4fc830Sdlw  *
1224b4fc830Sdlw  *	Actual program counter and locations of registers.
1234b4fc830Sdlw  */
1244b4fc830Sdlw static char	*pc;
1254b4fc830Sdlw static int	*regs0t6;
1264b4fc830Sdlw static int	*regs7t11;
1274b4fc830Sdlw static int	max_messages;
1284b4fc830Sdlw static int	total_overflows;
1294b4fc830Sdlw static union	{
1304b4fc830Sdlw 	long	v_long[2];
1314b4fc830Sdlw 	double	v_double;
1324b4fc830Sdlw 	} retrn;
133a0d0269cSbostic static sig_t sigill_default = (SIG_VAL)-1;
134a0d0269cSbostic static sig_t sigfpe_default;
1354b4fc830Sdlw 
1364b4fc830Sdlw /*
1374b4fc830Sdlw  *	This routine sets up the signal handler for the floating-point
1384b4fc830Sdlw  *	and reserved operand interrupts.
1394b4fc830Sdlw  */
1404b4fc830Sdlw 
trapov_(count,rtnval)1414b4fc830Sdlw trapov_(count, rtnval)
1424b4fc830Sdlw 	int *count;
1434b4fc830Sdlw 	double *rtnval;
1444b4fc830Sdlw {
145a0d0269cSbostic 	void got_overflow(), got_illegal_instruction();
1464b4fc830Sdlw 
14774d9401aSdlw 	sigfpe_default = signal(SIGFPE, got_overflow);
14874d9401aSdlw 	if (sigill_default == (SIG_VAL)-1)
14974d9401aSdlw 		sigill_default = signal(SIGILL, got_illegal_instruction);
1504b4fc830Sdlw 	total_overflows = 0;
1514b4fc830Sdlw 	max_messages = *count;
1524b4fc830Sdlw 	retrn.v_double = *rtnval;
1534b4fc830Sdlw }
1544b4fc830Sdlw 
1554b4fc830Sdlw 
1564b4fc830Sdlw 
1574b4fc830Sdlw /*
1584b4fc830Sdlw  *	got_overflow - routine called when overflow occurs
1594b4fc830Sdlw  *
1604b4fc830Sdlw  *	This routine just prints a message about the overflow.
1614b4fc830Sdlw  *	It is impossible to find the bad result at this point.
1624b4fc830Sdlw  *	Instead, we wait until we get the reserved operand exception
1634b4fc830Sdlw  *	when we try to use it.  This raises the SIGILL signal.
1644b4fc830Sdlw  */
1654b4fc830Sdlw 
1664b4fc830Sdlw /*ARGSUSED*/
16746f146c1Stef void
got_overflow(signo,codeword,myaddr,pc,ps)1684b4fc830Sdlw got_overflow(signo, codeword, myaddr, pc, ps)
1694b4fc830Sdlw 	char *myaddr, *pc;
1704b4fc830Sdlw {
17174d9401aSdlw 	int	*sp, i;
17274d9401aSdlw 	FILE	*ef;
17374d9401aSdlw 
1744b4fc830Sdlw 	signal(SIGFPE, got_overflow);
17574d9401aSdlw 	ef = units[STDERR].ufd;
17674d9401aSdlw 	switch (codeword) {
17774d9401aSdlw 		case INT_OVF_T:
17874d9401aSdlw 		case INT_DIV_T:
17974d9401aSdlw 		case FLT_UND_T:
18074d9401aSdlw 		case DEC_OVF_T:
18174d9401aSdlw 		case SUB_RNG_T:
18274d9401aSdlw 		case FLT_OVF_F:
18374d9401aSdlw 		case FLT_DIV_F:
18474d9401aSdlw 		case FLT_UND_F:
18574d9401aSdlw 			if (sigfpe_default > (SIG_VAL)7)
186a0d0269cSbostic 				(*sigfpe_default)(signo, codeword, myaddr,
187a0d0269cSbostic 				    pc, ps);
18874d9401aSdlw 			else
18974d9401aSdlw 				sigdie(signo, codeword, myaddr, pc, ps);
19074d9401aSdlw 				/* NOTREACHED */
19174d9401aSdlw 
19274d9401aSdlw 		case FLT_OVF_T:
19374d9401aSdlw 		case FLT_DIV_T:
19474d9401aSdlw 			if (++total_overflows <= max_messages) {
19574d9401aSdlw 				fprintf(ef, "trapov: %s",
19674d9401aSdlw 					act_fpe[codeword-1].mesg);
19774d9401aSdlw 				if (total_overflows == max_messages)
19874d9401aSdlw 					fprintf(ef, ": No more messages will be printed.\n");
19974d9401aSdlw 				else
20074d9401aSdlw 					fputc('\n', ef);
20174d9401aSdlw 			}
20274d9401aSdlw 			return;
20374d9401aSdlw 	}
2044b4fc830Sdlw }
2054b4fc830Sdlw 
2064b4fc830Sdlw int
ovcnt_()2074b4fc830Sdlw ovcnt_()
2084b4fc830Sdlw {
2094b4fc830Sdlw 	return total_overflows;
2104b4fc830Sdlw }
2114b4fc830Sdlw 
2124b4fc830Sdlw /*
2134b4fc830Sdlw  *	got_illegal_instruction - handle "illegal instruction" signals.
2144b4fc830Sdlw  *
2154b4fc830Sdlw  *	This really deals only with reserved operand exceptions.
2164b4fc830Sdlw  *	Since there is no way to check this directly, we look at the
2174b4fc830Sdlw  *	opcode of the instruction we are executing to see if it is a
2184b4fc830Sdlw  *	floating-point operation (with floating-point operands, not
2194b4fc830Sdlw  *	just results).
2204b4fc830Sdlw  *
2214b4fc830Sdlw  *	This is complicated by the fact that the registers that will
2224b4fc830Sdlw  *	eventually be restored are saved in two places.  registers 7-11
2234b4fc830Sdlw  *	are saved by this routine, and are in its call frame. (we have
2244b4fc830Sdlw  *	to take special care that these registers are specified in
2254b4fc830Sdlw  *	the procedure entry mask here.)
2264b4fc830Sdlw  *	Registers 0-6 are saved at interrupt time, and are at a offset
2274b4fc830Sdlw  *	-8 from the 'signo' parameter below.
2284b4fc830Sdlw  *	There is ane extremely inimate connection between the value of
2294b4fc830Sdlw  *	the entry mask set by the 'makefile' script, and the constants
2304b4fc830Sdlw  *	used in the register offset calculations below.
2314b4fc830Sdlw  *	Can someone think of a better way to do this?
2324b4fc830Sdlw  */
2334b4fc830Sdlw 
2344b4fc830Sdlw /*ARGSUSED*/
23546f146c1Stef void
got_illegal_instruction(signo,codeword,myaddr,trap_pc,ps)2364b4fc830Sdlw got_illegal_instruction(signo, codeword, myaddr, trap_pc, ps)
2374b4fc830Sdlw 	char *myaddr, *trap_pc;
2384b4fc830Sdlw {
2394b4fc830Sdlw 	int first_local[1];		/* must be first */
2404b4fc830Sdlw 	int i, opcode, type, o_no, no_reserved;
2414b4fc830Sdlw 	anyval *opnd;
2424b4fc830Sdlw 
2434b4fc830Sdlw 	regs7t11 = &first_local[0];
2444b4fc830Sdlw 	regs0t6 = &signo - 8;
2454b4fc830Sdlw 	pc = trap_pc;
2464b4fc830Sdlw 
2474b4fc830Sdlw 	opcode = fetch_byte() & 0xff;
2484b4fc830Sdlw 	no_reserved = 0;
24974d9401aSdlw 	if (codeword != RES_OPR_F || !is_floating_operation(opcode)) {
25046f146c1Stef 		if (sigill_default > (SIG_VAL)7) {
25146f146c1Stef 			(*sigill_default)(signo, codeword, myaddr, trap_pc, ps);
25246f146c1Stef 			return;
25346f146c1Stef 		} else
25474d9401aSdlw 			sigdie(signo, codeword, myaddr, trap_pc, ps);
25574d9401aSdlw 			/* NOTREACHED */
2564b4fc830Sdlw 	}
2574b4fc830Sdlw 
2584b4fc830Sdlw 	if (opcode == POLYD || opcode == POLYF) {
2594b4fc830Sdlw 		got_illegal_poly(opcode);
2604b4fc830Sdlw 		return;
2614b4fc830Sdlw 	}
2624b4fc830Sdlw 
2634b4fc830Sdlw 	if (opcode == EMODD || opcode == EMODF) {
2644b4fc830Sdlw 		got_illegal_emod(opcode);
2654b4fc830Sdlw 		return;
2664b4fc830Sdlw 	}
2674b4fc830Sdlw 
2684b4fc830Sdlw 	/*
2694b4fc830Sdlw 	 * This opcode wasn't "unusual".
2704b4fc830Sdlw 	 * Look at the operands to try and find a reserved operand.
2714b4fc830Sdlw 	 */
2724b4fc830Sdlw 	for (o_no = 1; o_no <= no_operands(opcode); ++o_no) {
2734b4fc830Sdlw 		type = operand_type(opcode, o_no);
2744b4fc830Sdlw 		if (type != F && type != D) {
2754b4fc830Sdlw 			advance_pc(type);
2764b4fc830Sdlw 			continue;
2774b4fc830Sdlw 		}
2784b4fc830Sdlw 
2794b4fc830Sdlw 		/* F or D operand.  Check it out */
2804b4fc830Sdlw 		opnd = get_operand_address(type);
2814b4fc830Sdlw 		if (opnd == NULL) {
2824b4fc830Sdlw 			fprintf(units[STDERR].ufd, "Can't get operand address: 0x%x, %d\n",
2834b4fc830Sdlw 				pc, o_no);
284999e6702Slibs 			f77_abort();
2854b4fc830Sdlw 		}
2864b4fc830Sdlw 		if (type == F && opnd->o_long == 0x00008000) {
2874b4fc830Sdlw 			/* found one */
2884b4fc830Sdlw 			opnd->o_long = retrn.v_long[0];
2894b4fc830Sdlw 			++no_reserved;
2904b4fc830Sdlw 		} else if (type == D && opnd->o_long == 0x00008000) {
2914b4fc830Sdlw 			/* found one here, too! */
2924b4fc830Sdlw 			opnd->o_quad[0] = retrn.v_long[0];
2934b4fc830Sdlw 			/* Fix next pointer */
2944b4fc830Sdlw 			if (opnd == addr_of_reg(6)) opnd = addr_of_reg(7);
2954b4fc830Sdlw 			else opnd = (anyval *) ((char *) opnd + 4);
2964b4fc830Sdlw 			opnd->o_quad[0] = retrn.v_long[1];
2974b4fc830Sdlw 			++no_reserved;
2984b4fc830Sdlw 		}
2994b4fc830Sdlw 
3004b4fc830Sdlw 	}
3014b4fc830Sdlw 
3024b4fc830Sdlw 	if (no_reserved == 0) {
3034b4fc830Sdlw 		fprintf(units[STDERR].ufd, "Can't find any reserved operand!\n");
304999e6702Slibs 		f77_abort();
3054b4fc830Sdlw 	}
3064b4fc830Sdlw }
3074b4fc830Sdlw /*
3084b4fc830Sdlw  * is_floating_exception - was the operation code for a floating instruction?
3094b4fc830Sdlw  */
3104b4fc830Sdlw 
is_floating_operation(opcode)3114b4fc830Sdlw is_floating_operation(opcode)
3124b4fc830Sdlw 	int opcode;
3134b4fc830Sdlw {
3144b4fc830Sdlw 	switch (opcode) {
3154b4fc830Sdlw 		case ACBD:	case ACBF:	case ADDD2:	case ADDD3:
3164b4fc830Sdlw 		case ADDF2:	case ADDF3:	case CMPD:	case CMPF:
3174b4fc830Sdlw 		case CVTDB:	case CVTDF:	case CVTDL:	case CVTDW:
3184b4fc830Sdlw 		case CVTFB:	case CVTFD:	case CVTFL:	case CVTFW:
3194b4fc830Sdlw 		case CVTRDL:	case CVTRFL:	case DIVD2:	case DIVD3:
3204b4fc830Sdlw 		case DIVF2:	case DIVF3:	case EMODD:	case EMODF:
3214b4fc830Sdlw 		case MNEGD:	case MNEGF:	case MOVD:	case MOVF:
3224b4fc830Sdlw 		case MULD2:	case MULD3:	case MULF2:	case MULF3:
3234b4fc830Sdlw 		case POLYD:	case POLYF:	case SUBD2:	case SUBD3:
3244b4fc830Sdlw 		case SUBF2:	case SUBF3:	case TSTD:	case TSTF:
3254b4fc830Sdlw 			return 1;
3264b4fc830Sdlw 
3274b4fc830Sdlw 		default:
3284b4fc830Sdlw 			return 0;
3294b4fc830Sdlw 	}
3304b4fc830Sdlw }
3314b4fc830Sdlw /*
3324b4fc830Sdlw  * got_illegal_poly - handle an illegal POLY[DF] instruction.
3334b4fc830Sdlw  *
3344b4fc830Sdlw  * We don't do anything here yet.
3354b4fc830Sdlw  */
3364b4fc830Sdlw 
3374b4fc830Sdlw /*ARGSUSED*/
got_illegal_poly(opcode)3384b4fc830Sdlw got_illegal_poly(opcode)
3394b4fc830Sdlw {
3404b4fc830Sdlw 	fprintf(units[STDERR].ufd, "Can't do 'poly' instructions yet\n");
341999e6702Slibs 	f77_abort();
3424b4fc830Sdlw }
3434b4fc830Sdlw 
3444b4fc830Sdlw 
3454b4fc830Sdlw 
3464b4fc830Sdlw /*
3474b4fc830Sdlw  * got_illegal_emod - handle illegal EMOD[DF] instruction.
3484b4fc830Sdlw  *
3494b4fc830Sdlw  * We don't do anything here yet.
3504b4fc830Sdlw  */
3514b4fc830Sdlw 
3524b4fc830Sdlw /*ARGSUSED*/
got_illegal_emod(opcode)3534b4fc830Sdlw got_illegal_emod(opcode)
3544b4fc830Sdlw {
3554b4fc830Sdlw 	fprintf(units[STDERR].ufd, "Can't do 'emod' instructions yet\n");
356999e6702Slibs 	f77_abort();
3574b4fc830Sdlw }
3584b4fc830Sdlw 
3594b4fc830Sdlw 
3604b4fc830Sdlw /*
3614b4fc830Sdlw  *	no_operands - determine the number of operands in this instruction.
3624b4fc830Sdlw  *
3634b4fc830Sdlw  */
3644b4fc830Sdlw 
no_operands(opcode)3654b4fc830Sdlw no_operands(opcode)
3664b4fc830Sdlw {
3674b4fc830Sdlw 	switch (opcode) {
3684b4fc830Sdlw 		case ACBD:
3694b4fc830Sdlw 		case ACBF:
3704b4fc830Sdlw 			return 3;
3714b4fc830Sdlw 
3724b4fc830Sdlw 		case MNEGD:
3734b4fc830Sdlw 		case MNEGF:
3744b4fc830Sdlw 		case MOVD:
3754b4fc830Sdlw 		case MOVF:
3764b4fc830Sdlw 		case TSTD:
3774b4fc830Sdlw 		case TSTF:
3784b4fc830Sdlw 			return 1;
3794b4fc830Sdlw 
3804b4fc830Sdlw 		default:
3814b4fc830Sdlw 			return 2;
3824b4fc830Sdlw 	}
3834b4fc830Sdlw }
3844b4fc830Sdlw 
3854b4fc830Sdlw 
3864b4fc830Sdlw 
3874b4fc830Sdlw /*
3884b4fc830Sdlw  *	operand_type - is the operand a D or an F?
3894b4fc830Sdlw  *
3904b4fc830Sdlw  *	We are only descriminating between Floats and Doubles here.
3914b4fc830Sdlw  *	Other operands may be possible on exotic instructions.
3924b4fc830Sdlw  */
3934b4fc830Sdlw 
3944b4fc830Sdlw /*ARGSUSED*/
operand_type(opcode,no)3954b4fc830Sdlw operand_type(opcode, no)
3964b4fc830Sdlw {
3974b4fc830Sdlw 	if (opcode >= 0x40 && opcode <= 0x56) return F;
3984b4fc830Sdlw 	if (opcode >= 0x60 && opcode <= 0x76) return D;
3994b4fc830Sdlw 	return IDUNNO;
4004b4fc830Sdlw }
4014b4fc830Sdlw 
4024b4fc830Sdlw 
4034b4fc830Sdlw 
4044b4fc830Sdlw /*
4054b4fc830Sdlw  *	advance_pc - Advance the program counter past an operand.
4064b4fc830Sdlw  *
4074b4fc830Sdlw  *	We just bump the pc by the appropriate values.
4084b4fc830Sdlw  */
4094b4fc830Sdlw 
advance_pc(type)4104b4fc830Sdlw advance_pc(type)
4114b4fc830Sdlw {
4124b4fc830Sdlw 	register int mode, reg;
4134b4fc830Sdlw 
4144b4fc830Sdlw 	mode = fetch_byte();
4154b4fc830Sdlw 	reg = mode & 0xf;
4164b4fc830Sdlw 	mode = (mode >> 4) & 0xf;
4174b4fc830Sdlw 	switch (mode) {
4184b4fc830Sdlw 		case LITERAL0:
4194b4fc830Sdlw 		case LITERAL1:
4204b4fc830Sdlw 		case LITERAL2:
4214b4fc830Sdlw 		case LITERAL3:
4224b4fc830Sdlw 			return;
4234b4fc830Sdlw 
4244b4fc830Sdlw 		case INDEXED:
4254b4fc830Sdlw 			advance_pc(type);
4264b4fc830Sdlw 			return;
4274b4fc830Sdlw 
4284b4fc830Sdlw 		case REGISTER:
4294b4fc830Sdlw 		case REG_DEF:
4304b4fc830Sdlw 		case AUTO_DEC:
4314b4fc830Sdlw 			return;
4324b4fc830Sdlw 
4334b4fc830Sdlw 		case AUTO_INC:
4344b4fc830Sdlw 			if (reg == PC) {
4354b4fc830Sdlw 				if (type == F) (void) fetch_long();
4364b4fc830Sdlw 				else if (type == D) {
4374b4fc830Sdlw 					(void) fetch_long();
4384b4fc830Sdlw 					(void) fetch_long();
4394b4fc830Sdlw 				} else {
4404b4fc830Sdlw 					fprintf(units[STDERR].ufd, "Bad type %d in advance\n",
4414b4fc830Sdlw 						type);
442999e6702Slibs 					f77_abort();
4434b4fc830Sdlw 				}
4444b4fc830Sdlw 			}
4454b4fc830Sdlw 			return;
4464b4fc830Sdlw 
4474b4fc830Sdlw 		case AUTO_INC_DEF:
4484b4fc830Sdlw 			if (reg == PC) (void) fetch_long();
4494b4fc830Sdlw 			return;
4504b4fc830Sdlw 
4514b4fc830Sdlw 		case BYTE_DISP:
4524b4fc830Sdlw 		case BYTE_DISP_DEF:
4534b4fc830Sdlw 			(void) fetch_byte();
4544b4fc830Sdlw 			return;
4554b4fc830Sdlw 
4564b4fc830Sdlw 		case WORD_DISP:
4574b4fc830Sdlw 		case WORD_DISP_DEF:
4584b4fc830Sdlw 			(void) fetch_word();
4594b4fc830Sdlw 			return;
4604b4fc830Sdlw 
4614b4fc830Sdlw 		case LONG_DISP:
4624b4fc830Sdlw 		case LONG_DISP_DEF:
4634b4fc830Sdlw 			(void) fetch_long();
4644b4fc830Sdlw 			return;
4654b4fc830Sdlw 
4664b4fc830Sdlw 		default:
4674b4fc830Sdlw 			fprintf(units[STDERR].ufd, "Bad mode 0x%x in op_length()\n", mode);
468999e6702Slibs 			f77_abort();
4694b4fc830Sdlw 	}
4704b4fc830Sdlw }
4714b4fc830Sdlw 
4724b4fc830Sdlw 
4734b4fc830Sdlw anyval *
get_operand_address(type)4744b4fc830Sdlw get_operand_address(type)
4754b4fc830Sdlw {
4764b4fc830Sdlw 	register int mode, reg, base;
4774b4fc830Sdlw 
4784b4fc830Sdlw 	mode = fetch_byte() & 0xff;
4794b4fc830Sdlw 	reg = mode & 0xf;
4804b4fc830Sdlw 	mode = (mode >> 4) & 0xf;
4814b4fc830Sdlw 	switch (mode) {
4824b4fc830Sdlw 		case LITERAL0:
4834b4fc830Sdlw 		case LITERAL1:
4844b4fc830Sdlw 		case LITERAL2:
4854b4fc830Sdlw 		case LITERAL3:
4864b4fc830Sdlw 			return NULL;
4874b4fc830Sdlw 
4884b4fc830Sdlw 		case INDEXED:
4894b4fc830Sdlw 			base = (int) get_operand_address(type);
4904b4fc830Sdlw 			if (base == NULL) return NULL;
4914b4fc830Sdlw 			base += contents_of_reg(reg)*type_length(type);
4924b4fc830Sdlw 			return (anyval *) base;
4934b4fc830Sdlw 
4944b4fc830Sdlw 		case REGISTER:
4954b4fc830Sdlw 			return addr_of_reg(reg);
4964b4fc830Sdlw 
4974b4fc830Sdlw 		case REG_DEF:
4984b4fc830Sdlw 			return (anyval *) contents_of_reg(reg);
4994b4fc830Sdlw 
5004b4fc830Sdlw 		case AUTO_DEC:
5014b4fc830Sdlw 			return (anyval *) (contents_of_reg(reg)
5024b4fc830Sdlw 				- type_length(type));
5034b4fc830Sdlw 
5044b4fc830Sdlw 		case AUTO_INC:
5054b4fc830Sdlw 			return (anyval *) contents_of_reg(reg);
5064b4fc830Sdlw 
5074b4fc830Sdlw 		case AUTO_INC_DEF:
5084b4fc830Sdlw 			return (anyval *) * (long *) contents_of_reg(reg);
5094b4fc830Sdlw 
5104b4fc830Sdlw 		case BYTE_DISP:
5114b4fc830Sdlw 			base = fetch_byte();
5124b4fc830Sdlw 			base += contents_of_reg(reg);
5134b4fc830Sdlw 			return (anyval *) base;
5144b4fc830Sdlw 
5154b4fc830Sdlw 		case BYTE_DISP_DEF:
5164b4fc830Sdlw 			base = fetch_byte();
5174b4fc830Sdlw 			base += contents_of_reg(reg);
5184b4fc830Sdlw 			return (anyval *) * (long *) base;
5194b4fc830Sdlw 
5204b4fc830Sdlw 		case WORD_DISP:
5214b4fc830Sdlw 			base = fetch_word();
5224b4fc830Sdlw 			base += contents_of_reg(reg);
5234b4fc830Sdlw 			return (anyval *) base;
5244b4fc830Sdlw 
5254b4fc830Sdlw 		case WORD_DISP_DEF:
5264b4fc830Sdlw 			base = fetch_word();
5274b4fc830Sdlw 			base += contents_of_reg(reg);
5284b4fc830Sdlw 			return (anyval *) * (long *) base;
5294b4fc830Sdlw 
5304b4fc830Sdlw 		case LONG_DISP:
5314b4fc830Sdlw 			base = fetch_long();
5324b4fc830Sdlw 			base += contents_of_reg(reg);
5334b4fc830Sdlw 			return (anyval *) base;
5344b4fc830Sdlw 
5354b4fc830Sdlw 		case LONG_DISP_DEF:
5364b4fc830Sdlw 			base = fetch_long();
5374b4fc830Sdlw 			base += contents_of_reg(reg);
5384b4fc830Sdlw 			return (anyval *) * (long *) base;
5394b4fc830Sdlw 
5404b4fc830Sdlw 		default:
5414b4fc830Sdlw 			fprintf(units[STDERR].ufd, "Bad mode 0x%x in get_addr()\n", mode);
542999e6702Slibs 			f77_abort();
5434b4fc830Sdlw 	}
5444b4fc830Sdlw 	return NULL;
5454b4fc830Sdlw }
5464b4fc830Sdlw 
5474b4fc830Sdlw 
5484b4fc830Sdlw 
contents_of_reg(reg)5494b4fc830Sdlw contents_of_reg(reg)
5504b4fc830Sdlw {
5514b4fc830Sdlw 	int value;
5524b4fc830Sdlw 
5534b4fc830Sdlw 	if (reg == PC) value = (int) pc;
5544b4fc830Sdlw 	else if (reg == SP) value = (int) &regs0t6[6];
5554b4fc830Sdlw 	else if (reg == FP) value = regs0t6[-2];
5564b4fc830Sdlw 	else if (reg == AP) value = regs0t6[-3];
5574b4fc830Sdlw 	else if (reg >= 0 && reg <= 6) value = regs0t6[reg];
5584b4fc830Sdlw 	else if (reg >= 7 && reg <= 11) value = regs7t11[reg];
5594b4fc830Sdlw 	else {
5604b4fc830Sdlw 		fprintf(units[STDERR].ufd, "Bad register 0x%x to contents_of()\n", reg);
561999e6702Slibs 		f77_abort();
5624b4fc830Sdlw 		value = -1;
5634b4fc830Sdlw 	}
5644b4fc830Sdlw 	return value;
5654b4fc830Sdlw }
5664b4fc830Sdlw 
5674b4fc830Sdlw 
5684b4fc830Sdlw anyval *
addr_of_reg(reg)5694b4fc830Sdlw addr_of_reg(reg)
5704b4fc830Sdlw {
5714b4fc830Sdlw 	if (reg >= 0 && reg <= 6) {
5724b4fc830Sdlw 		return (anyval *) &regs0t6[reg];
5734b4fc830Sdlw 	}
5744b4fc830Sdlw 	if (reg >= 7 && reg <= 11) {
5754b4fc830Sdlw 		return (anyval *) &regs7t11[reg];
5764b4fc830Sdlw 	}
5774b4fc830Sdlw 	fprintf(units[STDERR].ufd, "Bad reg 0x%x to addr_of()\n", reg);
578999e6702Slibs 	f77_abort();
5794b4fc830Sdlw 	return NULL;
5804b4fc830Sdlw }
5814b4fc830Sdlw /*
5824b4fc830Sdlw  *	fetch_{byte, word, long} - extract values from the PROGRAM area.
5834b4fc830Sdlw  *
5844b4fc830Sdlw  *	These routines are used in the operand decoding to extract various
5854b4fc830Sdlw  *	fields from where the program counter points.  This is because the
5864b4fc830Sdlw  *	addressing on the Vax is dynamic: the program counter advances
5874b4fc830Sdlw  *	while we are grabbing operands, as well as when we pass instructions.
5884b4fc830Sdlw  *	This makes things a bit messy, but I can't help it.
5894b4fc830Sdlw  */
fetch_byte()5904b4fc830Sdlw fetch_byte()
5914b4fc830Sdlw {
5924b4fc830Sdlw 	return *pc++;
5934b4fc830Sdlw }
5944b4fc830Sdlw 
5954b4fc830Sdlw 
5964b4fc830Sdlw 
fetch_word()5974b4fc830Sdlw fetch_word()
5984b4fc830Sdlw {
5994b4fc830Sdlw 	int *old_pc;
6004b4fc830Sdlw 
6014b4fc830Sdlw 	old_pc = (int *) pc;
6024b4fc830Sdlw 	pc += 2;
6034b4fc830Sdlw 	return *old_pc;
6044b4fc830Sdlw }
6054b4fc830Sdlw 
6064b4fc830Sdlw 
6074b4fc830Sdlw 
fetch_long()6084b4fc830Sdlw fetch_long()
6094b4fc830Sdlw {
6104b4fc830Sdlw 	long *old_pc;
6114b4fc830Sdlw 
6124b4fc830Sdlw 	old_pc = (long *) pc;
6134b4fc830Sdlw 	pc += 4;
6144b4fc830Sdlw 	return *old_pc;
6154b4fc830Sdlw }
616999e6702Slibs 
6174b4fc830Sdlw 
type_length(type)6184b4fc830Sdlw type_length(type)
6194b4fc830Sdlw {
6204b4fc830Sdlw 	if (type == F) return 4;
6214b4fc830Sdlw 	if (type == D) return 8;
6224b4fc830Sdlw 	fprintf(units[STDERR].ufd, "Bad type 0x%x in type_length()\n", type);
623999e6702Slibs 	f77_abort();
6244b4fc830Sdlw 	return -1;
6254b4fc830Sdlw }
6264b4fc830Sdlw 
6274b4fc830Sdlw 
6284b4fc830Sdlw 
opcode_name(opcode)6294b4fc830Sdlw char *opcode_name(opcode)
6304b4fc830Sdlw {
6314b4fc830Sdlw 	switch (opcode) {
6324b4fc830Sdlw 		case ACBD: 	return "ACBD";
6334b4fc830Sdlw 		case ACBF: 	return "ACBF";
6344b4fc830Sdlw 		case ADDD2: 	return "ADDD2";
6354b4fc830Sdlw 		case ADDD3: 	return "ADDD3";
6364b4fc830Sdlw 		case ADDF2: 	return "ADDF2";
6374b4fc830Sdlw 		case ADDF3: 	return "ADDF3";
6384b4fc830Sdlw 		case CMPD: 	return "CMPD";
6394b4fc830Sdlw 		case CMPF: 	return "CMPF";
6404b4fc830Sdlw 		case CVTDB: 	return "CVTDB";
6414b4fc830Sdlw 		case CVTDF: 	return "CVTDF";
6424b4fc830Sdlw 		case CVTDL: 	return "CVTDL";
6434b4fc830Sdlw 		case CVTDW: 	return "CVTDW";
6444b4fc830Sdlw 		case CVTFB: 	return "CVTFB";
6454b4fc830Sdlw 		case CVTFD: 	return "CVTFD";
6464b4fc830Sdlw 		case CVTFL: 	return "CVTFL";
6474b4fc830Sdlw 		case CVTFW: 	return "CVTFW";
6484b4fc830Sdlw 		case CVTRDL: 	return "CVTRDL";
6494b4fc830Sdlw 		case CVTRFL: 	return "CVTRFL";
6504b4fc830Sdlw 		case DIVD2: 	return "DIVD2";
6514b4fc830Sdlw 		case DIVD3: 	return "DIVD3";
6524b4fc830Sdlw 		case DIVF2: 	return "DIVF2";
6534b4fc830Sdlw 		case DIVF3: 	return "DIVF3";
6544b4fc830Sdlw 		case EMODD: 	return "EMODD";
6554b4fc830Sdlw 		case EMODF: 	return "EMODF";
6564b4fc830Sdlw 		case MNEGD: 	return "MNEGD";
6574b4fc830Sdlw 		case MNEGF: 	return "MNEGF";
6584b4fc830Sdlw 		case MOVD: 	return "MOVD";
6594b4fc830Sdlw 		case MOVF: 	return "MOVF";
6604b4fc830Sdlw 		case MULD2: 	return "MULD2";
6614b4fc830Sdlw 		case MULD3: 	return "MULD3";
6624b4fc830Sdlw 		case MULF2: 	return "MULF2";
6634b4fc830Sdlw 		case MULF3: 	return "MULF3";
6644b4fc830Sdlw 		case POLYD: 	return "POLYD";
6654b4fc830Sdlw 		case POLYF: 	return "POLYF";
6664b4fc830Sdlw 		case SUBD2: 	return "SUBD2";
6674b4fc830Sdlw 		case SUBD3: 	return "SUBD3";
6684b4fc830Sdlw 		case SUBF2: 	return "SUBF2";
6694b4fc830Sdlw 		case SUBF3: 	return "SUBF3";
6704b4fc830Sdlw 		case TSTD: 	return "TSTD";
6714b4fc830Sdlw 		case TSTF: 	return "TSTF";
6724b4fc830Sdlw 	}
6734b4fc830Sdlw }
6744b4fc830Sdlw #endif	vax
675c891893aSmckusick 
676c891893aSmckusick #ifdef tahoe
677c891893aSmckusick /*
678c891893aSmckusick  *	NO RESERVED OPERAND EXCEPTION ON RESULT OF FP OVERFLOW ON TAHOE.
679c891893aSmckusick  * 	JUST PRINT THE OVERFLOW MESSAGE. RESULT IS 0 (zero).
680c891893aSmckusick  */
681c891893aSmckusick 
682c891893aSmckusick /*
683c891893aSmckusick  *	GLOBAL VARIABLES (we need a few)
684c891893aSmckusick  *
685c891893aSmckusick  *	Actual program counter and locations of registers.
686c891893aSmckusick  */
687c891893aSmckusick static char	*pc;
688c891893aSmckusick static int	*regs0t1;
689c891893aSmckusick static int	*regs2t12;
690c891893aSmckusick static int	max_messages;
691c891893aSmckusick static int	total_overflows;
692c891893aSmckusick static union	{
693c891893aSmckusick 	long	v_long[2];
694c891893aSmckusick 	double	v_double;
695c891893aSmckusick 	} retrn;
696a0d0269cSbostic static sig_t sigill_default = (SIG_VAL)-1;
697a0d0269cSbostic static sig_t sigfpe_default;
698c891893aSmckusick 
699c891893aSmckusick 
700c891893aSmckusick /*
701c891893aSmckusick  *	This routine sets up the signal handler for the floating-point
702c891893aSmckusick  *	and reserved operand interrupts.
703c891893aSmckusick  */
704c891893aSmckusick 
trapov_(count,rtnval)705c891893aSmckusick trapov_(count, rtnval)
706c891893aSmckusick 	int *count;
707c891893aSmckusick 	double *rtnval;
708c891893aSmckusick {
709a0d0269cSbostic 	void got_overflow();
710c891893aSmckusick 
711c891893aSmckusick 	sigfpe_default = signal(SIGFPE, got_overflow);
712c891893aSmckusick 	total_overflows = 0;
713c891893aSmckusick 	max_messages = *count;
714c891893aSmckusick 	retrn.v_double = *rtnval;
715c891893aSmckusick }
716c891893aSmckusick 
717c891893aSmckusick 
718c891893aSmckusick 
719c891893aSmckusick /*
720c891893aSmckusick  *	got_overflow - routine called when overflow occurs
721c891893aSmckusick  *
722c891893aSmckusick  *	This routine just prints a message about the overflow.
723c891893aSmckusick  *	It is impossible to find the bad result at this point.
724c891893aSmckusick  * 	 NEXT 2 LINES DON'T HOLD FOR TAHOE !
725c891893aSmckusick  *	Instead, we wait until we get the reserved operand exception
726c891893aSmckusick  *	when we try to use it.  This raises the SIGILL signal.
727c891893aSmckusick  */
728c891893aSmckusick 
729c891893aSmckusick /*ARGSUSED*/
730a0d0269cSbostic void
got_overflow(signo,codeword,sc)731c891893aSmckusick got_overflow(signo, codeword, sc)
732c891893aSmckusick 	int signo, codeword;
733c891893aSmckusick 	struct sigcontext *sc;
734c891893aSmckusick {
735c891893aSmckusick 	int	*sp, i;
736c891893aSmckusick 	FILE	*ef;
737c891893aSmckusick 
738c891893aSmckusick 	signal(SIGFPE, got_overflow);
739c891893aSmckusick 	ef = units[STDERR].ufd;
740c891893aSmckusick 	switch (codeword) {
741c891893aSmckusick 		case INT_OVF_T:
742c891893aSmckusick 		case INT_DIV_T:
743c891893aSmckusick 		case FLT_UND_T:
744c891893aSmckusick 		case FLT_DIV_T:
745c891893aSmckusick 			if (sigfpe_default > (SIG_VAL)7)
746a0d0269cSbostic 				(*sigfpe_default)(signo, codeword, sc);
747c891893aSmckusick 			else
748c891893aSmckusick 				sigdie(signo, codeword, sc);
749c891893aSmckusick 				/* NOTREACHED */
750c891893aSmckusick 
751c891893aSmckusick 		case FLT_OVF_T:
752c891893aSmckusick 			if (++total_overflows <= max_messages) {
753c891893aSmckusick 				fprintf(ef, "trapov: %s",
754c891893aSmckusick 					act_fpe[codeword-1].mesg);
755c891893aSmckusick 				fprintf(ef, ": Current PC = %X", sc->sc_pc);
756c891893aSmckusick 				if (total_overflows == max_messages)
757c891893aSmckusick 					fprintf(ef, ": No more messages will be printed.\n");
758c891893aSmckusick 				else
759c891893aSmckusick 					fputc('\n', ef);
760c891893aSmckusick 			}
761c891893aSmckusick 			return;
762c891893aSmckusick 	}
763c891893aSmckusick }
764c891893aSmckusick int
ovcnt_()765c891893aSmckusick ovcnt_()
766c891893aSmckusick {
767c891893aSmckusick 	return total_overflows;
768c891893aSmckusick }
769c891893aSmckusick #endif tahoe
770