📄 softfloat.c
字号:
int16 aExp, bExp, zExp;
bits32 aSig, bSig, zSig;
int16 expDiff;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
bSig = extractFloat32Frac( b );
bExp = extractFloat32Exp( b );
expDiff = aExp - bExp;
aSig <<= 6;
bSig <<= 6;
if ( 0 < expDiff ) {
if ( aExp == 0xFF ) {
if ( aSig ) return propagateFloat32NaN( a, b );
return a;
}
if ( bExp == 0 ) {
--expDiff;
}
else {
bSig |= 0x20000000;
}
shift32RightJamming( bSig, expDiff, &bSig );
zExp = aExp;
}
else if ( expDiff < 0 ) {
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
return packFloat32( zSign, 0xFF, 0 );
}
if ( aExp == 0 ) {
++expDiff;
}
else {
aSig |= 0x20000000;
}
shift32RightJamming( aSig, - expDiff, &aSig );
zExp = bExp;
}
else {
if ( aExp == 0xFF ) {
if ( aSig | bSig ) return propagateFloat32NaN( a, b );
return a;
}
if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
zSig = 0x40000000 + aSig + bSig;
zExp = aExp;
goto roundAndPack;
}
aSig |= 0x20000000;
zSig = ( aSig + bSig )<<1;
--zExp;
if ( (sbits32) zSig < 0 ) {
zSig = aSig + bSig;
++zExp;
}
roundAndPack:
return roundAndPackFloat32( zSign, zExp, zSig );
}
/*----------------------------------------------------------------------------
| Returns the result of subtracting the absolute values of the single-
| precision floating-point values `a' and `b'. If `zSign' is 1, the
| difference is negated before being returned. `zSign' is ignored if the
| result is a NaN. The subtraction is performed according to the IEC/IEEE
| Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
static float32 subFloat32Sigs( float32 a, float32 b, flag zSign )
{
int16 aExp, bExp, zExp;
bits32 aSig, bSig, zSig;
int16 expDiff;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
bSig = extractFloat32Frac( b );
bExp = extractFloat32Exp( b );
expDiff = aExp - bExp;
aSig <<= 7;
bSig <<= 7;
if ( 0 < expDiff ) goto aExpBigger;
if ( expDiff < 0 ) goto bExpBigger;
if ( aExp == 0xFF ) {
if ( aSig | bSig ) return propagateFloat32NaN( a, b );
float_raise( float_flag_invalid );
return float32_default_nan;
}
if ( aExp == 0 ) {
aExp = 1;
bExp = 1;
}
if ( bSig < aSig ) goto aBigger;
if ( aSig < bSig ) goto bBigger;
return packFloat32( float_rounding_mode == float_round_down, 0, 0 );
bExpBigger:
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
return packFloat32( zSign ^ 1, 0xFF, 0 );
}
if ( aExp == 0 ) {
++expDiff;
}
else {
aSig |= 0x40000000;
}
shift32RightJamming( aSig, - expDiff, &aSig );
bSig |= 0x40000000;
bBigger:
zSig = bSig - aSig;
zExp = bExp;
zSign ^= 1;
goto normalizeRoundAndPack;
aExpBigger:
if ( aExp == 0xFF ) {
if ( aSig ) return propagateFloat32NaN( a, b );
return a;
}
if ( bExp == 0 ) {
--expDiff;
}
else {
bSig |= 0x40000000;
}
shift32RightJamming( bSig, expDiff, &bSig );
aSig |= 0x40000000;
aBigger:
zSig = aSig - bSig;
zExp = aExp;
normalizeRoundAndPack:
--zExp;
return normalizeRoundAndPackFloat32( zSign, zExp, zSig );
}
/*----------------------------------------------------------------------------
| Returns the result of adding the single-precision floating-point values `a'
| and `b'. The operation is performed according to the IEC/IEEE Standard for
| Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
/*
-- fpu operations (fpu_op_i): -- ======================== -- 000 = add, -- 001 = substract, -- 010 = multiply, -- 011 = divide, -- 100 = square root -- 101 = unused -- 110 = unused -- 111 = unused -- Rounding Mode: -- ============== -- 00 = round to nearest even(default), -- 01 = round to zero, -- 10 = round up, -- 11 = round down
*/
void print_roundmode(void)
{
if (float_rounding_mode==float_round_nearest_even) printf("00"); else
if (float_rounding_mode==float_round_to_zero) printf("01"); else
if (float_rounding_mode==float_round_up) printf("10"); else
if (float_rounding_mode==float_round_down) printf("11");
}
float32 float32_add2( float32 a, float32 b )
{
flag aSign, bSign;
aSign = extractFloat32Sign( a );
bSign = extractFloat32Sign( b );
if ( aSign == bSign ) {
return addFloat32Sigs( a, b, aSign );
}
else {
return subFloat32Sigs( a, b, aSign );
}
}
// for FPU testbench
float32 float32_add( float32 a, float32 b )
{
float32 output = float32_add2( a, b );
/*//This can be used for copy&paste test mode
printf("\t\t\twait for CLK_PERIOD; start_i <= '1';\n");
printf("\t\t\topa_i <= X\"%x\";\n",a);
printf("\t\t\topb_i <= X\"%x\";\n",b);
printf("\t\t\tfpu_op_i <= \"000\";\n");
printf("\t\t\trmode_i <= \""); print_roundmode(); printf("\";\n");
printf("\t\t\twait for CLK_PERIOD; start_i <= '0'; wait until ready_o='1';\n");
printf("\t\t\tassert output_o=x\"%x\"\n" ,output);
//for exceptions, but didn't work!!
//printf("\t\t\tassert output_o=x\"%x\" and ine_o='%d' and overflow_o='%d' and underflow_o='%d' and div_zero_o='%d' and qnan_o='%d' \n" ,output,exceptions.ine ,exceptions.overflow, exceptions.underflow, exceptions.div_zero, exceptions.invalid);
printf("\t\t\treport \"Error!!!\"\n");
printf("\t\t\tseverity failure;\n\n");*/
printf("%x \n",a);
printf("%x \n",b);
printf("000\n");
print_roundmode(); printf("\n");
printf("%x \n\n", output);
return output;
}
/*----------------------------------------------------------------------------
| Returns the result of subtracting the single-precision floating-point values
| `a' and `b'. The operation is performed according to the IEC/IEEE Standard
| for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float32 float32_sub2( float32 a, float32 b )
{
flag aSign, bSign;
aSign = extractFloat32Sign( a );
bSign = extractFloat32Sign( b );
if ( aSign == bSign ) {
return subFloat32Sigs( a, b, aSign );
}
else {
return addFloat32Sigs( a, b, aSign );
}
}
// for FPU testbench
float32 float32_sub( float32 a, float32 b )
{
float32 output = float32_sub2( a, b );
/*printf("\t\t\twait for CLK_PERIOD; start_i <= '1';\n");
printf("\t\t\topa_i <= X\"%x\";\n",a);
printf("\t\t\topb_i <= X\"%x\";\n",b);
printf("\t\t\tfpu_op_i <= \"001\";\n");
printf("\t\t\trmode_i <= \""); print_roundmode(); printf("\";\n");
printf("\t\t\twait for CLK_PERIOD; start_i <= '0'; wait until ready_o='1';\n");
printf("\t\t\tassert output_o=x\"%x\"\n" ,output);
printf("\t\t\treport \"Error!!!\"\n");
printf("\t\t\tseverity failure;\n\n");*/
printf("%x \n",a);
printf("%x \n",b);
printf("001\n");
print_roundmode(); printf("\n");
printf("%x \n\n", output);
return output;
}
/*----------------------------------------------------------------------------
| Returns the result of multiplying the single-precision floating-point values
| `a' and `b'. The operation is performed according to the IEC/IEEE Standard
| for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float32 float32_mul2( float32 a, float32 b )
{
flag aSign, bSign, zSign;
int16 aExp, bExp, zExp;
bits32 aSig, bSig, zSig0, zSig1;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
bSig = extractFloat32Frac( b );
bExp = extractFloat32Exp( b );
bSign = extractFloat32Sign( b );
zSign = aSign ^ bSign;
if ( aExp == 0xFF ) {
if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
return propagateFloat32NaN( a, b );
}
if ( ( bExp | bSig ) == 0 ) {
float_raise( float_flag_invalid );
return float32_default_nan;
}
return packFloat32( zSign, 0xFF, 0 );
}
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
if ( ( aExp | aSig ) == 0 ) {
float_raise( float_flag_invalid );
return float32_default_nan;
}
return packFloat32( zSign, 0xFF, 0 );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
}
if ( bExp == 0 ) {
if ( bSig == 0 ) return packFloat32( zSign, 0, 0 );
normalizeFloat32Subnormal( bSig, &bExp, &bSig );
}
zExp = aExp + bExp - 0x7F;
aSig = ( aSig | 0x00800000 )<<7;
bSig = ( bSig | 0x00800000 )<<8;
mul32To64( aSig, bSig, &zSig0, &zSig1 );
zSig0 |= ( zSig1 != 0 );
if ( 0 <= (sbits32) ( zSig0<<1 ) ) {
zSig0 <<= 1;
--zExp;
}
return roundAndPackFloat32( zSign, zExp, zSig0 );
}
// for FPU testbench
float32 float32_mul( float32 a, float32 b )
{
float32 output = float32_mul2( a, b );
/*printf("\t\t\twait for CLK_PERIOD; start_i <= '1';\n");
printf("\t\t\topa_i <= X\"%x\";\n",a);
printf("\t\t\topb_i <= X\"%x\";\n",b);
printf("\t\t\tfpu_op_i <= \"010\";\n");
printf("\t\t\trmode_i <= \""); print_roundmode(); printf("\";\n");
printf("\t\t\twait for CLK_PERIOD; start_i <= '0'; wait until ready_o='1';\n");
printf("\t\t\tassert output_o=x\"%x\"\n" ,output);
printf("\t\t\treport \"Error!!!\"\n");
printf("\t\t\tseverity failure;\n\n");*/
printf("%x \n",a);
printf("%x \n",b);
printf("010\n");
print_roundmode(); printf("\n");
printf("%x \n\n", output);
return output;
}
/*----------------------------------------------------------------------------
| Returns the result of dividing the single-precision floating-point value `a'
| by the corresponding value `b'. The operation is performed according to the
| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float32 float32_div2( float32 a, float32 b )
{
flag aSign, bSign, zSign;
int16 aExp, bExp, zExp;
bits32 aSig, bSig, zSig, rem0, rem1, term0, term1;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
bSig = extractFloat32Frac( b );
bExp = extractFloat32Exp( b );
bSign = extractFloat32Sign( b );
zSign = aSign ^ bSign;
if ( aExp == 0xFF ) {
if ( aSig ) return propagateFloat32NaN( a, b );
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
float_raise( float_flag_invalid );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -