Article View: comp.sys.next.programmer
Article #591Storing results to FP registers from within FP signal handler
From: Pedja Bogdanovich
Date: Thu, 09 Apr 1992 15:07
Date: Thu, 09 Apr 1992 15:07
214 lines
10041 bytes
10041 bytes
I am posting this for a friend. Please reply to him at
kerner%sava@cs.umd.edu
Thanks. Pedja
-----------------------------------------------------------------------------
I am writing a floating-point signal handler for the Motorola 68040 on
a NeXT workstation with NeXT OS 2.1 kernel. I have obtained a loadable
kernel server from NeXT which adds user enabled floating-point exceptions.
The following file describes a problem I have in changing the result of
an overflow.
/* FILE: fpoverflow.c Date: Apr 9, 1992 */
/*-----------------------------------------------------------------------------
* This file contains retrievfpcr(), storefpcr(), storefpsr(), retrievfpsr(),
* catcherr(), and main() for demonstrating difficulties with handling
* floating-point overflow signals on the NeXT computer with Motorola 68040.
*
* retrievfpcr() returns the contents of the 68040's floating point control
* register in the d0 data register. storefpcr() changes the contents of
* the 68040's floating point control register to its argument's value.
* storefpsr() changes the contents of the 68040's floating-point status
* register to its argument's value. retrievfpsr() returns the contents of
* the 68040's floating-point status register in the d0 data register.
* retrievfpcr() and storefpcr() are called in main() to store the initial
* floating point control register's value and to change bits 8-15 of the
* floating point control register to 0x08 (i.e. bits 8 through 15 are all
* zero except bit 12 which is 1) so that overflow errors are reported when
* they occur. main() also installs catcherr() as the floating-point error
* signal handler and stores the initial floating point error signal handler
* vector. Then main() generates an overflow error and prints the result.
* Finally, main() restores the initial floating point control register and
* floating point error signal handler.
*
* catcherr() prints the values of the arguments which are passed to it
* and stores MAXPOS--the largest floating-point number--in the fp0
* floating-point register with the appropriate sign.
*
* Problems:
* 1. Changes to the floating-point register within the signal handler
* catcherr() have no effect on the final result upon return from the
* signal handler. How can the result of the overflow be changed?
*---------------------------------------------------------------------------*/
/* defines from stdcsi.h: */
#define int32 int
#define uint32 unsigned int
/* the following structure is from sava-/usr/include/machine/signal.h and is
passed to the signal handler after the unmasked floating point signal
occurs */
/* Information pushed on stack when a signal is delivered. Used by kernel to
restore state following execution of signal handler. Also available to
handler to allow it to properly restore state if non-standard exit is
performed.*/
struct sigcontext
{int32 sc_onstack; /* sigstack state to restore */
int32 sc_mask; /* signal mask to restore */
int32 sc_sp; /* sp to restore */
int32 sc_pc; /* pc to restore */
int32 sc_ps; /* psl to restore */
int32 sc_d0; /* d0 to restore */
} *scp;
/* the following structure is from sava-/usr/include/sys/signal.h */
/* a sigvec structure exists for each type of signal. sigvec structures are
passed to the function sigvec() when changing a signal handler. A sigvec
structure defines the signal handler, mask, and flags for each signal. We
store two such structures corresponding to the default and the new floating
point signal handler. The sigvec structure is similar to the action
structure in AIX. */
struct sigvec
{void (*sv_handler)();
int32 sv_mask;
int32 sv_flags;
} old_sigvec, new_sigvec;
/* the following externs are from both UNIX Programmer's Manual and
sava-/usr/include/sys/signal.h */
extern int32 sigvec(int sig,struct sigvec *newvec,struct sigvec *oldvec);
/* the following array of 2 long integers is used to hold floating-point
stack elements */
uint32 fpr[2];
/* MAXPOS and MAXNEG are the positive and negative, largest magnitude, 64-bit
double values. Note that the constituent uint32's comprising these values
on the Motorola 68040 appear in different order than those comprising these
values on the Intel 80486. */
uint32
maxpos[2] = {0x7fefffff,0xffffffff},
maxneg[2] = {0xffefffff,0xffffffff};
#define MAXPOS (*(double *)maxpos)
#define MAXNEG (*(double *)maxneg)
/* the following macro is from both UNIX Programmer's Manual and
sava-/usr/include/sys/signal.h */
#define SIGFPE 8
/*========================================================================*/
static int32 retrievfpcr(void)
/*------------------------------------------------------------------------
* retrievfpcr() is an in-line assembler function which retrieves the floating
* point control register's contents, stores them in the data register d0,
* and returns.
*------------------------------------------------------------------------*/
{__asm volatile ("fmovel fpcr,d0");}
/*========================================================================*/
static void storefpcr(int32 ctl)
/*------------------------------------------------------------------------
* storefpcr() is an in-line assembler function which stores the 32-bit
* integer argument, ctl, which is on top of the argument stack, to the
* data register d0, and then moves d0 to the floating point control register.
*------------------------------------------------------------------------*/
{__asm volatile ("movel a6@(8),d0");
__asm volatile ("fmovel d0,fpcr");
}
/*========================================================================*/
static void storefpsr(int32 str)
/*------------------------------------------------------------------------
* storefpsr() is an in-line assembler function which stores the 32-bit
* integer argument, str, which is on top of the argument stack, to the
* data register d0, and then moves d0 to the floating point status register.
*------------------------------------------------------------------------*/
{__asm volatile ("movel a6@(8),d0");
__asm volatile ("fmovel d0,fpsr");
}
/*========================================================================*/
static int32 retrievfpsr(void)
/*------------------------------------------------------------------------
* retrievfpsr() is an in-line assembler function which retrieves the floating
* point status register's contents, stores it in the data register d0,
* and returns.
*------------------------------------------------------------------------*/
{__asm volatile ("fmovel fpsr,d0");}
/*========================================================================*/
void catcherr(int32 sig,int32 code,struct sigcontext *scp)
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
{uint32 st,status;
printf("\ncatcherr: sig = 0x%8x = %d, code = 0x%8x = %d",sig,sig,code,code);
printf("\n scp->sc_onstack = 0x%8x",scp->sc_onstack);
printf("\n scp->sc_mask = 0x%8x",scp->sc_mask);
printf("\n scp->sp = 0x%8x",scp->sc_sp);
printf("\n scp->pc = 0x%8x",scp->sc_pc);
printf("\n scp->ps = 0x%8x",scp->sc_ps);
printf("\n scp->d0 = 0x%8x",scp->sc_d0);
/* save the floating point status word in status */
status = retrievfpsr();
if (status & 0x00001040)
{printf("\noverflow");
/* copy the floating point register fp0 to fpr[0:1] */
__asm volatile("fmoved _fpr,fp0");
if (fpr[0] & 0x80000000)
{/* the overflow is negative so copy maxneg into fp0 */
__asm volatile("fmoved _maxneg,fp0");
}
else
{/* the overflow is positive so copy maxpos into fp0 */
__asm volatile("fmoved _maxpos,fp0");
}
}
/* print the contents of fp0 */
__asm volatile("fmoved fp0,_fpr");
printf("\nfp0: 0x%8lx 0x%8lx = %16.15le",fpr[0],fpr[1],*(double *)fpr);
/* zero the exception status bits, and restore the floating point status
register */
st = status&0xffff0000; storefpsr(st);
}
/*=========================================================================*/
main()
{double x,y;
uint32
rc,
ctl0, /* the initial contents of the floating point control register */
ctl1; /* ctl0 with overflow exception mask set to 1 */
union {uint32 zint[2]; double zdbl;} z;
/* set the floating point control register and floating point signal handler
so that floating point overflow errors are handled by catcherr() */
ctl0 = retrievfpcr();
ctl1 = (ctl0&0xffff00ff)|0x00003400;
storefpcr(ctl1);
new_sigvec.sv_handler = catcherr;
new_sigvec.sv_flags = 0;
new_sigvec.sv_mask = 0;
if ((rc = sigvec(SIGFPE,&new_sigvec,&old_sigvec))!=0)
printf("\nmain: sigvec() failed installing new sigvec");
/* generate a floating point overflow error */
x = 1.E200; y = 1.E300;
z.zdbl = x*y;
printf("\n1.E200*1.E300 = %16.15le 0x%8x 0x%8x",z.zdbl,z.zint[0],z.zint[1]);
/* restore the floating point control register and floating point signal
handler to their defaults */
storefpcr(ctl0);
if ((rc = sigvec(SIGFPE,&old_sigvec,&new_sigvec))!=0)
printf("\nmain: sigvec failed restoring default sigvec");
printf("\n");
}
/* end of fpoverflow.c */
Technical Details
Message-ID:
<PEDJA.92Apr9110700@dudley.cs.umd.edu>Path:
arc1-ca.pugleaf.net!sparky!uunet!dtix!mimsy!pedjaShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!sparky!uunet!dtix!mimsy!pedja From: pedja@dudley.cs.umd.edu (Pedja Bogdanovich) Newsgroups: comp.sys.next.programmer Subject: Storing results to FP registers from within FP signal handler Message-ID: <PEDJA.92Apr9110700@dudley.cs.umd.edu> Date: 9 Apr 92 15:07:00 GMT Sender: news@mimsy.umd.edu Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 214