|
|
1.1 root 1: /* #define OLD_BSD if you're running < 4.2bsd */
2: /*
3: char id_trpfpe[] = "@(#)trpfpe_.c 1.3";
4: *
5: * Fortran floating-point error handler
6: *
7: * Synopsis:
8: * call trpfpe (n, retval)
9: * causes floating point faults to be trapped, with the
10: * first 'n' errors getting a message printed.
11: * 'retval' is put in place of the bad result.
12: * k = fpecnt()
13: * causes 'k' to get the number of errors since the
14: * last call to trpfpe().
15: *
16: * common /fpeflt/ fpflag
17: * logical fpflag
18: * fpflag will become .true. on faults
19: *
20: * David Wasley, UCBerkeley, June 1983.
21: */
22:
23:
24: #include <stdio.h>
25: #include <signal.h>
26: #include "opcodes.h"
27: #include "operand.h"
28: #include "../libI77/fiodefs.h"
29:
30: #define SIG_VAL int (*)()
31:
32: #if vax /* only works on VAXen */
33:
34: struct arglist { /* what AP points to */
35: long al_numarg; /* only true in CALLS format */
36: long al_arg[256];
37: };
38:
39: struct cframe { /* VAX call frame */
40: long cf_handler;
41: unsigned short cf_psw;
42: unsigned short cf_mask;
43: struct arglist *cf_ap;
44: struct cframe *cf_fp;
45: char *cf_pc;
46: };
47:
48: /*
49: * bits in the PSW
50: */
51: #define PSW_V 0x2
52: #define PSW_FU 0x40
53: #define PSW_IV 0x20
54:
55: /*
56: * where the registers are stored as we see them in the handler
57: */
58: struct reg0_6 {
59: long reg[7];
60: };
61:
62: struct reg7_11 {
63: long reg[5];
64: };
65:
66: #define iR0 reg0_6->reg[0]
67: #define iR1 reg0_6->reg[1]
68: #define iR2 reg0_6->reg[2]
69: #define iR3 reg0_6->reg[3]
70: #define iR4 reg0_6->reg[4]
71: #define iR5 reg0_6->reg[5]
72: #define iR6 reg0_6->reg[6]
73: #define iR7 reg7_11->reg[0]
74: #define iR8 reg7_11->reg[1]
75: #define iR9 reg7_11->reg[2]
76: #define iR10 reg7_11->reg[3]
77: #define iR11 reg7_11->reg[4]
78:
79: union objects { /* for load/store */
80: char ua_byte;
81: short ua_word;
82: long ua_long;
83: float ua_float;
84: double ua_double;
85: union objects *ua_anything;
86: };
87:
88: typedef union objects anything;
89: enum object_type { BYTE, WORD, LONG, FLOAT, QUAD, DOUBLE, UNKNOWN };
90:
91:
92: /*
93: * assembly language assist
94: * There are some things you just can't do in C
95: */
96: asm(".text");
97:
98: struct cframe *myfp();
99: asm("_myfp: .word 0x0");
100: asm("movl 12(fp),r0");
101: asm("ret");
102:
103: struct arglist *myap();
104: asm("_myap: .word 0x0");
105: asm("movl 8(fp),r0");
106: asm("ret");
107:
108: char *mysp();
109: asm("_mysp: .word 0x0");
110: asm("extzv $30,$2,4(fp),r0");
111: asm("addl2 ap,r0"); /* SP in caller is AP+4 here + SPA bits! */
112: asm("addl2 $4,r0");
113: asm("ret");
114:
115: char *mypc();
116: asm("_mypc: .word 0x0");
117: asm("movl 16(fp),r0");
118: asm("ret");
119:
120: asm(".data");
121:
122:
123: /*
124: * Where interrupted objects are
125: */
126: static struct cframe **ifp; /* addr of saved FP */
127: static struct arglist **iap; /* addr of saved AP */
128: static char *isp; /* value of interrupted SP */
129: static char **ipc; /* addr of saved PC */
130: static struct reg0_6 *reg0_6;/* registers 0-6 are saved on the exception */
131: static struct reg7_11 *reg7_11;/* we save 7-11 by our entry mask */
132: static anything *result_addr; /* where the dummy result goes */
133: static enum object_type result_type; /* what kind of object it is */
134:
135: /*
136: * some globals
137: */
138: static union {
139: long rv_long[2];
140: float rv_float;
141: double rv_double;
142: } retval; /* the user specified dummy result */
143: static int max_messages = 1; /* the user can tell us */
144: static int fpe_count = 0; /* how bad is it ? */
145: long fpeflt_ = 0; /* fortran "common /fpeflt/ flag" */
146: static int (*sigfpe_dfl)() = SIG_DFL; /* if we can't fix it ... */
147:
148: /*
149: * The fortran unit control table
150: */
151: extern unit units[];
152:
153: /*
154: * Fortran message table is in main
155: */
156: struct msgtbl {
157: char *mesg;
158: int dummy;
159: };
160: extern struct msgtbl act_fpe[];
161:
162:
163: /*
164: * Get the address of the (saved) next operand & update saved PC.
165: * The major purpose of this is to determine where to store the result.
166: * There is one case we can't deal with: -(SP) or (SP)+
167: * since we can't change the size of the stack.
168: * Let's just hope compilers don't generate that for results.
169: */
170:
171: anything *
172: get_operand (oper_size)
173: int oper_size; /* size of operand we expect */
174: {
175: register int regnum;
176: register int operand_code;
177: int index;
178: anything *oper_addr;
179: anything *reg_addr;
180:
181: regnum = (**ipc & 0xf);
182: if (regnum == PC)
183: operand_code = (*(*ipc)++ & 0xff);
184: else
185: operand_code = (*(*ipc)++ & 0xf0);
186: if (regnum <= R6)
187: reg_addr = (anything *)®0_6->reg[regnum];
188: else if (regnum <= R11)
189: reg_addr = (anything *)®7_11->reg[regnum];
190: else if (regnum == AP)
191: reg_addr = (anything *)iap;
192: else if (regnum == FP)
193: reg_addr = (anything *)ifp;
194: else if (regnum == SP)
195: reg_addr = (anything *)&isp; /* We saved this ourselves */
196: else if (regnum == PC)
197: reg_addr = (anything *)ipc;
198:
199:
200: switch (operand_code)
201: {
202: case IMMEDIATE:
203: oper_addr = (anything *)(*ipc);
204: *ipc += oper_size;
205: return(oper_addr);
206:
207: case ABSOLUTE:
208: oper_addr = (anything *)(**ipc);
209: *ipc += sizeof (anything *);
210: return(oper_addr);
211:
212: case LITERAL0:
213: case LITERAL1:
214: case LITERAL2:
215: case LITERAL3:
216: /* we don't care about the address of these */
217: return((anything *)0);
218:
219: case INDEXED:
220: index = reg_addr->ua_long * oper_size;
221: oper_addr = (anything *)(get_operand(sizeof (long))->ua_long + index);
222: return(oper_addr);
223:
224: case REGISTER:
225: return(reg_addr);
226:
227: case REGDEFERED:
228: return(reg_addr->ua_anything);
229:
230: case AUTODEC:
231: if (regnum == SP)
232: {
233: fprintf(stderr, "trp: can't fix -(SP) operand\n");
234: exit(1);
235: }
236: reg_addr->ua_long -= oper_size;
237: oper_addr = reg_addr->ua_anything;
238: return(oper_addr);
239:
240: case AUTOINC:
241: if (regnum == SP)
242: {
243: fprintf(stderr, "trp: can't fix (SP)+ operand\n");
244: exit(1);
245: }
246: oper_addr = reg_addr->ua_anything;
247: reg_addr->ua_long += oper_size;
248: return(oper_addr);
249:
250: case AUTOINCDEF:
251: if (regnum == SP)
252: {
253: fprintf(stderr, "trp: can't fix @(SP)+ operand\n");
254: exit(1);
255: }
256: oper_addr = (reg_addr->ua_anything)->ua_anything;
257: reg_addr->ua_long += sizeof (anything *);
258: return(oper_addr);
259:
260: case BYTEDISP:
261: case BYTEREL:
262: index = ((anything *)(*ipc))->ua_byte;
263: *ipc += sizeof (char); /* do it now in case reg==PC */
264: oper_addr = (anything *)(index + reg_addr->ua_long);
265: return(oper_addr);
266:
267: case BYTEDISPDEF:
268: case BYTERELDEF:
269: index = ((anything *)(*ipc))->ua_byte;
270: *ipc += sizeof (char); /* do it now in case reg==PC */
271: oper_addr = (anything *)(index + reg_addr->ua_long);
272: oper_addr = oper_addr->ua_anything;
273: return(oper_addr);
274:
275: case WORDDISP:
276: case WORDREL:
277: index = ((anything *)(*ipc))->ua_word;
278: *ipc += sizeof (short); /* do it now in case reg==PC */
279: oper_addr = (anything *)(index + reg_addr->ua_long);
280: return(oper_addr);
281:
282: case WORDDISPDEF:
283: case WORDRELDEF:
284: index = ((anything *)(*ipc))->ua_word;
285: *ipc += sizeof (short); /* do it now in case reg==PC */
286: oper_addr = (anything *)(index + reg_addr->ua_long);
287: oper_addr = oper_addr->ua_anything;
288: return(oper_addr);
289:
290: case LONGDISP:
291: case LONGREL:
292: index = ((anything *)(*ipc))->ua_long;
293: *ipc += sizeof (long); /* do it now in case reg==PC */
294: oper_addr = (anything *)(index + reg_addr->ua_long);
295: return(oper_addr);
296:
297: case LONGDISPDEF:
298: case LONGRELDEF:
299: index = ((anything *)(*ipc))->ua_long;
300: *ipc += sizeof (long); /* do it now in case reg==PC */
301: oper_addr = (anything *)(index + reg_addr->ua_long);
302: oper_addr = oper_addr->ua_anything;
303: return(oper_addr);
304:
305: /* NOTREACHED */
306: }
307: }
308:
309: /*
310: * Trap & repair floating exceptions so that a program may proceed.
311: * There is no notion of "correctness" here; just the ability to continue.
312: *
313: * The on_fpe() routine first checks the type code to see if the
314: * exception is repairable. If so, it checks the opcode to see if
315: * it is one that it knows. If this is true, it then simulates the
316: * VAX cpu in retrieving operands in order to increment iPC correctly.
317: * It notes where the result of the operation would have been stored
318: * and substitutes a previously supplied value.
319: */
320:
321: #ifdef OLD_BSD
322: on_fpe(signo, code, myaddr, pc, ps)
323: int signo, code, ps;
324: char *myaddr, *pc;
325: #else
326: on_fpe(signo, code, sc, grbg)
327: int signo, code;
328: struct sigcontext *sc;
329: #endif
330: {
331: /*
332: * There must be at least 5 register variables here
333: * so our entry mask will save R11-R7.
334: */
335: register long *stk;
336: register long *sp;
337: register struct arglist *ap;
338: register struct cframe *fp;
339: register FILE *ef;
340:
341: ef = units[STDERR].ufd; /* fortran error stream */
342:
343: switch (code)
344: {
345: case FPE_INTOVF_TRAP: /* integer overflow */
346: case FPE_INTDIV_TRAP: /* integer divide by zero */
347: case FPE_FLTOVF_TRAP: /* floating overflow */
348: case FPE_FLTDIV_TRAP: /* floating/decimal divide by zero */
349: case FPE_FLTUND_TRAP: /* floating underflow */
350: case FPE_DECOVF_TRAP: /* decimal overflow */
351: case FPE_SUBRNG_TRAP: /* subscript out of range */
352: default:
353: cant_fix:
354: if (sigfpe_dfl > (SIG_VAL)7) /* user specified */
355: #ifdef OLD_BSD
356: return((*sigfpe_dfl)(signo, code, myaddr, pc, ps));
357: #else
358: return((*sigfpe_dfl)(signo, code, sc, grbg));
359: #endif
360: else
361: #ifdef OLD_BSD
362: sigdie(signo, code, myaddr, pc, ps);
363: #else
364: sigdie(signo, code, sc, grbg);
365: #endif
366: /* NOTREACHED */
367:
368: case FPE_FLTOVF_FAULT: /* floating overflow fault */
369: case FPE_FLTDIV_FAULT: /* divide by zero floating fault */
370: case FPE_FLTUND_FAULT: /* floating underflow fault */
371: if (++fpe_count <= max_messages) {
372: fprintf(ef, "trpfpe: %s",
373: act_fpe[code-1].mesg);
374: if (fpe_count == max_messages)
375: fprintf(ef, ": No more messages will be printed.\n");
376: else
377: fputc('\n', ef);
378: }
379: fpeflt_ = -1;
380: break;
381: }
382:
383: ap = myap(); /* my arglist pointer */
384: fp = myfp(); /* my frame pointer */
385: ifp = &(fp->cf_fp)->cf_fp; /* user's stored in next frame back */
386: iap = &(fp->cf_fp)->cf_ap;
387: /*
388: * these are likely to be system dependent
389: */
390: reg0_6 = (struct reg0_6 *)((char *)fp->cf_fp + sizeof (struct cframe));
391: reg7_11 = (struct reg7_11 *)((char *)fp->cf_fp - sizeof (struct reg7_11));
392:
393: #ifdef OLD_BSD
394: ipc = &pc;
395: isp = (char *)&ap->al_arg[ap->al_numarg + 2]; /* assumes 2 dummys */
396: ps &= ~(PSW_V|PSW_FU);
397: #else
398: ipc = (char **)&sc->sc_pc;
399: isp = (char *)sc + sizeof (struct sigcontext);
400: sc->sc_ps &= ~(PSW_V|PSW_FU);
401: #endif
402:
403:
404: switch (*(*ipc)++)
405: {
406: case ADDD3:
407: case DIVD3:
408: case MULD3:
409: case SUBD3:
410: (void) get_operand(sizeof (double));
411: /* intentional fall-thru */
412:
413: case ADDD2:
414: case DIVD2:
415: case MULD2:
416: case SUBD2:
417: case MNEGD:
418: case MOVD:
419: (void) get_operand(sizeof (double));
420: result_addr = get_operand(sizeof (double));
421: result_type = DOUBLE;
422: break;
423:
424: case ADDF3:
425: case DIVF3:
426: case MULF3:
427: case SUBF3:
428: (void) get_operand(sizeof (float));
429: /* intentional fall-thru */
430:
431: case ADDF2:
432: case DIVF2:
433: case MULF2:
434: case SUBF2:
435: case MNEGF:
436: case MOVF:
437: (void) get_operand(sizeof (float));
438: result_addr = get_operand(sizeof (float));
439: result_type = FLOAT;
440: break;
441:
442: case CVTDF:
443: (void) get_operand(sizeof (double));
444: result_addr = get_operand(sizeof (float));
445: result_type = FLOAT;
446: break;
447:
448: case CVTFD:
449: (void) get_operand(sizeof (float));
450: result_addr = get_operand(sizeof (double));
451: result_type = DOUBLE;
452: break;
453:
454: case EMODF:
455: case EMODD:
456: fprintf(ef, "trpfpe: can't fix emod yet\n");
457: goto cant_fix;
458:
459: case POLYF:
460: case POLYD:
461: fprintf(ef, "trpfpe: can't fix poly yet\n");
462: goto cant_fix;
463:
464: case ACBD:
465: case ACBF:
466: case CMPD:
467: case CMPF:
468: case TSTD:
469: case TSTF:
470: case CVTDB:
471: case CVTDL:
472: case CVTDW:
473: case CVTFB:
474: case CVTFL:
475: case CVTFW:
476: case CVTRDL:
477: case CVTRFL:
478: /* These can generate only reserved operand faults */
479: /* They are shown here for completeness */
480:
481: default:
482: fprintf(stderr, "trp: opcode 0x%02x unknown\n",
483: *(--(*ipc)) & 0xff);
484: goto cant_fix;
485: /* NOTREACHED */
486: }
487:
488: if (result_type == FLOAT)
489: result_addr->ua_float = retval.rv_float;
490: else
491: {
492: if (result_addr == (anything *)&iR6)
493: { /*
494: * special case - the R6/R7 pair is stored apart
495: */
496: result_addr->ua_long = retval.rv_long[0];
497: ((anything *)&iR7)->ua_long = retval.rv_long[1];
498: }
499: else
500: result_addr->ua_double = retval.rv_double;
501: }
502: signal(SIGFPE, on_fpe);
503: }
504: #endif vax
505:
506: trpfpe_ (count, rval)
507: long *count; /* how many to announce */
508: double *rval; /* dummy return value */
509: {
510: #if vax
511: max_messages = *count;
512: retval.rv_double = *rval;
513: sigfpe_dfl = signal(SIGFPE, on_fpe);
514: fpe_count = 0;
515: #endif
516: }
517:
518: long
519: fpecnt_ ()
520: {
521: #if vax
522: return (fpe_count);
523: #else
524: return (0L);
525: #endif
526: }
527:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.