diff options
author | Carl Shaw <carl.shaw@st.com> | 2008-09-05 03:36:19 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2008-09-07 21:35:05 -0400 |
commit | b6ad1e8c3f76fcc5dee506d5e79e752d296ff745 (patch) | |
tree | c626da55bdfc3e19419856e086a5cad1dc4829c4 /arch/sh/kernel/cpu | |
parent | f040ddaf4cfd28f25ea9d6a42d3c734d5c3f6798 (diff) |
sh: Subnormal double to float conversion
This patch adds support for the SH4 to convert a subnormal double
into a float by catching the FPE and implementing the FCNVDS
instruction in software.
Signed-off-by: Carl Shaw <carl.shaw@st.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/cpu')
-rw-r--r-- | arch/sh/kernel/cpu/sh4/fpu.c | 25 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh4/softfloat.c | 29 |
2 files changed, 53 insertions, 1 deletions
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c index 2d452f67fb87..2780917c0088 100644 --- a/arch/sh/kernel/cpu/sh4/fpu.c +++ b/arch/sh/kernel/cpu/sh4/fpu.c | |||
@@ -36,7 +36,7 @@ extern unsigned long int float32_add(unsigned long int a, unsigned long int b); | |||
36 | extern unsigned long long float64_sub(unsigned long long a, | 36 | extern unsigned long long float64_sub(unsigned long long a, |
37 | unsigned long long b); | 37 | unsigned long long b); |
38 | extern unsigned long int float32_sub(unsigned long int a, unsigned long int b); | 38 | extern unsigned long int float32_sub(unsigned long int a, unsigned long int b); |
39 | 39 | extern unsigned long int float64_to_float32(unsigned long long a); | |
40 | static unsigned int fpu_exception_flags; | 40 | static unsigned int fpu_exception_flags; |
41 | 41 | ||
42 | /* | 42 | /* |
@@ -417,6 +417,29 @@ static int ieee_fpe_handler(struct pt_regs *regs) | |||
417 | 417 | ||
418 | regs->pc = nextpc; | 418 | regs->pc = nextpc; |
419 | return 1; | 419 | return 1; |
420 | } else if ((finsn & 0xf0bd) == 0xf0bd) { | ||
421 | /* fcnvds - double to single precision convert */ | ||
422 | struct task_struct *tsk = current; | ||
423 | int m; | ||
424 | unsigned int hx; | ||
425 | |||
426 | m = (finsn >> 9) & 0x7; | ||
427 | hx = tsk->thread.fpu.hard.fp_regs[m]; | ||
428 | |||
429 | if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR) | ||
430 | && ((hx & 0x7fffffff) < 0x00100000)) { | ||
431 | /* subnormal double to float conversion */ | ||
432 | long long llx; | ||
433 | |||
434 | llx = ((long long)tsk->thread.fpu.hard.fp_regs[m] << 32) | ||
435 | | tsk->thread.fpu.hard.fp_regs[m + 1]; | ||
436 | |||
437 | tsk->thread.fpu.hard.fpul = float64_to_float32(llx); | ||
438 | } else | ||
439 | return 0; | ||
440 | |||
441 | regs->pc = nextpc; | ||
442 | return 1; | ||
420 | } | 443 | } |
421 | 444 | ||
422 | return 0; | 445 | return 0; |
diff --git a/arch/sh/kernel/cpu/sh4/softfloat.c b/arch/sh/kernel/cpu/sh4/softfloat.c index 828cb57cb959..2b747f3b02bd 100644 --- a/arch/sh/kernel/cpu/sh4/softfloat.c +++ b/arch/sh/kernel/cpu/sh4/softfloat.c | |||
@@ -85,6 +85,7 @@ float64 float64_div(float64 a, float64 b); | |||
85 | float32 float32_div(float32 a, float32 b); | 85 | float32 float32_div(float32 a, float32 b); |
86 | float32 float32_mul(float32 a, float32 b); | 86 | float32 float32_mul(float32 a, float32 b); |
87 | float64 float64_mul(float64 a, float64 b); | 87 | float64 float64_mul(float64 a, float64 b); |
88 | float32 float64_to_float32(float64 a); | ||
88 | inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, | 89 | inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, |
89 | bits64 * z1Ptr); | 90 | bits64 * z1Ptr); |
90 | inline void sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, | 91 | inline void sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, |
@@ -890,3 +891,31 @@ float64 float64_mul(float64 a, float64 b) | |||
890 | } | 891 | } |
891 | return roundAndPackFloat64(zSign, zExp, zSig0); | 892 | return roundAndPackFloat64(zSign, zExp, zSig0); |
892 | } | 893 | } |
894 | |||
895 | /* | ||
896 | * ------------------------------------------------------------------------------- | ||
897 | * Returns the result of converting the double-precision floating-point value | ||
898 | * `a' to the single-precision floating-point format. The conversion is | ||
899 | * performed according to the IEC/IEEE Standard for Binary Floating-point | ||
900 | * Arithmetic. | ||
901 | * ------------------------------------------------------------------------------- | ||
902 | * */ | ||
903 | float32 float64_to_float32(float64 a) | ||
904 | { | ||
905 | flag aSign; | ||
906 | int16 aExp; | ||
907 | bits64 aSig; | ||
908 | bits32 zSig; | ||
909 | |||
910 | aSig = extractFloat64Frac( a ); | ||
911 | aExp = extractFloat64Exp( a ); | ||
912 | aSign = extractFloat64Sign( a ); | ||
913 | |||
914 | shift64RightJamming( aSig, 22, &aSig ); | ||
915 | zSig = aSig; | ||
916 | if ( aExp || zSig ) { | ||
917 | zSig |= 0x40000000; | ||
918 | aExp -= 0x381; | ||
919 | } | ||
920 | return roundAndPackFloat32(aSign, aExp, zSig); | ||
921 | } | ||