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