File: [local] / sys / arch / hppa / spmath / sfsub.c (download)
Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:05:46 2008 UTC (16 years, 6 months ago) by nbrk
Branch: OPENBSD_4_2_BASE, MAIN
CVS Tags: jornada-partial-support-wip, HEAD Changes since 1.1: +0 -0 lines
Import of OpenBSD 4.2 release kernel tree with initial code to support
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO
Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)
|
/* $OpenBSD: sfsub.c,v 1.6 2002/11/29 09:27:34 deraadt Exp $ */
/*
(c) Copyright 1986 HEWLETT-PACKARD COMPANY
To anyone who acknowledges that this file is provided "AS IS"
without any express or implied warranty:
permission to use, copy, modify, and distribute this file
for any purpose is hereby granted without fee, provided that
the above copyright notice and this notice appears in all
copies, and that the name of Hewlett-Packard Company not be
used in advertising or publicity pertaining to distribution
of the software without specific, written prior permission.
Hewlett-Packard Company makes no representations about the
suitability of this software for any purpose.
*/
/* @(#)sfsub.c: Revision: 2.7.88.1 Date: 93/12/07 15:07:15 */
#include "float.h"
#include "sgl_float.h"
/*
* Single_subtract: subtract two single precision values.
*/
int
sgl_fsub(leftptr, rightptr, dstptr, status)
sgl_floating_point *leftptr, *rightptr, *dstptr;
unsigned int *status;
{
register unsigned int left, right, result, extent;
register unsigned int signless_upper_left, signless_upper_right, save;
register int result_exponent, right_exponent, diff_exponent;
register int sign_save, jumpsize;
register int inexact = FALSE, underflowtrap;
/* Create local copies of the numbers */
left = *leftptr;
right = *rightptr;
/* A zero "save" helps discover equal operands (for later), *
* and is used in swapping operands (if needed). */
Sgl_xortointp1(left,right,/*to*/save);
/*
* check first operand for NaN's or infinity
*/
if ((result_exponent = Sgl_exponent(left)) == SGL_INFINITY_EXPONENT)
{
if (Sgl_iszero_mantissa(left))
{
if (Sgl_isnotnan(right))
{
if (Sgl_isinfinity(right) && save==0)
{
/*
* invalid since operands are same signed infinity's
*/
if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
Set_invalidflag();
Sgl_makequietnan(result);
*dstptr = result;
return(NOEXCEPTION);
}
/*
* return infinity
*/
*dstptr = left;
return(NOEXCEPTION);
}
}
else
{
/*
* is NaN; signaling or quiet?
*/
if (Sgl_isone_signaling(left))
{
/* trap if INVALIDTRAP enabled */
if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
/* make NaN quiet */
Set_invalidflag();
Sgl_set_quiet(left);
}
/*
* is second operand a signaling NaN?
*/
else if (Sgl_is_signalingnan(right))
{
/* trap if INVALIDTRAP enabled */
if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
/* make NaN quiet */
Set_invalidflag();
Sgl_set_quiet(right);
*dstptr = right;
return(NOEXCEPTION);
}
/*
* return quiet NaN
*/
*dstptr = left;
return(NOEXCEPTION);
}
} /* End left NaN or Infinity processing */
/*
* check second operand for NaN's or infinity
*/
if (Sgl_isinfinity_exponent(right))
{
if (Sgl_iszero_mantissa(right))
{
/* return infinity */
Sgl_invert_sign(right);
*dstptr = right;
return(NOEXCEPTION);
}
/*
* is NaN; signaling or quiet?
*/
if (Sgl_isone_signaling(right))
{
/* trap if INVALIDTRAP enabled */
if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
/* make NaN quiet */
Set_invalidflag();
Sgl_set_quiet(right);
}
/*
* return quiet NaN
*/
*dstptr = right;
return(NOEXCEPTION);
} /* End right NaN or Infinity processing */
/* Invariant: Must be dealing with finite numbers */
/* Compare operands by removing the sign */
Sgl_copytoint_exponentmantissa(left,signless_upper_left);
Sgl_copytoint_exponentmantissa(right,signless_upper_right);
/* sign difference selects sub or add operation. */
if(Sgl_ismagnitudeless(signless_upper_left,signless_upper_right))
{
/* Set the left operand to the larger one by XOR swap *
* First finish the first word using "save" */
Sgl_xorfromintp1(save,right,/*to*/right);
Sgl_xorfromintp1(save,left,/*to*/left);
result_exponent = Sgl_exponent(left);
Sgl_invert_sign(left);
}
/* Invariant: left is not smaller than right. */
if((right_exponent = Sgl_exponent(right)) == 0)
{
/* Denormalized operands. First look for zeroes */
if(Sgl_iszero_mantissa(right))
{
/* right is zero */
if(Sgl_iszero_exponentmantissa(left))
{
/* Both operands are zeros */
Sgl_invert_sign(right);
if(Is_rounding_mode(ROUNDMINUS))
{
Sgl_or_signs(left,/*with*/right);
}
else
{
Sgl_and_signs(left,/*with*/right);
}
}
else
{
/* Left is not a zero and must be the result. Trapped
* underflows are signaled if left is denormalized. Result
* is always exact. */
if( (result_exponent == 0) && Is_underflowtrap_enabled() )
{
/* need to normalize results mantissa */
sign_save = Sgl_signextendedsign(left);
Sgl_leftshiftby1(left);
Sgl_normalize(left,result_exponent);
Sgl_set_sign(left,/*using*/sign_save);
Sgl_setwrapped_exponent(left,result_exponent,unfl);
*dstptr = left;
/* inexact = FALSE */
return(UNDERFLOWEXCEPTION);
}
}
*dstptr = left;
return(NOEXCEPTION);
}
/* Neither are zeroes */
Sgl_clear_sign(right); /* Exponent is already cleared */
if(result_exponent == 0 )
{
/* Both operands are denormalized. The result must be exact
* and is simply calculated. A sum could become normalized and a
* difference could cancel to a true zero. */
if( (/*signed*/int) save >= 0 )
{
Sgl_subtract(left,/*minus*/right,/*into*/result);
if(Sgl_iszero_mantissa(result))
{
if(Is_rounding_mode(ROUNDMINUS))
{
Sgl_setone_sign(result);
}
else
{
Sgl_setzero_sign(result);
}
*dstptr = result;
return(NOEXCEPTION);
}
}
else
{
Sgl_addition(left,right,/*into*/result);
if(Sgl_isone_hidden(result))
{
*dstptr = result;
return(NOEXCEPTION);
}
}
if(Is_underflowtrap_enabled())
{
/* need to normalize result */
sign_save = Sgl_signextendedsign(result);
Sgl_leftshiftby1(result);
Sgl_normalize(result,result_exponent);
Sgl_set_sign(result,/*using*/sign_save);
Sgl_setwrapped_exponent(result,result_exponent,unfl);
*dstptr = result;
/* inexact = FALSE */
return(UNDERFLOWEXCEPTION);
}
*dstptr = result;
return(NOEXCEPTION);
}
right_exponent = 1; /* Set exponent to reflect different bias
* with denomalized numbers. */
}
else
{
Sgl_clear_signexponent_set_hidden(right);
}
Sgl_clear_exponent_set_hidden(left);
diff_exponent = result_exponent - right_exponent;
/*
* Special case alignment of operands that would force alignment
* beyond the extent of the extension. A further optimization
* could special case this but only reduces the path length for this
* infrequent case.
*/
if(diff_exponent > SGL_THRESHOLD)
{
diff_exponent = SGL_THRESHOLD;
}
/* Align right operand by shifting to right */
Sgl_right_align(/*operand*/right,/*shifted by*/diff_exponent,
/*and lower to*/extent);
/* Treat sum and difference of the operands separately. */
if( (/*signed*/int) save >= 0 )
{
/*
* Difference of the two operands. Their can be no overflow. A
* borrow can occur out of the hidden bit and force a post
* normalization phase.
*/
Sgl_subtract_withextension(left,/*minus*/right,/*with*/extent,/*into*/result);
if(Sgl_iszero_hidden(result))
{
/* Handle normalization */
/* A straight forward algorithm would now shift the result
* and extension left until the hidden bit becomes one. Not
* all of the extension bits need participate in the shift.
* Only the two most significant bits (round and guard) are
* needed. If only a single shift is needed then the guard
* bit becomes a significant low order bit and the extension
* must participate in the rounding. If more than a single
* shift is needed, then all bits to the right of the guard
* bit are zeros, and the guard bit may or may not be zero. */
sign_save = Sgl_signextendedsign(result);
Sgl_leftshiftby1_withextent(result,extent,result);
/* Need to check for a zero result. The sign and exponent
* fields have already been zeroed. The more efficient test
* of the full object can be used.
*/
if(Sgl_iszero(result))
/* Must have been "x-x" or "x+(-x)". */
{
if(Is_rounding_mode(ROUNDMINUS)) Sgl_setone_sign(result);
*dstptr = result;
return(NOEXCEPTION);
}
result_exponent--;
/* Look to see if normalization is finished. */
if(Sgl_isone_hidden(result))
{
if(result_exponent==0)
{
/* Denormalized, exponent should be zero. Left operand *
* was normalized, so extent (guard, round) was zero */
goto underflow;
}
else
{
/* No further normalization is needed. */
Sgl_set_sign(result,/*using*/sign_save);
Ext_leftshiftby1(extent);
goto round;
}
}
/* Check for denormalized, exponent should be zero. Left *
* operand was normalized, so extent (guard, round) was zero */
if(!(underflowtrap = Is_underflowtrap_enabled()) &&
result_exponent==0) goto underflow;
/* Shift extension to complete one bit of normalization and
* update exponent. */
Ext_leftshiftby1(extent);
/* Discover first one bit to determine shift amount. Use a
* modified binary search. We have already shifted the result
* one position right and still not found a one so the remainder
* of the extension must be zero and simplifies rounding. */
/* Scan bytes */
while(Sgl_iszero_hiddenhigh7mantissa(result))
{
Sgl_leftshiftby8(result);
if((result_exponent -= 8) <= 0 && !underflowtrap)
goto underflow;
}
/* Now narrow it down to the nibble */
if(Sgl_iszero_hiddenhigh3mantissa(result))
{
/* The lower nibble contains the normalizing one */
Sgl_leftshiftby4(result);
if((result_exponent -= 4) <= 0 && !underflowtrap)
goto underflow;
}
/* Select case were first bit is set (already normalized)
* otherwise select the proper shift. */
if((jumpsize = Sgl_hiddenhigh3mantissa(result)) > 7)
{
/* Already normalized */
if(result_exponent <= 0) goto underflow;
Sgl_set_sign(result,/*using*/sign_save);
Sgl_set_exponent(result,/*using*/result_exponent);
*dstptr = result;
return(NOEXCEPTION);
}
Sgl_sethigh4bits(result,/*using*/sign_save);
switch(jumpsize)
{
case 1:
{
Sgl_leftshiftby3(result);
result_exponent -= 3;
break;
}
case 2:
case 3:
{
Sgl_leftshiftby2(result);
result_exponent -= 2;
break;
}
case 4:
case 5:
case 6:
case 7:
{
Sgl_leftshiftby1(result);
result_exponent -= 1;
break;
}
}
if(result_exponent > 0)
{
Sgl_set_exponent(result,/*using*/result_exponent);
*dstptr = result; /* Sign bit is already set */
return(NOEXCEPTION);
}
/* Fixup potential underflows */
underflow:
if(Is_underflowtrap_enabled())
{
Sgl_set_sign(result,sign_save);
Sgl_setwrapped_exponent(result,result_exponent,unfl);
*dstptr = result;
/* inexact = FALSE */
return(UNDERFLOWEXCEPTION);
}
/*
* Since we cannot get an inexact denormalized result,
* we can now return.
*/
Sgl_right_align(result,/*by*/(1-result_exponent),extent);
Sgl_clear_signexponent(result);
Sgl_set_sign(result,sign_save);
*dstptr = result;
return(NOEXCEPTION);
} /* end if(hidden...)... */
/* Fall through and round */
} /* end if(save >= 0)... */
else
{
/* Add magnitudes */
Sgl_addition(left,right,/*to*/result);
if(Sgl_isone_hiddenoverflow(result))
{
/* Prenormalization required. */
Sgl_rightshiftby1_withextent(result,extent,extent);
Sgl_arithrightshiftby1(result);
result_exponent++;
} /* end if hiddenoverflow... */
} /* end else ...sub magnitudes... */
/* Round the result. If the extension is all zeros,then the result is
* exact. Otherwise round in the correct direction. No underflow is
* possible. If a postnormalization is necessary, then the mantissa is
* all zeros so no shift is needed. */
round:
if(Ext_isnotzero(extent))
{
inexact = TRUE;
switch(Rounding_mode())
{
case ROUNDNEAREST: /* The default. */
if(Ext_isone_sign(extent))
{
/* at least 1/2 ulp */
if(Ext_isnotzero_lower(extent) ||
Sgl_isone_lowmantissa(result))
{
/* either exactly half way and odd or more than 1/2ulp */
Sgl_increment(result);
}
}
break;
case ROUNDPLUS:
if(Sgl_iszero_sign(result))
{
/* Round up positive results */
Sgl_increment(result);
}
break;
case ROUNDMINUS:
if(Sgl_isone_sign(result))
{
/* Round down negative results */
Sgl_increment(result);
}
case ROUNDZERO:;
/* truncate is simple */
} /* end switch... */
if(Sgl_isone_hiddenoverflow(result)) result_exponent++;
}
if(result_exponent == SGL_INFINITY_EXPONENT)
{
/* Overflow */
if(Is_overflowtrap_enabled())
{
Sgl_setwrapped_exponent(result,result_exponent,ovfl);
*dstptr = result;
if (inexact) {
if (Is_inexacttrap_enabled())
return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
else Set_inexactflag();
}
return(OVERFLOWEXCEPTION);
}
else
{
Set_overflowflag();
inexact = TRUE;
Sgl_setoverflow(result);
}
}
else Sgl_set_exponent(result,result_exponent);
*dstptr = result;
if(inexact) {
if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
else Set_inexactflag();
}
return(NOEXCEPTION);
}