diff -urN glibc-2.5/ports/sysdeps/arm/eabi/bits/fenv.h glibc-2.5/ports/sysdeps/arm/eabi/bits/fenv.h --- glibc-2.5/ports/sysdeps/arm/eabi/bits/fenv.h 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/bits/fenv.h 2008-04-02 13:35:39.000000000 +1000 @@ -20,7 +20,7 @@ # error "Never use directly; include instead." #endif -/* Define bits representing exceptions in the FPU status word. */ +/* Define bits representing exceptions in the VFP FPU status word. */ enum { FE_INVALID = 1, @@ -55,6 +55,40 @@ #define FE_TOWARDZERO FE_TOWARDZERO }; +/* Define bits representing exceptions in the CRUNCH FPU status word. */ +enum + { + FE_CRUNCH_INVALID = (1), +#define FE_CRUNCH_INVALID FE_CRUNCH_INVALID + FE_CRUNCH_OVERFLOW = (4), +#define FE_CRUNCH_OVERFLOW FE_CRUNCH_OVERFLOW + FE_CRUNCH_UNDERFLOW = (8), +#define FE_CRUNCH_UNDERFLOW FE_CRUNCH_UNDERFLOW + FE_CRUNCH_INEXACT = (16), +#define FE_CRUNCH_INEXACT FE_CRUNCH_INEXACT + }; + +/* Amount to shift by to convert an exception to a mask bit. */ +#define FE_CRUNCH_EXCEPT_SHIFT 5 + +/* All supported exceptions, except DIVBYZERO. */ +#define FE_CRUNCH_ALL_EXCEPT \ + (FE_CRUNCH_INVALID | FE_CRUNCH_OVERFLOW | FE_CRUNCH_UNDERFLOW | FE_CRUNCH_INEXACT) + +/* CRUNCH supports all of the four defined rounding modes. */ +enum + { + FE_CRUNCH_TONEAREST = 0, +#define FE_CRUNCH_TONEAREST FE_CRUNCH_TONEAREST + FE_CRUNCH_TOWARDZERO = 0x400, +#define FE_CRUNCH_TOWARDZERO FE_CRUNCH_TOWARDZERO + FE_CRUNCH_DOWNWARD = 0x800, +#define FE_CRUNCH_DOWNWARD FE_CRUNCH_DOWNWARD + FE_CRUNCH_UPWARD = 0xc00 +#define FE_CRUNCH_UPWARD FE_CRUNCH_UPWARD + }; + + /* Type representing exception flags. */ typedef unsigned int fexcept_t; diff -urN glibc-2.5/ports/sysdeps/arm/eabi/fclrexcpt.c glibc-2.5/ports/sysdeps/arm/eabi/fclrexcpt.c --- glibc-2.5/ports/sysdeps/arm/eabi/fclrexcpt.c 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/fclrexcpt.c 2008-04-02 13:25:09.000000000 +1000 @@ -48,6 +48,26 @@ return 0; } + if (GLRO (dl_hwcap) & HWCAP_ARM_CRUNCH) + { + unsigned long int temp; + + /* Mask out unsupported bits/exceptions. */ + excepts &= FE_CRUNCH_ALL_EXCEPT; + + /* Get the current floating point status. */ + _FPU_CRUNCH_GETCW (temp); + + /* Clear the relevant bits. */ + temp = (temp & ~FE_CRUNCH_ALL_EXCEPT) | (temp & FE_CRUNCH_ALL_EXCEPT & ~excepts); + + /* Put the new data in effect. */ + _FPU_CRUNCH_SETCW (temp); + + /* Success. */ + return 0; + } + /* Unsupported, so fail. */ return 1; } diff -urN glibc-2.5/ports/sysdeps/arm/eabi/fedisblxcpt.c glibc-2.5/ports/sysdeps/arm/eabi/fedisblxcpt.c --- glibc-2.5/ports/sysdeps/arm/eabi/fedisblxcpt.c 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/fedisblxcpt.c 2008-04-02 13:29:44.000000000 +1000 @@ -46,6 +46,23 @@ return old_exc; } + if (GLRO (dl_hwcap) & HWCAP_ARM_CRUNCH) + { + unsigned long int new_exc, old_exc; + + _FPU_CRUNCH_GETCW(new_exc); + + old_exc = (new_exc >> FE_CRUNCH_EXCEPT_SHIFT) & FE_CRUNCH_ALL_EXCEPT; + + excepts &= FE_CRUNCH_ALL_EXCEPT; + + new_exc &= ~(excepts << FE_CRUNCH_EXCEPT_SHIFT); + + _FPU_CRUNCH_SETCW(new_exc); + + return old_exc; + } + /* Unsupported, so return -1 for failure. */ return -1; } diff -urN glibc-2.5/ports/sysdeps/arm/eabi/feenablxcpt.c glibc-2.5/ports/sysdeps/arm/eabi/feenablxcpt.c --- glibc-2.5/ports/sysdeps/arm/eabi/feenablxcpt.c 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/feenablxcpt.c 2008-04-02 13:30:30.000000000 +1000 @@ -46,6 +46,23 @@ return old_exc; } + if (GLRO (dl_hwcap) & HWCAP_ARM_CRUNCH) + { + unsigned long int new_exc, old_exc; + + _FPU_CRUNCH_GETCW(new_exc); + + old_exc = (new_exc >> FE_CRUNCH_EXCEPT_SHIFT) & FE_CRUNCH_ALL_EXCEPT; + + excepts &= FE_CRUNCH_ALL_EXCEPT; + + new_exc |= (excepts << FE_CRUNCH_EXCEPT_SHIFT); + + _FPU_CRUNCH_SETCW(new_exc); + + return old_exc; + } + /* Unsupported, so return -1 for failure. */ return -1; } diff -urN glibc-2.5/ports/sysdeps/arm/eabi/fegetenv.c glibc-2.5/ports/sysdeps/arm/eabi/fegetenv.c --- glibc-2.5/ports/sysdeps/arm/eabi/fegetenv.c 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/fegetenv.c 2008-04-02 13:31:08.000000000 +1000 @@ -38,6 +38,16 @@ return 0; } + if (GLRO (dl_hwcap) & HWCAP_ARM_CRUNCH) + { + unsigned long int temp; + _FPU_CRUNCH_GETCW (temp); + envp->__cw = temp; + + /* Success. */ + return 0; + } + /* Unsupported, so fail. */ return 1; } diff -urN glibc-2.5/ports/sysdeps/arm/eabi/fegetexcept.c glibc-2.5/ports/sysdeps/arm/eabi/fegetexcept.c --- glibc-2.5/ports/sysdeps/arm/eabi/fegetexcept.c 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/fegetexcept.c 2008-04-02 13:31:40.000000000 +1000 @@ -38,6 +38,15 @@ return (temp >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT; } + if (GLRO (dl_hwcap) & HWCAP_ARM_CRUNCH) + { + unsigned long temp; + + _FPU_CRUNCH_GETCW (temp); + + return (temp >> FE_CRUNCH_EXCEPT_SHIFT) & FE_CRUNCH_ALL_EXCEPT; + } + /* Unsupported. Return all exceptions disabled. */ return 0; } diff -urN glibc-2.5/ports/sysdeps/arm/eabi/fegetround.c glibc-2.5/ports/sysdeps/arm/eabi/fegetround.c --- glibc-2.5/ports/sysdeps/arm/eabi/fegetround.c 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/fegetround.c 2008-04-02 13:32:18.000000000 +1000 @@ -38,6 +38,16 @@ return temp & FE_TOWARDZERO; } + if (GLRO (dl_hwcap) & HWCAP_ARM_CRUNCH) + { + unsigned int temp; + + /* Get the current environment. */ + _FPU_CRUNCH_GETCW (temp); + + return temp & FE_CRUNCH_UPWARD; + } + /* The current soft-float implementation only handles TONEAREST. */ return FE_TONEAREST; } diff -urN glibc-2.5/ports/sysdeps/arm/eabi/feholdexcpt.c glibc-2.5/ports/sysdeps/arm/eabi/feholdexcpt.c --- glibc-2.5/ports/sysdeps/arm/eabi/feholdexcpt.c 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/feholdexcpt.c 2008-04-02 13:36:24.000000000 +1000 @@ -47,6 +47,25 @@ return 0; } + if (GLRO (dl_hwcap) & HWCAP_ARM_CRUNCH) + { + unsigned long int temp; + + /* Store the environment. */ + _FPU_CRUNCH_GETCW(temp); + envp->__cw = temp; + + /* Now set all exceptions to non-stop. */ + temp &= ~(FE_CRUNCH_ALL_EXCEPT << FE_CRUNCH_EXCEPT_SHIFT); + + /* And clear all exception flags. */ + temp &= ~FE_CRUNCH_ALL_EXCEPT; + + _FPU_CRUNCH_SETCW(temp); + + return 0; + } + /* Unsupported, so fail. */ return 1; } diff -urN glibc-2.5/ports/sysdeps/arm/eabi/fesetenv.c glibc-2.5/ports/sysdeps/arm/eabi/fesetenv.c --- glibc-2.5/ports/sysdeps/arm/eabi/fesetenv.c 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/fesetenv.c 2008-04-02 13:43:31.000000000 +1000 @@ -48,6 +48,26 @@ return 0; } + if (GLRO (dl_hwcap) & HWCAP_ARM_CRUNCH) + { + unsigned int temp; + + _FPU_CRUNCH_GETCW (temp); + temp &= _FPU_CRUNCH_RESERVED; + + if (envp == FE_DFL_ENV) + temp |= _FPU_CRUNCH_DEFAULT; + else if (envp == FE_NOMASK_ENV) + temp |= _FPU_CRUNCH_IEEE; + else + temp |= envp->__cw & ~_FPU_CRUNCH_RESERVED; + + _FPU_CRUNCH_SETCW (temp); + + /* Success. */ + return 0; + } + /* Unsupported, so fail. */ return 1; } diff -urN glibc-2.5/ports/sysdeps/arm/eabi/fesetround.c glibc-2.5/ports/sysdeps/arm/eabi/fesetround.c --- glibc-2.5/ports/sysdeps/arm/eabi/fesetround.c 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/fesetround.c 2008-04-02 13:57:35.000000000 +1000 @@ -45,6 +45,24 @@ default: return 1; } } + else if (GLRO (dl_hwcap) & HWCAP_ARM_CRUNCH) + { + fpu_control_t temp; + + switch (round) + { + case FE_CRUNCH_TONEAREST: + case FE_CRUNCH_UPWARD: + case FE_CRUNCH_DOWNWARD: + case FE_CRUNCH_TOWARDZERO: + _FPU_CRUNCH_GETCW (temp); + temp = (temp & ~FE_CRUNCH_UPWARD) | round; + _FPU_CRUNCH_SETCW (temp); + return 0; + default: + return 1; + } + } else if (round == FE_TONEAREST) /* This is the only supported rounding mode for soft-fp. */ diff -urN glibc-2.5/ports/sysdeps/arm/eabi/fpu_control.h glibc-2.5/ports/sysdeps/arm/eabi/fpu_control.h --- glibc-2.5/ports/sysdeps/arm/eabi/fpu_control.h 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/fpu_control.h 2008-04-02 13:43:05.000000000 +1000 @@ -45,6 +45,86 @@ #define _FPU_SETCW(cw) \ __asm__ __volatile__ ("mcr p10, 7, %0, cr1, cr0, 0" : : "r" (cw)) +/* CRUNCH SECTION */ + +/* DSPSC register: (from EP9312 User's Guide) + * + * bits 31..29 - DAID + * bits 28..26 - HVID + * bits 25..24 - RSVD + * bit 23 - ISAT + * bit 22 - UI + * bit 21 - INT + * bit 20 - AEXC + * bits 19..18 - SAT + * bits 17..16 - FCC + * bit 15 - V + * bit 14 - FWDEN + * bit 13 - Invalid + * bit 12 - Denorm + * bits 11..10 - RM + * bits 9..5 - IXE, UFE, OFE, RSVD, IOE + * bits 4..0 - IX, UF, OF, RSVD, IO + */ + +/* masking of interrupts */ +#define _FPU_CRUNCH_MASK_IM (1 << 5) /* invalid operation */ +#define _FPU_CRUNCH_MASK_ZM 0 /* divide by zero */ +#define _FPU_CRUNCH_MASK_OM (1 << 7) /* overflow */ +#define _FPU_CRUNCH_MASK_UM (1 << 8) /* underflow */ +#define _FPU_CRUNCH_MASK_PM (1 << 9) /* inexact */ +#define _FPU_CRUNCH_MASK_DM 0 /* denormalized operation */ + +/* Some bits in the FPSCR are not yet defined. They must be preserved when + modifying the contents. */ +#define _FPU_CRUNCH_RESERVED 0x03000042 +#define _FPU_CRUNCH_DEFAULT 0x00b00000 +/* Default + exceptions enabled. */ +#define _FPU_CRUNCH_IEEE (_FPU_CRUNCH_DEFAULT | 0x000003a0) + + +/* Macros for accessing the hardware control word. */ +/* cfmvr64l %1, mvdx0 */ +/* cfmvr64h %2, mvdx0 */ +/* cfmv32sc mvdx0, dspsc */ +/* cfmvr64l %0, mvdx0 */ +/* cfmv64lr mvdx0, %1 */ +/* cfmv64hr mvdx0, %2 */ +#define _FPU_CRUNCH_GETCW(cw) ({ \ + register int __t1, __t2; \ + \ + __asm__ volatile ( \ + "mrc p5, 0, %1, cr0, cr0, 0\n\t" \ + "mrc p5, 0, %2, cr0, cr0, 1\n\t" \ + "cdp p4, 0, cr0, cr0, cr0, 7\n\t" \ + "mrc p5, 0, %0, cr0, cr0, 0\n\t" \ + "mcr p5, 0, %1, cr0, cr0, 0\n\t" \ + "mcr p5, 0, %2, cr0, cr0, 1" \ + : "=r" (cw), "=r" (__t1), "=r" (__t2) \ + ); \ +}) + +/* cfmvr64l %1, mvdx0 */ +/* cfmvr64h %2, mvdx0 */ +/* cfmv64lr mvdx0, %0 */ +/* cfmvsc32 dspsc, mvdx0 */ +/* cfmv64lr mvdx0, %1 */ +/* cfmv64hr mvdx0, %2 */ +#define _FPU_CRUNCH_SETCW(cw) ({ \ + register int __t1, __t2; \ + \ + __asm__ volatile ( \ + "mrc p5, 0, %0, cr0, cr0, 0\n\t" \ + "mrc p5, 0, %1, cr0, cr0, 1\n\t" \ + "mcr p5, 0, %2, cr0, cr0, 0\n\t" \ + "cdp p4, 1, cr0, cr0, cr0, 7\n\t" \ + "mcr p5, 0, %0, cr0, cr0, 0\n\t" \ + "mcr p5, 0, %1, cr0, cr0, 1\n\t" \ + : "=r" (__t1), "=r" (__t2) : "r" (cw) \ + ); \ +}) + + /* Default control word set at startup. */ extern fpu_control_t __fpu_control; diff -urN glibc-2.5/ports/sysdeps/arm/eabi/fraiseexcpt.c glibc-2.5/ports/sysdeps/arm/eabi/fraiseexcpt.c --- glibc-2.5/ports/sysdeps/arm/eabi/fraiseexcpt.c 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/fraiseexcpt.c 2008-04-07 16:48:09.000000000 +1000 @@ -103,6 +103,12 @@ return 0; } + if (GLRO (dl_hwcap) & HWCAP_ARM_CRUNCH) + { + /* Unsupported, for now. */ + return 1; + } + /* Unsupported, so fail. */ return 1; } diff -urN glibc-2.5/ports/sysdeps/arm/eabi/fsetexcptflg.c glibc-2.5/ports/sysdeps/arm/eabi/fsetexcptflg.c --- glibc-2.5/ports/sysdeps/arm/eabi/fsetexcptflg.c 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/fsetexcptflg.c 2008-04-02 13:49:34.000000000 +1000 @@ -47,6 +47,24 @@ return 0; } + if (GLRO (dl_hwcap) & HWCAP_ARM_CRUNCH) + { + fexcept_t temp; + + /* Get the current environment. */ + _FPU_CRUNCH_GETCW (temp); + + /* Set the desired exception mask. */ + temp &= ~((excepts & FE_CRUNCH_ALL_EXCEPT) << FE_CRUNCH_EXCEPT_SHIFT); + temp |= (*flagp & excepts & FE_CRUNCH_ALL_EXCEPT) << FE_CRUNCH_EXCEPT_SHIFT; + + /* Save state back to the FPU. */ + _FPU_CRUNCH_SETCW (temp); + + /* Success. */ + return 0; + } + /* Unsupported, so fail. */ return 1; } diff -urN glibc-2.5/ports/sysdeps/arm/eabi/ftestexcept.c glibc-2.5/ports/sysdeps/arm/eabi/ftestexcept.c --- glibc-2.5/ports/sysdeps/arm/eabi/ftestexcept.c 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/ftestexcept.c 2008-04-02 13:50:10.000000000 +1000 @@ -38,6 +38,16 @@ return temp & excepts & FE_ALL_EXCEPT; } + if (GLRO (dl_hwcap) & HWCAP_ARM_CRUNCH) + { + fexcept_t temp; + + /* Get current exceptions. */ + _FPU_CRUNCH_GETCW(temp); + + return temp & excepts & FE_CRUNCH_ALL_EXCEPT; + } + /* Unsupported, return 0. */ return 0; } diff -urN glibc-2.5/ports/sysdeps/arm/eabi/setfpucw.c glibc-2.5/ports/sysdeps/arm/eabi/setfpucw.c --- glibc-2.5/ports/sysdeps/arm/eabi/setfpucw.c 2005-10-11 01:29:32.000000000 +1000 +++ glibc-2.5/ports/sysdeps/arm/eabi/setfpucw.c 2008-04-02 13:51:28.000000000 +1000 @@ -43,5 +43,20 @@ _FPU_SETCW (cw); } + if (GLRO (dl_hwcap) & HWCAP_ARM_CRUNCH) + { + fpu_control_t cw; + + /* Fetch the current control word. */ + _FPU_CRUNCH_GETCW (cw); + + /* Preserve the reserved bits, and set the rest as the user + specified (or the default, if the user gave zero). */ + cw &= _FPU_CRUNCH_RESERVED; + cw |= set & ~_FPU_CRUNCH_RESERVED; + + _FPU_CRUNCH_SETCW (cw); + } + /* Do nothing if a VFP unit isn't present. */ }