Ultrix-3.1/src/cmd/olx/fpx.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

static char Sccsid[] = "@(#)fpx.c	3.0	4/22/86";
/*
 * ULTRIX-11 Floating Point exerciser program (fpx).
 *
 * Fred Canter 5/12/83
 * Bill Burns  4/23/84
 *	added event flag code
 *
 *	********************************************
 *	*					   *
 *	* This program will not function correctly *
 *	* unless the current unix monitor file is  *
 *	* named "unix".				   *
 *	*					   *
 *	********************************************
 *
 * This program exercises the FP11-A/B/C/E/F floating point
 * processors, and the FPF11 11/23 & 11/24 floating point,
 * the 11/40 FIS is not supported by Unix.
 * The fpx program crunches floating point numbers and
 * tests the floating point exception mechanism.
 *
 * USAGE:
 *
 *	fpx [-n #] [-e #]
 *
 *	-n #	Limit the number of data mismatch errors to be 
 *		printed to # for each error occurrence.
 *
 *	-e #	Set the data error limit to #, default = 100 maximum = 1000.
 *		If the number of error occurrences exceeds # terminate fpx.
 *		An error occurrence can represent upto [-n #] error printouts.
 *
 */

#include <sys/param.h>	/* Does not matter which one ! */
#include <stdio.h>
#include <a.out.h>
#include <signal.h>

#define	ITER	99999L
long	iter = ITER;	/* will be lowered for fp emulation */

#define	NPASS	12	/* number of forks to make a pass */
int	npass = NPASS;	/* will be lowered for fp emulation */

int	fcount;

struct nlist nl[] =
{
	{ "fpp" },
	{ "_fpemulation" },
	{ "" }
};
int	fpp;		/* floating point present */
int	fpx;		/* expected FP exception error code, 0 if not */
			/* status returned by fperr() system call */
int	fpemulation;
int	fpstat[3];	/* FP status register */
			/* FP error code */
			/* FP error address */

double	a, b;

int	tn;
time_t timbuf;
long randx;

/*
 * 16 doubles sorted in assending order,
 * no magic in these numbers.
 * Don't use zero !!!
 */

double	n_sort[] =
{
	-6522261.8,
	-333156.29743,
	-22416.15,
	-7522.5482,
	-321.42,
	-42.6,
	-1.1,
	-0.0021,
	0.00014,
	2.2,
	34.156,
	752.8,
	9561.42865,
	17291.64,
	156242.849,
	9651422.35,
};

/*
 * Empty array,
 * a place to put the answer.
 */

double	n_ans[16];

/*
 * Two arrays of 16 numbers for the
 * add/subtract test and two arrays of the
 * expected answers.
 * again, no magic !
 */

double	n_as1[] =
{
	879321.45,
	-5432543.197,
	435678.0001,
	-1000000.4,
	0.00002,
	-0.12345,
	1.9999,
	-3.459011,
	348943.1,
	-999999.999,
	4562999.9003,
	-9999321.0009,
	4589.12006,
	-43999.00009,
	12002.5,
	-55000.0003,
};

double	n_as2[] =
{
	0.29,
	-1.4,
	-0.123456,
	0.000001,
	4.0003,
	-0.5,
	-2.25,
	0.04999,
	3965135.0004,
	-99368.00032,
	-54999.9,
	99111346.12345,
	45832.01,
	-22479.0245,
	-4765.1,
	345.9999,
};

double	n_plus[] =
{
	879321.74,
	-5432544.597,
	435677.876644,
	-1000000.399999,
	4.00032,
	-0.62345,
	-0.2501,
	-3.409021,
	4314078.1004,
	-1099367.99932,
	4508000.0003,
	89112025.12255,
	50421.13006,
	-66478.02459,
	7237.4,
	-54654.0004
};

double	n_min[] =
{
	879321.16,
	-5432541.797,
	435678.123556,
	-1000000.400001,
	-4.00028,
	0.37655,
	4.2499,
	-3.509001,
	-3616191.9004,
	-900631.99868,
	4617999.8003,
	-109110667.12435,
	-41242.88994,
	-21519.97559,
	16767.6,
	-55346.0002
};

char	c_exp[100], c_act[100];

/*
 * Two arrays of 16 numbers for the
 * multiply/divide test.
 */

double	n_md1[] =
{
	0.12345,
	-0.589,
	0.00001,
	-0.6,
	12345.0,
	-4.0,
	2001.0,
	-99000.0,
	3896.003,
	-10999.98,
	44367.5489,
	-2003.478,
	1000043.59,
	-99345.999,
	87003.5,
	-832002.123
};

double	n_md2[] =
{
	0.58999,
	-0.1,
	-0.9,
	0.3401,
	23.0,
	-567.0,
	-1234.0,
	9.0,
	4899.003,
	-1234.4321,
	-9984.02,
	45903.12,
	1.003,
	-13.6702,
	-3.002,
	5.0034
};

double	n_mul[] =
{
	0.072834,
	0.0589,
	-0.000009,
	-0.204060,
	283935.0,
	2268.0,
	-2469234.0,
	-891000.0,
	19086530.385009,
	13578728.411358,
	-442966495.568578,
	-91965891.05136,
	1003043.72077,
	1358079.675530,
	-261184.507,
	-4162839.422218
};

double	n_div[] =
{
	0.209241,
	5.89,
	-0.000011,
	-1.764187,
	536.739130,
	0.007055,
	-1.621556,
	-11000.0,
	0.795264,
	8.910964,
	-4.443856,
	-0.043646,
	997052.432702,
	7267.340566,
	-28981.845436,
	-166287.349203
};

int	ndep = 5;
int	ndrop = 100;
int	ndec;

char	*dex = "\n\n[ data error print limit exceeded ]";
int	ntec;

#ifdef EFLG
#include <sys/eflg.h>
char	*efpis;
char	*efids;
int	efbit;
int	efid;
long	evntflg();
long	efret;
int	zflag;
#else
char	*killfn = "fpx.kill";
#endif

main(argc, argv)
char *argv[];
int argc;
{
	int	intr(), stop();
	register int i, j;
	int fpxerr();
	FILE	*argf;
	long	li;
	int	mem;

	signal(SIGTTOU, SIG_IGN);
	signal(SIGINT, SIG_IGN);
	signal(SIGTERM, intr);
	signal(SIGQUIT, stop);
/*
	if(((argc & 1) == 0) || (argc > 7)) {
	argerr:
		fprintf(stderr, "\nfpx: bad arg\n");
		fprintf(stderr, "\nUsage: fpx [-n #] [-e #]\n\n");
		exit(1);
	}
*/
	for(i=1; i<argc; i++) {
		if(argv[i] [0] != '-') {
		argerr:
			exit(1);
		}
#ifdef EFLG
		if(argv[i] [1] == 'z') {
			zflag++;
			i++;
			efpis = argv[i];
			i++;
			efids = argv[i];
		}
#else
		if(argv[i] [1] == 'r') {
			i++;
			killfn = argv[i];
		}
#endif
		if(argv[i] [1] == 'n') {
			i++;
			if((argv[i] [0] < '0') || (argv[i] [0] > '9'))
				goto argerr;
			ndep = atoi(argv[i]);
		}
		if(argv[i] [1] == 'e') {
			i++;
			if((argv[i] [0] < '0') || (argv[i] [0] > '9'))
				goto argerr;
			ndrop = atoi(argv[i]);
			if((ndrop < 0) || (ndrop > 1000)) {
			    fprintf(stderr, "\nfpx bad [-e #], using 100 !\n");
				ndrop = 100;
			}
		}
	}
	if(!zflag) {
		if(isatty(2)) {
		    fprintf(stderr, "fpx: detaching... type \"sysxstop\" to stop\n");
		    fflush(stderr);
		}
		if((i = fork()) == -1) {
			printf("fpx: Can't fork new copy !\n");
			exit(1);
		}
		if(i != 0)
			exit(0);
	}
	setpgrp(0, 31111);
	nlist("/unix", nl);
	if(nl[1].n_value == 0) {
	    fprintf(stderr,"\nfpx: ULTRIX-11 not configured for Floating Point\n");
	    exit(1);
	}
	if((mem = open("/dev/mem", 0)) < 0) {
		fprintf(stderr, "\nfpx: Can't open /dev/mem\n");
		exit(1);
	}
	lseek(mem, (long)nl[0].n_value, 0);
	read(mem, (char *)&fpp, sizeof(fpp));
	lseek(mem, (long)nl[1].n_value, 0);
	read(mem, (char *)&fpemulation, sizeof(fpemulation));
	close(mem);
	if(fpp == 0) {
		iter = 999;
		npass = 6;
	}
	if((fpp == 0) && (fpemulation != 1)) {
		fprintf(stderr, "\nfpx: No Floating Point present, ");
		if(fpemulation == 2)
			fprintf(stderr, "and FP Emulation not in kernel !\n");
		else
			fprintf(stderr, "and FP Emulation turned off !\n");
		exit(0);
	}
	time(&timbuf);
	randx = timbuf & 0777;
	printf("\n\nFloating Point exerciser started - %s", ctime(&timbuf));
	fflush(stdout);
#ifdef EFLG
	if(zflag) {
		efbit = atoi(efpis);
		efid = atoi(efids);
		evntflg(EFCLR, efid, (long)efbit);
	}
#else
	unlink(killfn);		/* tell sysx fpx started */
#endif
	signal(SIGFPE, fpxerr);
loop:
/*
 * TEST 1 - increment/decrement
 *
 *	Two floating point numbers starting at 0.0 are incremented
 *	by 0.1 iter (see above define) times. Each time they are
 *	compared to make sure they match. They are then decremented
 *	by 0.1 iter times and checked for a match each time,
 *	and check for a 0.0 result after all iterations are done.
 *
 * note - The checking of a & b for >= 0.00001 is really a test
 *	for equal to zero, because with floating point numbers
 *	zero is not always really zero when it gets out the the
 *	Nth decimal place.
 */

	tn = 1;
	ndec = 0;
	a = 0.0;
	b = 0.0;
	for(li=0; li<iter; li++) {
		a += 1.00001;
		b += 1.00001;
		if((a != b) || (a < 0.00001) || (b < 0.00001)) {
			em(tn);
			printf("\nIncrement a & b by 1.00001, %D times,", iter);
			printf("\na & b should match");
			printf("\ncount\t= %D", li);
			printf("\na\t= %f\nb\t= %f\n", a, b);
			if(++ndec >= ndep) {
				printf("%s", dex);
				break;
			}
		}
	}
	if(ndec)
		ntec++;
	ndec = 0;
	for(li=0; li<iter; li++) {
		if((a < 0.00001) || (b < 0.00001))
			goto err1;
		a -= 1.00001;
		b -= 1.00001;
		if(a != b) {
	err1:
			em(tn);
			printf("\nDecrement a & b by 1.00001, %D times,", iter);
			printf("\na & b should match");
			printf("\ncount\t= %D", li);
			printf("\na\t= %f\nb\t= %f\n", a, b);
			if(++ndec >= ndep) {
				printf("%s", dex);
				break;
			}
		}
	}
	if(ndec)
		ntec++;
	if((a >= 0.00001) || (b >= 0.00001)) {
		em(tn);
		printf("\nAfter test %02d, a & b should equal zero", tn);
		printf("\na\t= %f\nb\t= %f\n",a,b);
		ntec++;
	}
	elcheck();	/* check for error limit exceeded */
/*
 * TEST 2 - exceptions
 *
 *	Test as many of the floating point exceptions as possible
 *	by attempting illegal operations like divide by zero and
 * 	catching the SIGFPE signal. The fperr() system call is used
 *	to obtain the floating point exception status.
 *	NOTE -	As it turns out, divide by zero is the only floating
 *		point exception that can be tested.
 */

	tn = 2;
	fpx = 4;	/* divide by zero */
	a = 1.1/0.0;
	fpxck();
	elcheck();
/*
 * TEST 3 - sort
 *
 *	Copy a presorted array of 16 numbers to an empty array
 *	in randum order, then sort them and compare the result
 *	against the original array.
 */

	tn = 3;
	ndec = 0;
	for(i=0; i<16; i++)
		n_ans[i] = 0.0;	/* answer set to all zeroes */
	for(i=0; i<16; i++) {	/* copy to answer, out of order */
		j = rng() & 017;
		while(n_ans[j] != 0.0)
			if(++j >= 16)
				j = 0;
		n_ans[j] = n_sort[i];
	}
t3_sl:			/* sort */
	j = 0;
	for(i=0; i<15; i++)
		if(n_ans[i] > n_ans[i+1]) {
			j++;
			a = n_ans[i];
			n_ans[i] = n_ans[i+1];
			n_ans[i+1] = a;
		}
	if(j)
		goto t3_sl;
	j = 0;			/* compare */
	for(i=0; i<16; i++)
		if(n_sort[i] != n_ans[i])
			j++;
	if(j) {			/* print any errors */
		em(tn);
		printf("\nSort 16 numbers, arrays should match");
		printf("\n\nExpected\tActual\n");
		for(i=0; i<16; i++) {
			printf("\n%15.6f\t%15.6f", n_sort[i], n_ans[i]);
			if(++ndec >= ndep) {
				printf("%s", dex);
				break;
			}
		}
	printf("\n");
	}
	if(ndec)
		ntec++;
	elcheck();
/*
 * TEST 4 - add
 *
 *	Add two arrays of 16 numbers and
 *	check the result against an array
 *	of the expected answers.
 *	Strings are used to compare the results of
 *	floating point arithmetic operations because of the
 *	inaccuracy of the FP11 in the Nth decimal place.
 *	Printf rounds the results for me.
 *	"Oh silly me !"
 */
	tn = 4;
	ndec = 0;
	for(i=0; i<16; i++) {
		n_ans[i] = n_as1[i] + n_as2[i];
		sprintf(&c_exp, "%.6f", n_plus[i]);
		sprintf(&c_act, "%.6f", n_ans[i]);
		if(strcmp(&c_exp, &c_act) != 0) {
			em(tn);
			printf("\nAddition test");
			printf("\n\n%.6f plus %.7f = ", n_as1[i], n_as2[i]);
			printf("%s S/B %s\n", &c_act, &c_exp);
			if(++ndec >= ndep) {
				printf("%s", dex);
				break;
			}
		}
	}
	if(ndec)
		ntec++;
	elcheck();
/*
 * TEST 5 - subtract
 *
 *	Subtract two arrays of 16 numbers and
 *	check the result against an array
 *	of the expected answers.
 *	Strings are used to compare the results of
 *	floating point arithmetic operations because of the
 *	inaccuracy of the FP11 in the Nth decimal place.
 *	Printf rounds the results for me.
 */
	tn = 5;
	ndec = 0;
	for(i=0; i<16; i++) {
		n_ans[i] = n_as1[i] - n_as2[i];
		sprintf(&c_exp, "%.6f", n_min[i]);
		sprintf(&c_act, "%.6f", n_ans[i]);
		if(strcmp(&c_exp, &c_act) != 0) {
			em(tn);
			printf("\nSubtraction test");
			printf("\n\n%.6f minus %.7f = ", n_as1[i], n_as2[i]);
			printf("%s S/B %s\n", &c_act, &c_exp);
			if(++ndec >= ndep) {
				printf("%s", dex);
				break;
			}
		}
	}
	if(ndec)
		ntec++;
	elcheck();
/*
 * TEST 6 - multiply
 *
 *	Multiply two arrays of 16 numbers and
 *	check the result against an array
 *	of the expected answers.
 *	Strings are used to compare the results of
 *	floating point arithmetic operations because of the
 *	inaccuracy of the FP11 in the Nth decimal place.
 *	Printf rounds the results for me.
 */
	tn = 6;
	ndec = 0;
	for(i=0; i<16; i++) {
		n_ans[i] = n_md1[i] * n_md2[i];
		sprintf(&c_exp, "%.6f", n_mul[i]);
		sprintf(&c_act, "%.6f", n_ans[i]);
		if(strcmp(&c_exp, &c_act) != 0) {
			em(tn);
			printf("\nMultiplication test");
			printf("\n\n%.6f * %.7f = ", n_md1[i], n_md2[i]);
			printf("%s S/B %s\n", &c_act, &c_exp);
			if(++ndec >= ndep) {
				printf("%s", dex);
				break;
			}
		}
	}
	if(ndec)
		ntec++;
	elcheck();
/*
 * TEST 7 - divide
 *
 *	Divide two arrays of 16 numbers and
 *	check the result against an array
 *	of the expected answers.
 *	Strings are used to compare the results of
 *	floating point arithmetic operations because of the
 *	inaccuracy of the FP11 in the Nth decimal place.
 *	Printf rounds the results for me.
 */
	tn = 7;
	ndec = 0;
	for(i=0; i<16; i++) {
		n_ans[i] = n_md1[i] / n_md2[i];
		sprintf(&c_exp, "%.6f", n_div[i]);
		sprintf(&c_act, "%.6f", n_ans[i]);
		if(strcmp(&c_exp, &c_act) != 0) {
			em(tn);
			printf("\nDivision test");
			printf("\n\n%.6f / %.7f = ", n_md1[i], n_md2[i]);
			printf("%s S/B %s\n", &c_act, &c_exp);
			if(++ndec >= ndep) {
				printf("%s", dex);
				break;
			}
		}
	}
	if(ndec)
		ntec++;
	elcheck();
	if(++fcount >= npass) {	/* end of pass */
		fcount = 0;
		time(&timbuf);
	  printf("\nFloating Point exerciser end of pass - %s", ctime(&timbuf));
	}
	fflush(stdout);
	if((i = fork()) == 0)
		goto loop;
	if(i == -1) {
		fprintf(stderr, "\nfpx: Can't fork new copy of fpx !\n");
		goto loop;
	}
	exit(0);
}

intr()
{
	signal(SIGTERM, intr);
#ifdef EFLG
	if(zflag) {
		if(!checkflg())
			return;
	} else
		return;
#else
	if(access(killfn, 0) != 0)
		return;
#endif
	stop();
}

stop()
{
	signal(SIGTERM, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);
	time(&timbuf);
	printf("\n\nFloating Point exerciser stopped - %s\n", ctime(&timbuf));
	fflush(stdout);
#ifdef EFLG
	if(zflag)
		evntflg(EFCLR, efid, (long)efbit);
#else
	unlink(killfn);	/* tell SYSX fpx stopped */
#endif
	exit(0);
}

rng()
{
	return(((randx = randx * 1103515245 + 12345) >> 16) & 0177777);
}

em(tn)
{
	printf("\n\n****** FPP EXERCISER ERROR ******");
	printf("\n****** TEST NUMBER %02d      ******", tn);
}

/*
 * Floating point exception error codes.
 */

char	*fpxec[] =
{
	"",
	"Floating OP code error",
	"Floating divide by zero",
	"Floating (or double) to integer conversion error",
	"Floating overflow",
	"Floating underflow",
	"Floating undefined variable",
	"Maintenance trap",
};

/*
 * Floating point status register bits.
 */

char	*fpsr[] =
{
	"FER","FID","","","FIUV","FIU","FIV","FIC",
	"FD","FL","FT","FMM","FN","FZ","FV","FC",
};

/*
 * Floating point exception handler.
 * The variable fpx is set to the error code if
 * an exception is expected or zero if not.
 */

fpxerr()
{
	register int i;

	fperr(&fpstat);		/* get FP exception status */
	if(fpx && (fpx == fpstat[1]))
		goto xit;		/* expected exception occurred */
	ntec++;
	printf("\n****** Test Number %02d - ", tn);
	if(fpx == 0)
		printf("UNEXPECTED ");
	else
		printf("INCORRECT ");
	printf("Floating Point Exception ******");
	if(fpx) {
		printf("\nExpected - %s", fpxec[fpx >> 1]);
		printf("\nReceived - ");
		if((fpstat[1] == 0) || (fpstat[1] > 14))
			printf("Unknown exception");
		else
			printf("%s", fpxec[fpstat[1] >> 1]);
	}
	printf("\n\nFP status register\t%6o\t", fpstat[0]);
	for(i=0; i<16; i++)
		if(fpstat[0] & (1 << (15 - i)))
			printf("%s ", fpsr[i]);
	printf("\nFP error code\t\t%6o\t", fpstat[1]);
	if((fpstat[1] == 0) || (fpstat[1] > 14))
		printf("Unknown exception");
	else
		printf("%s", fpxec[fpstat[1] >> 1]);
	printf("\nFP error address\t%6o\n", fpstat[2]);
xit:
	fpx = 0;
	signal(SIGFPE, fpxerr);
}

/*
 * Make sure that the floating
 * point exception did occur.
 */

fpxck()
{
	if(fpx == 0)
		return;
	printf("\n\n****** Test number %02d - ", tn);
	printf("MISSED Floating Point Exception ******");
	printf("\nExpected - %s", fpxec[fpx >> 1]);
	printf("\nReceived - No Floating Point exception\n");
	ntec++;
}

elcheck()
{
	
#ifdef EFLG
	if(zflag) {
		if(checkflg())
			stop();
	}
#else
	if(access("fpx.kill", 0) == 0)
		stop();
#endif
	if(ntec >= ndrop) {
		printf("\nTotal error limit exceeded, FPX terminated !\n");
		fflush(stdout);
		for( ;; )
			sleep(3600);
	}
}

/*
 * Check eventflags to stop
 * return 0 for continuation
 * return 1 to stop
 */
extern int errno;
checkflg()
{
	union efrt {
		long	efret;
		struct {
			int	a;
			int	b;
		} retval
	} ef;
	errno = 0;
	ef.efret = evntflg(EFRD, efid, (long)0);
	if(errno && ef.retval.a == -1) {
		zflag = 0;
		return(0);
	}
	if(ef.efret & (1L << efbit))
		return(1);
	return(0);
}