[patch][0/5] powerpc: Add support to fully comply with IEEE-754 standard
Zhu Ebony-r57400
ebony.zhu at freescale.com
Mon Jan 15 19:41:09 EST 2007
> -----Original Message-----
> From: Segher Boessenkool [mailto:segher at kernel.crashing.org]
> Sent: 2007年1月12日 20:06
> To: Zhu Ebony-r57400
> Cc: Kumar Gala; Paul Mackerras; linuxppc-dev at ozlabs.org
> Subject: Re: [patch][0/5] powerpc: Add support to fully
> comply with IEEE-754 standard
>
> > I wrote some cases for testing. For SPFP and DPFP exception
> testing,
> > the test cases included plus, minus, multiply, divide, comparisons,
> > conversions, DBZ... for Nan/Denorm/Inf numbers. I also tested the
> > cases that the operation result would generate
> > Nan/Denorm/Inf/overflow/underflow numbers. For Vector SPFP
> exception
> > testing, I wrote inline asm based testing program to test the
> > instructions directly.
>
> Any chance you could submit that testing code too? Would be
> useful for others :-)
>
>
> Segher
>
>
The below snipped code just tests limited instructions. On actural developing
process all instructrions were tested, FYI.
--------------------------Snip-----------------------------------------------------
/* compile with freescale gcc for MPC8548 powerpc platform
/opt/mtwk/usr/local/gcc-3_4-e500-glibc-2.3.4-dp/powerpc-linux-gnuspe/bin/
powerpc-linux-gnuspe-gcc -mcpu=8548 -mhard-float -ffloat-store
-fno-strict-aliasing -o Mult Mult.c -lm
*/
#include <stdio.h>
#include <math.h>
int main() {
float j =0.0;
float k =0.0;
float result, result0, result1, result2, result3;
printf ("Invalid operation (denorm) 1:\n");
k = 2.1E-44;
j = 1.5666666;
result0 = k * j;
result1 = k + j;
result2 = k - j ;
result3 = k / j ;
printf("after %g * %g result is %g \n",k,j,result0 );
printf("after %g + %g result is %g \n",k,j,result1 );
printf("after %g - %g result is %g \n",k,j,result2 );
printf("after %g / %g result is %g \n",k,j,result3 );
if (k>j) {
printf("The bigger one is %g\n",k);
}
if (k<j) {
printf("The smaller one is %g\n",k);
}
if (k == j) {
printf("equal\n");
}
}
--------------------------Snip-----------------------------------------------------
To test VSPFT instructions, inline asm based C code is used like:
--------------------------Snip-----------------------------------------------------
#include <stdlib.h>
#include <asm/reg.h>
static void write_reg(volatile unsigned *addr, float val);
static float read_reg(volatile unsigned *addr);
static void
write_reg(volatile unsigned *addr, float val)
{
__asm__ __volatile__("stwx %1,0,%2; eieio" : "=m" (*addr) :
"r" (val), "r" (addr));
}
static void
write_reg_dbl(volatile unsigned *addr, double val)
{
__asm__ __volatile__("evstddx %1,0,%2; eieio" : "=m" (*addr) :
"r" (val), "r" (addr));
}
static float
read_reg(volatile unsigned *addr)
{
float ret;
__asm__ __volatile__("lwzx %0,0,%1; eieio" : "=r" (ret) :
"r" (addr), "m" (*addr));
return ret;
}
static int
read_reg_int(volatile unsigned *addr)
{
unsigned int ret;
__asm__ __volatile__("lwzx %0,0,%1; eieio" : "=r" (ret) :
"r" (addr), "m" (*addr));
return ret;
}
inline void
evfsadd(volatile unsigned *addr)
{
unsigned int rA;
unsigned int rB;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evlddx %4, 0, %3\n"
"evfsadd %1, %1, %4\n"
"evstdwx %1, 0, %5\n"
: "=m" (*addr)
: "r" (rA), "r" (addr), "r" (addr+2), "r" (rB), "r" (addr+4)
);
}
inline void
evfssub(volatile unsigned *addr)
{
unsigned int rA;
unsigned int rB;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evlddx %4, 0, %3\n"
"evfssub %1, %1, %4\n"
"evstdwx %1, 0, %5\n"
: "=m" (*addr)
: "r" (rA), "r" (addr), "r" (addr+2), "r" (rB), "r" (addr+4)
);
}
inline void
evfsmul(volatile unsigned *addr)
{
unsigned int rA;
unsigned int rB;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evlddx %4, 0, %3\n"
"evfsmul %1, %1, %4\n"
"evstdwx %1, 0, %5\n"
: "=m" (*addr)
: "r" (rA), "r" (addr), "r" (addr+2), "r" (rB), "r" (addr+4)
);
}
inline void
evfsdiv(volatile unsigned *addr)
{
unsigned int rA;
unsigned int rB;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evlddx %4, 0, %3\n"
"evfsdiv %1, %1, %4\n"
"evstdwx %1, 0, %5\n"
: "=m" (*addr)
: "r" (rA), "r" (addr), "r" (addr+2), "r" (rB), "r" (addr+4)
);
}
inline int
evfscmpeq(volatile unsigned *addr)
{
unsigned int rA;
unsigned int rB;
unsigned int val;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evlddx %4, 0, %3\n"
"evfscmpeq %0, %1, %4\n"
"mfcr %0\n"
: "=r" (val)
: "r" (rA), "r" (addr), "r" (addr+2), "r" (rB));
return (val);
}
inline int
evfscmpgt(volatile unsigned *addr)
{
unsigned int rA;
unsigned int rB;
unsigned int val;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evlddx %4, 0, %3\n"
"evfscmpgt %0, %1, %4\n"
"mfcr %0\n"
: "=r" (val)
: "r" (rA), "r" (addr), "r" (addr+2), "r" (rB));
return (val);
}
inline int
evfscmplt(volatile unsigned *addr)
{
unsigned int rA;
unsigned int rB;
unsigned int val;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evlddx %4, 0, %3\n"
"evfscmplt %0, %1, %4\n"
"mfcr %0\n"
: "=r" (val)
: "r" (rA), "r" (addr), "r" (addr+2), "r" (rB));
return (val);
}
inline void
evfsabs(volatile unsigned *addr)
{
unsigned int rD;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evfsabs %1, %1\n"
"evstdwx %1, 0, %3\n"
: "=m" (*addr)
: "r" (rD), "r" (addr), "r" (addr+4)
);
}
inline void
evfsnabs(volatile unsigned *addr)
{
unsigned int rD;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evfsnabs %1, %1\n"
"evstdwx %1, 0, %3\n"
: "=m" (*addr)
: "r" (rD), "r" (addr), "r" (addr+4)
);
}
inline void
evfsneg(volatile unsigned *addr)
{
unsigned int rD;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evfsneg %1, %1\n"
"evstdwx %1, 0, %3\n"
: "=m" (*addr)
: "r" (rD), "r" (addr), "r" (addr+4)
);
}
inline void
evfsctui(volatile unsigned *addr)
{
unsigned int rD;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evfsctui %1, %1\n"
"evstdwx %1, 0, %3\n"
: "=m" (*addr)
: "r" (rD), "r" (addr), "r" (addr+4)
);
}
inline void
evfsctsi(volatile unsigned *addr)
{
unsigned int rD;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evfsctsi %1, %1\n"
"evstdwx %1, 0, %3\n"
: "=m" (*addr)
: "r" (rD), "r" (addr), "r" (addr+4)
);
}
inline void
evfsctsiz(volatile unsigned *addr)
{
unsigned int rD;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evfsctsiz %1, %1\n"
"evstdwx %1, 0, %3\n"
: "=m" (*addr)
: "r" (rD), "r" (addr), "r" (addr+4)
);
}
inline void
evfsctuiz(volatile unsigned *addr)
{
unsigned int rD;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evfsctuiz %1, %1\n"
"evstdwx %1, 0, %3\n"
: "=m" (*addr)
: "r" (rD), "r" (addr), "r" (addr+4)
);
}
inline void
evfsctuf(volatile unsigned *addr)
{
unsigned int rD;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evfsctuf %1, %1\n"
"evstdwx %1, 0, %3\n"
: "=m" (*addr)
: "r" (rD), "r" (addr), "r" (addr+4)
);
}
inline void
evfsctsf(volatile unsigned *addr)
{
unsigned int rD;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"evfsctsf %1, %1\n"
"evstdwx %1, 0, %3\n"
: "=m" (*addr)
: "r" (rD), "r" (addr), "r" (addr+4)
);
}
inline void
efsctsf(volatile unsigned *addr)
{
unsigned int rD;
__asm__ __volatile__ ("lwzx %1, 0, %2\n"
"efsctsf %1, %1\n"
"stwx %1, 0, %3\n"
: "=m" (*addr)
: "r" (rD), "r" (addr), "r" (addr+4)
);
}
inline void
efsctuf(volatile unsigned *addr)
{
unsigned int rD;
__asm__ __volatile__ ("lwzx %1, 0, %2\n"
"efsctuf %1, %1\n"
"stwx %1, 0, %3\n"
: "=m" (*addr)
: "r" (rD), "r" (addr), "r" (addr+4)
);
}
inline void
efdctuf(volatile unsigned *addr)
{
unsigned int rD;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"efdctuf %1, %1\n"
"evstdwx %1, 0, %3\n"
: "=m" (*addr)
: "r" (rD), "r" (addr), "r" (addr+4)
);
}
inline void
efdctsf(volatile unsigned *addr)
{
unsigned int rD;
__asm__ __volatile__ ("evlddx %1, 0, %2\n"
"efdctsf %1, %1\n"
"evstdwx %1, 0, %3\n"
: "=m" (*addr)
: "r" (rD), "r" (addr), "r" (addr+4)
);
}
inline void
write_reg_vec (unsigned int *addr, float rA0, float rA1, float rB0, float rB1)
{
write_reg (addr, rA0);
write_reg (addr+1, rA1);
write_reg (addr+2, rB0);
write_reg (addr+3, rB1);
}
int main()
{
unsigned *store_addr;
float a0 = 2.1e-44;
float a1 = -5.738e-42;
float b0 = 1.5666666;
float b1 = 1.0001221;
float d0, d1;
double b = 0.9999999996507541e+320;
unsigned int d0_uint, d1_uint;
unsigned int crD;
double result;
printf ("a0, a1 = %g, %g\n", a0, a1);
printf ("b0, b1 = %g, %g\n", b0, b1);
printf ("b = %g\n", b);
store_addr = malloc (sizeof(float)*6);
write_reg_vec (store_addr, a0, a1, b0, b1);
evfsadd(store_addr);
d0 = read_reg (store_addr+4);
d1 = read_reg (store_addr+5);
printf ("evfsadd: d0 = %g, d1 = %g\n", d0, d1);
evfssub(store_addr);
d0 = read_reg (store_addr+4);
d1 = read_reg (store_addr+5);
printf ("evfssub: d0 = %g, d1 = %g\n", d0, d1);
evfsmul(store_addr);
d0 = read_reg (store_addr+4);
d1 = read_reg (store_addr+5);
printf ("evfsmul: d0 = %g, d1 = %g\n", d0, d1);
evfsdiv(store_addr);
d0 = read_reg (store_addr+4);
d1 = read_reg (store_addr+5);
printf ("evfsdiv: d0 = %g, d1 = %g\n", d0, d1);
evfsabs(store_addr);
d0 = read_reg (store_addr+4);
d1 = read_reg (store_addr+5);
printf ("evfsabs: d0 = %g, d1 = %g\n", d0, d1);
evfsnabs(store_addr);
d0 = read_reg (store_addr+4);
d1 = read_reg (store_addr+5);
printf ("evfsnabs: d0 = %g, d1 = %g\n", d0, d1);
evfsneg(store_addr);
d0 = read_reg (store_addr+4);
d1 = read_reg (store_addr+5);
printf ("evfsneg: d0 = %g, d1 = %g\n", d0, d1);
crD = evfscmpeq(store_addr);
printf ("efscmpeq: crD = %08x\n", crD);
crD = evfscmpgt(store_addr);
printf ("efscmpgt: crD = %08x\n", crD);
crD = evfscmplt(store_addr);
printf ("efscmplt: crD = %08x\n", crD);
evfsctui(store_addr);
d0_uint = read_reg_int (store_addr+4);
d1_uint = read_reg_int (store_addr+5);
printf ("evfsctui: d0 = %u, d1 = %u\n", d0_uint, d1_uint);
evfsctuiz(store_addr);
d0_uint = read_reg_int (store_addr+4);
d1_uint = read_reg_int (store_addr+5);
printf ("evfsctuiz: d0 = %u, d1 = %u\n", d0_uint, d1_uint);
evfsctsi(store_addr);
d0_uint = read_reg_int (store_addr+4);
d1_uint = read_reg_int (store_addr+5);
printf ("evfsctsi: d0 = %d, d1 = %d\n", d0_uint, d1_uint);
evfsctsiz(store_addr);
d0_uint = read_reg_int (store_addr+4);
d1_uint = read_reg_int (store_addr+5);
printf ("evfsctsiz: d0 = %d, d1 = %d\n", d0_uint, d1_uint);
evfsctuf(store_addr);
d0_uint = read_reg_int (store_addr+4);
d1_uint = read_reg_int (store_addr+5);
printf ("evfsctuf: d0 = %08x, d1 = %08x\n", d0_uint, d1_uint);
evfsctsf(store_addr);
d0_uint = read_reg_int (store_addr+4);
d1_uint = read_reg_int (store_addr+5);
printf ("evfsctsf: d0 = %08x, d1 = %08x\n", d0_uint, d1_uint);
efsctsf(store_addr);
d0_uint = read_reg_int (store_addr+4);
printf ("efsctsf: d0 = %08x\n", d0_uint);
efsctuf(store_addr);
d0_uint = read_reg_int (store_addr+4);
printf ("efsctuf: d0 = %08x\n", d0_uint);
write_reg_dbl (store_addr, b);
efdctuf(store_addr);
d0_uint = read_reg_int (store_addr+4);
d1_uint = read_reg_int (store_addr+5);
printf ("efdctuf: d0 = %08x, d1 = %08x\n", d0_uint, d1_uint);
efdctsf(store_addr);
d0_uint = read_reg_int (store_addr+4);
d1_uint = read_reg_int (store_addr+5);
printf ("efdctsf: d0 = %08x, d1 = %08x\n", d0_uint, d1_uint);
}
--------------------------Snip-----------------------------------------------------
Ebony
More information about the Linuxppc-dev
mailing list