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