new file organization
[unix-history] / usr / src / usr.bin / f77 / libF77 / trapov_.c
CommitLineData
2e5ec501 1/*
8fa9a471 2char id_trapov[] = "@(#)trapov_.c 1.2";
2e5ec501
DW
3 *
4 * Fortran/C floating-point overflow handler
5 *
6 * The idea of these routines is to catch floating-point overflows
7 * and print an eror message. When we then get a reserved operand
8 * exception, we then fix up the value to the highest possible
9 * number. Keen, no?
10 * Messy, yes!
11 *
12 * Synopsis:
13 * call trapov(n)
14 * causes overflows to be trapped, with the first 'n'
15 * overflows getting an "Overflow!" message printed.
16 * k = ovcnt(0)
17 * causes 'k' to get the number of overflows since the
18 * last call to trapov().
19 *
20 * Gary Klimowicz, April 17, 1981
21 * Integerated with libF77: David Wasley, UCB, July 1981.
22 */
23
24# include <stdio.h>
25# include <signal.h>
26# include "opcodes.h"
27# include "../libI77/fiodefs.h"
8fa9a471 28# define SIG_VAL int (*)()
2e5ec501
DW
29
30/*
31 * Operand modes
32 */
33# define LITERAL0 0x0
34# define LITERAL1 0x1
35# define LITERAL2 0x2
36# define LITERAL3 0x3
37# define INDEXED 0x4
38# define REGISTER 0x5
39# define REG_DEF 0x6
40# define AUTO_DEC 0x7
41# define AUTO_INC 0x8
42# define AUTO_INC_DEF 0x9
43# define BYTE_DISP 0xa
44# define BYTE_DISP_DEF 0xb
45# define WORD_DISP 0xc
46# define WORD_DISP_DEF 0xd
47# define LONG_DISP 0xe
48# define LONG_DISP_DEF 0xf
49
50/*
51 * Operand value types
52 */
53# define F 1
54# define D 2
55# define IDUNNO 3
56
57# define PC 0xf
58# define SP 0xe
59# define FP 0xd
60# define AP 0xc
61
8fa9a471
DW
62/*
63 * trap type codes
64 */
65# define INT_OVF_T 1
66# define INT_DIV_T 2
67# define FLT_OVF_T 3
68# define FLT_DIV_T 4
69# define FLT_UND_T 5
70# define DEC_OVF_T 6
71# define SUB_RNG_T 7
72# define FLT_OVF_F 8
73# define FLT_DIV_F 9
74# define FLT_UND_F 10
75
76# define RES_ADR_F 0
77# define RES_OPC_F 1
78# define RES_OPR_F 2
79
2e5ec501
DW
80/*
81 * Potential operand values
82 */
83typedef union operand_types {
84 char o_byte;
85 short o_word;
86 long o_long;
87 float o_float;
88 long o_quad[2];
89 double o_double;
90 } anyval;
91
92/*
93 * GLOBAL VARIABLES (we need a few)
94 *
95 * Actual program counter and locations of registers.
96 */
8fa9a471 97#if vax
2e5ec501
DW
98static char *pc;
99static int *regs0t6;
100static int *regs7t11;
101static int max_messages;
102static int total_overflows;
103static union {
104 long v_long[2];
105 double v_double;
106 } retrn;
8fa9a471
DW
107static int (*sigill_default)() = (SIG_VAL)-1;
108static int (*sigfpe_default)();
109#endif vax
2e5ec501
DW
110
111/*
112 * the fortran unit control table
113 */
114extern unit units[];
115
8fa9a471
DW
116/*
117 * Fortran message table is in main
118 */
119struct msgtbl {
120 char *mesg;
121 int dummy;
122};
123extern struct msgtbl act_fpe[];
124
125
126
2e5ec501
DW
127anyval *get_operand_address(), *addr_of_reg();
128char *opcode_name();
129\f
130/*
131 * This routine sets up the signal handler for the floating-point
132 * and reserved operand interrupts.
133 */
134
135trapov_(count, rtnval)
136 int *count;
137 double *rtnval;
138{
139#if vax
140 extern got_overflow(), got_illegal_instruction();
141
8fa9a471
DW
142 sigfpe_default = signal(SIGFPE, got_overflow);
143 if (sigill_default == (SIG_VAL)-1)
144 sigill_default = signal(SIGILL, got_illegal_instruction);
2e5ec501
DW
145 total_overflows = 0;
146 max_messages = *count;
147 retrn.v_double = *rtnval;
148}
149
150
151
152/*
153 * got_overflow - routine called when overflow occurs
154 *
155 * This routine just prints a message about the overflow.
156 * It is impossible to find the bad result at this point.
157 * Instead, we wait until we get the reserved operand exception
158 * when we try to use it. This raises the SIGILL signal.
159 */
160
161/*ARGSUSED*/
162got_overflow(signo, codeword, myaddr, pc, ps)
163 char *myaddr, *pc;
164{
8fa9a471
DW
165 int *sp, i;
166 FILE *ef;
167
2e5ec501 168 signal(SIGFPE, got_overflow);
8fa9a471
DW
169 ef = units[STDERR].ufd;
170 switch (codeword) {
171 case INT_OVF_T:
172 case INT_DIV_T:
173 case FLT_UND_T:
174 case DEC_OVF_T:
175 case SUB_RNG_T:
176 case FLT_OVF_F:
177 case FLT_DIV_F:
178 case FLT_UND_F:
179 if (sigfpe_default > (SIG_VAL)7)
180 return((*sigfpe_default)(signo, codeword, myaddr, pc, ps));
181 else
182 sigdie(signo, codeword, myaddr, pc, ps);
183 /* NOTREACHED */
184
185 case FLT_OVF_T:
186 case FLT_DIV_T:
187 if (++total_overflows <= max_messages) {
188 fprintf(ef, "trapov: %s",
189 act_fpe[codeword-1].mesg);
190 if (total_overflows == max_messages)
191 fprintf(ef, ": No more messages will be printed.\n");
192 else
193 fputc('\n', ef);
194 }
195 return;
196 }
2e5ec501
DW
197#endif vax
198}
199
200int
201ovcnt_()
202{
203 return total_overflows;
204}
205\f
206#if vax
207/*
208 * got_illegal_instruction - handle "illegal instruction" signals.
209 *
210 * This really deals only with reserved operand exceptions.
211 * Since there is no way to check this directly, we look at the
212 * opcode of the instruction we are executing to see if it is a
213 * floating-point operation (with floating-point operands, not
214 * just results).
215 *
216 * This is complicated by the fact that the registers that will
217 * eventually be restored are saved in two places. registers 7-11
218 * are saved by this routine, and are in its call frame. (we have
219 * to take special care that these registers are specified in
220 * the procedure entry mask here.)
221 * Registers 0-6 are saved at interrupt time, and are at a offset
222 * -8 from the 'signo' parameter below.
223 * There is ane extremely inimate connection between the value of
224 * the entry mask set by the 'makefile' script, and the constants
225 * used in the register offset calculations below.
226 * Can someone think of a better way to do this?
227 */
228
229/*ARGSUSED*/
230got_illegal_instruction(signo, codeword, myaddr, trap_pc, ps)
231 char *myaddr, *trap_pc;
232{
233 int first_local[1]; /* must be first */
234 int i, opcode, type, o_no, no_reserved;
235 anyval *opnd;
236
237 regs7t11 = &first_local[0];
238 regs0t6 = &signo - 8;
239 pc = trap_pc;
240
241 opcode = fetch_byte() & 0xff;
242 no_reserved = 0;
8fa9a471
DW
243 if (codeword != RES_OPR_F || !is_floating_operation(opcode)) {
244 if (sigill_default > (SIG_VAL)7)
245 return((*sigill_default)(signo, codeword, myaddr, trap_pc, ps));
246 else
247 sigdie(signo, codeword, myaddr, trap_pc, ps);
248 /* NOTREACHED */
2e5ec501
DW
249 }
250
251 if (opcode == POLYD || opcode == POLYF) {
252 got_illegal_poly(opcode);
253 return;
254 }
255
256 if (opcode == EMODD || opcode == EMODF) {
257 got_illegal_emod(opcode);
258 return;
259 }
260
261 /*
262 * This opcode wasn't "unusual".
263 * Look at the operands to try and find a reserved operand.
264 */
265 for (o_no = 1; o_no <= no_operands(opcode); ++o_no) {
266 type = operand_type(opcode, o_no);
267 if (type != F && type != D) {
268 advance_pc(type);
269 continue;
270 }
271
272 /* F or D operand. Check it out */
273 opnd = get_operand_address(type);
274 if (opnd == NULL) {
275 fprintf(units[STDERR].ufd, "Can't get operand address: 0x%x, %d\n",
276 pc, o_no);
277 force_abort();
278 }
279 if (type == F && opnd->o_long == 0x00008000) {
280 /* found one */
281 opnd->o_long = retrn.v_long[0];
282 ++no_reserved;
283 } else if (type == D && opnd->o_long == 0x00008000) {
284 /* found one here, too! */
285 opnd->o_quad[0] = retrn.v_long[0];
286 /* Fix next pointer */
287 if (opnd == addr_of_reg(6)) opnd = addr_of_reg(7);
288 else opnd = (anyval *) ((char *) opnd + 4);
289 opnd->o_quad[0] = retrn.v_long[1];
290 ++no_reserved;
291 }
292
293 }
294
295 if (no_reserved == 0) {
296 fprintf(units[STDERR].ufd, "Can't find any reserved operand!\n");
297 force_abort();
298 }
299}
300\f/*
301 * is_floating_exception - was the operation code for a floating instruction?
302 */
303
304is_floating_operation(opcode)
305 int opcode;
306{
307 switch (opcode) {
308 case ACBD: case ACBF: case ADDD2: case ADDD3:
309 case ADDF2: case ADDF3: case CMPD: case CMPF:
310 case CVTDB: case CVTDF: case CVTDL: case CVTDW:
311 case CVTFB: case CVTFD: case CVTFL: case CVTFW:
312 case CVTRDL: case CVTRFL: case DIVD2: case DIVD3:
313 case DIVF2: case DIVF3: case EMODD: case EMODF:
314 case MNEGD: case MNEGF: case MOVD: case MOVF:
315 case MULD2: case MULD3: case MULF2: case MULF3:
316 case POLYD: case POLYF: case SUBD2: case SUBD3:
317 case SUBF2: case SUBF3: case TSTD: case TSTF:
318 return 1;
319
320 default:
321 return 0;
322 }
323}
324\f/*
325 * got_illegal_poly - handle an illegal POLY[DF] instruction.
326 *
327 * We don't do anything here yet.
328 */
329
330/*ARGSUSED*/
331got_illegal_poly(opcode)
332{
333 fprintf(units[STDERR].ufd, "Can't do 'poly' instructions yet\n");
334 force_abort();
335}
336
337
338
339/*
340 * got_illegal_emod - handle illegal EMOD[DF] instruction.
341 *
342 * We don't do anything here yet.
343 */
344
345/*ARGSUSED*/
346got_illegal_emod(opcode)
347{
348 fprintf(units[STDERR].ufd, "Can't do 'emod' instructions yet\n");
349 force_abort();
350}
351
352
353/*
354 * no_operands - determine the number of operands in this instruction.
355 *
356 */
357
358no_operands(opcode)
359{
360 switch (opcode) {
361 case ACBD:
362 case ACBF:
363 return 3;
364
365 case MNEGD:
366 case MNEGF:
367 case MOVD:
368 case MOVF:
369 case TSTD:
370 case TSTF:
371 return 1;
372
373 default:
374 return 2;
375 }
376}
377
378
379
380/*
381 * operand_type - is the operand a D or an F?
382 *
383 * We are only descriminating between Floats and Doubles here.
384 * Other operands may be possible on exotic instructions.
385 */
386
387/*ARGSUSED*/
388operand_type(opcode, no)
389{
390 if (opcode >= 0x40 && opcode <= 0x56) return F;
391 if (opcode >= 0x60 && opcode <= 0x76) return D;
392 return IDUNNO;
393}
394
395
396
397/*
398 * advance_pc - Advance the program counter past an operand.
399 *
400 * We just bump the pc by the appropriate values.
401 */
402
403advance_pc(type)
404{
405 register int mode, reg;
406
407 mode = fetch_byte();
408 reg = mode & 0xf;
409 mode = (mode >> 4) & 0xf;
410 switch (mode) {
411 case LITERAL0:
412 case LITERAL1:
413 case LITERAL2:
414 case LITERAL3:
415 return;
416
417 case INDEXED:
418 advance_pc(type);
419 return;
420
421 case REGISTER:
422 case REG_DEF:
423 case AUTO_DEC:
424 return;
425
426 case AUTO_INC:
427 if (reg == PC) {
428 if (type == F) (void) fetch_long();
429 else if (type == D) {
430 (void) fetch_long();
431 (void) fetch_long();
432 } else {
433 fprintf(units[STDERR].ufd, "Bad type %d in advance\n",
434 type);
435 force_abort();
436 }
437 }
438 return;
439
440 case AUTO_INC_DEF:
441 if (reg == PC) (void) fetch_long();
442 return;
443
444 case BYTE_DISP:
445 case BYTE_DISP_DEF:
446 (void) fetch_byte();
447 return;
448
449 case WORD_DISP:
450 case WORD_DISP_DEF:
451 (void) fetch_word();
452 return;
453
454 case LONG_DISP:
455 case LONG_DISP_DEF:
456 (void) fetch_long();
457 return;
458
459 default:
460 fprintf(units[STDERR].ufd, "Bad mode 0x%x in op_length()\n", mode);
461 force_abort();
462 }
463}
464
465
466anyval *
467get_operand_address(type)
468{
469 register int mode, reg, base;
470
471 mode = fetch_byte() & 0xff;
472 reg = mode & 0xf;
473 mode = (mode >> 4) & 0xf;
474 switch (mode) {
475 case LITERAL0:
476 case LITERAL1:
477 case LITERAL2:
478 case LITERAL3:
479 return NULL;
480
481 case INDEXED:
482 base = (int) get_operand_address(type);
483 if (base == NULL) return NULL;
484 base += contents_of_reg(reg)*type_length(type);
485 return (anyval *) base;
486
487 case REGISTER:
488 return addr_of_reg(reg);
489
490 case REG_DEF:
491 return (anyval *) contents_of_reg(reg);
492
493 case AUTO_DEC:
494 return (anyval *) (contents_of_reg(reg)
495 - type_length(type));
496
497 case AUTO_INC:
498 return (anyval *) contents_of_reg(reg);
499
500 case AUTO_INC_DEF:
501 return (anyval *) * (long *) contents_of_reg(reg);
502
503 case BYTE_DISP:
504 base = fetch_byte();
505 base += contents_of_reg(reg);
506 return (anyval *) base;
507
508 case BYTE_DISP_DEF:
509 base = fetch_byte();
510 base += contents_of_reg(reg);
511 return (anyval *) * (long *) base;
512
513 case WORD_DISP:
514 base = fetch_word();
515 base += contents_of_reg(reg);
516 return (anyval *) base;
517
518 case WORD_DISP_DEF:
519 base = fetch_word();
520 base += contents_of_reg(reg);
521 return (anyval *) * (long *) base;
522
523 case LONG_DISP:
524 base = fetch_long();
525 base += contents_of_reg(reg);
526 return (anyval *) base;
527
528 case LONG_DISP_DEF:
529 base = fetch_long();
530 base += contents_of_reg(reg);
531 return (anyval *) * (long *) base;
532
533 default:
534 fprintf(units[STDERR].ufd, "Bad mode 0x%x in get_addr()\n", mode);
535 force_abort();
536 }
537 return NULL;
538}
539
540
541
542contents_of_reg(reg)
543{
544 int value;
545
546 if (reg == PC) value = (int) pc;
547 else if (reg == SP) value = (int) &regs0t6[6];
548 else if (reg == FP) value = regs0t6[-2];
549 else if (reg == AP) value = regs0t6[-3];
550 else if (reg >= 0 && reg <= 6) value = regs0t6[reg];
551 else if (reg >= 7 && reg <= 11) value = regs7t11[reg];
552 else {
553 fprintf(units[STDERR].ufd, "Bad register 0x%x to contents_of()\n", reg);
554 force_abort();
555 value = -1;
556 }
557 return value;
558}
559
560
561anyval *
562addr_of_reg(reg)
563{
564 if (reg >= 0 && reg <= 6) {
565 return (anyval *) &regs0t6[reg];
566 }
567 if (reg >= 7 && reg <= 11) {
568 return (anyval *) &regs7t11[reg];
569 }
570 fprintf(units[STDERR].ufd, "Bad reg 0x%x to addr_of()\n", reg);
571 force_abort();
572 return NULL;
573}
574\f/*
575 * fetch_{byte, word, long} - extract values from the PROGRAM area.
576 *
577 * These routines are used in the operand decoding to extract various
578 * fields from where the program counter points. This is because the
579 * addressing on the Vax is dynamic: the program counter advances
580 * while we are grabbing operands, as well as when we pass instructions.
581 * This makes things a bit messy, but I can't help it.
582 */
583fetch_byte()
584{
585 return *pc++;
586}
587
588
589
590fetch_word()
591{
592 int *old_pc;
593
594 old_pc = (int *) pc;
595 pc += 2;
596 return *old_pc;
597}
598
599
600
601fetch_long()
602{
603 long *old_pc;
604
605 old_pc = (long *) pc;
606 pc += 4;
607 return *old_pc;
608}
609\f/*
610 * force_abort - force us to abort.
611 *
612 * We have to change the signal handler for illegal instructions back,
613 * or we'll end up calling 'got_illegal_instruction()' again when
614 * abort() does it's dirty work.
615 */
616force_abort()
617{
8fa9a471 618 signal(SIGILL, SIG_DFL);
2e5ec501
DW
619 abort();
620}
621
622
623type_length(type)
624{
625 if (type == F) return 4;
626 if (type == D) return 8;
627 fprintf(units[STDERR].ufd, "Bad type 0x%x in type_length()\n", type);
628 force_abort();
629 return -1;
630}
631
632
633
634char *opcode_name(opcode)
635{
636 switch (opcode) {
637 case ACBD: return "ACBD";
638 case ACBF: return "ACBF";
639 case ADDD2: return "ADDD2";
640 case ADDD3: return "ADDD3";
641 case ADDF2: return "ADDF2";
642 case ADDF3: return "ADDF3";
643 case CMPD: return "CMPD";
644 case CMPF: return "CMPF";
645 case CVTDB: return "CVTDB";
646 case CVTDF: return "CVTDF";
647 case CVTDL: return "CVTDL";
648 case CVTDW: return "CVTDW";
649 case CVTFB: return "CVTFB";
650 case CVTFD: return "CVTFD";
651 case CVTFL: return "CVTFL";
652 case CVTFW: return "CVTFW";
653 case CVTRDL: return "CVTRDL";
654 case CVTRFL: return "CVTRFL";
655 case DIVD2: return "DIVD2";
656 case DIVD3: return "DIVD3";
657 case DIVF2: return "DIVF2";
658 case DIVF3: return "DIVF3";
659 case EMODD: return "EMODD";
660 case EMODF: return "EMODF";
661 case MNEGD: return "MNEGD";
662 case MNEGF: return "MNEGF";
663 case MOVD: return "MOVD";
664 case MOVF: return "MOVF";
665 case MULD2: return "MULD2";
666 case MULD3: return "MULD3";
667 case MULF2: return "MULF2";
668 case MULF3: return "MULF3";
669 case POLYD: return "POLYD";
670 case POLYF: return "POLYF";
671 case SUBD2: return "SUBD2";
672 case SUBD3: return "SUBD3";
673 case SUBF2: return "SUBF2";
674 case SUBF3: return "SUBF3";
675 case TSTD: return "TSTD";
676 case TSTF: return "TSTF";
677 }
678}
679#endif vax