Home | History | Annotate | Download | only in switchback
      1 /*
      2 ** emfloat.c
      3 ** Source for emulated floating-point routines.
      4 ** BYTEmark (tm)
      5 ** BYTE's Native Mode Benchmarks
      6 ** Rick Grehan, BYTE Magazine.
      7 **
      8 ** Created:
      9 ** Last update: 3/95
     10 **
     11 ** DISCLAIMER
     12 ** The source, executable, and documentation files that comprise
     13 ** the BYTEmark benchmarks are made available on an "as is" basis.
     14 ** This means that we at BYTE Magazine have made every reasonable
     15 ** effort to verify that the there are no errors in the source and
     16 ** executable code.  We cannot, however, guarantee that the programs
     17 ** are error-free.  Consequently, McGraw-HIll and BYTE Magazine make
     18 ** no claims in regard to the fitness of the source code, executable
     19 ** code, and documentation of the BYTEmark.
     20 **  Furthermore, BYTE Magazine, McGraw-Hill, and all employees
     21 ** of McGraw-Hill cannot be held responsible for any damages resulting
     22 ** from the use of this code or the results obtained from using
     23 ** this code.
     24 */
     25 
     26 #include "../pub/libvex_basictypes.h"
     27 
     28 static HWord (*serviceFn)(HWord,HWord) = 0;
     29 
     30 
     31 /////////////////////////////////////////////////////////////////////
     32 /////////////////////////////////////////////////////////////////////
     33 
     34 static char* my_strcpy ( char* dest, const char* src )
     35 {
     36    char* dest_orig = dest;
     37    while (*src) *dest++ = *src++;
     38    *dest = 0;
     39    return dest_orig;
     40 }
     41 
     42 static void* my_memcpy ( void *dest, const void *src, int sz )
     43 {
     44    const char *s = (const char *)src;
     45    char *d = (char *)dest;
     46 
     47    while (sz--)
     48       *d++ = *s++;
     49 
     50    return dest;
     51 }
     52 
     53 static void* my_memmove( void *dst, const void *src, unsigned int len )
     54 {
     55     register char *d;
     56     register char *s;
     57     if ( dst > src ) {
     58         d = (char *)dst + len - 1;
     59         s = (char *)src + len - 1;
     60         while ( len >= 4 ) {
     61             *d-- = *s--;
     62             *d-- = *s--;
     63             *d-- = *s--;
     64             *d-- = *s--;
     65             len -= 4;
     66         }
     67         while ( len-- ) {
     68             *d-- = *s--;
     69         }
     70     } else if ( dst < src ) {
     71         d = (char *)dst;
     72         s = (char *)src;
     73         while ( len >= 4 ) {
     74             *d++ = *s++;
     75             *d++ = *s++;
     76             *d++ = *s++;
     77             *d++ = *s++;
     78             len -= 4;
     79         }
     80         while ( len-- ) {
     81             *d++ = *s++;
     82         }
     83     }
     84     return dst;
     85 }
     86 
     87 /////////////////////////////////////////////////////////////////////
     88 
     89 static void vexxx_log_bytes ( char* p, int n )
     90 {
     91    int i;
     92    for (i = 0; i < n; i++)
     93       (*serviceFn)( 1, (int)p[i] );
     94 }
     95 
     96 /*---------------------------------------------------------*/
     97 /*--- vexxx_printf                                        ---*/
     98 /*---------------------------------------------------------*/
     99 
    100 /* This should be the only <...> include in the entire VEXXX library.
    101    New code for vexxx_util.c should go above this point. */
    102 #include <stdarg.h>
    103 
    104 static HChar vexxx_toupper ( HChar c )
    105 {
    106    if (c >= 'a' && c <= 'z')
    107       return toHChar(c + ('A' - 'a'));
    108    else
    109       return c;
    110 }
    111 
    112 static Int vexxx_strlen ( const HChar* str )
    113 {
    114    Int i = 0;
    115    while (str[i] != 0) i++;
    116    return i;
    117 }
    118 
    119 Bool vexxx_streq ( const HChar* s1, const HChar* s2 )
    120 {
    121    while (True) {
    122       if (*s1 == 0 && *s2 == 0)
    123          return True;
    124       if (*s1 != *s2)
    125          return False;
    126       s1++;
    127       s2++;
    128    }
    129 }
    130 
    131 /* Some flags.  */
    132 #define VG_MSG_SIGNED    1 /* The value is signed. */
    133 #define VG_MSG_ZJUSTIFY  2 /* Must justify with '0'. */
    134 #define VG_MSG_LJUSTIFY  4 /* Must justify on the left. */
    135 #define VG_MSG_PAREN     8 /* Parenthesize if present (for %y) */
    136 #define VG_MSG_COMMA    16 /* Add commas to numbers (for %d, %u) */
    137 
    138 /* Copy a string into the buffer. */
    139 static UInt
    140 myvprintf_str ( void(*send)(HChar), Int flags, Int width, HChar* str,
    141                 Bool capitalise )
    142 {
    143 #  define MAYBE_TOUPPER(ch) toHChar(capitalise ? vexxx_toupper(ch) : (ch))
    144    UInt ret = 0;
    145    Int i, extra;
    146    Int len = vexxx_strlen(str);
    147 
    148    if (width == 0) {
    149       ret += len;
    150       for (i = 0; i < len; i++)
    151          send(MAYBE_TOUPPER(str[i]));
    152       return ret;
    153    }
    154 
    155    if (len > width) {
    156       ret += width;
    157       for (i = 0; i < width; i++)
    158          send(MAYBE_TOUPPER(str[i]));
    159       return ret;
    160    }
    161 
    162    extra = width - len;
    163    if (flags & VG_MSG_LJUSTIFY) {
    164       ret += extra;
    165       for (i = 0; i < extra; i++)
    166          send(' ');
    167    }
    168    ret += len;
    169    for (i = 0; i < len; i++)
    170       send(MAYBE_TOUPPER(str[i]));
    171    if (!(flags & VG_MSG_LJUSTIFY)) {
    172       ret += extra;
    173       for (i = 0; i < extra; i++)
    174          send(' ');
    175    }
    176 
    177 #  undef MAYBE_TOUPPER
    178 
    179    return ret;
    180 }
    181 
    182 /* Write P into the buffer according to these args:
    183  *  If SIGN is true, p is a signed.
    184  *  BASE is the base.
    185  *  If WITH_ZERO is true, '0' must be added.
    186  *  WIDTH is the width of the field.
    187  */
    188 static UInt
    189 myvprintf_int64 ( void(*send)(HChar), Int flags, Int base, Int width, ULong pL)
    190 {
    191    HChar buf[40];
    192    Int   ind = 0;
    193    Int   i, nc = 0;
    194    Bool  neg = False;
    195    HChar *digits = "0123456789ABCDEF";
    196    UInt  ret = 0;
    197    UInt  p = (UInt)pL;
    198 
    199    if (base < 2 || base > 16)
    200       return ret;
    201 
    202    if ((flags & VG_MSG_SIGNED) && (Int)p < 0) {
    203       p   = - (Int)p;
    204       neg = True;
    205    }
    206 
    207    if (p == 0)
    208       buf[ind++] = '0';
    209    else {
    210       while (p > 0) {
    211          if ((flags & VG_MSG_COMMA) && 10 == base &&
    212              0 == (ind-nc) % 3 && 0 != ind)
    213          {
    214             buf[ind++] = ',';
    215             nc++;
    216          }
    217          buf[ind++] = digits[p % base];
    218          p /= base;
    219       }
    220    }
    221 
    222    if (neg)
    223       buf[ind++] = '-';
    224 
    225    if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
    226       for(; ind < width; ind++) {
    227 	//vassert(ind < 39);
    228          buf[ind] = toHChar((flags & VG_MSG_ZJUSTIFY) ? '0': ' ');
    229       }
    230    }
    231 
    232    /* Reverse copy to buffer.  */
    233    ret += ind;
    234    for (i = ind -1; i >= 0; i--) {
    235       send(buf[i]);
    236    }
    237    if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
    238       for(; ind < width; ind++) {
    239 	 ret++;
    240          send(' ');  // Never pad with zeroes on RHS -- changes the value!
    241       }
    242    }
    243    return ret;
    244 }
    245 
    246 
    247 /* A simple vprintf().  */
    248 static
    249 UInt vprintf_wrk ( void(*send)(HChar), const HChar *format, va_list vargs )
    250 {
    251    UInt ret = 0;
    252    int i;
    253    int flags;
    254    int width;
    255    Bool is_long;
    256 
    257    /* We assume that vargs has already been initialised by the
    258       caller, using va_start, and that the caller will similarly
    259       clean up with va_end.
    260    */
    261 
    262    for (i = 0; format[i] != 0; i++) {
    263       if (format[i] != '%') {
    264          send(format[i]);
    265 	 ret++;
    266          continue;
    267       }
    268       i++;
    269       /* A '%' has been found.  Ignore a trailing %. */
    270       if (format[i] == 0)
    271          break;
    272       if (format[i] == '%') {
    273          /* `%%' is replaced by `%'. */
    274          send('%');
    275 	 ret++;
    276          continue;
    277       }
    278       flags = 0;
    279       is_long = False;
    280       width = 0; /* length of the field. */
    281       if (format[i] == '(') {
    282 	 flags |= VG_MSG_PAREN;
    283 	 i++;
    284       }
    285       /* If ',' follows '%', commas will be inserted. */
    286       if (format[i] == ',') {
    287          flags |= VG_MSG_COMMA;
    288          i++;
    289       }
    290       /* If '-' follows '%', justify on the left. */
    291       if (format[i] == '-') {
    292          flags |= VG_MSG_LJUSTIFY;
    293          i++;
    294       }
    295       /* If '0' follows '%', pads will be inserted. */
    296       if (format[i] == '0') {
    297          flags |= VG_MSG_ZJUSTIFY;
    298          i++;
    299       }
    300       /* Compute the field length. */
    301       while (format[i] >= '0' && format[i] <= '9') {
    302          width *= 10;
    303          width += format[i++] - '0';
    304       }
    305       while (format[i] == 'l') {
    306          i++;
    307          is_long = True;
    308       }
    309 
    310       switch (format[i]) {
    311          case 'd': /* %d */
    312             flags |= VG_MSG_SIGNED;
    313             if (is_long)
    314                ret += myvprintf_int64(send, flags, 10, width,
    315 				      (ULong)(va_arg (vargs, Long)));
    316             else
    317                ret += myvprintf_int64(send, flags, 10, width,
    318 				      (ULong)(va_arg (vargs, Int)));
    319             break;
    320          case 'u': /* %u */
    321             if (is_long)
    322                ret += myvprintf_int64(send, flags, 10, width,
    323 				      (ULong)(va_arg (vargs, ULong)));
    324             else
    325                ret += myvprintf_int64(send, flags, 10, width,
    326 				      (ULong)(va_arg (vargs, UInt)));
    327             break;
    328          case 'p': /* %p */
    329 	    ret += 2;
    330             send('0');
    331             send('x');
    332             ret += myvprintf_int64(send, flags, 16, width,
    333 				   (ULong)((HWord)va_arg (vargs, void *)));
    334             break;
    335          case 'x': /* %x */
    336             if (is_long)
    337                ret += myvprintf_int64(send, flags, 16, width,
    338 				      (ULong)(va_arg (vargs, ULong)));
    339             else
    340                ret += myvprintf_int64(send, flags, 16, width,
    341 				      (ULong)(va_arg (vargs, UInt)));
    342             break;
    343          case 'c': /* %c */
    344 	    ret++;
    345             send(toHChar(va_arg (vargs, int)));
    346             break;
    347          case 's': case 'S': { /* %s */
    348             char *str = va_arg (vargs, char *);
    349             if (str == (char*) 0) str = "(null)";
    350             ret += myvprintf_str(send, flags, width, str,
    351                                  toBool(format[i]=='S'));
    352             break;
    353 	 }
    354 #        if 0
    355 	 case 'y': { /* %y - print symbol */
    356 	    Addr a = va_arg(vargs, Addr);
    357 
    358             HChar *name;
    359 	    if (VG_(get_fnname_w_offset)(a, &name)) {
    360                HChar buf[1 + VG_strlen(name) + 1 + 1];
    361 	       if (flags & VG_MSG_PAREN) {
    362                   VG_(sprintf)(str, "(%s)", name):
    363 	       } else {
    364                   VG_(sprintf)(str, "%s", name):
    365                }
    366 	       ret += myvprintf_str(send, flags, width, buf, 0);
    367 	    }
    368 	    break;
    369 	 }
    370 #        endif
    371          default:
    372             break;
    373       }
    374    }
    375    return ret;
    376 }
    377 
    378 
    379 /* A general replacement for printf().  Note that only low-level
    380    debugging info should be sent via here.  The official route is to
    381    to use vg_message().  This interface is deprecated.
    382 */
    383 static HChar myprintf_buf[1000];
    384 static Int   n_myprintf_buf;
    385 
    386 static void add_to_myprintf_buf ( HChar c )
    387 {
    388    if (c == '\n' || n_myprintf_buf >= 1000-10 /*paranoia*/ ) {
    389       (*vexxx_log_bytes)( myprintf_buf, vexxx_strlen(myprintf_buf) );
    390       n_myprintf_buf = 0;
    391       myprintf_buf[n_myprintf_buf] = 0;
    392    }
    393    myprintf_buf[n_myprintf_buf++] = c;
    394    myprintf_buf[n_myprintf_buf] = 0;
    395 }
    396 
    397 static UInt vexxx_printf ( const char *format, ... )
    398 {
    399    UInt ret;
    400    va_list vargs;
    401    va_start(vargs,format);
    402 
    403    n_myprintf_buf = 0;
    404    myprintf_buf[n_myprintf_buf] = 0;
    405    ret = vprintf_wrk ( add_to_myprintf_buf, format, vargs );
    406 
    407    if (n_myprintf_buf > 0) {
    408       (*vexxx_log_bytes)( myprintf_buf, n_myprintf_buf );
    409    }
    410 
    411    va_end(vargs);
    412 
    413    return ret;
    414 }
    415 
    416 /*---------------------------------------------------------------*/
    417 /*--- end                                          vexxx_util.c ---*/
    418 /*---------------------------------------------------------------*/
    419 
    420 
    421 /////////////////////////////////////////////////////////////////////
    422 /////////////////////////////////////////////////////////////////////
    423 
    424 //#include <stdio.h>
    425 //#include <string.h>
    426 //#include <malloc.h>
    427 
    428 typedef unsigned char uchar;
    429 typedef unsigned int uint;
    430 typedef unsigned short ushort;
    431 typedef unsigned long ulong;
    432 typedef int int32;              /* Signed 32 bit integer */
    433 
    434 #define INTERNAL_FPF_PRECISION 4
    435 #define CPUEMFLOATLOOPMAX 500000L
    436 #define EMFARRAYSIZE 3000L
    437 
    438 typedef struct {
    439         int adjust;             /* Set adjust code */
    440         ulong request_secs;     /* # of seconds requested */
    441         ulong arraysize;        /* Size of array */
    442         ulong loops;            /* Loops per iterations */
    443         double emflops;         /* Results */
    444 } EmFloatStruct;
    445 
    446 
    447 
    448 /* Is this a 64 bit architecture? If so, this will define LONG64 */
    449 /* Uwe F. Mayer 15 November 1997                                 */
    450 // #include "pointer.h"
    451 
    452 #define u8 unsigned char
    453 #define u16 unsigned short
    454 #ifdef LONG64
    455 #define u32 unsigned int
    456 #else
    457 #define u32 unsigned long
    458 #endif
    459 #define uchar unsigned char
    460 #define ulong unsigned long
    461 
    462 #define MAX_EXP 32767L
    463 #define MIN_EXP (-32767L)
    464 
    465 #define IFPF_IS_ZERO 0
    466 #define IFPF_IS_SUBNORMAL 1
    467 #define IFPF_IS_NORMAL 2
    468 #define IFPF_IS_INFINITY 3
    469 #define IFPF_IS_NAN 4
    470 #define IFPF_TYPE_COUNT 5
    471 
    472 #define ZERO_ZERO                       0
    473 #define ZERO_SUBNORMAL                  1
    474 #define ZERO_NORMAL                     2
    475 #define ZERO_INFINITY                   3
    476 #define ZERO_NAN                        4
    477 
    478 #define SUBNORMAL_ZERO                  5
    479 #define SUBNORMAL_SUBNORMAL             6
    480 #define SUBNORMAL_NORMAL                7
    481 #define SUBNORMAL_INFINITY              8
    482 #define SUBNORMAL_NAN                   9
    483 
    484 #define NORMAL_ZERO                     10
    485 #define NORMAL_SUBNORMAL                11
    486 #define NORMAL_NORMAL                   12
    487 #define NORMAL_INFINITY                 13
    488 #define NORMAL_NAN                      14
    489 
    490 #define INFINITY_ZERO                   15
    491 #define INFINITY_SUBNORMAL              16
    492 #define INFINITY_NORMAL                 17
    493 #define INFINITY_INFINITY               18
    494 #define INFINITY_NAN                    19
    495 
    496 #define NAN_ZERO                        20
    497 #define NAN_SUBNORMAL                   21
    498 #define NAN_NORMAL                      22
    499 #define NAN_INFINITY                    23
    500 #define NAN_NAN                         24
    501 #define OPERAND_ZERO                    0
    502 #define OPERAND_SUBNORMAL               1
    503 #define OPERAND_NORMAL                  2
    504 #define OPERAND_INFINITY                3
    505 #define OPERAND_NAN                     4
    506 
    507 typedef struct
    508 {
    509         u8 type;        /* Indicates, NORMAL, SUBNORMAL, etc. */
    510         u8 sign;        /* Mantissa sign */
    511         short exp;      /* Signed exponent...no bias */
    512         u16 mantissa[INTERNAL_FPF_PRECISION];
    513 } InternalFPF;
    514 
    515 static
    516 void SetupCPUEmFloatArrays(InternalFPF *abase,
    517         InternalFPF *bbase, InternalFPF *cbase, ulong arraysize);
    518 static
    519 ulong DoEmFloatIteration(InternalFPF *abase,
    520         InternalFPF *bbase, InternalFPF *cbase,
    521         ulong arraysize, ulong loops);
    522 
    523 static void SetInternalFPFZero(InternalFPF *dest,
    524                         uchar sign);
    525 static void SetInternalFPFInfinity(InternalFPF *dest,
    526                         uchar sign);
    527 static void SetInternalFPFNaN(InternalFPF *dest);
    528 static int IsMantissaZero(u16 *mant);
    529 static void Add16Bits(u16 *carry,u16 *a,u16 b,u16 c);
    530 static void Sub16Bits(u16 *borrow,u16 *a,u16 b,u16 c);
    531 static void ShiftMantLeft1(u16 *carry,u16 *mantissa);
    532 static void ShiftMantRight1(u16 *carry,u16 *mantissa);
    533 static void StickyShiftRightMant(InternalFPF *ptr,int amount);
    534 static void normalize(InternalFPF *ptr);
    535 static void denormalize(InternalFPF *ptr,int minimum_exponent);
    536 static void RoundInternalFPF(InternalFPF *ptr);
    537 static void choose_nan(InternalFPF *x,InternalFPF *y,InternalFPF *z,
    538                 int intel_flag);
    539 static void AddSubInternalFPF(uchar operation,InternalFPF *x,
    540                 InternalFPF *y,InternalFPF *z);
    541 static void MultiplyInternalFPF(InternalFPF *x,InternalFPF *y,
    542                         InternalFPF *z);
    543 static void DivideInternalFPF(InternalFPF *x,InternalFPF *y,
    544                         InternalFPF *z);
    545 
    546 static void Int32ToInternalFPF(int32 mylong,
    547                 InternalFPF *dest);
    548 static int InternalFPFToString(char *dest,
    549                 InternalFPF *src);
    550 
    551 static int32 randnum(int32 lngval);
    552 
    553 static int32 randwc(int32 num)
    554 {
    555 	return(randnum((int32)0)%num);
    556 }
    557 
    558 static int32 randw[2] = { (int32)13 , (int32)117 };
    559 static int32 randnum(int32 lngval)
    560 {
    561 	register int32 interm;
    562 
    563 	if (lngval!=(int32)0)
    564 	{	randw[0]=(int32)13; randw[1]=(int32)117; }
    565 
    566 	interm=(randw[0]*(int32)254754+randw[1]*(int32)529562)%(int32)999563;
    567 	randw[1]=randw[0];
    568 	randw[0]=interm;
    569 	return(interm);
    570 }
    571 
    572 
    573 static
    574 void SetupCPUEmFloatArrays(InternalFPF *abase,
    575                 InternalFPF *bbase,
    576                 InternalFPF *cbase,
    577                 ulong arraysize)
    578 {
    579 ulong i;
    580 InternalFPF locFPF1,locFPF2;
    581 
    582 randnum((int32)13);
    583 
    584 for(i=0;i<arraysize;i++)
    585 {/*       LongToInternalFPF(randwc(50000L),&locFPF1); */
    586         Int32ToInternalFPF(randwc((int32)50000),&locFPF1);
    587  /*       LongToInternalFPF(randwc(50000L)+1L,&locFPF2); */
    588         Int32ToInternalFPF(randwc((int32)50000)+(int32)1,&locFPF2);
    589         DivideInternalFPF(&locFPF1,&locFPF2,abase+i);
    590  /*       LongToInternalFPF(randwc(50000L)+1L,&locFPF2); */
    591         Int32ToInternalFPF(randwc((int32)50000)+(int32)1,&locFPF2);
    592         DivideInternalFPF(&locFPF1,&locFPF2,bbase+i);
    593 }
    594 return;
    595 }
    596 
    597 
    598 static char* str1 = "loops %d\n";
    599 static
    600 ulong DoEmFloatIteration(InternalFPF *abase,
    601                 InternalFPF *bbase,
    602                 InternalFPF *cbase,
    603                 ulong arraysize, ulong loops)
    604 {
    605 static uchar jtable[16] = {0,0,0,0,1,1,1,1,2,2,2,2,2,3,3,3};
    606 ulong i;
    607 int number_of_loops;
    608  loops = 100;
    609 number_of_loops=loops-1; /* the index of the first loop we run */
    610 
    611 vexxx_printf(str1, (int)loops);
    612 
    613 /*
    614 ** Each pass through the array performs operations in
    615 ** the followingratios:
    616 **   4 adds, 4 subtracts, 5 multiplies, 3 divides
    617 ** (adds and subtracts being nearly the same operation)
    618 */
    619 
    620 {
    621         for(i=0;i<arraysize;i++)
    622                 switch(jtable[i % 16])
    623                 {
    624                         case 0: /* Add */
    625                                 AddSubInternalFPF(0,abase+i,
    626                                   bbase+i,
    627                                   cbase+i);
    628                                 break;
    629                         case 1: /* Subtract */
    630                                 AddSubInternalFPF(1,abase+i,
    631                                   bbase+i,
    632                                   cbase+i);
    633                                 break;
    634                         case 2: /* Multiply */
    635                                 MultiplyInternalFPF(abase+i,
    636                                   bbase+i,
    637                                   cbase+i);
    638                                 break;
    639                         case 3: /* Divide */
    640                                 DivideInternalFPF(abase+i,
    641                                   bbase+i,
    642                                   cbase+i);
    643                                 break;
    644                 }
    645 {
    646   ulong j[8];   /* we test 8 entries */
    647   int k;
    648   ulong i;
    649   char buffer[1024];
    650   if (100==loops) /* the first loop */
    651     {
    652       j[0]=(ulong)2;
    653       j[1]=(ulong)6;
    654       j[2]=(ulong)10;
    655       j[3]=(ulong)14;
    656       j[4]=(ulong)(arraysize-14);
    657       j[5]=(ulong)(arraysize-10);
    658       j[6]=(ulong)(arraysize-6);
    659       j[7]=(ulong)(arraysize-2);
    660       for(k=0;k<8;k++){
    661 	i=j[k];
    662 	InternalFPFToString(buffer,abase+i);
    663 	vexxx_printf("%6d: (%s) ",i,buffer);
    664 	switch(jtable[i % 16])
    665 	  {
    666 	  case 0: my_strcpy(buffer,"+"); break;
    667 	  case 1: my_strcpy(buffer,"-"); break;
    668 	  case 2: my_strcpy(buffer,"*"); break;
    669 	  case 3: my_strcpy(buffer,"/"); break;
    670 	  }
    671 	vexxx_printf("%s ",buffer);
    672 	InternalFPFToString(buffer,bbase+i);
    673 	vexxx_printf("(%s) = ",buffer);
    674 	InternalFPFToString(buffer,cbase+i);
    675 	vexxx_printf("%s\n",buffer);
    676       }
    677 return 0;
    678     }
    679 }
    680 }
    681 return 0;
    682 }
    683 
    684 /***********************
    685 ** SetInternalFPFZero **
    686 ************************
    687 ** Set an internal floating-point-format number to zero.
    688 ** sign determines the sign of the zero.
    689 */
    690 static void SetInternalFPFZero(InternalFPF *dest,
    691                         uchar sign)
    692 {
    693 int i;          /* Index */
    694 
    695 dest->type=IFPF_IS_ZERO;
    696 dest->sign=sign;
    697 dest->exp=MIN_EXP;
    698 for(i=0;i<INTERNAL_FPF_PRECISION;i++)
    699         dest->mantissa[i]=0;
    700 return;
    701 }
    702 
    703 /***************************
    704 ** SetInternalFPFInfinity **
    705 ****************************
    706 ** Set an internal floating-point-format number to infinity.
    707 ** This can happen if the exponent exceeds MAX_EXP.
    708 ** As above, sign picks the sign of infinity.
    709 */
    710 static void SetInternalFPFInfinity(InternalFPF *dest,
    711                         uchar sign)
    712 {
    713 int i;          /* Index */
    714 
    715 dest->type=IFPF_IS_INFINITY;
    716 dest->sign=sign;
    717 dest->exp=MIN_EXP;
    718 for(i=0;i<INTERNAL_FPF_PRECISION;i++)
    719         dest->mantissa[i]=0;
    720 return;
    721 }
    722 
    723 /**********************
    724 ** SetInternalFPFNaN **
    725 ***********************
    726 ** Set an internal floating-point-format number to Nan
    727 ** (not a number).  Note that we "emulate" an 80x87 as far
    728 ** as the mantissa bits go.
    729 */
    730 static void SetInternalFPFNaN(InternalFPF *dest)
    731 {
    732 int i;          /* Index */
    733 
    734 dest->type=IFPF_IS_NAN;
    735 dest->exp=MAX_EXP;
    736 dest->sign=1;
    737 dest->mantissa[0]=0x4000;
    738 for(i=1;i<INTERNAL_FPF_PRECISION;i++)
    739         dest->mantissa[i]=0;
    740 
    741 return;
    742 }
    743 
    744 /*******************
    745 ** IsMantissaZero **
    746 ********************
    747 ** Pass this routine a pointer to an internal floating point format
    748 ** number's mantissa.  It checks for an all-zero mantissa.
    749 ** Returns 0 if it is NOT all zeros, !=0 otherwise.
    750 */
    751 static int IsMantissaZero(u16 *mant)
    752 {
    753 int i;          /* Index */
    754 int n;          /* Return value */
    755 
    756 n=0;
    757 for(i=0;i<INTERNAL_FPF_PRECISION;i++)
    758         n|=mant[i];
    759 
    760 return(!n);
    761 }
    762 
    763 /**************
    764 ** Add16Bits **
    765 ***************
    766 ** Add b, c, and carry.  Retult in a.  New carry in carry.
    767 */
    768 static void Add16Bits(u16 *carry,
    769                 u16 *a,
    770                 u16 b,
    771                 u16 c)
    772 {
    773 u32 accum;              /* Accumulator */
    774 
    775 /*
    776 ** Do the work in the 32-bit accumulator so we can return
    777 ** the carry.
    778 */
    779 accum=(u32)b;
    780 accum+=(u32)c;
    781 accum+=(u32)*carry;
    782 *carry=(u16)((accum & 0x00010000) ? 1 : 0);     /* New carry */
    783 *a=(u16)(accum & 0xFFFF);       /* Result is lo 16 bits */
    784 return;
    785 }
    786 
    787 /**************
    788 ** Sub16Bits **
    789 ***************
    790 ** Additive inverse of above.
    791 */
    792 static void Sub16Bits(u16 *borrow,
    793                 u16 *a,
    794                 u16 b,
    795                 u16 c)
    796 {
    797 u32 accum;              /* Accumulator */
    798 
    799 accum=(u32)b;
    800 accum-=(u32)c;
    801 accum-=(u32)*borrow;
    802 *borrow=(u32)((accum & 0x00010000) ? 1 : 0);    /* New borrow */
    803 *a=(u16)(accum & 0xFFFF);
    804 return;
    805 }
    806 
    807 /*******************
    808 ** ShiftMantLeft1 **
    809 ********************
    810 ** Shift a vector of 16-bit numbers left 1 bit.  Also provides
    811 ** a carry bit, which is shifted in at the beginning, and
    812 ** shifted out at the end.
    813 */
    814 static void ShiftMantLeft1(u16 *carry,
    815                         u16 *mantissa)
    816 {
    817 int i;          /* Index */
    818 int new_carry;
    819 u16 accum;      /* Temporary holding placed */
    820 
    821 for(i=INTERNAL_FPF_PRECISION-1;i>=0;i--)
    822 {       accum=mantissa[i];
    823         new_carry=accum & 0x8000;       /* Get new carry */
    824         accum=accum<<1;                 /* Do the shift */
    825         if(*carry)
    826                 accum|=1;               /* Insert previous carry */
    827         *carry=new_carry;
    828         mantissa[i]=accum;              /* Return shifted value */
    829 }
    830 return;
    831 }
    832 
    833 /********************
    834 ** ShiftMantRight1 **
    835 *********************
    836 ** Shift a mantissa right by 1 bit.  Provides carry, as
    837 ** above
    838 */
    839 static void ShiftMantRight1(u16 *carry,
    840                         u16 *mantissa)
    841 {
    842 int i;          /* Index */
    843 int new_carry;
    844 u16 accum;
    845 
    846 for(i=0;i<INTERNAL_FPF_PRECISION;i++)
    847 {       accum=mantissa[i];
    848         new_carry=accum & 1;            /* Get new carry */
    849         accum=accum>>1;
    850         if(*carry)
    851                 accum|=0x8000;
    852         *carry=new_carry;
    853         mantissa[i]=accum;
    854 }
    855 return;
    856 }
    857 
    858 
    859 /*****************************
    860 ** StickyShiftMantRight **
    861 ******************************
    862 ** This is a shift right of the mantissa with a "sticky bit".
    863 ** I.E., if a carry of 1 is shifted out of the least significant
    864 ** bit, the least significant bit is set to 1.
    865 */
    866 static void StickyShiftRightMant(InternalFPF *ptr,
    867                         int amount)
    868 {
    869 int i;          /* Index */
    870 u16 carry;      /* Self-explanatory */
    871 u16 *mantissa;
    872 
    873 mantissa=ptr->mantissa;
    874 
    875 if(ptr->type!=IFPF_IS_ZERO)     /* Don't bother shifting a zero */
    876 {
    877         /*
    878         ** If the amount of shifting will shift everyting
    879         ** out of existence, then just clear the whole mantissa
    880         ** and set the lowmost bit to 1.
    881         */
    882         if(amount>=INTERNAL_FPF_PRECISION * 16)
    883         {
    884                 for(i=0;i<INTERNAL_FPF_PRECISION-1;i++)
    885                         mantissa[i]=0;
    886                 mantissa[INTERNAL_FPF_PRECISION-1]=1;
    887         }
    888         else
    889                 for(i=0;i<amount;i++)
    890                 {
    891                         carry=0;
    892                         ShiftMantRight1(&carry,mantissa);
    893                         if(carry)
    894                                 mantissa[INTERNAL_FPF_PRECISION-1] |= 1;
    895                 }
    896 }
    897 return;
    898 }
    899 
    900 
    901 /**************************************************
    902 **         POST ARITHMETIC PROCESSING            **
    903 **  (NORMALIZE, ROUND, OVERFLOW, AND UNDERFLOW)  **
    904 **************************************************/
    905 
    906 /**************
    907 ** normalize **
    908 ***************
    909 ** Normalize an internal-representation number.  Normalization
    910 ** discards empty most-significant bits.
    911 */
    912 static void normalize(InternalFPF *ptr)
    913 {
    914 u16     carry;
    915 
    916 /*
    917 ** As long as there's a highmost 0 bit, shift the significand
    918 ** left 1 bit.  Each time you do this, though, you've
    919 ** gotta decrement the exponent.
    920 */
    921 while ((ptr->mantissa[0] & 0x8000) == 0)
    922 {
    923         carry = 0;
    924         ShiftMantLeft1(&carry, ptr->mantissa);
    925         ptr->exp--;
    926 }
    927 return;
    928 }
    929 
    930 /****************
    931 ** denormalize **
    932 *****************
    933 ** Denormalize an internal-representation number.  This means
    934 ** shifting it right until its exponent is equivalent to
    935 ** minimum_exponent. (You have to do this often in order
    936 ** to perform additions and subtractions).
    937 */
    938 static void denormalize(InternalFPF *ptr,
    939                 int minimum_exponent)
    940 {
    941 long exponent_difference;
    942 
    943 if (IsMantissaZero(ptr->mantissa))
    944 {
    945         vexxx_printf("Error:  zero significand in denormalize\n");
    946 }
    947 
    948 exponent_difference = ptr->exp-minimum_exponent;
    949 if (exponent_difference < 0)
    950 {
    951         /*
    952         ** The number is subnormal
    953         */
    954         exponent_difference = -exponent_difference;
    955         if (exponent_difference >= (INTERNAL_FPF_PRECISION * 16))
    956         {
    957                 /* Underflow */
    958                 SetInternalFPFZero(ptr, ptr->sign);
    959         }
    960         else
    961         {
    962                 ptr->exp+=exponent_difference;
    963                 StickyShiftRightMant(ptr, exponent_difference);
    964         }
    965 }
    966 return;
    967 }
    968 
    969 
    970 /*********************
    971 ** RoundInternalFPF **
    972 **********************
    973 ** Round an internal-representation number.
    974 ** The kind of rounding we do here is simplest...referred to as
    975 ** "chop".  "Extraneous" rightmost bits are simply hacked off.
    976 */
    977 void RoundInternalFPF(InternalFPF *ptr)
    978 {
    979 /* int i; */
    980 
    981 if (ptr->type == IFPF_IS_NORMAL ||
    982         ptr->type == IFPF_IS_SUBNORMAL)
    983 {
    984         denormalize(ptr, MIN_EXP);
    985         if (ptr->type != IFPF_IS_ZERO)
    986         {
    987 
    988                 /* clear the extraneous bits */
    989                 ptr->mantissa[3] &= 0xfff8;
    990 /*              for (i=4; i<INTERNAL_FPF_PRECISION; i++)
    991                 {
    992                         ptr->mantissa[i] = 0;
    993                 }
    994 */
    995                 /*
    996                 ** Check for overflow
    997                 */
    998 /*              Does not do anything as ptr->exp is a short and MAX_EXP=37268
    999 		if (ptr->exp > MAX_EXP)
   1000                 {
   1001                         SetInternalFPFInfinity(ptr, ptr->sign);
   1002                 }
   1003 */
   1004         }
   1005 }
   1006 return;
   1007 }
   1008 
   1009 /*******************************************************
   1010 **  ARITHMETIC OPERATIONS ON INTERNAL REPRESENTATION  **
   1011 *******************************************************/
   1012 
   1013 /***************
   1014 ** choose_nan **
   1015 ****************
   1016 ** Called by routines that are forced to perform math on
   1017 ** a pair of NaN's.  This routine "selects" which NaN is
   1018 ** to be returned.
   1019 */
   1020 static void choose_nan(InternalFPF *x,
   1021                 InternalFPF *y,
   1022                 InternalFPF *z,
   1023                 int intel_flag)
   1024 {
   1025 int i;
   1026 
   1027 /*
   1028 ** Compare the two mantissas,
   1029 ** return the larger.  Note that we will be emulating
   1030 ** an 80387 in this operation.
   1031 */
   1032 for (i=0; i<INTERNAL_FPF_PRECISION; i++)
   1033 {
   1034         if (x->mantissa[i] > y->mantissa[i])
   1035         {
   1036                 my_memmove((void *)x,(void *)z,sizeof(InternalFPF));
   1037                 return;
   1038         }
   1039         if (x->mantissa[i] < y->mantissa[i])
   1040         {
   1041                 my_memmove((void *)y,(void *)z,sizeof(InternalFPF));
   1042                 return;
   1043         }
   1044 }
   1045 
   1046 /*
   1047 ** They are equal
   1048 */
   1049 if (!intel_flag)
   1050         /* if the operation is addition */
   1051         my_memmove((void *)x,(void *)z,sizeof(InternalFPF));
   1052 else
   1053         /* if the operation is multiplication */
   1054         my_memmove((void *)y,(void *)z,sizeof(InternalFPF));
   1055 return;
   1056 }
   1057 
   1058 
   1059 /**********************
   1060 ** AddSubInternalFPF **
   1061 ***********************
   1062 ** Adding or subtracting internal-representation numbers.
   1063 ** Internal-representation numbers pointed to by x and y are
   1064 ** added/subtracted and the result returned in z.
   1065 */
   1066 static void AddSubInternalFPF(uchar operation,
   1067                 InternalFPF *x,
   1068                 InternalFPF *y,
   1069                 InternalFPF *z)
   1070 {
   1071 int exponent_difference;
   1072 u16 borrow;
   1073 u16 carry;
   1074 int i;
   1075 InternalFPF locx,locy;  /* Needed since we alter them */
   1076 
   1077 /*
   1078 ** Following big switch statement handles the
   1079 ** various combinations of operand types.
   1080 */
   1081 switch ((x->type * IFPF_TYPE_COUNT) + y->type)
   1082 {
   1083 case ZERO_ZERO:
   1084         my_memmove((void *)x,(void *)z,sizeof(InternalFPF));
   1085         if (x->sign ^ y->sign ^ operation)
   1086         {
   1087                 z->sign = 0; /* positive */
   1088         }
   1089         break;
   1090 
   1091 case NAN_ZERO:
   1092 case NAN_SUBNORMAL:
   1093 case NAN_NORMAL:
   1094 case NAN_INFINITY:
   1095 case SUBNORMAL_ZERO:
   1096 case NORMAL_ZERO:
   1097 case INFINITY_ZERO:
   1098 case INFINITY_SUBNORMAL:
   1099 case INFINITY_NORMAL:
   1100         my_memmove((void *)x,(void *)z,sizeof(InternalFPF));
   1101         break;
   1102 
   1103 
   1104 case ZERO_NAN:
   1105 case SUBNORMAL_NAN:
   1106 case NORMAL_NAN:
   1107 case INFINITY_NAN:
   1108         my_memmove((void *)y,(void *)z,sizeof(InternalFPF));
   1109         break;
   1110 
   1111 case ZERO_SUBNORMAL:
   1112 case ZERO_NORMAL:
   1113 case ZERO_INFINITY:
   1114 case SUBNORMAL_INFINITY:
   1115 case NORMAL_INFINITY:
   1116         my_memmove((void *)y,(void *)z,sizeof(InternalFPF));
   1117         z->sign ^= operation;
   1118         break;
   1119 
   1120 case SUBNORMAL_SUBNORMAL:
   1121 case SUBNORMAL_NORMAL:
   1122 case NORMAL_SUBNORMAL:
   1123 case NORMAL_NORMAL:
   1124         /*
   1125         ** Copy x and y to locals, since we may have
   1126         ** to alter them.
   1127         */
   1128         my_memmove((void *)&locx,(void *)x,sizeof(InternalFPF));
   1129         my_memmove((void *)&locy,(void *)y,sizeof(InternalFPF));
   1130 
   1131         /* compute sum/difference */
   1132         exponent_difference = locx.exp-locy.exp;
   1133         if (exponent_difference == 0)
   1134         {
   1135                 /*
   1136                 ** locx.exp == locy.exp
   1137                 ** so, no shifting required
   1138                 */
   1139                 if (locx.type == IFPF_IS_SUBNORMAL ||
   1140                   locy.type == IFPF_IS_SUBNORMAL)
   1141                         z->type = IFPF_IS_SUBNORMAL;
   1142                 else
   1143                         z->type = IFPF_IS_NORMAL;
   1144 
   1145                 /*
   1146                 ** Assume that locx.mantissa > locy.mantissa
   1147                 */
   1148                 z->sign = locx.sign;
   1149                 z->exp= locx.exp;
   1150         }
   1151         else
   1152                 if (exponent_difference > 0)
   1153                 {
   1154                         /*
   1155                         ** locx.exp > locy.exp
   1156                         */
   1157                         StickyShiftRightMant(&locy,
   1158                                  exponent_difference);
   1159                         z->type = locx.type;
   1160                         z->sign = locx.sign;
   1161                         z->exp = locx.exp;
   1162                 }
   1163                 else    /* if (exponent_difference < 0) */
   1164                 {
   1165                         /*
   1166                         ** locx.exp < locy.exp
   1167                         */
   1168                         StickyShiftRightMant(&locx,
   1169                                 -exponent_difference);
   1170                         z->type = locy.type;
   1171                         z->sign = locy.sign ^ operation;
   1172                         z->exp = locy.exp;
   1173                 }
   1174 
   1175                 if (locx.sign ^ locy.sign ^ operation)
   1176                 {
   1177                         /*
   1178                         ** Signs are different, subtract mantissas
   1179                         */
   1180                         borrow = 0;
   1181                         for (i=(INTERNAL_FPF_PRECISION-1); i>=0; i--)
   1182                                 Sub16Bits(&borrow,
   1183                                         &z->mantissa[i],
   1184                                         locx.mantissa[i],
   1185                                         locy.mantissa[i]);
   1186 
   1187                         if (borrow)
   1188                         {
   1189                                 /* The y->mantissa was larger than the
   1190                                 ** x->mantissa leaving a negative
   1191                                 ** result.  Change the result back to
   1192                                 ** an unsigned number and flip the
   1193                                 ** sign flag.
   1194                                 */
   1195                                 z->sign = locy.sign ^ operation;
   1196                                 borrow = 0;
   1197                                 for (i=(INTERNAL_FPF_PRECISION-1); i>=0; i--)
   1198                                 {
   1199                                         Sub16Bits(&borrow,
   1200                                                 &z->mantissa[i],
   1201                                                 0,
   1202                                                 z->mantissa[i]);
   1203                                 }
   1204                         }
   1205                         else
   1206                         {
   1207                                 /* The assumption made above
   1208                                 ** (i.e. x->mantissa >= y->mantissa)
   1209                                 ** was correct.  Therefore, do nothing.
   1210                                 ** z->sign = x->sign;
   1211                                 */
   1212                         }
   1213 
   1214                         if (IsMantissaZero(z->mantissa))
   1215                         {
   1216                                 z->type = IFPF_IS_ZERO;
   1217                                 z->sign = 0; /* positive */
   1218                         }
   1219                         else
   1220                                 if (locx.type == IFPF_IS_NORMAL ||
   1221                                          locy.type == IFPF_IS_NORMAL)
   1222                                 {
   1223                                         normalize(z);
   1224                                 }
   1225                 }
   1226                 else
   1227                 {
   1228                         /* signs are the same, add mantissas */
   1229                         carry = 0;
   1230                         for (i=(INTERNAL_FPF_PRECISION-1); i>=0; i--)
   1231                         {
   1232                                 Add16Bits(&carry,
   1233                                         &z->mantissa[i],
   1234                                         locx.mantissa[i],
   1235                                         locy.mantissa[i]);
   1236                         }
   1237 
   1238                         if (carry)
   1239                         {
   1240                                 z->exp++;
   1241                                 carry=0;
   1242                                 ShiftMantRight1(&carry,z->mantissa);
   1243                                 z->mantissa[0] |= 0x8000;
   1244                                 z->type = IFPF_IS_NORMAL;
   1245                         }
   1246                         else
   1247                                 if (z->mantissa[0] & 0x8000)
   1248                                         z->type = IFPF_IS_NORMAL;
   1249         }
   1250         break;
   1251 
   1252 case INFINITY_INFINITY:
   1253         SetInternalFPFNaN(z);
   1254         break;
   1255 
   1256 case NAN_NAN:
   1257         choose_nan(x, y, z, 1);
   1258         break;
   1259 }
   1260 
   1261 /*
   1262 ** All the math is done; time to round.
   1263 */
   1264 RoundInternalFPF(z);
   1265 return;
   1266 }
   1267 
   1268 
   1269 /************************
   1270 ** MultiplyInternalFPF **
   1271 *************************
   1272 ** Two internal-representation numbers x and y are multiplied; the
   1273 ** result is returned in z.
   1274 */
   1275 static void MultiplyInternalFPF(InternalFPF *x,
   1276                         InternalFPF *y,
   1277                         InternalFPF *z)
   1278 {
   1279 int i;
   1280 int j;
   1281 u16 carry;
   1282 u16 extra_bits[INTERNAL_FPF_PRECISION];
   1283 InternalFPF locy;       /* Needed since this will be altered */
   1284 /*
   1285 ** As in the preceding function, this large switch
   1286 ** statement selects among the many combinations
   1287 ** of operands.
   1288 */
   1289 switch ((x->type * IFPF_TYPE_COUNT) + y->type)
   1290 {
   1291 case INFINITY_SUBNORMAL:
   1292 case INFINITY_NORMAL:
   1293 case INFINITY_INFINITY:
   1294 case ZERO_ZERO:
   1295 case ZERO_SUBNORMAL:
   1296 case ZERO_NORMAL:
   1297         my_memmove((void *)x,(void *)z,sizeof(InternalFPF));
   1298         z->sign ^= y->sign;
   1299         break;
   1300 
   1301 case SUBNORMAL_INFINITY:
   1302 case NORMAL_INFINITY:
   1303 case SUBNORMAL_ZERO:
   1304 case NORMAL_ZERO:
   1305         my_memmove((void *)y,(void *)z,sizeof(InternalFPF));
   1306         z->sign ^= x->sign;
   1307         break;
   1308 
   1309 case ZERO_INFINITY:
   1310 case INFINITY_ZERO:
   1311         SetInternalFPFNaN(z);
   1312         break;
   1313 
   1314 case NAN_ZERO:
   1315 case NAN_SUBNORMAL:
   1316 case NAN_NORMAL:
   1317 case NAN_INFINITY:
   1318         my_memmove((void *)x,(void *)z,sizeof(InternalFPF));
   1319         break;
   1320 
   1321 case ZERO_NAN:
   1322 case SUBNORMAL_NAN:
   1323 case NORMAL_NAN:
   1324 case INFINITY_NAN:
   1325         my_memmove((void *)y,(void *)z,sizeof(InternalFPF));
   1326         break;
   1327 
   1328 
   1329 case SUBNORMAL_SUBNORMAL:
   1330 case SUBNORMAL_NORMAL:
   1331 case NORMAL_SUBNORMAL:
   1332 case NORMAL_NORMAL:
   1333         /*
   1334         ** Make a local copy of the y number, since we will be
   1335         ** altering it in the process of multiplying.
   1336         */
   1337         my_memmove((void *)&locy,(void *)y,sizeof(InternalFPF));
   1338 
   1339         /*
   1340         ** Check for unnormal zero arguments
   1341         */
   1342         if (IsMantissaZero(x->mantissa) || IsMantissaZero(y->mantissa))
   1343                 SetInternalFPFInfinity(z, 0);
   1344 
   1345         /*
   1346         ** Initialize the result
   1347         */
   1348         if (x->type == IFPF_IS_SUBNORMAL ||
   1349             y->type == IFPF_IS_SUBNORMAL)
   1350                 z->type = IFPF_IS_SUBNORMAL;
   1351         else
   1352                 z->type = IFPF_IS_NORMAL;
   1353 
   1354         z->sign = x->sign ^ y->sign;
   1355         z->exp = x->exp + y->exp ;
   1356         for (i=0; i<INTERNAL_FPF_PRECISION; i++)
   1357         {
   1358                 z->mantissa[i] = 0;
   1359                 extra_bits[i] = 0;
   1360         }
   1361 
   1362         for (i=0; i<(INTERNAL_FPF_PRECISION*16); i++)
   1363         {
   1364                 /*
   1365                 ** Get rightmost bit of the multiplier
   1366                 */
   1367                 carry = 0;
   1368                 ShiftMantRight1(&carry, locy.mantissa);
   1369                 if (carry)
   1370                 {
   1371                         /*
   1372                         ** Add the multiplicand to the product
   1373                         */
   1374                         carry = 0;
   1375                         for (j=(INTERNAL_FPF_PRECISION-1); j>=0; j--)
   1376                                 Add16Bits(&carry,
   1377                                         &z->mantissa[j],
   1378                                         z->mantissa[j],
   1379                                         x->mantissa[j]);
   1380                 }
   1381                 else
   1382                 {
   1383                         carry = 0;
   1384                 }
   1385 
   1386                 /*
   1387                 ** Shift the product right.  Overflow bits get
   1388                 ** shifted into extra_bits.  We'll use it later
   1389                 ** to help with the "sticky" bit.
   1390                 */
   1391                 ShiftMantRight1(&carry, z->mantissa);
   1392                 ShiftMantRight1(&carry, extra_bits);
   1393         }
   1394 
   1395         /*
   1396         ** Normalize
   1397         ** Note that we use a "special" normalization routine
   1398         ** because we need to use the extra bits. (These are
   1399         ** bits that may have been shifted off the bottom that
   1400         ** we want to reclaim...if we can.
   1401         */
   1402         while ((z->mantissa[0] & 0x8000) == 0)
   1403         {
   1404                 carry = 0;
   1405                 ShiftMantLeft1(&carry, extra_bits);
   1406                 ShiftMantLeft1(&carry, z->mantissa);
   1407                 z->exp--;
   1408         }
   1409 
   1410         /*
   1411         ** Set the sticky bit if any bits set in extra bits.
   1412         */
   1413         if (IsMantissaZero(extra_bits))
   1414         {
   1415                 z->mantissa[INTERNAL_FPF_PRECISION-1] |= 1;
   1416         }
   1417         break;
   1418 
   1419 case NAN_NAN:
   1420         choose_nan(x, y, z, 0);
   1421         break;
   1422 }
   1423 
   1424 /*
   1425 ** All math done...do rounding.
   1426 */
   1427 RoundInternalFPF(z);
   1428 return;
   1429 }
   1430 
   1431 
   1432 /**********************
   1433 ** DivideInternalFPF **
   1434 ***********************
   1435 ** Divide internal FPF number x by y.  Return result in z.
   1436 */
   1437 static void DivideInternalFPF(InternalFPF *x,
   1438                         InternalFPF *y,
   1439                         InternalFPF *z)
   1440 {
   1441 int i;
   1442 int j;
   1443 u16 carry;
   1444 u16 extra_bits[INTERNAL_FPF_PRECISION];
   1445 InternalFPF locx;       /* Local for x number */
   1446 
   1447 /*
   1448 ** As with preceding function, the following switch
   1449 ** statement selects among the various possible
   1450 ** operands.
   1451 */
   1452 switch ((x->type * IFPF_TYPE_COUNT) + y->type)
   1453 {
   1454 case ZERO_ZERO:
   1455 case INFINITY_INFINITY:
   1456         SetInternalFPFNaN(z);
   1457         break;
   1458 
   1459 case ZERO_SUBNORMAL:
   1460 case ZERO_NORMAL:
   1461         if (IsMantissaZero(y->mantissa))
   1462         {
   1463                 SetInternalFPFNaN(z);
   1464                 break;
   1465         }
   1466 
   1467 case ZERO_INFINITY:
   1468 case SUBNORMAL_INFINITY:
   1469 case NORMAL_INFINITY:
   1470         SetInternalFPFZero(z, x->sign ^ y->sign);
   1471         break;
   1472 
   1473 case SUBNORMAL_ZERO:
   1474 case NORMAL_ZERO:
   1475         if (IsMantissaZero(x->mantissa))
   1476         {
   1477                 SetInternalFPFNaN(z);
   1478                 break;
   1479         }
   1480 
   1481 case INFINITY_ZERO:
   1482 case INFINITY_SUBNORMAL:
   1483 case INFINITY_NORMAL:
   1484         SetInternalFPFInfinity(z, 0);
   1485         z->sign = x->sign ^ y->sign;
   1486         break;
   1487 
   1488 case NAN_ZERO:
   1489 case NAN_SUBNORMAL:
   1490 case NAN_NORMAL:
   1491 case NAN_INFINITY:
   1492         my_memmove((void *)x,(void *)z,sizeof(InternalFPF));
   1493         break;
   1494 
   1495 case ZERO_NAN:
   1496 case SUBNORMAL_NAN:
   1497 case NORMAL_NAN:
   1498 case INFINITY_NAN:
   1499         my_memmove((void *)y,(void *)z,sizeof(InternalFPF));
   1500         break;
   1501 
   1502 case SUBNORMAL_SUBNORMAL:
   1503 case NORMAL_SUBNORMAL:
   1504 case SUBNORMAL_NORMAL:
   1505 case NORMAL_NORMAL:
   1506         /*
   1507         ** Make local copy of x number, since we'll be
   1508         ** altering it in the process of dividing.
   1509         */
   1510         my_memmove((void *)&locx,(void *)x,sizeof(InternalFPF));
   1511 
   1512         /*
   1513         ** Check for unnormal zero arguments
   1514         */
   1515         if (IsMantissaZero(locx.mantissa))
   1516         {
   1517                 if (IsMantissaZero(y->mantissa))
   1518                         SetInternalFPFNaN(z);
   1519                 else
   1520                         SetInternalFPFZero(z, 0);
   1521                 break;
   1522         }
   1523         if (IsMantissaZero(y->mantissa))
   1524         {
   1525                 SetInternalFPFInfinity(z, 0);
   1526                 break;
   1527         }
   1528 
   1529         /*
   1530         ** Initialize the result
   1531         */
   1532         z->type = x->type;
   1533         z->sign = x->sign ^ y->sign;
   1534         z->exp = x->exp - y->exp +
   1535                         ((INTERNAL_FPF_PRECISION * 16 * 2));
   1536         for (i=0; i<INTERNAL_FPF_PRECISION; i++)
   1537         {
   1538                 z->mantissa[i] = 0;
   1539                 extra_bits[i] = 0;
   1540         }
   1541 
   1542         while ((z->mantissa[0] & 0x8000) == 0)
   1543         {
   1544                 carry = 0;
   1545                 ShiftMantLeft1(&carry, locx.mantissa);
   1546                 ShiftMantLeft1(&carry, extra_bits);
   1547 
   1548                 /*
   1549                 ** Time to subtract yet?
   1550                 */
   1551                 if (carry == 0)
   1552                         for (j=0; j<INTERNAL_FPF_PRECISION; j++)
   1553                         {
   1554                                 if (y->mantissa[j] > extra_bits[j])
   1555                                 {
   1556                                         carry = 0;
   1557                                         goto no_subtract;
   1558                                 }
   1559                                 if (y->mantissa[j] < extra_bits[j])
   1560                                         break;
   1561                         }
   1562                 /*
   1563                 ** Divisor (y) <= dividend (x), subtract
   1564                 */
   1565                 carry = 0;
   1566                 for (j=(INTERNAL_FPF_PRECISION-1); j>=0; j--)
   1567                         Sub16Bits(&carry,
   1568                                 &extra_bits[j],
   1569                                 extra_bits[j],
   1570                                 y->mantissa[j]);
   1571                 carry = 1;      /* 1 shifted into quotient */
   1572         no_subtract:
   1573                 ShiftMantLeft1(&carry, z->mantissa);
   1574                 z->exp--;
   1575         }
   1576         break;
   1577 
   1578 case NAN_NAN:
   1579         choose_nan(x, y, z, 0);
   1580         break;
   1581 }
   1582 
   1583 /*
   1584 ** Math complete...do rounding
   1585 */
   1586 RoundInternalFPF(z);
   1587 }
   1588 
   1589 /**********************
   1590 ** LongToInternalFPF **
   1591 ** Int32ToInternalFPF **
   1592 ***********************
   1593 ** Convert a signed (long) 32-bit integer into an internal FPF number.
   1594 */
   1595 /* static void LongToInternalFPF(long mylong, */
   1596 static void Int32ToInternalFPF(int32 mylong,
   1597                 InternalFPF *dest)
   1598 {
   1599 int i;          /* Index */
   1600 u16 myword;     /* Used to hold converted stuff */
   1601 /*
   1602 ** Save the sign and get the absolute value.  This will help us
   1603 ** with 64-bit machines, since we use only the lower 32
   1604 ** bits just in case. (No longer necessary after we use int32.)
   1605 */
   1606 /* if(mylong<0L) */
   1607 if(mylong<(int32)0)
   1608 {       dest->sign=1;
   1609         mylong=(int32)0-mylong;
   1610 }
   1611 else
   1612         dest->sign=0;
   1613 /*
   1614 ** Prepare the destination floating point number
   1615 */
   1616 dest->type=IFPF_IS_NORMAL;
   1617 for(i=0;i<INTERNAL_FPF_PRECISION;i++)
   1618         dest->mantissa[i]=0;
   1619 
   1620 /*
   1621 ** See if we've got a zero.  If so, make the resultant FP
   1622 ** number a true zero and go home.
   1623 */
   1624 if(mylong==0)
   1625 {       dest->type=IFPF_IS_ZERO;
   1626         dest->exp=0;
   1627         return;
   1628 }
   1629 
   1630 /*
   1631 ** Not a true zero.  Set the exponent to 32 (internal FPFs have
   1632 ** no bias) and load the low and high words into their proper
   1633 ** locations in the mantissa.  Then normalize.  The action of
   1634 ** normalizing slides the mantissa bits into place and sets
   1635 ** up the exponent properly.
   1636 */
   1637 dest->exp=32;
   1638 myword=(u16)((mylong >> 16) & 0xFFFFL);
   1639 dest->mantissa[0]=myword;
   1640 myword=(u16)(mylong & 0xFFFFL);
   1641 dest->mantissa[1]=myword;
   1642 normalize(dest);
   1643 return;
   1644 }
   1645 
   1646 #if 1
   1647 /************************
   1648 ** InternalFPFToString **
   1649 *************************
   1650 ** FOR DEBUG PURPOSES
   1651 ** This routine converts an internal floating point representation
   1652 ** number to a string.  Used in debugging the package.
   1653 ** Returns length of converted number.
   1654 ** NOTE: dest must point to a buffer big enough to hold the
   1655 **  result.  Also, this routine does append a null (an effect
   1656 **  of using the sprintf() function).  It also returns
   1657 **  a length count.
   1658 ** NOTE: This routine returns 5 significant digits.  Thats
   1659 **  about all I feel safe with, given the method of
   1660 **  conversion.  It should be more than enough for programmers
   1661 **  to determine whether the package is properly ported.
   1662 */
   1663 static int InternalFPFToString(char *dest,
   1664                 InternalFPF *src)
   1665 {
   1666 InternalFPF locFPFNum;          /* Local for src (will be altered) */
   1667 InternalFPF IFPF10;             /* Floating-point 10 */
   1668 InternalFPF IFPFComp;           /* For doing comparisons */
   1669 int msign;                      /* Holding for mantissa sign */
   1670 int expcount;                   /* Exponent counter */
   1671 int ccount;                     /* Character counter */
   1672 int i,j,k;                      /* Index */
   1673 u16 carryaccum;                 /* Carry accumulator */
   1674 u16 mycarry;                    /* Local for carry */
   1675 
   1676 /*
   1677 ** Check first for the simple things...Nan, Infinity, Zero.
   1678 ** If found, copy the proper string in and go home.
   1679 */
   1680 switch(src->type)
   1681 {
   1682         case IFPF_IS_NAN:
   1683                 my_memcpy(dest,"NaN",3);
   1684                 return(3);
   1685 
   1686         case IFPF_IS_INFINITY:
   1687                 if(src->sign==0)
   1688                         my_memcpy(dest,"+Inf",4);
   1689                 else
   1690                         my_memcpy(dest,"-Inf",4);
   1691                 return(4);
   1692 
   1693         case IFPF_IS_ZERO:
   1694                 if(src->sign==0)
   1695                         my_memcpy(dest,"+0",2);
   1696                 else
   1697                         my_memcpy(dest,"-0",2);
   1698                 return(2);
   1699 }
   1700 
   1701 /*
   1702 ** Move the internal number into our local holding area, since
   1703 ** we'll be altering it to print it out.
   1704 */
   1705 my_memcpy((void *)&locFPFNum,(void *)src,sizeof(InternalFPF));
   1706 
   1707 /*
   1708 ** Set up a floating-point 10...which we'll use a lot in a minute.
   1709 */
   1710 /* LongToInternalFPF(10L,&IFPF10); */
   1711 Int32ToInternalFPF((int32)10,&IFPF10);
   1712 
   1713 /*
   1714 ** Save the mantissa sign and make it positive.
   1715 */
   1716 msign=src->sign;
   1717 
   1718 /* src->sign=0 */ /* bug, fixed Nov. 13, 1997 */
   1719 (&locFPFNum)->sign=0;
   1720 
   1721 expcount=0;             /* Init exponent counter */
   1722 
   1723 /*
   1724 ** See if the number is less than 10.  If so, multiply
   1725 ** the number repeatedly by 10 until it's not.   For each
   1726 ** multiplication, decrement a counter so we can keep track
   1727 ** of the exponent.
   1728 */
   1729 
   1730 while(1)
   1731 {       AddSubInternalFPF(1,&locFPFNum,&IFPF10,&IFPFComp);
   1732         if(IFPFComp.sign==0) break;
   1733         MultiplyInternalFPF(&locFPFNum,&IFPF10,&IFPFComp);
   1734         expcount--;
   1735         my_memcpy((void *)&locFPFNum,(void *)&IFPFComp,sizeof(InternalFPF));
   1736 }
   1737 /*
   1738 ** Do the reverse of the above.  As long as the number is
   1739 ** greater than or equal to 10, divide it by 10.  Increment the
   1740 ** exponent counter for each multiplication.
   1741 */
   1742 
   1743 while(1)
   1744 {
   1745         AddSubInternalFPF(1,&locFPFNum,&IFPF10,&IFPFComp);
   1746         if(IFPFComp.sign!=0) break;
   1747         DivideInternalFPF(&locFPFNum,&IFPF10,&IFPFComp);
   1748         expcount++;
   1749         my_memcpy((void *)&locFPFNum,(void *)&IFPFComp,sizeof(InternalFPF));
   1750 }
   1751 
   1752 /*
   1753 ** About time to start storing things.  First, store the
   1754 ** mantissa sign.
   1755 */
   1756 ccount=1;               /* Init character counter */
   1757 if(msign==0)
   1758         *dest++='+';
   1759 else
   1760         *dest++='-';
   1761 
   1762 /*
   1763 ** At this point we know that the number is in the range
   1764 ** 10 > n >=1.  We need to "strip digits" out of the
   1765 ** mantissa.  We do this by treating the mantissa as
   1766 ** an integer and multiplying by 10. (Not a floating-point
   1767 ** 10, but an integer 10.  Since this is debug code and we
   1768 ** could care less about speed, we'll do it the stupid
   1769 ** way and simply add the number to itself 10 times.
   1770 ** Anything that makes it to the left of the implied binary point
   1771 ** gets stripped off and emitted.  We'll do this for
   1772 ** 5 significant digits (which should be enough to
   1773 ** verify things).
   1774 */
   1775 /*
   1776 ** Re-position radix point
   1777 */
   1778 carryaccum=0;
   1779 while(locFPFNum.exp>0)
   1780 {
   1781         mycarry=0;
   1782         ShiftMantLeft1(&mycarry,locFPFNum.mantissa);
   1783         carryaccum=(carryaccum<<1);
   1784         if(mycarry) carryaccum++;
   1785         locFPFNum.exp--;
   1786 }
   1787 
   1788 while(locFPFNum.exp<0)
   1789 {
   1790         mycarry=0;
   1791         ShiftMantRight1(&mycarry,locFPFNum.mantissa);
   1792         locFPFNum.exp++;
   1793 }
   1794 
   1795 for(i=0;i<6;i++)
   1796         if(i==1)
   1797         {       /* Emit decimal point */
   1798                 *dest++='.';
   1799                 ccount++;
   1800         }
   1801         else
   1802         {       /* Emit a digit */
   1803                 *dest++=('0'+carryaccum);
   1804                 ccount++;
   1805 
   1806                 carryaccum=0;
   1807                 my_memcpy((void *)&IFPF10,
   1808                         (void *)&locFPFNum,
   1809                         sizeof(InternalFPF));
   1810 
   1811                 /* Do multiply via repeated adds */
   1812                 for(j=0;j<9;j++)
   1813                 {
   1814                         mycarry=0;
   1815                         for(k=(INTERNAL_FPF_PRECISION-1);k>=0;k--)
   1816                                 Add16Bits(&mycarry,&(IFPFComp.mantissa[k]),
   1817                                         locFPFNum.mantissa[k],
   1818                                         IFPF10.mantissa[k]);
   1819                         carryaccum+=mycarry ? 1 : 0;
   1820                         my_memcpy((void *)&locFPFNum,
   1821                                 (void *)&IFPFComp,
   1822                                 sizeof(InternalFPF));
   1823                 }
   1824         }
   1825 
   1826 /*
   1827 ** Now move the 'E', the exponent sign, and the exponent
   1828 ** into the string.
   1829 */
   1830 *dest++='E';
   1831 
   1832 /* sprint is supposed to return an integer, but it caused problems on SunOS
   1833  * with the native cc. Hence we force it.
   1834  * Uwe F. Mayer
   1835  */
   1836 if (expcount < 0) {
   1837      *dest++ = '-';
   1838      expcount =- expcount;
   1839 }
   1840 else *dest++ = ' ';
   1841 
   1842 *dest++ = (char)(expcount + '0');
   1843 *dest++ = 0;
   1844 
   1845 ccount += 3;
   1846 /*
   1847 ** All done, go home.
   1848 */
   1849 return(ccount);
   1850 
   1851 }
   1852 
   1853 #endif
   1854 
   1855 
   1856 
   1857 ////////////////////////////////////////////////////////////////////////
   1858 static
   1859 void* AllocateMemory ( unsigned long n, int* p )
   1860 {
   1861   *p = 0;
   1862   void* r = (void*) (*serviceFn)(2,n);
   1863   return r;
   1864 }
   1865 static
   1866 void FreeMemory ( void* p, int* zz )
   1867 {
   1868   *zz = 0;
   1869   // free(p);
   1870 }
   1871 
   1872 
   1873 
   1874 /**************
   1875 ** DoEmFloat **
   1876 ***************
   1877 ** Perform the floating-point emulation routines portion of the
   1878 ** CPU benchmark.  Returns the operations per second.
   1879 */
   1880 static
   1881 void DoEmFloat(void)
   1882 {
   1883 EmFloatStruct *locemfloatstruct;        /* Local structure */
   1884 InternalFPF *abase;             /* Base of A array */
   1885 InternalFPF *bbase;             /* Base of B array */
   1886 InternalFPF *cbase;             /* Base of C array */
   1887 ulong tickcount;                /* # of ticks */
   1888 char *errorcontext;             /* Error context string pointer */
   1889 int systemerror;                /* For holding error code */
   1890 ulong loops;                    /* # of loops */
   1891 
   1892 /*
   1893 ** Link to global structure
   1894 */
   1895 EmFloatStruct global_emfloatstruct;
   1896  global_emfloatstruct.adjust = 0;
   1897  global_emfloatstruct.request_secs = 0;
   1898  global_emfloatstruct.arraysize = 100;
   1899  global_emfloatstruct.loops = 1;
   1900  global_emfloatstruct.emflops = 0.0;
   1901 locemfloatstruct=&global_emfloatstruct;
   1902 
   1903 /*
   1904 ** Set the error context
   1905 */
   1906 errorcontext="CPU:Floating Emulation";
   1907 
   1908 
   1909 abase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF),
   1910 		&systemerror);
   1911 
   1912 bbase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF),
   1913 		&systemerror);
   1914 
   1915 cbase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF),
   1916 		&systemerror);
   1917 
   1918 /*
   1919 ** Set up the arrays
   1920 */
   1921 SetupCPUEmFloatArrays(abase,bbase,cbase,locemfloatstruct->arraysize);
   1922 
   1923  loops=100;
   1924 	       tickcount=DoEmFloatIteration(abase,bbase,cbase,
   1925 			locemfloatstruct->arraysize,
   1926 			loops);
   1927 
   1928 FreeMemory((void *)abase,&systemerror);
   1929 FreeMemory((void *)bbase,&systemerror);
   1930 FreeMemory((void *)cbase,&systemerror);
   1931 
   1932 return;
   1933 }
   1934 
   1935 //////////////////
   1936 void entry ( HWord(*f)(HWord,HWord) )
   1937 {
   1938   serviceFn = f;
   1939   vexxx_printf("starting\n");
   1940   DoEmFloat();
   1941   (*serviceFn)(0,0);
   1942 }
   1943