Commit b6ad1e8c authored by Carl Shaw's avatar Carl Shaw Committed by Paul Mundt

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: default avatarCarl Shaw <carl.shaw@st.com>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent f040ddaf
...@@ -36,7 +36,7 @@ extern unsigned long int float32_add(unsigned long int a, unsigned long int b); ...@@ -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, extern unsigned long long float64_sub(unsigned long long a,
unsigned long long b); unsigned long long b);
extern unsigned long int float32_sub(unsigned long int a, unsigned long int 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; static unsigned int fpu_exception_flags;
/* /*
...@@ -415,6 +415,29 @@ static int ieee_fpe_handler(struct pt_regs *regs) ...@@ -415,6 +415,29 @@ static int ieee_fpe_handler(struct pt_regs *regs)
} else } else
return 0; return 0;
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; regs->pc = nextpc;
return 1; return 1;
} }
......
...@@ -85,6 +85,7 @@ float64 float64_div(float64 a, float64 b); ...@@ -85,6 +85,7 @@ float64 float64_div(float64 a, float64 b);
float32 float32_div(float32 a, float32 b); float32 float32_div(float32 a, float32 b);
float32 float32_mul(float32 a, float32 b); float32 float32_mul(float32 a, float32 b);
float64 float64_mul(float64 a, float64 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, inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
bits64 * z1Ptr); bits64 * z1Ptr);
inline void sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr, 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,3 +891,31 @@ float64 float64_mul(float64 a, float64 b)
} }
return roundAndPackFloat64(zSign, zExp, zSig0); 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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment