aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu
diff options
context:
space:
mode:
authorCarl Shaw <carl.shaw@st.com>2008-09-05 03:36:19 -0400
committerPaul Mundt <lethal@linux-sh.org>2008-09-07 21:35:05 -0400
commitb6ad1e8c3f76fcc5dee506d5e79e752d296ff745 (patch)
treec626da55bdfc3e19419856e086a5cad1dc4829c4 /arch/sh/kernel/cpu
parentf040ddaf4cfd28f25ea9d6a42d3c734d5c3f6798 (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.c25
-rw-r--r--arch/sh/kernel/cpu/sh4/softfloat.c29
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);
36extern unsigned long long float64_sub(unsigned long long a, 36extern unsigned long long float64_sub(unsigned long long a,
37 unsigned long long b); 37 unsigned long long b);
38extern unsigned long int float32_sub(unsigned long int a, unsigned long int b); 38extern unsigned long int float32_sub(unsigned long int a, unsigned long int b);
39 39extern unsigned long int float64_to_float32(unsigned long long a);
40static unsigned int fpu_exception_flags; 40static 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);
85float32 float32_div(float32 a, float32 b); 85float32 float32_div(float32 a, float32 b);
86float32 float32_mul(float32 a, float32 b); 86float32 float32_mul(float32 a, float32 b);
87float64 float64_mul(float64 a, float64 b); 87float64 float64_mul(float64 a, float64 b);
88float32 float64_to_float32(float64 a);
88inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, 89inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
89 bits64 * z1Ptr); 90 bits64 * z1Ptr);
90inline void sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, 91inline 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 * */
903float32 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}