ieee floating point interrupt handling
Jeff Hanson
tohanson at gonzo.lerc.nasa.gov
Wed Jun 12 01:50:24 AEST 1991
This was posted to comp.lang.fortran for MIPS. I made extremely minor
modifications for SGI. I've not tried it. Caveat receptor.
/**********************************************************************
* Modified for SGI
*Here is a simple floating point exception handler that I wrote (Mips *
*Fortran version). Compile it with C and link with your Fortran (or C)*
*program, like this: *
* *
* % cc -c fpx_sgi.c *
* % f77 prog.f fpx_sgi.o -o prog *
* *
*or something like that. *
* *
*To use it, just insert a statement *
* *
* call standard_fpx() *
*-- *
*Fritz Keinert phone: (515) 294-5128 *
*Department of Mathematics fax: (515) 294-5454 *
*Iowa State University e-mail: keinert at iastate.edu*
*Ames, IA 50011 *
* *
* Floating point exception handler for MIPS machines *
* Fritz Keinert (keinert at iastate.edu) *
* April 5, 1991 *
* *
* building on routines by Howard Jespersen and Srini Uppugunduri *
* *
* As they say in NETLIB: Everything free comes with no guarantee. *
* *
* This file contains the following routines: *
* *
* int getcsr() - returns the contents of the control/status *
* register (CSR) of the MIPS floating point *
* unit (FPU). The register contents are *
* described in /usr/include/sys/fpu.h *
* *
* int getcsr_() - same routine, callable from Fortran *
* *
* int setcsr(csr) - sets CSR to new value, returns old value; *
* also installs fpx_handler *
* *
* int setcsr_(csr) - same routine, callable from Fortran *
* *
* void fpx_handler(...) - floating point exception handler. Prints *
* an error message and dies. *
* *
* int standard_fpx() - same as setcsr(3584), to set up the *
* most frequently useful behavior. *
* *
* *
* int standard_fpx_() - same routine, callable from Fortran *
* *
* *
**********************************************************************
* *
* The floating point exception handling works like this: *
* *
* First, you have to tell the floating point unit to enable *
* interrupts, by setting the CSR accordingly. (I assume this *
* stands for Control and Status Register). The correct value *
* for CSR is found by adding *
* *
* one of the following, to define the rounding behavior: *
* *
* 0 - round to nearest *
* 1 - zero *
* 2 - + infinity *
* 3 - - infinity *
* *
* plus as many as needed of the following, to turn on *
* interrupts: *
* *
* 128 - cause interrupt on inexact result *
* 256 - underflow *
* 512 - overflow *
* 1024 - division by zero *
* 2048 - invalid operation *
* *
* The standard values are: *
* *
* 1. round to nearest, interrupt on overflow, division by zero *
* and invalid operation. CSR = 3584. *
* *
* 2. round to nearest, interrupt on underflow, overflow, *
* division by zero and invalid operation. CSR = 3840. *
* *
* Second, you have to install an interrupt handler to give you *
* a message when an interrupt actually happens. Otherwise, the *
* operating system will just ignore it, or kill your program with *
* a highly informative message like "illegal operation". *
* *
* My interrupt handler just prints a message and dies. For more *
* sophisticated behavior, like "print a message on underflow, set *
* the result to zero, and continue", or a traceback of where this *
* happened, you are on your own. *
* *
* Use the dbx debugger to find out where in your source code the *
* problem is. Here is an example: program test dies with the *
* message *
* *
* caught signal 4, code 0 *
* floating point error: overflow *
* at or near location 0x400448 *
* *
* Call up dbx, execute the first line of your program, set the *
* program counter to the address reported by the interrupt routine, *
* and ask dbx where that is: *
* *
* % dbx test *
* dbx version 2.0 *
* Type 'help' for help. *
* reading symbolic information ... *
* [using test.test] *
* test: 6 print*,'round to nearest = 0' *
* (dbx) stop at 6 *
* [2] stop at "test.f":6 *
* (dbx) run *
* [2] stopped at [test.test:6 ,0x40020c] *
* print*,'round to nearest = 0' *
* (dbx) assign $pc=0x400448 *
* 4195400 *
* (dbx) where *
* > 0 test.test() ["test.f":24, 0x400448] *
* 1 main.main(0x7fffb9c4, 0x7fffb9cc, 0x0, 0x0, 0x0) *
* ["main.c":35, 0x400f2c] *
* (dbx) quit *
* *
* and we know: it was around line 24 in file test.f. *
* *
* This method may not work if the error is in a system subroutine. *
* For example, if you try sqrt(-1.), this will tell you that the *
* problem is inside a square root, but there may be many square *
* roots in your program. *
* *
* If all else fails, just run your program inside dbx until it *
* dies, and then type "where". This will get you an exact *
* traceback of where you are (sqrt function, called from line *
* ?? of subroutine ??, which was called from line ?? in main *
* program). *
* *
* You may have to use the "-g" flag for compiling, to get the *
* debugger to work properly. *
* *
**********************************************************************/
#include <sys/fpu.h>
#include <sys/cpu.h>
#include <signal.h>
#include <stdio.h>
void fpx_handler(int sig, int code, struct sigcontext *scp)
{
union fpc_csr csr;
csr.fc_word = scp->sc_fpc_csr;
fprintf(stderr,"caught signal %d, code %d\n", sig, code);
if (csr.fc_struct.ex_invalid)
{
fprintf(stderr,"floating point error: invalid operation\n");
fprintf(stderr,"at or near location 0x%x\n",scp->sc_pc);
exit(1);
}
if (csr.fc_struct.ex_divide0)
{
fprintf(stderr,"floating point error: division by zero\n");
fprintf(stderr,"at or near location 0x%x\n",scp->sc_pc);
exit(1);
}
if (csr.fc_struct.ex_underflow)
{
fprintf(stderr,"floating point error: underflow\n");
fprintf(stderr,"at or near location 0x%x\n",scp->sc_pc);
exit(1);
}
if (csr.fc_struct.ex_overflow)
{
fprintf(stderr,"floating point error: overflow\n");
fprintf(stderr,"at or near location 0x%x\n",scp->sc_pc);
exit(1);
}
if (csr.fc_struct.ex_inexact)
{
fprintf(stderr,"floating point error: inexact operation\n");
fprintf(stderr,"at or near location 0x%x\n",scp->sc_pc);
exit(1);
}
if (csr.fc_struct.ex_unimplemented)
{
fprintf(stderr,"floating point error: unimplemented operation\n");
fprintf(stderr,"at or near location 0x%x\n",scp->sc_pc);
exit(1);
}
if (code == BRK_DIVZERO) {
fprintf(stderr,"integer error: division by zero\n");
fprintf(stderr,"at or near location 0x%x\n",scp->sc_pc);
exit(1);
}
exit(1);
fprintf(stderr,"floating point error: unknown exception code\n");
fprintf(stderr,"at or near location 0x%x\n",scp->sc_pc);
fprintf(stderr,"fp status word 0x%x\n",csr);
exit(1);
}
int getcsr()
/*
* return contents of fpu control and status register
*/
{
return get_fpc_csr();
}
int getcsr_()
/*
* Fortran wrapper for getcsr()
*/
{
return getcsr();
}
int setcsr(unsigned int csr)
/*
* set up floating point interrupt handler, turn on interrupts
*/
{
signal(SIGTRAP, fpx_handler);
signal(SIGFPE, fpx_handler);
signal(SIGILL, fpx_handler);
return set_fpc_csr(csr);
}
int setcsr_(unsigned int *csr)
/*
* Fortran wrapper for setcsr()
*/
{
return setcsr(*csr);
}
int standard_fpx()
/*
* set up standard error handling: die on overflow,
* division by zero, illegal operation, but continue
* on underflow. Round to nearest.
*/
{
return setcsr((unsigned int) 3584);
}
int standard_fpx_()
/*
* Fortran wrapper for standard_fpx()
*/
{
return standard_fpx();
}
--
---------------------------------------------------------------------------
Jeff Hanson - Scientific Graphics Programmer and Workstation Administrator
NASA Lewis Research Center, MS 86-4, Cleveland, Ohio 44135
Telephone - (216) 433-2284 Fax - (216) 433-2182
tohanson at gonzo.lerc.nasa.gov - ViSC: Better Science Through Pictures
More information about the Comp.sys.sgi
mailing list