drd/tests/tsan_unittest: Avoid that this test reads from uninitialized memory
[valgrind.git] / VEX / switchback / test_emfloat.c
blobc47ccf8353ad839be86e8e7e57ed15583b016210
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
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.
26 #include "../pub/libvex_basictypes.h"
28 static HWord (*serviceFn)(HWord,HWord) = 0;
31 /////////////////////////////////////////////////////////////////////
32 /////////////////////////////////////////////////////////////////////
34 static char* my_strcpy ( char* dest, const char* src )
36 char* dest_orig = dest;
37 while (*src) *dest++ = *src++;
38 *dest = 0;
39 return dest_orig;
42 static void* my_memcpy ( void *dest, const void *src, int sz )
44 const char *s = (const char *)src;
45 char *d = (char *)dest;
47 while (sz--)
48 *d++ = *s++;
50 return dest;
53 static void* my_memmove( void *dst, const void *src, unsigned int len )
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;
67 while ( len-- ) {
68 *d-- = *s--;
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;
80 while ( len-- ) {
81 *d++ = *s++;
84 return dst;
87 /////////////////////////////////////////////////////////////////////
89 static void vexxx_log_bytes ( char* p, int n )
91 int i;
92 for (i = 0; i < n; i++)
93 (*serviceFn)( 1, (int)p[i] );
96 /*---------------------------------------------------------*/
97 /*--- vexxx_printf ---*/
98 /*---------------------------------------------------------*/
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>
104 static HChar vexxx_toupper ( HChar c )
106 if (c >= 'a' && c <= 'z')
107 return toHChar(c + ('A' - 'a'));
108 else
109 return c;
112 static Int vexxx_strlen ( const HChar* str )
114 Int i = 0;
115 while (str[i] != 0) i++;
116 return i;
119 Bool vexxx_streq ( const HChar* s1, const HChar* s2 )
121 while (True) {
122 if (*s1 == 0 && *s2 == 0)
123 return True;
124 if (*s1 != *s2)
125 return False;
126 s1++;
127 s2++;
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) */
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 )
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);
148 if (width == 0) {
149 ret += len;
150 for (i = 0; i < len; i++)
151 send(MAYBE_TOUPPER(str[i]));
152 return ret;
155 if (len > width) {
156 ret += width;
157 for (i = 0; i < width; i++)
158 send(MAYBE_TOUPPER(str[i]));
159 return ret;
162 extra = width - len;
163 if (flags & VG_MSG_LJUSTIFY) {
164 ret += extra;
165 for (i = 0; i < extra; i++)
166 send(' ');
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(' ');
177 # undef MAYBE_TOUPPER
179 return ret;
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.
188 static UInt
189 myvprintf_int64 ( void(*send)(HChar), Int flags, Int base, Int width, ULong pL)
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;
199 if (base < 2 || base > 16)
200 return ret;
202 if ((flags & VG_MSG_SIGNED) && (Int)p < 0) {
203 p = - (Int)p;
204 neg = True;
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)
214 buf[ind++] = ',';
215 nc++;
217 buf[ind++] = digits[p % base];
218 p /= base;
222 if (neg)
223 buf[ind++] = '-';
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': ' ');
232 /* Reverse copy to buffer. */
233 ret += ind;
234 for (i = ind -1; i >= 0; i--) {
235 send(buf[i]);
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!
243 return ret;
247 /* A simple vprintf(). */
248 static
249 UInt vprintf_wrk ( void(*send)(HChar), const HChar *format, va_list vargs )
251 UInt ret = 0;
252 int i;
253 int flags;
254 int width;
255 Bool is_long;
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.
262 for (i = 0; format[i] != 0; i++) {
263 if (format[i] != '%') {
264 send(format[i]);
265 ret++;
266 continue;
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;
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++;
285 /* If ',' follows '%', commas will be inserted. */
286 if (format[i] == ',') {
287 flags |= VG_MSG_COMMA;
288 i++;
290 /* If '-' follows '%', justify on the left. */
291 if (format[i] == '-') {
292 flags |= VG_MSG_LJUSTIFY;
293 i++;
295 /* If '0' follows '%', pads will be inserted. */
296 if (format[i] == '0') {
297 flags |= VG_MSG_ZJUSTIFY;
298 i++;
300 /* Compute the field length. */
301 while (format[i] >= '0' && format[i] <= '9') {
302 width *= 10;
303 width += format[i++] - '0';
305 while (format[i] == 'l') {
306 i++;
307 is_long = True;
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;
354 # if 0
355 case 'y': { /* %y - print symbol */
356 Addr a = va_arg(vargs, Addr);
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):
366 ret += myvprintf_str(send, flags, width, buf, 0);
368 break;
370 # endif
371 default:
372 break;
375 return ret;
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.
383 static HChar myprintf_buf[1000];
384 static Int n_myprintf_buf;
386 static void add_to_myprintf_buf ( HChar c )
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;
393 myprintf_buf[n_myprintf_buf++] = c;
394 myprintf_buf[n_myprintf_buf] = 0;
397 static UInt vexxx_printf ( const char *format, ... )
399 UInt ret;
400 va_list vargs;
401 va_start(vargs,format);
403 n_myprintf_buf = 0;
404 myprintf_buf[n_myprintf_buf] = 0;
405 ret = vprintf_wrk ( add_to_myprintf_buf, format, vargs );
407 if (n_myprintf_buf > 0) {
408 (*vexxx_log_bytes)( myprintf_buf, n_myprintf_buf );
411 va_end(vargs);
413 return ret;
416 /*---------------------------------------------------------------*/
417 /*--- end vexxx_util.c ---*/
418 /*---------------------------------------------------------------*/
421 /////////////////////////////////////////////////////////////////////
422 /////////////////////////////////////////////////////////////////////
424 //#include <stdio.h>
425 //#include <string.h>
426 //#include <malloc.h>
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 */
434 #define INTERNAL_FPF_PRECISION 4
435 #define CPUEMFLOATLOOPMAX 500000L
436 #define EMFARRAYSIZE 3000L
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;
448 /* Is this a 64 bit architecture? If so, this will define LONG64 */
449 /* Uwe F. Mayer 15 November 1997 */
450 // #include "pointer.h"
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
462 #define MAX_EXP 32767L
463 #define MIN_EXP (-32767L)
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
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
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
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
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
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
507 typedef struct
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;
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);
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);
546 static void Int32ToInternalFPF(int32 mylong,
547 InternalFPF *dest);
548 static int InternalFPFToString(char *dest,
549 InternalFPF *src);
551 static int32 randnum(int32 lngval);
553 static int32 randwc(int32 num)
555 return(randnum((int32)0)%num);
558 static int32 randw[2] = { (int32)13 , (int32)117 };
559 static int32 randnum(int32 lngval)
561 register int32 interm;
563 if (lngval!=(int32)0)
564 { randw[0]=(int32)13; randw[1]=(int32)117; }
566 interm=(randw[0]*(int32)254754+randw[1]*(int32)529562)%(int32)999563;
567 randw[1]=randw[0];
568 randw[0]=interm;
569 return(interm);
573 static
574 void SetupCPUEmFloatArrays(InternalFPF *abase,
575 InternalFPF *bbase,
576 InternalFPF *cbase,
577 ulong arraysize)
579 ulong i;
580 InternalFPF locFPF1,locFPF2;
582 randnum((int32)13);
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);
594 return;
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)
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 */
611 vexxx_printf(str1, (int)loops);
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)
621 for(i=0;i<arraysize;i++)
622 switch(jtable[i % 16])
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;
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 */
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])
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;
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);
677 return 0;
681 return 0;
684 /***********************
685 ** SetInternalFPFZero **
686 ************************
687 ** Set an internal floating-point-format number to zero.
688 ** sign determines the sign of the zero.
690 static void SetInternalFPFZero(InternalFPF *dest,
691 uchar sign)
693 int i; /* Index */
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;
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.
710 static void SetInternalFPFInfinity(InternalFPF *dest,
711 uchar sign)
713 int i; /* Index */
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;
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.
730 static void SetInternalFPFNaN(InternalFPF *dest)
732 int i; /* Index */
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;
741 return;
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.
751 static int IsMantissaZero(u16 *mant)
753 int i; /* Index */
754 int n; /* Return value */
756 n=0;
757 for(i=0;i<INTERNAL_FPF_PRECISION;i++)
758 n|=mant[i];
760 return(!n);
763 /**************
764 ** Add16Bits **
765 ***************
766 ** Add b, c, and carry. Retult in a. New carry in carry.
768 static void Add16Bits(u16 *carry,
769 u16 *a,
770 u16 b,
771 u16 c)
773 u32 accum; /* Accumulator */
776 ** Do the work in the 32-bit accumulator so we can return
777 ** the carry.
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;
787 /**************
788 ** Sub16Bits **
789 ***************
790 ** Additive inverse of above.
792 static void Sub16Bits(u16 *borrow,
793 u16 *a,
794 u16 b,
795 u16 c)
797 u32 accum; /* Accumulator */
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;
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.
814 static void ShiftMantLeft1(u16 *carry,
815 u16 *mantissa)
817 int i; /* Index */
818 int new_carry;
819 u16 accum; /* Temporary holding placed */
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 */
830 return;
833 /********************
834 ** ShiftMantRight1 **
835 *********************
836 ** Shift a mantissa right by 1 bit. Provides carry, as
837 ** above
839 static void ShiftMantRight1(u16 *carry,
840 u16 *mantissa)
842 int i; /* Index */
843 int new_carry;
844 u16 accum;
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;
855 return;
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.
866 static void StickyShiftRightMant(InternalFPF *ptr,
867 int amount)
869 int i; /* Index */
870 u16 carry; /* Self-explanatory */
871 u16 *mantissa;
873 mantissa=ptr->mantissa;
875 if(ptr->type!=IFPF_IS_ZERO) /* Don't bother shifting a zero */
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.
882 if(amount>=INTERNAL_FPF_PRECISION * 16)
884 for(i=0;i<INTERNAL_FPF_PRECISION-1;i++)
885 mantissa[i]=0;
886 mantissa[INTERNAL_FPF_PRECISION-1]=1;
888 else
889 for(i=0;i<amount;i++)
891 carry=0;
892 ShiftMantRight1(&carry,mantissa);
893 if(carry)
894 mantissa[INTERNAL_FPF_PRECISION-1] |= 1;
897 return;
901 /**************************************************
902 ** POST ARITHMETIC PROCESSING **
903 ** (NORMALIZE, ROUND, OVERFLOW, AND UNDERFLOW) **
904 **************************************************/
906 /**************
907 ** normalize **
908 ***************
909 ** Normalize an internal-representation number. Normalization
910 ** discards empty most-significant bits.
912 static void normalize(InternalFPF *ptr)
914 u16 carry;
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.
921 while ((ptr->mantissa[0] & 0x8000) == 0)
923 carry = 0;
924 ShiftMantLeft1(&carry, ptr->mantissa);
925 ptr->exp--;
927 return;
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).
938 static void denormalize(InternalFPF *ptr,
939 int minimum_exponent)
941 long exponent_difference;
943 if (IsMantissaZero(ptr->mantissa))
945 vexxx_printf("Error: zero significand in denormalize\n");
948 exponent_difference = ptr->exp-minimum_exponent;
949 if (exponent_difference < 0)
952 ** The number is subnormal
954 exponent_difference = -exponent_difference;
955 if (exponent_difference >= (INTERNAL_FPF_PRECISION * 16))
957 /* Underflow */
958 SetInternalFPFZero(ptr, ptr->sign);
960 else
962 ptr->exp+=exponent_difference;
963 StickyShiftRightMant(ptr, exponent_difference);
966 return;
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.
977 void RoundInternalFPF(InternalFPF *ptr)
979 /* int i; */
981 if (ptr->type == IFPF_IS_NORMAL ||
982 ptr->type == IFPF_IS_SUBNORMAL)
984 denormalize(ptr, MIN_EXP);
985 if (ptr->type != IFPF_IS_ZERO)
988 /* clear the extraneous bits */
989 ptr->mantissa[3] &= 0xfff8;
990 /* for (i=4; i<INTERNAL_FPF_PRECISION; i++)
992 ptr->mantissa[i] = 0;
996 ** Check for overflow
998 /* Does not do anything as ptr->exp is a short and MAX_EXP=37268
999 if (ptr->exp > MAX_EXP)
1001 SetInternalFPFInfinity(ptr, ptr->sign);
1006 return;
1009 /*******************************************************
1010 ** ARITHMETIC OPERATIONS ON INTERNAL REPRESENTATION **
1011 *******************************************************/
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.
1020 static void choose_nan(InternalFPF *x,
1021 InternalFPF *y,
1022 InternalFPF *z,
1023 int intel_flag)
1025 int i;
1028 ** Compare the two mantissas,
1029 ** return the larger. Note that we will be emulating
1030 ** an 80387 in this operation.
1032 for (i=0; i<INTERNAL_FPF_PRECISION; i++)
1034 if (x->mantissa[i] > y->mantissa[i])
1036 my_memmove((void *)x,(void *)z,sizeof(InternalFPF));
1037 return;
1039 if (x->mantissa[i] < y->mantissa[i])
1041 my_memmove((void *)y,(void *)z,sizeof(InternalFPF));
1042 return;
1047 ** They are equal
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;
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.
1066 static void AddSubInternalFPF(uchar operation,
1067 InternalFPF *x,
1068 InternalFPF *y,
1069 InternalFPF *z)
1071 int exponent_difference;
1072 u16 borrow;
1073 u16 carry;
1074 int i;
1075 InternalFPF locx,locy; /* Needed since we alter them */
1078 ** Following big switch statement handles the
1079 ** various combinations of operand types.
1081 switch ((x->type * IFPF_TYPE_COUNT) + y->type)
1083 case ZERO_ZERO:
1084 my_memmove((void *)x,(void *)z,sizeof(InternalFPF));
1085 if (x->sign ^ y->sign ^ operation)
1087 z->sign = 0; /* positive */
1089 break;
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;
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;
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;
1120 case SUBNORMAL_SUBNORMAL:
1121 case SUBNORMAL_NORMAL:
1122 case NORMAL_SUBNORMAL:
1123 case NORMAL_NORMAL:
1125 ** Copy x and y to locals, since we may have
1126 ** to alter them.
1128 my_memmove((void *)&locx,(void *)x,sizeof(InternalFPF));
1129 my_memmove((void *)&locy,(void *)y,sizeof(InternalFPF));
1131 /* compute sum/difference */
1132 exponent_difference = locx.exp-locy.exp;
1133 if (exponent_difference == 0)
1136 ** locx.exp == locy.exp
1137 ** so, no shifting required
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;
1146 ** Assume that locx.mantissa > locy.mantissa
1148 z->sign = locx.sign;
1149 z->exp= locx.exp;
1151 else
1152 if (exponent_difference > 0)
1155 ** locx.exp > locy.exp
1157 StickyShiftRightMant(&locy,
1158 exponent_difference);
1159 z->type = locx.type;
1160 z->sign = locx.sign;
1161 z->exp = locx.exp;
1163 else /* if (exponent_difference < 0) */
1166 ** locx.exp < locy.exp
1168 StickyShiftRightMant(&locx,
1169 -exponent_difference);
1170 z->type = locy.type;
1171 z->sign = locy.sign ^ operation;
1172 z->exp = locy.exp;
1175 if (locx.sign ^ locy.sign ^ operation)
1178 ** Signs are different, subtract mantissas
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]);
1187 if (borrow)
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.
1195 z->sign = locy.sign ^ operation;
1196 borrow = 0;
1197 for (i=(INTERNAL_FPF_PRECISION-1); i>=0; i--)
1199 Sub16Bits(&borrow,
1200 &z->mantissa[i],
1202 z->mantissa[i]);
1205 else
1207 /* The assumption made above
1208 ** (i.e. x->mantissa >= y->mantissa)
1209 ** was correct. Therefore, do nothing.
1210 ** z->sign = x->sign;
1214 if (IsMantissaZero(z->mantissa))
1216 z->type = IFPF_IS_ZERO;
1217 z->sign = 0; /* positive */
1219 else
1220 if (locx.type == IFPF_IS_NORMAL ||
1221 locy.type == IFPF_IS_NORMAL)
1223 normalize(z);
1226 else
1228 /* signs are the same, add mantissas */
1229 carry = 0;
1230 for (i=(INTERNAL_FPF_PRECISION-1); i>=0; i--)
1232 Add16Bits(&carry,
1233 &z->mantissa[i],
1234 locx.mantissa[i],
1235 locy.mantissa[i]);
1238 if (carry)
1240 z->exp++;
1241 carry=0;
1242 ShiftMantRight1(&carry,z->mantissa);
1243 z->mantissa[0] |= 0x8000;
1244 z->type = IFPF_IS_NORMAL;
1246 else
1247 if (z->mantissa[0] & 0x8000)
1248 z->type = IFPF_IS_NORMAL;
1250 break;
1252 case INFINITY_INFINITY:
1253 SetInternalFPFNaN(z);
1254 break;
1256 case NAN_NAN:
1257 choose_nan(x, y, z, 1);
1258 break;
1262 ** All the math is done; time to round.
1264 RoundInternalFPF(z);
1265 return;
1269 /************************
1270 ** MultiplyInternalFPF **
1271 *************************
1272 ** Two internal-representation numbers x and y are multiplied; the
1273 ** result is returned in z.
1275 static void MultiplyInternalFPF(InternalFPF *x,
1276 InternalFPF *y,
1277 InternalFPF *z)
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 */
1285 ** As in the preceding function, this large switch
1286 ** statement selects among the many combinations
1287 ** of operands.
1289 switch ((x->type * IFPF_TYPE_COUNT) + y->type)
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;
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;
1309 case ZERO_INFINITY:
1310 case INFINITY_ZERO:
1311 SetInternalFPFNaN(z);
1312 break;
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;
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;
1329 case SUBNORMAL_SUBNORMAL:
1330 case SUBNORMAL_NORMAL:
1331 case NORMAL_SUBNORMAL:
1332 case NORMAL_NORMAL:
1334 ** Make a local copy of the y number, since we will be
1335 ** altering it in the process of multiplying.
1337 my_memmove((void *)&locy,(void *)y,sizeof(InternalFPF));
1340 ** Check for unnormal zero arguments
1342 if (IsMantissaZero(x->mantissa) || IsMantissaZero(y->mantissa))
1343 SetInternalFPFInfinity(z, 0);
1346 ** Initialize the result
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;
1354 z->sign = x->sign ^ y->sign;
1355 z->exp = x->exp + y->exp ;
1356 for (i=0; i<INTERNAL_FPF_PRECISION; i++)
1358 z->mantissa[i] = 0;
1359 extra_bits[i] = 0;
1362 for (i=0; i<(INTERNAL_FPF_PRECISION*16); i++)
1365 ** Get rightmost bit of the multiplier
1367 carry = 0;
1368 ShiftMantRight1(&carry, locy.mantissa);
1369 if (carry)
1372 ** Add the multiplicand to the product
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]);
1381 else
1383 carry = 0;
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.
1391 ShiftMantRight1(&carry, z->mantissa);
1392 ShiftMantRight1(&carry, extra_bits);
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.
1402 while ((z->mantissa[0] & 0x8000) == 0)
1404 carry = 0;
1405 ShiftMantLeft1(&carry, extra_bits);
1406 ShiftMantLeft1(&carry, z->mantissa);
1407 z->exp--;
1411 ** Set the sticky bit if any bits set in extra bits.
1413 if (IsMantissaZero(extra_bits))
1415 z->mantissa[INTERNAL_FPF_PRECISION-1] |= 1;
1417 break;
1419 case NAN_NAN:
1420 choose_nan(x, y, z, 0);
1421 break;
1425 ** All math done...do rounding.
1427 RoundInternalFPF(z);
1428 return;
1432 /**********************
1433 ** DivideInternalFPF **
1434 ***********************
1435 ** Divide internal FPF number x by y. Return result in z.
1437 static void DivideInternalFPF(InternalFPF *x,
1438 InternalFPF *y,
1439 InternalFPF *z)
1441 int i;
1442 int j;
1443 u16 carry;
1444 u16 extra_bits[INTERNAL_FPF_PRECISION];
1445 InternalFPF locx; /* Local for x number */
1448 ** As with preceding function, the following switch
1449 ** statement selects among the various possible
1450 ** operands.
1452 switch ((x->type * IFPF_TYPE_COUNT) + y->type)
1454 case ZERO_ZERO:
1455 case INFINITY_INFINITY:
1456 SetInternalFPFNaN(z);
1457 break;
1459 case ZERO_SUBNORMAL:
1460 case ZERO_NORMAL:
1461 if (IsMantissaZero(y->mantissa))
1463 SetInternalFPFNaN(z);
1464 break;
1467 case ZERO_INFINITY:
1468 case SUBNORMAL_INFINITY:
1469 case NORMAL_INFINITY:
1470 SetInternalFPFZero(z, x->sign ^ y->sign);
1471 break;
1473 case SUBNORMAL_ZERO:
1474 case NORMAL_ZERO:
1475 if (IsMantissaZero(x->mantissa))
1477 SetInternalFPFNaN(z);
1478 break;
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;
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;
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;
1502 case SUBNORMAL_SUBNORMAL:
1503 case NORMAL_SUBNORMAL:
1504 case SUBNORMAL_NORMAL:
1505 case NORMAL_NORMAL:
1507 ** Make local copy of x number, since we'll be
1508 ** altering it in the process of dividing.
1510 my_memmove((void *)&locx,(void *)x,sizeof(InternalFPF));
1513 ** Check for unnormal zero arguments
1515 if (IsMantissaZero(locx.mantissa))
1517 if (IsMantissaZero(y->mantissa))
1518 SetInternalFPFNaN(z);
1519 else
1520 SetInternalFPFZero(z, 0);
1521 break;
1523 if (IsMantissaZero(y->mantissa))
1525 SetInternalFPFInfinity(z, 0);
1526 break;
1530 ** Initialize the result
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++)
1538 z->mantissa[i] = 0;
1539 extra_bits[i] = 0;
1542 while ((z->mantissa[0] & 0x8000) == 0)
1544 carry = 0;
1545 ShiftMantLeft1(&carry, locx.mantissa);
1546 ShiftMantLeft1(&carry, extra_bits);
1549 ** Time to subtract yet?
1551 if (carry == 0)
1552 for (j=0; j<INTERNAL_FPF_PRECISION; j++)
1554 if (y->mantissa[j] > extra_bits[j])
1556 carry = 0;
1557 goto no_subtract;
1559 if (y->mantissa[j] < extra_bits[j])
1560 break;
1563 ** Divisor (y) <= dividend (x), subtract
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--;
1576 break;
1578 case NAN_NAN:
1579 choose_nan(x, y, z, 0);
1580 break;
1584 ** Math complete...do rounding
1586 RoundInternalFPF(z);
1589 /**********************
1590 ** LongToInternalFPF **
1591 ** Int32ToInternalFPF **
1592 ***********************
1593 ** Convert a signed (long) 32-bit integer into an internal FPF number.
1595 /* static void LongToInternalFPF(long mylong, */
1596 static void Int32ToInternalFPF(int32 mylong,
1597 InternalFPF *dest)
1599 int i; /* Index */
1600 u16 myword; /* Used to hold converted stuff */
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.)
1606 /* if(mylong<0L) */
1607 if(mylong<(int32)0)
1608 { dest->sign=1;
1609 mylong=(int32)0-mylong;
1611 else
1612 dest->sign=0;
1614 ** Prepare the destination floating point number
1616 dest->type=IFPF_IS_NORMAL;
1617 for(i=0;i<INTERNAL_FPF_PRECISION;i++)
1618 dest->mantissa[i]=0;
1621 ** See if we've got a zero. If so, make the resultant FP
1622 ** number a true zero and go home.
1624 if(mylong==0)
1625 { dest->type=IFPF_IS_ZERO;
1626 dest->exp=0;
1627 return;
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.
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;
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.
1663 static int InternalFPFToString(char *dest,
1664 InternalFPF *src)
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 */
1677 ** Check first for the simple things...Nan, Infinity, Zero.
1678 ** If found, copy the proper string in and go home.
1680 switch(src->type)
1682 case IFPF_IS_NAN:
1683 my_memcpy(dest,"NaN",3);
1684 return(3);
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);
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);
1702 ** Move the internal number into our local holding area, since
1703 ** we'll be altering it to print it out.
1705 my_memcpy((void *)&locFPFNum,(void *)src,sizeof(InternalFPF));
1708 ** Set up a floating-point 10...which we'll use a lot in a minute.
1710 /* LongToInternalFPF(10L,&IFPF10); */
1711 Int32ToInternalFPF((int32)10,&IFPF10);
1714 ** Save the mantissa sign and make it positive.
1716 msign=src->sign;
1718 /* src->sign=0 */ /* bug, fixed Nov. 13, 1997 */
1719 (&locFPFNum)->sign=0;
1721 expcount=0; /* Init exponent counter */
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.
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));
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.
1743 while(1)
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));
1753 ** About time to start storing things. First, store the
1754 ** mantissa sign.
1756 ccount=1; /* Init character counter */
1757 if(msign==0)
1758 *dest++='+';
1759 else
1760 *dest++='-';
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).
1776 ** Re-position radix point
1778 carryaccum=0;
1779 while(locFPFNum.exp>0)
1781 mycarry=0;
1782 ShiftMantLeft1(&mycarry,locFPFNum.mantissa);
1783 carryaccum=(carryaccum<<1);
1784 if(mycarry) carryaccum++;
1785 locFPFNum.exp--;
1788 while(locFPFNum.exp<0)
1790 mycarry=0;
1791 ShiftMantRight1(&mycarry,locFPFNum.mantissa);
1792 locFPFNum.exp++;
1795 for(i=0;i<6;i++)
1796 if(i==1)
1797 { /* Emit decimal point */
1798 *dest++='.';
1799 ccount++;
1801 else
1802 { /* Emit a digit */
1803 *dest++=('0'+carryaccum);
1804 ccount++;
1806 carryaccum=0;
1807 my_memcpy((void *)&IFPF10,
1808 (void *)&locFPFNum,
1809 sizeof(InternalFPF));
1811 /* Do multiply via repeated adds */
1812 for(j=0;j<9;j++)
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));
1827 ** Now move the 'E', the exponent sign, and the exponent
1828 ** into the string.
1830 *dest++='E';
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
1836 if (expcount < 0) {
1837 *dest++ = '-';
1838 expcount =- expcount;
1840 else *dest++ = ' ';
1842 *dest++ = (char)(expcount + '0');
1843 *dest++ = 0;
1845 ccount += 3;
1847 ** All done, go home.
1849 return(ccount);
1853 #endif
1857 ////////////////////////////////////////////////////////////////////////
1858 static
1859 void* AllocateMemory ( unsigned long n, int* p )
1861 *p = 0;
1862 void* r = (void*) (*serviceFn)(2,n);
1863 return r;
1865 static
1866 void FreeMemory ( void* p, int* zz )
1868 *zz = 0;
1869 // free(p);
1874 /**************
1875 ** DoEmFloat **
1876 ***************
1877 ** Perform the floating-point emulation routines portion of the
1878 ** CPU benchmark. Returns the operations per second.
1880 static
1881 void DoEmFloat(void)
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 */
1893 ** Link to global structure
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;
1904 ** Set the error context
1906 errorcontext="CPU:Floating Emulation";
1909 abase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF),
1910 &systemerror);
1912 bbase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF),
1913 &systemerror);
1915 cbase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF),
1916 &systemerror);
1919 ** Set up the arrays
1921 SetupCPUEmFloatArrays(abase,bbase,cbase,locemfloatstruct->arraysize);
1923 loops=100;
1924 tickcount=DoEmFloatIteration(abase,bbase,cbase,
1925 locemfloatstruct->arraysize,
1926 loops);
1928 FreeMemory((void *)abase,&systemerror);
1929 FreeMemory((void *)bbase,&systemerror);
1930 FreeMemory((void *)cbase,&systemerror);
1932 return;
1935 //////////////////
1936 void entry ( HWord(*f)(HWord,HWord) )
1938 serviceFn = f;
1939 vexxx_printf("starting\n");
1940 DoEmFloat();
1941 (*serviceFn)(0,0);