From: Julian Seward Date: Sat, 12 Feb 2005 19:01:03 +0000 (+0000) Subject: Heavily modified emfloat benchmark from bytemark, changed to be X-Git-Tag: svn/VALGRIND_3_0_1^2~441 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b93bbc09f7462f9bc9a9193e487f2540b7007d0a;p=thirdparty%2Fvalgrind.git Heavily modified emfloat benchmark from bytemark, changed to be self-contained so that switchback can run it. git-svn-id: svn://svn.valgrind.org/vex/trunk@893 --- diff --git a/VEX/switchback/test_emfloat.c b/VEX/switchback/test_emfloat.c new file mode 100644 index 0000000000..7d4434f36c --- /dev/null +++ b/VEX/switchback/test_emfloat.c @@ -0,0 +1,1944 @@ +/* +** emfloat.c +** Source for emulated floating-point routines. +** BYTEmark (tm) +** BYTE's Native Mode Benchmarks +** Rick Grehan, BYTE Magazine. +** +** Created: +** Last update: 3/95 +** +** DISCLAIMER +** The source, executable, and documentation files that comprise +** the BYTEmark benchmarks are made available on an "as is" basis. +** This means that we at BYTE Magazine have made every reasonable +** effort to verify that the there are no errors in the source and +** executable code. We cannot, however, guarantee that the programs +** are error-free. Consequently, McGraw-HIll and BYTE Magazine make +** no claims in regard to the fitness of the source code, executable +** code, and documentation of the BYTEmark. +** Furthermore, BYTE Magazine, McGraw-Hill, and all employees +** of McGraw-Hill cannot be held responsible for any damages resulting +** from the use of this code or the results obtained from using +** this code. +*/ + +#include "../pub/libvex_basictypes.h" + +static HWord (*serviceFn)(HWord,HWord) = 0; + + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// + +static char* my_strcpy ( char* dest, const char* src ) +{ + char* dest_orig = dest; + while (*src) *dest++ = *src++; + *dest = 0; + return dest_orig; +} + +static void* my_memcpy ( void *dest, const void *src, int sz ) +{ + const char *s = (const char *)src; + char *d = (char *)dest; + + while (sz--) + *d++ = *s++; + + return dest; +} + +static void* my_memmove( void *dst, const void *src, unsigned int len ) +{ + register char *d; + register char *s; + if ( dst > src ) { + d = (char *)dst + len - 1; + s = (char *)src + len - 1; + while ( len >= 4 ) { + *d-- = *s--; + *d-- = *s--; + *d-- = *s--; + *d-- = *s--; + len -= 4; + } + while ( len-- ) { + *d-- = *s--; + } + } else if ( dst < src ) { + d = (char *)dst; + s = (char *)src; + while ( len >= 4 ) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + len -= 4; + } + while ( len-- ) { + *d++ = *s++; + } + } + return dst; +} + +///////////////////////////////////////////////////////////////////// + +static void vex_log_bytes ( char* p, int n ) +{ + int i; + for (i = 0; i < n; i++) + (*serviceFn)( 1, (int)p[i] ); +} + +/*---------------------------------------------------------*/ +/*--- vex_printf ---*/ +/*---------------------------------------------------------*/ + +/* This should be the only <...> include in the entire VEX library. + New code for vex_util.c should go above this point. */ +#include + +static HChar vex_toupper ( HChar c ) +{ + if (c >= 'a' && c <= 'z') + return toHChar(c + ('A' - 'a')); + else + return c; +} + +static Int vex_strlen ( const HChar* str ) +{ + Int i = 0; + while (str[i] != 0) i++; + return i; +} + +Bool vex_streq ( const HChar* s1, const HChar* s2 ) +{ + while (True) { + if (*s1 == 0 && *s2 == 0) + return True; + if (*s1 != *s2) + return False; + s1++; + s2++; + } +} + +/* Some flags. */ +#define VG_MSG_SIGNED 1 /* The value is signed. */ +#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */ +#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */ +#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */ +#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */ + +/* Copy a string into the buffer. */ +static UInt +myvprintf_str ( void(*send)(HChar), Int flags, Int width, HChar* str, + Bool capitalise ) +{ +# define MAYBE_TOUPPER(ch) toHChar(capitalise ? vex_toupper(ch) : (ch)) + UInt ret = 0; + Int i, extra; + Int len = vex_strlen(str); + + if (width == 0) { + ret += len; + for (i = 0; i < len; i++) + send(MAYBE_TOUPPER(str[i])); + return ret; + } + + if (len > width) { + ret += width; + for (i = 0; i < width; i++) + send(MAYBE_TOUPPER(str[i])); + return ret; + } + + extra = width - len; + if (flags & VG_MSG_LJUSTIFY) { + ret += extra; + for (i = 0; i < extra; i++) + send(' '); + } + ret += len; + for (i = 0; i < len; i++) + send(MAYBE_TOUPPER(str[i])); + if (!(flags & VG_MSG_LJUSTIFY)) { + ret += extra; + for (i = 0; i < extra; i++) + send(' '); + } + +# undef MAYBE_TOUPPER + + return ret; +} + +/* Write P into the buffer according to these args: + * If SIGN is true, p is a signed. + * BASE is the base. + * If WITH_ZERO is true, '0' must be added. + * WIDTH is the width of the field. + */ +static UInt +myvprintf_int64 ( void(*send)(HChar), Int flags, Int base, Int width, ULong pL) +{ + HChar buf[40]; + Int ind = 0; + Int i, nc = 0; + Bool neg = False; + HChar *digits = "0123456789ABCDEF"; + UInt ret = 0; + UInt p = (UInt)pL; + + if (base < 2 || base > 16) + return ret; + + if ((flags & VG_MSG_SIGNED) && (Int)p < 0) { + p = - (Int)p; + neg = True; + } + + if (p == 0) + buf[ind++] = '0'; + else { + while (p > 0) { + if ((flags & VG_MSG_COMMA) && 10 == base && + 0 == (ind-nc) % 3 && 0 != ind) + { + buf[ind++] = ','; + nc++; + } + buf[ind++] = digits[p % base]; + p /= base; + } + } + + if (neg) + buf[ind++] = '-'; + + if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) { + for(; ind < width; ind++) { + //vassert(ind < 39); + buf[ind] = toHChar((flags & VG_MSG_ZJUSTIFY) ? '0': ' '); + } + } + + /* Reverse copy to buffer. */ + ret += ind; + for (i = ind -1; i >= 0; i--) { + send(buf[i]); + } + if (width > 0 && (flags & VG_MSG_LJUSTIFY)) { + for(; ind < width; ind++) { + ret++; + send(' '); // Never pad with zeroes on RHS -- changes the value! + } + } + return ret; +} + + +/* A simple vprintf(). */ +static +UInt vprintf_wrk ( void(*send)(HChar), const HChar *format, va_list vargs ) +{ + UInt ret = 0; + int i; + int flags; + int width; + Bool is_long; + + /* We assume that vargs has already been initialised by the + caller, using va_start, and that the caller will similarly + clean up with va_end. + */ + + for (i = 0; format[i] != 0; i++) { + if (format[i] != '%') { + send(format[i]); + ret++; + continue; + } + i++; + /* A '%' has been found. Ignore a trailing %. */ + if (format[i] == 0) + break; + if (format[i] == '%') { + /* `%%' is replaced by `%'. */ + send('%'); + ret++; + continue; + } + flags = 0; + is_long = False; + width = 0; /* length of the field. */ + if (format[i] == '(') { + flags |= VG_MSG_PAREN; + i++; + } + /* If ',' follows '%', commas will be inserted. */ + if (format[i] == ',') { + flags |= VG_MSG_COMMA; + i++; + } + /* If '-' follows '%', justify on the left. */ + if (format[i] == '-') { + flags |= VG_MSG_LJUSTIFY; + i++; + } + /* If '0' follows '%', pads will be inserted. */ + if (format[i] == '0') { + flags |= VG_MSG_ZJUSTIFY; + i++; + } + /* Compute the field length. */ + while (format[i] >= '0' && format[i] <= '9') { + width *= 10; + width += format[i++] - '0'; + } + while (format[i] == 'l') { + i++; + is_long = True; + } + + switch (format[i]) { + case 'd': /* %d */ + flags |= VG_MSG_SIGNED; + if (is_long) + ret += myvprintf_int64(send, flags, 10, width, + (ULong)(va_arg (vargs, Long))); + else + ret += myvprintf_int64(send, flags, 10, width, + (ULong)(va_arg (vargs, Int))); + break; + case 'u': /* %u */ + if (is_long) + ret += myvprintf_int64(send, flags, 10, width, + (ULong)(va_arg (vargs, ULong))); + else + ret += myvprintf_int64(send, flags, 10, width, + (ULong)(va_arg (vargs, UInt))); + break; + case 'p': /* %p */ + ret += 2; + send('0'); + send('x'); + ret += myvprintf_int64(send, flags, 16, width, + (ULong)((HWord)va_arg (vargs, void *))); + break; + case 'x': /* %x */ + if (is_long) + ret += myvprintf_int64(send, flags, 16, width, + (ULong)(va_arg (vargs, ULong))); + else + ret += myvprintf_int64(send, flags, 16, width, + (ULong)(va_arg (vargs, UInt))); + break; + case 'c': /* %c */ + ret++; + send(toHChar(va_arg (vargs, int))); + break; + case 's': case 'S': { /* %s */ + char *str = va_arg (vargs, char *); + if (str == (char*) 0) str = "(null)"; + ret += myvprintf_str(send, flags, width, str, + toBool(format[i]=='S')); + break; + } +# if 0 + case 'y': { /* %y - print symbol */ + Char buf[100]; + Char *cp = buf; + Addr a = va_arg(vargs, Addr); + + if (flags & VG_MSG_PAREN) + *cp++ = '('; + if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) { + if (flags & VG_MSG_PAREN) { + cp += VG_(strlen)(cp); + *cp++ = ')'; + *cp = '\0'; + } + ret += myvprintf_str(send, flags, width, buf, 0); + } + break; + } +# endif + default: + break; + } + } + return ret; +} + + +/* A general replacement for printf(). Note that only low-level + debugging info should be sent via here. The official route is to + to use vg_message(). This interface is deprecated. +*/ +static HChar myprintf_buf[1000]; +static Int n_myprintf_buf; + +static void add_to_myprintf_buf ( HChar c ) +{ + if (c == '\n' || n_myprintf_buf >= 1000-10 /*paranoia*/ ) { + (*vex_log_bytes)( myprintf_buf, vex_strlen(myprintf_buf) ); + n_myprintf_buf = 0; + myprintf_buf[n_myprintf_buf] = 0; + } + myprintf_buf[n_myprintf_buf++] = c; + myprintf_buf[n_myprintf_buf] = 0; +} + +static UInt vex_printf ( const char *format, ... ) +{ + UInt ret; + va_list vargs; + va_start(vargs,format); + + n_myprintf_buf = 0; + myprintf_buf[n_myprintf_buf] = 0; + ret = vprintf_wrk ( add_to_myprintf_buf, format, vargs ); + + if (n_myprintf_buf > 0) { + (*vex_log_bytes)( myprintf_buf, n_myprintf_buf ); + } + + va_end(vargs); + + return ret; +} + +/*---------------------------------------------------------------*/ +/*--- end vex_util.c ---*/ +/*---------------------------------------------------------------*/ + + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// + +//#include +//#include +//#include + +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned short ushort; +typedef unsigned long ulong; +typedef int int32; /* Signed 32 bit integer */ + +#define INTERNAL_FPF_PRECISION 4 +#define CPUEMFLOATLOOPMAX 500000L +#define EMFARRAYSIZE 3000L + +typedef struct { + int adjust; /* Set adjust code */ + ulong request_secs; /* # of seconds requested */ + ulong arraysize; /* Size of array */ + ulong loops; /* Loops per iterations */ + double emflops; /* Results */ +} EmFloatStruct; + + + +/* Is this a 64 bit architecture? If so, this will define LONG64 */ +/* Uwe F. Mayer 15 November 1997 */ +// #include "pointer.h" + +#define u8 unsigned char +#define u16 unsigned short +#ifdef LONG64 +#define u32 unsigned int +#else +#define u32 unsigned long +#endif +#define uchar unsigned char +#define ulong unsigned long + +#define MAX_EXP 32767L +#define MIN_EXP (-32767L) + +#define IFPF_IS_ZERO 0 +#define IFPF_IS_SUBNORMAL 1 +#define IFPF_IS_NORMAL 2 +#define IFPF_IS_INFINITY 3 +#define IFPF_IS_NAN 4 +#define IFPF_TYPE_COUNT 5 + +#define ZERO_ZERO 0 +#define ZERO_SUBNORMAL 1 +#define ZERO_NORMAL 2 +#define ZERO_INFINITY 3 +#define ZERO_NAN 4 + +#define SUBNORMAL_ZERO 5 +#define SUBNORMAL_SUBNORMAL 6 +#define SUBNORMAL_NORMAL 7 +#define SUBNORMAL_INFINITY 8 +#define SUBNORMAL_NAN 9 + +#define NORMAL_ZERO 10 +#define NORMAL_SUBNORMAL 11 +#define NORMAL_NORMAL 12 +#define NORMAL_INFINITY 13 +#define NORMAL_NAN 14 + +#define INFINITY_ZERO 15 +#define INFINITY_SUBNORMAL 16 +#define INFINITY_NORMAL 17 +#define INFINITY_INFINITY 18 +#define INFINITY_NAN 19 + +#define NAN_ZERO 20 +#define NAN_SUBNORMAL 21 +#define NAN_NORMAL 22 +#define NAN_INFINITY 23 +#define NAN_NAN 24 +#define OPERAND_ZERO 0 +#define OPERAND_SUBNORMAL 1 +#define OPERAND_NORMAL 2 +#define OPERAND_INFINITY 3 +#define OPERAND_NAN 4 + +typedef struct +{ + u8 type; /* Indicates, NORMAL, SUBNORMAL, etc. */ + u8 sign; /* Mantissa sign */ + short exp; /* Signed exponent...no bias */ + u16 mantissa[INTERNAL_FPF_PRECISION]; +} InternalFPF; + +static +void SetupCPUEmFloatArrays(InternalFPF *abase, + InternalFPF *bbase, InternalFPF *cbase, ulong arraysize); +static +ulong DoEmFloatIteration(InternalFPF *abase, + InternalFPF *bbase, InternalFPF *cbase, + ulong arraysize, ulong loops); + +static void SetInternalFPFZero(InternalFPF *dest, + uchar sign); +static void SetInternalFPFInfinity(InternalFPF *dest, + uchar sign); +static void SetInternalFPFNaN(InternalFPF *dest); +static int IsMantissaZero(u16 *mant); +static void Add16Bits(u16 *carry,u16 *a,u16 b,u16 c); +static void Sub16Bits(u16 *borrow,u16 *a,u16 b,u16 c); +static void ShiftMantLeft1(u16 *carry,u16 *mantissa); +static void ShiftMantRight1(u16 *carry,u16 *mantissa); +static void StickyShiftRightMant(InternalFPF *ptr,int amount); +static void normalize(InternalFPF *ptr); +static void denormalize(InternalFPF *ptr,int minimum_exponent); +static void RoundInternalFPF(InternalFPF *ptr); +static void choose_nan(InternalFPF *x,InternalFPF *y,InternalFPF *z, + int intel_flag); +static void AddSubInternalFPF(uchar operation,InternalFPF *x, + InternalFPF *y,InternalFPF *z); +static void MultiplyInternalFPF(InternalFPF *x,InternalFPF *y, + InternalFPF *z); +static void DivideInternalFPF(InternalFPF *x,InternalFPF *y, + InternalFPF *z); + +static void Int32ToInternalFPF(int32 mylong, + InternalFPF *dest); +static int InternalFPFToString(char *dest, + InternalFPF *src); + +static int32 randnum(int32 lngval); + +static int32 randwc(int32 num) +{ + return(randnum((int32)0)%num); +} + +static int32 randw[2] = { (int32)13 , (int32)117 }; +static int32 randnum(int32 lngval) +{ + register int32 interm; + + if (lngval!=(int32)0) + { randw[0]=(int32)13; randw[1]=(int32)117; } + + interm=(randw[0]*(int32)254754+randw[1]*(int32)529562)%(int32)999563; + randw[1]=randw[0]; + randw[0]=interm; + return(interm); +} + + +static +void SetupCPUEmFloatArrays(InternalFPF *abase, + InternalFPF *bbase, + InternalFPF *cbase, + ulong arraysize) +{ +ulong i; +InternalFPF locFPF1,locFPF2; + +randnum((int32)13); + +for(i=0;itype=IFPF_IS_ZERO; +dest->sign=sign; +dest->exp=MIN_EXP; +for(i=0;imantissa[i]=0; +return; +} + +/*************************** +** SetInternalFPFInfinity ** +**************************** +** Set an internal floating-point-format number to infinity. +** This can happen if the exponent exceeds MAX_EXP. +** As above, sign picks the sign of infinity. +*/ +static void SetInternalFPFInfinity(InternalFPF *dest, + uchar sign) +{ +int i; /* Index */ + +dest->type=IFPF_IS_INFINITY; +dest->sign=sign; +dest->exp=MIN_EXP; +for(i=0;imantissa[i]=0; +return; +} + +/********************** +** SetInternalFPFNaN ** +*********************** +** Set an internal floating-point-format number to Nan +** (not a number). Note that we "emulate" an 80x87 as far +** as the mantissa bits go. +*/ +static void SetInternalFPFNaN(InternalFPF *dest) +{ +int i; /* Index */ + +dest->type=IFPF_IS_NAN; +dest->exp=MAX_EXP; +dest->sign=1; +dest->mantissa[0]=0x4000; +for(i=1;imantissa[i]=0; + +return; +} + +/******************* +** IsMantissaZero ** +******************** +** Pass this routine a pointer to an internal floating point format +** number's mantissa. It checks for an all-zero mantissa. +** Returns 0 if it is NOT all zeros, !=0 otherwise. +*/ +static int IsMantissaZero(u16 *mant) +{ +int i; /* Index */ +int n; /* Return value */ + +n=0; +for(i=0;i=0;i--) +{ accum=mantissa[i]; + new_carry=accum & 0x8000; /* Get new carry */ + accum=accum<<1; /* Do the shift */ + if(*carry) + accum|=1; /* Insert previous carry */ + *carry=new_carry; + mantissa[i]=accum; /* Return shifted value */ +} +return; +} + +/******************** +** ShiftMantRight1 ** +********************* +** Shift a mantissa right by 1 bit. Provides carry, as +** above +*/ +static void ShiftMantRight1(u16 *carry, + u16 *mantissa) +{ +int i; /* Index */ +int new_carry; +u16 accum; + +for(i=0;i>1; + if(*carry) + accum|=0x8000; + *carry=new_carry; + mantissa[i]=accum; +} +return; +} + + +/***************************** +** StickyShiftMantRight ** +****************************** +** This is a shift right of the mantissa with a "sticky bit". +** I.E., if a carry of 1 is shifted out of the least significant +** bit, the least significant bit is set to 1. +*/ +static void StickyShiftRightMant(InternalFPF *ptr, + int amount) +{ +int i; /* Index */ +u16 carry; /* Self-explanatory */ +u16 *mantissa; + +mantissa=ptr->mantissa; + +if(ptr->type!=IFPF_IS_ZERO) /* Don't bother shifting a zero */ +{ + /* + ** If the amount of shifting will shift everyting + ** out of existence, then just clear the whole mantissa + ** and set the lowmost bit to 1. + */ + if(amount>=INTERNAL_FPF_PRECISION * 16) + { + for(i=0;imantissa[0] & 0x8000) == 0) +{ + carry = 0; + ShiftMantLeft1(&carry, ptr->mantissa); + ptr->exp--; +} +return; +} + +/**************** +** denormalize ** +***************** +** Denormalize an internal-representation number. This means +** shifting it right until its exponent is equivalent to +** minimum_exponent. (You have to do this often in order +** to perform additions and subtractions). +*/ +static void denormalize(InternalFPF *ptr, + int minimum_exponent) +{ +long exponent_difference; + +if (IsMantissaZero(ptr->mantissa)) +{ + vex_printf("Error: zero significand in denormalize\n"); +} + +exponent_difference = ptr->exp-minimum_exponent; +if (exponent_difference < 0) +{ + /* + ** The number is subnormal + */ + exponent_difference = -exponent_difference; + if (exponent_difference >= (INTERNAL_FPF_PRECISION * 16)) + { + /* Underflow */ + SetInternalFPFZero(ptr, ptr->sign); + } + else + { + ptr->exp+=exponent_difference; + StickyShiftRightMant(ptr, exponent_difference); + } +} +return; +} + + +/********************* +** RoundInternalFPF ** +********************** +** Round an internal-representation number. +** The kind of rounding we do here is simplest...referred to as +** "chop". "Extraneous" rightmost bits are simply hacked off. +*/ +void RoundInternalFPF(InternalFPF *ptr) +{ +/* int i; */ + +if (ptr->type == IFPF_IS_NORMAL || + ptr->type == IFPF_IS_SUBNORMAL) +{ + denormalize(ptr, MIN_EXP); + if (ptr->type != IFPF_IS_ZERO) + { + + /* clear the extraneous bits */ + ptr->mantissa[3] &= 0xfff8; +/* for (i=4; imantissa[i] = 0; + } +*/ + /* + ** Check for overflow + */ +/* Does not do anything as ptr->exp is a short and MAX_EXP=37268 + if (ptr->exp > MAX_EXP) + { + SetInternalFPFInfinity(ptr, ptr->sign); + } +*/ + } +} +return; +} + +/******************************************************* +** ARITHMETIC OPERATIONS ON INTERNAL REPRESENTATION ** +*******************************************************/ + +/*************** +** choose_nan ** +**************** +** Called by routines that are forced to perform math on +** a pair of NaN's. This routine "selects" which NaN is +** to be returned. +*/ +static void choose_nan(InternalFPF *x, + InternalFPF *y, + InternalFPF *z, + int intel_flag) +{ +int i; + +/* +** Compare the two mantissas, +** return the larger. Note that we will be emulating +** an 80387 in this operation. +*/ +for (i=0; imantissa[i] > y->mantissa[i]) + { + my_memmove((void *)x,(void *)z,sizeof(InternalFPF)); + return; + } + if (x->mantissa[i] < y->mantissa[i]) + { + my_memmove((void *)y,(void *)z,sizeof(InternalFPF)); + return; + } +} + +/* +** They are equal +*/ +if (!intel_flag) + /* if the operation is addition */ + my_memmove((void *)x,(void *)z,sizeof(InternalFPF)); +else + /* if the operation is multiplication */ + my_memmove((void *)y,(void *)z,sizeof(InternalFPF)); +return; +} + + +/********************** +** AddSubInternalFPF ** +*********************** +** Adding or subtracting internal-representation numbers. +** Internal-representation numbers pointed to by x and y are +** added/subtracted and the result returned in z. +*/ +static void AddSubInternalFPF(uchar operation, + InternalFPF *x, + InternalFPF *y, + InternalFPF *z) +{ +int exponent_difference; +u16 borrow; +u16 carry; +int i; +InternalFPF locx,locy; /* Needed since we alter them */ + +/* +** Following big switch statement handles the +** various combinations of operand types. +*/ +switch ((x->type * IFPF_TYPE_COUNT) + y->type) +{ +case ZERO_ZERO: + my_memmove((void *)x,(void *)z,sizeof(InternalFPF)); + if (x->sign ^ y->sign ^ operation) + { + z->sign = 0; /* positive */ + } + break; + +case NAN_ZERO: +case NAN_SUBNORMAL: +case NAN_NORMAL: +case NAN_INFINITY: +case SUBNORMAL_ZERO: +case NORMAL_ZERO: +case INFINITY_ZERO: +case INFINITY_SUBNORMAL: +case INFINITY_NORMAL: + my_memmove((void *)x,(void *)z,sizeof(InternalFPF)); + break; + + +case ZERO_NAN: +case SUBNORMAL_NAN: +case NORMAL_NAN: +case INFINITY_NAN: + my_memmove((void *)y,(void *)z,sizeof(InternalFPF)); + break; + +case ZERO_SUBNORMAL: +case ZERO_NORMAL: +case ZERO_INFINITY: +case SUBNORMAL_INFINITY: +case NORMAL_INFINITY: + my_memmove((void *)y,(void *)z,sizeof(InternalFPF)); + z->sign ^= operation; + break; + +case SUBNORMAL_SUBNORMAL: +case SUBNORMAL_NORMAL: +case NORMAL_SUBNORMAL: +case NORMAL_NORMAL: + /* + ** Copy x and y to locals, since we may have + ** to alter them. + */ + my_memmove((void *)&locx,(void *)x,sizeof(InternalFPF)); + my_memmove((void *)&locy,(void *)y,sizeof(InternalFPF)); + + /* compute sum/difference */ + exponent_difference = locx.exp-locy.exp; + if (exponent_difference == 0) + { + /* + ** locx.exp == locy.exp + ** so, no shifting required + */ + if (locx.type == IFPF_IS_SUBNORMAL || + locy.type == IFPF_IS_SUBNORMAL) + z->type = IFPF_IS_SUBNORMAL; + else + z->type = IFPF_IS_NORMAL; + + /* + ** Assume that locx.mantissa > locy.mantissa + */ + z->sign = locx.sign; + z->exp= locx.exp; + } + else + if (exponent_difference > 0) + { + /* + ** locx.exp > locy.exp + */ + StickyShiftRightMant(&locy, + exponent_difference); + z->type = locx.type; + z->sign = locx.sign; + z->exp = locx.exp; + } + else /* if (exponent_difference < 0) */ + { + /* + ** locx.exp < locy.exp + */ + StickyShiftRightMant(&locx, + -exponent_difference); + z->type = locy.type; + z->sign = locy.sign ^ operation; + z->exp = locy.exp; + } + + if (locx.sign ^ locy.sign ^ operation) + { + /* + ** Signs are different, subtract mantissas + */ + borrow = 0; + for (i=(INTERNAL_FPF_PRECISION-1); i>=0; i--) + Sub16Bits(&borrow, + &z->mantissa[i], + locx.mantissa[i], + locy.mantissa[i]); + + if (borrow) + { + /* The y->mantissa was larger than the + ** x->mantissa leaving a negative + ** result. Change the result back to + ** an unsigned number and flip the + ** sign flag. + */ + z->sign = locy.sign ^ operation; + borrow = 0; + for (i=(INTERNAL_FPF_PRECISION-1); i>=0; i--) + { + Sub16Bits(&borrow, + &z->mantissa[i], + 0, + z->mantissa[i]); + } + } + else + { + /* The assumption made above + ** (i.e. x->mantissa >= y->mantissa) + ** was correct. Therefore, do nothing. + ** z->sign = x->sign; + */ + } + + if (IsMantissaZero(z->mantissa)) + { + z->type = IFPF_IS_ZERO; + z->sign = 0; /* positive */ + } + else + if (locx.type == IFPF_IS_NORMAL || + locy.type == IFPF_IS_NORMAL) + { + normalize(z); + } + } + else + { + /* signs are the same, add mantissas */ + carry = 0; + for (i=(INTERNAL_FPF_PRECISION-1); i>=0; i--) + { + Add16Bits(&carry, + &z->mantissa[i], + locx.mantissa[i], + locy.mantissa[i]); + } + + if (carry) + { + z->exp++; + carry=0; + ShiftMantRight1(&carry,z->mantissa); + z->mantissa[0] |= 0x8000; + z->type = IFPF_IS_NORMAL; + } + else + if (z->mantissa[0] & 0x8000) + z->type = IFPF_IS_NORMAL; + } + break; + +case INFINITY_INFINITY: + SetInternalFPFNaN(z); + break; + +case NAN_NAN: + choose_nan(x, y, z, 1); + break; +} + +/* +** All the math is done; time to round. +*/ +RoundInternalFPF(z); +return; +} + + +/************************ +** MultiplyInternalFPF ** +************************* +** Two internal-representation numbers x and y are multiplied; the +** result is returned in z. +*/ +static void MultiplyInternalFPF(InternalFPF *x, + InternalFPF *y, + InternalFPF *z) +{ +int i; +int j; +u16 carry; +u16 extra_bits[INTERNAL_FPF_PRECISION]; +InternalFPF locy; /* Needed since this will be altered */ +/* +** As in the preceding function, this large switch +** statement selects among the many combinations +** of operands. +*/ +switch ((x->type * IFPF_TYPE_COUNT) + y->type) +{ +case INFINITY_SUBNORMAL: +case INFINITY_NORMAL: +case INFINITY_INFINITY: +case ZERO_ZERO: +case ZERO_SUBNORMAL: +case ZERO_NORMAL: + my_memmove((void *)x,(void *)z,sizeof(InternalFPF)); + z->sign ^= y->sign; + break; + +case SUBNORMAL_INFINITY: +case NORMAL_INFINITY: +case SUBNORMAL_ZERO: +case NORMAL_ZERO: + my_memmove((void *)y,(void *)z,sizeof(InternalFPF)); + z->sign ^= x->sign; + break; + +case ZERO_INFINITY: +case INFINITY_ZERO: + SetInternalFPFNaN(z); + break; + +case NAN_ZERO: +case NAN_SUBNORMAL: +case NAN_NORMAL: +case NAN_INFINITY: + my_memmove((void *)x,(void *)z,sizeof(InternalFPF)); + break; + +case ZERO_NAN: +case SUBNORMAL_NAN: +case NORMAL_NAN: +case INFINITY_NAN: + my_memmove((void *)y,(void *)z,sizeof(InternalFPF)); + break; + + +case SUBNORMAL_SUBNORMAL: +case SUBNORMAL_NORMAL: +case NORMAL_SUBNORMAL: +case NORMAL_NORMAL: + /* + ** Make a local copy of the y number, since we will be + ** altering it in the process of multiplying. + */ + my_memmove((void *)&locy,(void *)y,sizeof(InternalFPF)); + + /* + ** Check for unnormal zero arguments + */ + if (IsMantissaZero(x->mantissa) || IsMantissaZero(y->mantissa)) + SetInternalFPFInfinity(z, 0); + + /* + ** Initialize the result + */ + if (x->type == IFPF_IS_SUBNORMAL || + y->type == IFPF_IS_SUBNORMAL) + z->type = IFPF_IS_SUBNORMAL; + else + z->type = IFPF_IS_NORMAL; + + z->sign = x->sign ^ y->sign; + z->exp = x->exp + y->exp ; + for (i=0; imantissa[i] = 0; + extra_bits[i] = 0; + } + + for (i=0; i<(INTERNAL_FPF_PRECISION*16); i++) + { + /* + ** Get rightmost bit of the multiplier + */ + carry = 0; + ShiftMantRight1(&carry, locy.mantissa); + if (carry) + { + /* + ** Add the multiplicand to the product + */ + carry = 0; + for (j=(INTERNAL_FPF_PRECISION-1); j>=0; j--) + Add16Bits(&carry, + &z->mantissa[j], + z->mantissa[j], + x->mantissa[j]); + } + else + { + carry = 0; + } + + /* + ** Shift the product right. Overflow bits get + ** shifted into extra_bits. We'll use it later + ** to help with the "sticky" bit. + */ + ShiftMantRight1(&carry, z->mantissa); + ShiftMantRight1(&carry, extra_bits); + } + + /* + ** Normalize + ** Note that we use a "special" normalization routine + ** because we need to use the extra bits. (These are + ** bits that may have been shifted off the bottom that + ** we want to reclaim...if we can. + */ + while ((z->mantissa[0] & 0x8000) == 0) + { + carry = 0; + ShiftMantLeft1(&carry, extra_bits); + ShiftMantLeft1(&carry, z->mantissa); + z->exp--; + } + + /* + ** Set the sticky bit if any bits set in extra bits. + */ + if (IsMantissaZero(extra_bits)) + { + z->mantissa[INTERNAL_FPF_PRECISION-1] |= 1; + } + break; + +case NAN_NAN: + choose_nan(x, y, z, 0); + break; +} + +/* +** All math done...do rounding. +*/ +RoundInternalFPF(z); +return; +} + + +/********************** +** DivideInternalFPF ** +*********************** +** Divide internal FPF number x by y. Return result in z. +*/ +static void DivideInternalFPF(InternalFPF *x, + InternalFPF *y, + InternalFPF *z) +{ +int i; +int j; +u16 carry; +u16 extra_bits[INTERNAL_FPF_PRECISION]; +InternalFPF locx; /* Local for x number */ + +/* +** As with preceding function, the following switch +** statement selects among the various possible +** operands. +*/ +switch ((x->type * IFPF_TYPE_COUNT) + y->type) +{ +case ZERO_ZERO: +case INFINITY_INFINITY: + SetInternalFPFNaN(z); + break; + +case ZERO_SUBNORMAL: +case ZERO_NORMAL: + if (IsMantissaZero(y->mantissa)) + { + SetInternalFPFNaN(z); + break; + } + +case ZERO_INFINITY: +case SUBNORMAL_INFINITY: +case NORMAL_INFINITY: + SetInternalFPFZero(z, x->sign ^ y->sign); + break; + +case SUBNORMAL_ZERO: +case NORMAL_ZERO: + if (IsMantissaZero(x->mantissa)) + { + SetInternalFPFNaN(z); + break; + } + +case INFINITY_ZERO: +case INFINITY_SUBNORMAL: +case INFINITY_NORMAL: + SetInternalFPFInfinity(z, 0); + z->sign = x->sign ^ y->sign; + break; + +case NAN_ZERO: +case NAN_SUBNORMAL: +case NAN_NORMAL: +case NAN_INFINITY: + my_memmove((void *)x,(void *)z,sizeof(InternalFPF)); + break; + +case ZERO_NAN: +case SUBNORMAL_NAN: +case NORMAL_NAN: +case INFINITY_NAN: + my_memmove((void *)y,(void *)z,sizeof(InternalFPF)); + break; + +case SUBNORMAL_SUBNORMAL: +case NORMAL_SUBNORMAL: +case SUBNORMAL_NORMAL: +case NORMAL_NORMAL: + /* + ** Make local copy of x number, since we'll be + ** altering it in the process of dividing. + */ + my_memmove((void *)&locx,(void *)x,sizeof(InternalFPF)); + + /* + ** Check for unnormal zero arguments + */ + if (IsMantissaZero(locx.mantissa)) + { + if (IsMantissaZero(y->mantissa)) + SetInternalFPFNaN(z); + else + SetInternalFPFZero(z, 0); + break; + } + if (IsMantissaZero(y->mantissa)) + { + SetInternalFPFInfinity(z, 0); + break; + } + + /* + ** Initialize the result + */ + z->type = x->type; + z->sign = x->sign ^ y->sign; + z->exp = x->exp - y->exp + + ((INTERNAL_FPF_PRECISION * 16 * 2)); + for (i=0; imantissa[i] = 0; + extra_bits[i] = 0; + } + + while ((z->mantissa[0] & 0x8000) == 0) + { + carry = 0; + ShiftMantLeft1(&carry, locx.mantissa); + ShiftMantLeft1(&carry, extra_bits); + + /* + ** Time to subtract yet? + */ + if (carry == 0) + for (j=0; jmantissa[j] > extra_bits[j]) + { + carry = 0; + goto no_subtract; + } + if (y->mantissa[j] < extra_bits[j]) + break; + } + /* + ** Divisor (y) <= dividend (x), subtract + */ + carry = 0; + for (j=(INTERNAL_FPF_PRECISION-1); j>=0; j--) + Sub16Bits(&carry, + &extra_bits[j], + extra_bits[j], + y->mantissa[j]); + carry = 1; /* 1 shifted into quotient */ + no_subtract: + ShiftMantLeft1(&carry, z->mantissa); + z->exp--; + } + break; + +case NAN_NAN: + choose_nan(x, y, z, 0); + break; +} + +/* +** Math complete...do rounding +*/ +RoundInternalFPF(z); +} + +/********************** +** LongToInternalFPF ** +** Int32ToInternalFPF ** +*********************** +** Convert a signed (long) 32-bit integer into an internal FPF number. +*/ +/* static void LongToInternalFPF(long mylong, */ +static void Int32ToInternalFPF(int32 mylong, + InternalFPF *dest) +{ +int i; /* Index */ +u16 myword; /* Used to hold converted stuff */ +/* +** Save the sign and get the absolute value. This will help us +** with 64-bit machines, since we use only the lower 32 +** bits just in case. (No longer necessary after we use int32.) +*/ +/* if(mylong<0L) */ +if(mylong<(int32)0) +{ dest->sign=1; + mylong=(int32)0-mylong; +} +else + dest->sign=0; +/* +** Prepare the destination floating point number +*/ +dest->type=IFPF_IS_NORMAL; +for(i=0;imantissa[i]=0; + +/* +** See if we've got a zero. If so, make the resultant FP +** number a true zero and go home. +*/ +if(mylong==0) +{ dest->type=IFPF_IS_ZERO; + dest->exp=0; + return; +} + +/* +** Not a true zero. Set the exponent to 32 (internal FPFs have +** no bias) and load the low and high words into their proper +** locations in the mantissa. Then normalize. The action of +** normalizing slides the mantissa bits into place and sets +** up the exponent properly. +*/ +dest->exp=32; +myword=(u16)((mylong >> 16) & 0xFFFFL); +dest->mantissa[0]=myword; +myword=(u16)(mylong & 0xFFFFL); +dest->mantissa[1]=myword; +normalize(dest); +return; +} + +#if 1 +/************************ +** InternalFPFToString ** +************************* +** FOR DEBUG PURPOSES +** This routine converts an internal floating point representation +** number to a string. Used in debugging the package. +** Returns length of converted number. +** NOTE: dest must point to a buffer big enough to hold the +** result. Also, this routine does append a null (an effect +** of using the sprintf() function). It also returns +** a length count. +** NOTE: This routine returns 5 significant digits. Thats +** about all I feel safe with, given the method of +** conversion. It should be more than enough for programmers +** to determine whether the package is properly ported. +*/ +static int InternalFPFToString(char *dest, + InternalFPF *src) +{ +InternalFPF locFPFNum; /* Local for src (will be altered) */ +InternalFPF IFPF10; /* Floating-point 10 */ +InternalFPF IFPFComp; /* For doing comparisons */ +int msign; /* Holding for mantissa sign */ +int expcount; /* Exponent counter */ +int ccount; /* Character counter */ +int i,j,k; /* Index */ +u16 carryaccum; /* Carry accumulator */ +u16 mycarry; /* Local for carry */ + +/* +** Check first for the simple things...Nan, Infinity, Zero. +** If found, copy the proper string in and go home. +*/ +switch(src->type) +{ + case IFPF_IS_NAN: + my_memcpy(dest,"NaN",3); + return(3); + + case IFPF_IS_INFINITY: + if(src->sign==0) + my_memcpy(dest,"+Inf",4); + else + my_memcpy(dest,"-Inf",4); + return(4); + + case IFPF_IS_ZERO: + if(src->sign==0) + my_memcpy(dest,"+0",2); + else + my_memcpy(dest,"-0",2); + return(2); +} + +/* +** Move the internal number into our local holding area, since +** we'll be altering it to print it out. +*/ +my_memcpy((void *)&locFPFNum,(void *)src,sizeof(InternalFPF)); + +/* +** Set up a floating-point 10...which we'll use a lot in a minute. +*/ +/* LongToInternalFPF(10L,&IFPF10); */ +Int32ToInternalFPF((int32)10,&IFPF10); + +/* +** Save the mantissa sign and make it positive. +*/ +msign=src->sign; + +/* src->sign=0 */ /* bug, fixed Nov. 13, 1997 */ +(&locFPFNum)->sign=0; + +expcount=0; /* Init exponent counter */ + +/* +** See if the number is less than 10. If so, multiply +** the number repeatedly by 10 until it's not. For each +** multiplication, decrement a counter so we can keep track +** of the exponent. +*/ + +while(1) +{ AddSubInternalFPF(1,&locFPFNum,&IFPF10,&IFPFComp); + if(IFPFComp.sign==0) break; + MultiplyInternalFPF(&locFPFNum,&IFPF10,&IFPFComp); + expcount--; + my_memcpy((void *)&locFPFNum,(void *)&IFPFComp,sizeof(InternalFPF)); +} +/* +** Do the reverse of the above. As long as the number is +** greater than or equal to 10, divide it by 10. Increment the +** exponent counter for each multiplication. +*/ + +while(1) +{ + AddSubInternalFPF(1,&locFPFNum,&IFPF10,&IFPFComp); + if(IFPFComp.sign!=0) break; + DivideInternalFPF(&locFPFNum,&IFPF10,&IFPFComp); + expcount++; + my_memcpy((void *)&locFPFNum,(void *)&IFPFComp,sizeof(InternalFPF)); +} + +/* +** About time to start storing things. First, store the +** mantissa sign. +*/ +ccount=1; /* Init character counter */ +if(msign==0) + *dest++='+'; +else + *dest++='-'; + +/* +** At this point we know that the number is in the range +** 10 > n >=1. We need to "strip digits" out of the +** mantissa. We do this by treating the mantissa as +** an integer and multiplying by 10. (Not a floating-point +** 10, but an integer 10. Since this is debug code and we +** could care less about speed, we'll do it the stupid +** way and simply add the number to itself 10 times. +** Anything that makes it to the left of the implied binary point +** gets stripped off and emitted. We'll do this for +** 5 significant digits (which should be enough to +** verify things). +*/ +/* +** Re-position radix point +*/ +carryaccum=0; +while(locFPFNum.exp>0) +{ + mycarry=0; + ShiftMantLeft1(&mycarry,locFPFNum.mantissa); + carryaccum=(carryaccum<<1); + if(mycarry) carryaccum++; + locFPFNum.exp--; +} + +while(locFPFNum.exp<0) +{ + mycarry=0; + ShiftMantRight1(&mycarry,locFPFNum.mantissa); + locFPFNum.exp++; +} + +for(i=0;i<6;i++) + if(i==1) + { /* Emit decimal point */ + *dest++='.'; + ccount++; + } + else + { /* Emit a digit */ + *dest++=('0'+carryaccum); + ccount++; + + carryaccum=0; + my_memcpy((void *)&IFPF10, + (void *)&locFPFNum, + sizeof(InternalFPF)); + + /* Do multiply via repeated adds */ + for(j=0;j<9;j++) + { + mycarry=0; + for(k=(INTERNAL_FPF_PRECISION-1);k>=0;k--) + Add16Bits(&mycarry,&(IFPFComp.mantissa[k]), + locFPFNum.mantissa[k], + IFPF10.mantissa[k]); + carryaccum+=mycarry ? 1 : 0; + my_memcpy((void *)&locFPFNum, + (void *)&IFPFComp, + sizeof(InternalFPF)); + } + } + +/* +** Now move the 'E', the exponent sign, and the exponent +** into the string. +*/ +*dest++='E'; + +/* sprint is supposed to return an integer, but it caused problems on SunOS + * with the native cc. Hence we force it. + * Uwe F. Mayer + */ +if (expcount < 0) { + *dest++ = '-'; + expcount =- expcount; +} +else *dest++ = ' '; + +*dest++ = (char)(expcount + '0'); +*dest++ = 0; + +ccount += 3; +/* +** All done, go home. +*/ +return(ccount); + +} + +#endif + + + +//////////////////////////////////////////////////////////////////////// +static +void* AllocateMemory ( unsigned long n, int* p ) +{ + *p = 0; + void* r = (void*) (*serviceFn)(2,n); + return r; +} +static +void FreeMemory ( void* p, int* zz ) +{ + *zz = 0; + // free(p); +} + + + +/************** +** DoEmFloat ** +*************** +** Perform the floating-point emulation routines portion of the +** CPU benchmark. Returns the operations per second. +*/ +static +void DoEmFloat(void) +{ +EmFloatStruct *locemfloatstruct; /* Local structure */ +InternalFPF *abase; /* Base of A array */ +InternalFPF *bbase; /* Base of B array */ +InternalFPF *cbase; /* Base of C array */ +ulong tickcount; /* # of ticks */ +char *errorcontext; /* Error context string pointer */ +int systemerror; /* For holding error code */ +ulong loops; /* # of loops */ + +/* +** Link to global structure +*/ +EmFloatStruct global_emfloatstruct; + global_emfloatstruct.adjust = 0; + global_emfloatstruct.request_secs = 0; + global_emfloatstruct.arraysize = 100; + global_emfloatstruct.loops = 1; + global_emfloatstruct.emflops = 0.0; +locemfloatstruct=&global_emfloatstruct; + +/* +** Set the error context +*/ +errorcontext="CPU:Floating Emulation"; + + +abase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF), + &systemerror); + +bbase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF), + &systemerror); + +cbase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF), + &systemerror); + +/* +** Set up the arrays +*/ +SetupCPUEmFloatArrays(abase,bbase,cbase,locemfloatstruct->arraysize); + + loops=100; + tickcount=DoEmFloatIteration(abase,bbase,cbase, + locemfloatstruct->arraysize, + loops); + +FreeMemory((void *)abase,&systemerror); +FreeMemory((void *)bbase,&systemerror); +FreeMemory((void *)cbase,&systemerror); + +return; +} + +////////////////// +void entry ( HWord(*f)(HWord,HWord) ) +{ + serviceFn = f; + vex_printf("starting\n"); + DoEmFloat(); + (*serviceFn)(0,0); +}