Mercurial > flash_v2
diff packages/hal/mips/arch/current/src/mipsfp.c @ 62:7a6ac9edc838 ecos-sw-2000-01-24
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
| author | jlarmour |
|---|---|
| date | Mon, 24 Jan 2000 21:43:17 +0000 |
| parents | 641b639be825 |
| children | c38311975d4f |
line wrap: on
line diff
--- a/packages/hal/mips/arch/current/src/mipsfp.c +++ b/packages/hal/mips/arch/current/src/mipsfp.c @@ -263,7 +263,27 @@ typedef enum { // FUNCTIONS -#define issubnormal(_x_) ((_x_)->number.exponent == 0) +#define issubnormal(_x_) ((_x_).number.exponent == 0) + +// These functions convert between single precision floating point numbers +// represented in register or union form. This is required because endian-ness +// matters when a 32-bit float is in a 64-bit register. + +static __inline__ void +reg2flt( CYG_HAL_FPU_REG *fpu_reg_p, Cyg_libm_ieee_float_shape_type *flt) +{ +#if defined(CYGHWR_HAL_MIPS_FPU_32BIT) || (CYG_BYTEORDER == CYG_LSBFIRST) + flt->asi32 = *(cyg_int32 *)fpu_reg_p; +#else + flt->asi32 = *((cyg_int32 *)fpu_reg_p + 1); +# endif +} // reg2flt() + +static __inline__ void +flt2reg( Cyg_libm_ieee_float_shape_type *flt, CYG_HAL_FPU_REG *fpu_reg_p ) +{ + *fpu_reg_p = flt->asi32; +} // flt2reg() // This function returns non-zero if the exception has been handled // successfully. @@ -355,13 +375,18 @@ cyg_hal_mips_process_fpe( HAL_SavedRegis case DIV_INSN: if (fp64bit) { - Cyg_libm_ieee_double_shape_type *s1, *s2; + Cyg_libm_ieee_double_shape_type s1, s2; + + s1.asi64 = *srcreg1; + s2.asi64 = *srcreg2; - s1 = (Cyg_libm_ieee_double_shape_type *)srcreg1; - s2 = (Cyg_libm_ieee_double_shape_type *)srcreg2; - - if (issubnormal(s1)) { // flush to 0 and restart - s1->value=0.0; + if ( issubnormal( s1 ) ) { // flush to 0 and restart + // but preserve sign + if (s1.number.sign) + s1.value = -0.0; + else + s1.value = 0.0; + *srcreg1 = s1.asi64; handled++; } @@ -371,59 +396,95 @@ cyg_hal_mips_process_fpe( HAL_SavedRegis // get 0/0 even when the program explicitly checked for // denominator != 0. That's also why we check s1 first. - else if (issubnormal(s2)) { // flush to 0 and restart - s2->value=0.0; + else if ( issubnormal( s2 ) ) { // flush to 0 and restart + // but preserve sign + if (s2.number.sign) + s2.value = -0.0; + else + s2.value = 0.0; + *srcreg2 = s2.asi64; handled++; } + } else { // 32-bit - Cyg_libm_ieee_float_shape_type *s1, *s2; + Cyg_libm_ieee_float_shape_type s1, s2; + + reg2flt( srcreg1, &s1 ); + reg2flt( srcreg2, &s2 ); - s1 = (Cyg_libm_ieee_float_shape_type *)srcreg1; - s2 = (Cyg_libm_ieee_float_shape_type *)srcreg2; - - if (issubnormal(s1)) { // flush to 0 and restart - s1->value=0.0; + if ( issubnormal( s1 )) { // flush to 0 and restart + // but preserve sign + if (s1.number.sign) + s1.value = -0.0; + else + s1.value = 0.0; + flt2reg( &s1, srcreg1 ); handled++; } - else if (issubnormal(s2)) { // flush to 0 and restart - s2->value=0.0; + else if ( issubnormal( s2 ) ) { // flush to 0 and restart + // but preserve sign + if (s2.number.sign) + s2.value = -0.0; + else + s2.value = 0.0; + flt2reg( &s2, srcreg2 ); handled++; } } break; case SQRT_INSN: - if (fp64bit) { - Cyg_libm_ieee_double_shape_type *d, *s; + if ( fp64bit ) { + Cyg_libm_ieee_double_shape_type d, s; - d = (Cyg_libm_ieee_double_shape_type *)dstreg; - s = (Cyg_libm_ieee_double_shape_type *)srcreg1; + d.asi64 = *dstreg; + s.asi64 = *srcreg1; - if (issubnormal(s)) { // Sqrt of something tiny is 0 + if ( issubnormal( s ) ) { // Sqrt of something tiny is 0 // if this is a delay slot, we can't restart properly - // so clear the source register instead - if (delay_slot) - s->value=0.0; - else { - d->value=0.0; + // so if it is subnormal, clear the source register instead + if ( delay_slot ) { + // but preserve sign + if (s.number.sign) + s.value = -0.0; + else + s.value = 0.0; + *srcreg1 = s.asi64; + } else { + // but preserve sign + if (s.number.sign) + d.value = -0.0; + else + d.value = 0.0; + *dstreg = d.asi64; regs->pc += 4; // We've dealt with this so move on } handled++; } } else { // 32-bit - Cyg_libm_ieee_float_shape_type *d, *s; + Cyg_libm_ieee_float_shape_type d, s; - d = (Cyg_libm_ieee_float_shape_type *)dstreg; - s = (Cyg_libm_ieee_float_shape_type *)srcreg1; + reg2flt( dstreg, &d ); + reg2flt( srcreg1, &s ); - if (issubnormal(s)) { // Sqrt of something tiny is 0 + if ( issubnormal( s ) ) { // Sqrt of something tiny is 0 // if this is a delay slot, we can't restart properly - // so clear the source register instead - if (delay_slot) - s->value=0.0; - else { - d->value=0.0; + // so if it is subnormal, clear the source register instead + if ( delay_slot ) { + // but preserve sign + if (s.number.sign) + s.value = -0.0; + else + s.value = 0.0; + flt2reg( &s, srcreg1 ); + } else { + // but preserve sign + if (s.number.sign) + d.value = -0.0; + else + d.value = 0.0; + flt2reg( &d, dstreg ); regs->pc += 4; // We've dealt with this so move on } handled++; @@ -433,85 +494,282 @@ cyg_hal_mips_process_fpe( HAL_SavedRegis case ABS_INSN: // We may as well do this right if we can - if (fp64bit) { - Cyg_libm_ieee_double_shape_type *d, *s; + if ( fp64bit ) { + Cyg_libm_ieee_double_shape_type d, s; - d = (Cyg_libm_ieee_double_shape_type *)dstreg; - s = (Cyg_libm_ieee_double_shape_type *)srcreg1; + d.asi64 = *dstreg; + s.asi64 = *srcreg1; // if this is a delay slot, we can't restart properly - // so clear the source register instead - if (delay_slot) { - s->value=0.0; + // so if it is subnormal, clear the source register instead + if ( delay_slot ) { + if ( issubnormal( s ) ) { + // The sign is still important for abs in case + // there are any further operations on the same + // register + if (s.number.sign) + s.value = -0.0; + else + s.value = 0.0; + *srcreg1 = s.asi64; + handled++; + } } else { - d->asi64 = s->asi64; - d->number.sign = 0; + d.asi64 = s.asi64; + d.number.sign = 0; + *dstreg = d.asi64; regs->pc += 4; + handled++; } } else { // 32-bit - Cyg_libm_ieee_float_shape_type *d, *s; + Cyg_libm_ieee_float_shape_type d, s; + + reg2flt( dstreg, &d ); + reg2flt( srcreg1, &s ); - d = (Cyg_libm_ieee_float_shape_type *)dstreg; - s = (Cyg_libm_ieee_float_shape_type *)srcreg1; + // if this is a delay slot, we can't restart properly + // so if it is subnormal, clear the source register instead + if ( delay_slot ) { + if ( issubnormal( s ) ) { + // The sign is still important for abs in case + // there are any further operations on the same + // register + if (s.number.sign) + s.value = -0.0; + else + s.value = 0.0; + flt2reg( &s, srcreg1 ); + handled++; + } + } else { + d.asi32 = s.asi32; + d.number.sign = 0; + flt2reg( &d, dstreg ); + regs->pc += 4; + handled++; + } + } + break; + + case MOV_INSN: + // We may as well do this right if we can + if ( fp64bit ) { + Cyg_libm_ieee_double_shape_type d, s; + + d.asi64 = *dstreg; + s.asi64 = *srcreg1; // if this is a delay slot, we can't restart properly - // so clear the source register instead - if (delay_slot) { - s->value=0.0; + // so if it is subnormal, clear the source register instead + if ( delay_slot ) { + if ( issubnormal( s ) ) { + // but preserve sign + if (s.number.sign) + s.value = -0.0; + else + s.value = 0.0; + *srcreg1 = s.asi64; + handled++; + } } else { - d->asi32 = s->asi32; - d->number.sign = 0; + d.asi64 = s.asi64; + *dstreg = d.asi64; regs->pc += 4; + handled++; + } + } else { // 32-bit + Cyg_libm_ieee_float_shape_type d, s; + + reg2flt( dstreg, &d ); + reg2flt( srcreg1, &s ); + + // if this is a delay slot, we can't restart properly + // so if it is subnormal, clear the source register instead + if ( delay_slot ) { + if ( issubnormal( s ) ) { + // The sign is still important for abs in case + // there are any further operations on the same + // register + if (s.number.sign) + s.value = -0.0; + else + s.value = 0.0; + flt2reg( &s, srcreg1 ); + handled++; + } + } else { + d.asi32 = s.asi32; + flt2reg( &d, dstreg ); + regs->pc += 4; + handled++; } } - handled++; break; case NEG_INSN: // We may as well do this right if we can - if (fp64bit) { - Cyg_libm_ieee_double_shape_type *d, *s; + if ( fp64bit ) { + Cyg_libm_ieee_double_shape_type d, s; - d = (Cyg_libm_ieee_double_shape_type *)dstreg; - s = (Cyg_libm_ieee_double_shape_type *)srcreg1; + d.asi64 = *dstreg; + s.asi64 = *srcreg1; // if this is a delay slot, we can't restart properly - // so clear the source register instead - if (delay_slot) { - s->value=0.0; + // so if it is subnormal, clear the source register instead + if ( delay_slot ) { + if ( issubnormal( s ) ) { + // but preserve sign + if (s.number.sign) + s.value = -0.0; + else + s.value = 0.0; + *srcreg1 = s.asi64; + handled++; + } } else { - d->asi64 = s->asi64; - d->number.sign = s->number.sign ? 0 : 1; + d.asi64 = s.asi64; + d.number.sign = s.number.sign ? 0 : 1; + *dstreg = d.asi64; regs->pc += 4; + handled++; } } else { // 32-bit - Cyg_libm_ieee_float_shape_type *d, *s; + Cyg_libm_ieee_float_shape_type d, s; - d = (Cyg_libm_ieee_float_shape_type *)dstreg; - s = (Cyg_libm_ieee_float_shape_type *)srcreg1; + reg2flt( dstreg, &d ); + reg2flt( srcreg1, &s ); // if this is a delay slot, we can't restart properly - // so clear the source register instead - if (delay_slot) { - s->value=0.0; + // so if it is subnormal, clear the source register instead + if ( delay_slot ) { + if ( issubnormal( s ) ) { + // but preserve sign + if (s.number.sign) + s.value = -0.0; + else + s.value = 0.0; + flt2reg( &s, srcreg1 ); + handled++; + } } else { - d->asi32 = s->asi32; - d->number.sign = s->number.sign ? 0 : 1; + d.asi32 = s.asi32; + d.number.sign = s.number.sign ? 0 : 1; + flt2reg( &d, dstreg ); regs->pc += 4; + handled++; } } - handled++; + break; + + // We can't do much about floating-point to fixed-point arithmetic + // without emulating the FPU here ourselves! + // So simply zero denormalized numbers + case ROUNDL_INSN: + case TRUNCL_INSN: + case CEILL_INSN: + case FLOORL_INSN: + case ROUNDW_INSN: + case TRUNCW_INSN: + case CEILW_INSN: + case FLOORW_INSN: + case CVTS_INSN: + case CVTD_INSN: + case CVTW_INSN: + case CVTL_INSN: + + if ( fp64bit ) { + Cyg_libm_ieee_double_shape_type s; + + s.asi64 = *srcreg1; + + // just try and 0 the source register if it is subnormal + if ( issubnormal( s ) ) { + // but preserve sign + if (s.number.sign) + s.value = -0.0; + else + s.value = 0.0; + *srcreg1 = s.asi64; + handled++; + } + } else { // 32-bit + Cyg_libm_ieee_float_shape_type s; + + reg2flt( srcreg1, &s ); + + // just try and 0 the source register if it is subnormal + if ( issubnormal( s ) ) { + // but preserve sign + if (s.number.sign) + s.value = -0.0; + else + s.value = 0.0; + flt2reg( &s, srcreg1 ); + handled++; + } + } break; default: + // check for floating-point compare (C.cond.fmt) + if ( (insn & 0x30) == 0x30 ) { + if (fp64bit) { + Cyg_libm_ieee_double_shape_type s1, s2; + + s1.asi64 = *srcreg1; + s2.asi64 = *srcreg2; + + if ( issubnormal( s1 ) ) { // flush to 0 and restart + // but preserve sign + if (s1.number.sign) + s1.value = -0.0; + else + s1.value = 0.0; + *srcreg1 = s1.asi64; + handled++; + } + + if ( issubnormal( s2 ) ) { // flush to 0 and restart + // but preserve sign + if (s2.number.sign) + s2.value = -0.0; + else + s2.value = 0.0; + *srcreg2 = s2.asi64; + handled++; + } + + } else { // 32-bit + Cyg_libm_ieee_float_shape_type s1, s2; + + reg2flt( srcreg1, &s1 ); + reg2flt( srcreg2, &s2 ); + + if ( issubnormal( s1 )) { // flush to 0 and restart + // but preserve sign + if (s1.number.sign) + s1.value = -0.0; + else + s1.value = 0.0; + flt2reg( &s1, srcreg1 ); + handled++; + } + if ( issubnormal( s2 ) ) { // flush to 0 and restart + // but preserve sign + if (s2.number.sign) + s2.value = -0.0; + else + s2.value = 0.0; + flt2reg( &s2, srcreg2 ); + handled++; + } + } // else + } // if break; } // switch - - // As well as all the other opcodes in the enum, there are also all - // the floating point compare operations between 48 and 63 - } + } // if (computational_insn && !fixedpoint) - if (handled) { + if ( handled != 0) { // We must clear the cause and flag bits before restoring FPCR31 regs->fcr31 &= ~(FCR31_CAUSE_E | FCR31_CAUSE_V | FCR31_CAUSE_Z | FCR31_CAUSE_O | FCR31_CAUSE_U | FCR31_CAUSE_I | @@ -520,7 +778,7 @@ cyg_hal_mips_process_fpe( HAL_SavedRegis } - CYG_REPORT_RETVAL(handled); + CYG_REPORT_RETVAL( handled ); return handled; } // cyg_hal_mips_process_fpe()
