[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