diff options
Diffstat (limited to 'arch/sh/kernel/cpu/sh4')
-rw-r--r-- | arch/sh/kernel/cpu/sh4/fpu.c | 25 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh4/setup-sh7760.c | 5 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh4/softfloat.c | 29 |
3 files changed, 58 insertions, 1 deletions
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c index 2d452f67fb8..2780917c008 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); extern unsigned long long float64_sub(unsigned long long a, unsigned long long b); extern unsigned long int float32_sub(unsigned long int a, unsigned long int b); - +extern unsigned long int float64_to_float32(unsigned long long a); static unsigned int fpu_exception_flags; /* @@ -417,6 +417,29 @@ static int ieee_fpe_handler(struct pt_regs *regs) regs->pc = nextpc; return 1; + } else if ((finsn & 0xf0bd) == 0xf0bd) { + /* fcnvds - double to single precision convert */ + struct task_struct *tsk = current; + int m; + unsigned int hx; + + m = (finsn >> 9) & 0x7; + hx = tsk->thread.fpu.hard.fp_regs[m]; + + if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR) + && ((hx & 0x7fffffff) < 0x00100000)) { + /* subnormal double to float conversion */ + long long llx; + + llx = ((long long)tsk->thread.fpu.hard.fp_regs[m] << 32) + | tsk->thread.fpu.hard.fp_regs[m + 1]; + + tsk->thread.fpu.hard.fpul = float64_to_float32(llx); + } else + return 0; + + regs->pc = nextpc; + return 1; } return 0; diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c index 254c5c55ab9..d9bdc931ac0 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <linux/serial.h> #include <linux/serial_sci.h> +#include <linux/io.h> enum { UNUSED = 0, @@ -178,10 +179,14 @@ static int __init sh7760_devices_setup(void) } __initcall(sh7760_devices_setup); +#define INTC_ICR 0xffd00000UL +#define INTC_ICR_IRLM (1 << 7) + void __init plat_irq_setup_pins(int mode) { switch (mode) { case IRQ_MODE_IRQ: + ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); register_intc_controller(&intc_desc_irq); break; default: diff --git a/arch/sh/kernel/cpu/sh4/softfloat.c b/arch/sh/kernel/cpu/sh4/softfloat.c index 828cb57cb95..2b747f3b02b 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); float32 float32_div(float32 a, float32 b); float32 float32_mul(float32 a, float32 b); float64 float64_mul(float64 a, float64 b); +float32 float64_to_float32(float64 a); inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, bits64 * z1Ptr); inline void sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, @@ -890,3 +891,31 @@ float64 float64_mul(float64 a, float64 b) } return roundAndPackFloat64(zSign, zExp, zSig0); } + +/* + * ------------------------------------------------------------------------------- + * Returns the result of converting the double-precision floating-point value + * `a' to the single-precision floating-point format. The conversion is + * performed according to the IEC/IEEE Standard for Binary Floating-point + * Arithmetic. + * ------------------------------------------------------------------------------- + * */ +float32 float64_to_float32(float64 a) +{ + flag aSign; + int16 aExp; + bits64 aSig; + bits32 zSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + + shift64RightJamming( aSig, 22, &aSig ); + zSig = aSig; + if ( aExp || zSig ) { + zSig |= 0x40000000; + aExp -= 0x381; + } + return roundAndPackFloat32(aSign, aExp, zSig); +} |