3 ** Source for emulated floating-point routines.
5 ** BYTE's Native Mode Benchmarks
6 ** Rick Grehan, BYTE Magazine.
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
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
++;
42 static void* my_memcpy ( void *dest
, const void *src
, int sz
)
44 const char *s
= (const char *)src
;
45 char *d
= (char *)dest
;
53 static void* my_memmove( void *dst
, const void *src
, unsigned int len
)
58 d
= (char *)dst
+ len
- 1;
59 s
= (char *)src
+ len
- 1;
70 } else if ( dst
< src
) {
87 /////////////////////////////////////////////////////////////////////
89 static void vexxx_log_bytes ( char* p
, int n
)
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. */
104 static HChar
vexxx_toupper ( HChar c
)
106 if (c
>= 'a' && c
<= 'z')
107 return toHChar(c
+ ('A' - 'a'));
112 static Int
vexxx_strlen ( const HChar
* str
)
115 while (str
[i
] != 0) i
++;
119 Bool
vexxx_streq ( const HChar
* s1
, const HChar
* s2
)
122 if (*s1
== 0 && *s2
== 0)
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. */
140 myvprintf_str ( void(*send
)(HChar
), Int flags
, Int width
, HChar
* str
,
143 # define MAYBE_TOUPPER(ch) toHChar(capitalise ? vexxx_toupper(ch) : (ch))
146 Int len
= vexxx_strlen(str
);
150 for (i
= 0; i
< len
; i
++)
151 send(MAYBE_TOUPPER(str
[i
]));
157 for (i
= 0; i
< width
; i
++)
158 send(MAYBE_TOUPPER(str
[i
]));
163 if (flags
& VG_MSG_LJUSTIFY
) {
165 for (i
= 0; i
< extra
; i
++)
169 for (i
= 0; i
< len
; i
++)
170 send(MAYBE_TOUPPER(str
[i
]));
171 if (!(flags
& VG_MSG_LJUSTIFY
)) {
173 for (i
= 0; i
< extra
; i
++)
177 # undef MAYBE_TOUPPER
182 /* Write P into the buffer according to these args:
183 * If SIGN is true, p is a signed.
185 * If WITH_ZERO is true, '0' must be added.
186 * WIDTH is the width of the field.
189 myvprintf_int64 ( void(*send
)(HChar
), Int flags
, Int base
, Int width
, ULong pL
)
195 HChar
*digits
= "0123456789ABCDEF";
199 if (base
< 2 || base
> 16)
202 if ((flags
& VG_MSG_SIGNED
) && (Int
)p
< 0) {
211 if ((flags
& VG_MSG_COMMA
) && 10 == base
&&
212 0 == (ind
-nc
) % 3 && 0 != ind
)
217 buf
[ind
++] = digits
[p
% base
];
225 if (width
> 0 && !(flags
& VG_MSG_LJUSTIFY
)) {
226 for(; ind
< width
; ind
++) {
228 buf
[ind
] = toHChar((flags
& VG_MSG_ZJUSTIFY
) ? '0': ' ');
232 /* Reverse copy to buffer. */
234 for (i
= ind
-1; i
>= 0; i
--) {
237 if (width
> 0 && (flags
& VG_MSG_LJUSTIFY
)) {
238 for(; ind
< width
; ind
++) {
240 send(' '); // Never pad with zeroes on RHS -- changes the value!
247 /* A simple vprintf(). */
249 UInt
vprintf_wrk ( void(*send
)(HChar
), const HChar
*format
, va_list vargs
)
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
] != '%') {
269 /* A '%' has been found. Ignore a trailing %. */
272 if (format
[i
] == '%') {
273 /* `%%' is replaced by `%'. */
280 width
= 0; /* length of the field. */
281 if (format
[i
] == '(') {
282 flags
|= VG_MSG_PAREN
;
285 /* If ',' follows '%', commas will be inserted. */
286 if (format
[i
] == ',') {
287 flags
|= VG_MSG_COMMA
;
290 /* If '-' follows '%', justify on the left. */
291 if (format
[i
] == '-') {
292 flags
|= VG_MSG_LJUSTIFY
;
295 /* If '0' follows '%', pads will be inserted. */
296 if (format
[i
] == '0') {
297 flags
|= VG_MSG_ZJUSTIFY
;
300 /* Compute the field length. */
301 while (format
[i
] >= '0' && format
[i
] <= '9') {
303 width
+= format
[i
++] - '0';
305 while (format
[i
] == 'l') {
312 flags
|= VG_MSG_SIGNED
;
314 ret
+= myvprintf_int64(send
, flags
, 10, width
,
315 (ULong
)(va_arg (vargs
, Long
)));
317 ret
+= myvprintf_int64(send
, flags
, 10, width
,
318 (ULong
)(va_arg (vargs
, Int
)));
322 ret
+= myvprintf_int64(send
, flags
, 10, width
,
323 (ULong
)(va_arg (vargs
, ULong
)));
325 ret
+= myvprintf_int64(send
, flags
, 10, width
,
326 (ULong
)(va_arg (vargs
, UInt
)));
332 ret
+= myvprintf_int64(send
, flags
, 16, width
,
333 (ULong
)((HWord
)va_arg (vargs
, void *)));
337 ret
+= myvprintf_int64(send
, flags
, 16, width
,
338 (ULong
)(va_arg (vargs
, ULong
)));
340 ret
+= myvprintf_int64(send
, flags
, 16, width
,
341 (ULong
)(va_arg (vargs
, UInt
)));
345 send(toHChar(va_arg (vargs
, int)));
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'));
355 case 'y': { /* %y - print symbol */
356 Addr a
= va_arg(vargs
, Addr
);
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
):
364 VG_(sprintf
)(str
, "%s", name
):
366 ret
+= myvprintf_str(send
, flags
, width
, buf
, 0);
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
) );
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
, ... )
401 va_start(vargs
,format
);
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
);
416 /*---------------------------------------------------------------*/
417 /*--- end vexxx_util.c ---*/
418 /*---------------------------------------------------------------*/
421 /////////////////////////////////////////////////////////////////////
422 /////////////////////////////////////////////////////////////////////
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
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 */
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
455 #define u32 unsigned int
457 #define u32 unsigned long
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
473 #define ZERO_SUBNORMAL 1
474 #define ZERO_NORMAL 2
475 #define ZERO_INFINITY 3
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
497 #define NAN_SUBNORMAL 21
498 #define NAN_NORMAL 22
499 #define NAN_INFINITY 23
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
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
];
516 void SetupCPUEmFloatArrays(InternalFPF
*abase
,
517 InternalFPF
*bbase
, InternalFPF
*cbase
, ulong arraysize
);
519 ulong
DoEmFloatIteration(InternalFPF
*abase
,
520 InternalFPF
*bbase
, InternalFPF
*cbase
,
521 ulong arraysize
, ulong loops
);
523 static void SetInternalFPFZero(InternalFPF
*dest
,
525 static void SetInternalFPFInfinity(InternalFPF
*dest
,
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
,
539 static void AddSubInternalFPF(uchar operation
,InternalFPF
*x
,
540 InternalFPF
*y
,InternalFPF
*z
);
541 static void MultiplyInternalFPF(InternalFPF
*x
,InternalFPF
*y
,
543 static void DivideInternalFPF(InternalFPF
*x
,InternalFPF
*y
,
546 static void Int32ToInternalFPF(int32 mylong
,
548 static int InternalFPFToString(char *dest
,
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;
574 void SetupCPUEmFloatArrays(InternalFPF
*abase
,
580 InternalFPF locFPF1
,locFPF2
;
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
);
598 static char* str1
= "loops %d\n";
600 ulong
DoEmFloatIteration(InternalFPF
*abase
,
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};
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])
625 AddSubInternalFPF(0,abase
+i
,
629 case 1: /* Subtract */
630 AddSubInternalFPF(1,abase
+i
,
634 case 2: /* Multiply */
635 MultiplyInternalFPF(abase
+i
,
640 DivideInternalFPF(abase
+i
,
646 ulong j
[8]; /* we test 8 entries */
650 if (100==loops
) /* the first loop */
656 j
[4]=(ulong
)(arraysize
-14);
657 j
[5]=(ulong
)(arraysize
-10);
658 j
[6]=(ulong
)(arraysize
-6);
659 j
[7]=(ulong
)(arraysize
-2);
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
);
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
,
695 dest
->type
=IFPF_IS_ZERO
;
698 for(i
=0;i
<INTERNAL_FPF_PRECISION
;i
++)
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
,
715 dest
->type
=IFPF_IS_INFINITY
;
718 for(i
=0;i
<INTERNAL_FPF_PRECISION
;i
++)
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
)
734 dest
->type
=IFPF_IS_NAN
;
737 dest
->mantissa
[0]=0x4000;
738 for(i
=1;i
<INTERNAL_FPF_PRECISION
;i
++)
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
)
754 int n
; /* Return value */
757 for(i
=0;i
<INTERNAL_FPF_PRECISION
;i
++)
766 ** Add b, c, and carry. Retult in a. New carry in carry.
768 static void Add16Bits(u16
*carry
,
773 u32 accum
; /* Accumulator */
776 ** Do the work in the 32-bit accumulator so we can return
782 *carry
=(u16
)((accum
& 0x00010000) ? 1 : 0); /* New carry */
783 *a
=(u16
)(accum
& 0xFFFF); /* Result is lo 16 bits */
790 ** Additive inverse of above.
792 static void Sub16Bits(u16
*borrow
,
797 u32 accum
; /* Accumulator */
802 *borrow
=(u32
)((accum
& 0x00010000) ? 1 : 0); /* New borrow */
803 *a
=(u16
)(accum
& 0xFFFF);
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
,
819 u16 accum
; /* Temporary holding placed */
821 for(i
=INTERNAL_FPF_PRECISION
-1;i
>=0;i
--)
823 new_carry
=accum
& 0x8000; /* Get new carry */
824 accum
=accum
<<1; /* Do the shift */
826 accum
|=1; /* Insert previous carry */
828 mantissa
[i
]=accum
; /* Return shifted value */
833 /********************
834 ** ShiftMantRight1 **
835 *********************
836 ** Shift a mantissa right by 1 bit. Provides carry, as
839 static void ShiftMantRight1(u16
*carry
,
846 for(i
=0;i
<INTERNAL_FPF_PRECISION
;i
++)
848 new_carry
=accum
& 1; /* Get new carry */
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
,
870 u16 carry
; /* Self-explanatory */
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
++)
886 mantissa
[INTERNAL_FPF_PRECISION
-1]=1;
889 for(i
=0;i
<amount
;i
++)
892 ShiftMantRight1(&carry
,mantissa
);
894 mantissa
[INTERNAL_FPF_PRECISION
-1] |= 1;
901 /**************************************************
902 ** POST ARITHMETIC PROCESSING **
903 ** (NORMALIZE, ROUND, OVERFLOW, AND UNDERFLOW) **
904 **************************************************/
909 ** Normalize an internal-representation number. Normalization
910 ** discards empty most-significant bits.
912 static void normalize(InternalFPF
*ptr
)
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)
924 ShiftMantLeft1(&carry
, ptr
->mantissa
);
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))
958 SetInternalFPFZero(ptr
, ptr
->sign
);
962 ptr
->exp
+=exponent_difference
;
963 StickyShiftRightMant(ptr
, exponent_difference
);
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
)
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);
1009 /*******************************************************
1010 ** ARITHMETIC OPERATIONS ON INTERNAL REPRESENTATION **
1011 *******************************************************/
1016 ** Called by routines that are forced to perform math on
1017 ** a pair of NaN's. This routine "selects" which NaN is
1020 static void choose_nan(InternalFPF
*x
,
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
));
1039 if (x
->mantissa
[i
] < y
->mantissa
[i
])
1041 my_memmove((void *)y
,(void *)z
,sizeof(InternalFPF
));
1050 /* if the operation is addition */
1051 my_memmove((void *)x
,(void *)z
,sizeof(InternalFPF
));
1053 /* if the operation is multiplication */
1054 my_memmove((void *)y
,(void *)z
,sizeof(InternalFPF
));
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
,
1071 int exponent_difference
;
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
)
1084 my_memmove((void *)x
,(void *)z
,sizeof(InternalFPF
));
1085 if (x
->sign
^ y
->sign
^ operation
)
1087 z
->sign
= 0; /* positive */
1095 case SUBNORMAL_ZERO
:
1098 case INFINITY_SUBNORMAL
:
1099 case INFINITY_NORMAL
:
1100 my_memmove((void *)x
,(void *)z
,sizeof(InternalFPF
));
1108 my_memmove((void *)y
,(void *)z
,sizeof(InternalFPF
));
1111 case ZERO_SUBNORMAL
:
1114 case SUBNORMAL_INFINITY
:
1115 case NORMAL_INFINITY
:
1116 my_memmove((void *)y
,(void *)z
,sizeof(InternalFPF
));
1117 z
->sign
^= operation
;
1120 case SUBNORMAL_SUBNORMAL
:
1121 case SUBNORMAL_NORMAL
:
1122 case NORMAL_SUBNORMAL
:
1125 ** Copy x and y to locals, since we may have
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
;
1143 z
->type
= IFPF_IS_NORMAL
;
1146 ** Assume that locx.mantissa > locy.mantissa
1148 z
->sign
= locx
.sign
;
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
;
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
;
1175 if (locx
.sign
^ locy
.sign
^ operation
)
1178 ** Signs are different, subtract mantissas
1181 for (i
=(INTERNAL_FPF_PRECISION
-1); i
>=0; i
--)
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
1195 z
->sign
= locy
.sign
^ operation
;
1197 for (i
=(INTERNAL_FPF_PRECISION
-1); i
>=0; i
--)
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 */
1220 if (locx
.type
== IFPF_IS_NORMAL
||
1221 locy
.type
== IFPF_IS_NORMAL
)
1228 /* signs are the same, add mantissas */
1230 for (i
=(INTERNAL_FPF_PRECISION
-1); i
>=0; i
--)
1242 ShiftMantRight1(&carry
,z
->mantissa
);
1243 z
->mantissa
[0] |= 0x8000;
1244 z
->type
= IFPF_IS_NORMAL
;
1247 if (z
->mantissa
[0] & 0x8000)
1248 z
->type
= IFPF_IS_NORMAL
;
1252 case INFINITY_INFINITY
:
1253 SetInternalFPFNaN(z
);
1257 choose_nan(x
, y
, z
, 1);
1262 ** All the math is done; time to round.
1264 RoundInternalFPF(z
);
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
,
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
1289 switch ((x
->type
* IFPF_TYPE_COUNT
) + y
->type
)
1291 case INFINITY_SUBNORMAL
:
1292 case INFINITY_NORMAL
:
1293 case INFINITY_INFINITY
:
1295 case ZERO_SUBNORMAL
:
1297 my_memmove((void *)x
,(void *)z
,sizeof(InternalFPF
));
1301 case SUBNORMAL_INFINITY
:
1302 case NORMAL_INFINITY
:
1303 case SUBNORMAL_ZERO
:
1305 my_memmove((void *)y
,(void *)z
,sizeof(InternalFPF
));
1311 SetInternalFPFNaN(z
);
1318 my_memmove((void *)x
,(void *)z
,sizeof(InternalFPF
));
1325 my_memmove((void *)y
,(void *)z
,sizeof(InternalFPF
));
1329 case SUBNORMAL_SUBNORMAL
:
1330 case SUBNORMAL_NORMAL
:
1331 case NORMAL_SUBNORMAL
:
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
;
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
++)
1362 for (i
=0; i
<(INTERNAL_FPF_PRECISION
*16); i
++)
1365 ** Get rightmost bit of the multiplier
1368 ShiftMantRight1(&carry
, locy
.mantissa
);
1372 ** Add the multiplicand to the product
1375 for (j
=(INTERNAL_FPF_PRECISION
-1); j
>=0; j
--)
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
);
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)
1405 ShiftMantLeft1(&carry
, extra_bits
);
1406 ShiftMantLeft1(&carry
, z
->mantissa
);
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;
1420 choose_nan(x
, y
, z
, 0);
1425 ** All math done...do rounding.
1427 RoundInternalFPF(z
);
1432 /**********************
1433 ** DivideInternalFPF **
1434 ***********************
1435 ** Divide internal FPF number x by y. Return result in z.
1437 static void DivideInternalFPF(InternalFPF
*x
,
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
1452 switch ((x
->type
* IFPF_TYPE_COUNT
) + y
->type
)
1455 case INFINITY_INFINITY
:
1456 SetInternalFPFNaN(z
);
1459 case ZERO_SUBNORMAL
:
1461 if (IsMantissaZero(y
->mantissa
))
1463 SetInternalFPFNaN(z
);
1468 case SUBNORMAL_INFINITY
:
1469 case NORMAL_INFINITY
:
1470 SetInternalFPFZero(z
, x
->sign
^ y
->sign
);
1473 case SUBNORMAL_ZERO
:
1475 if (IsMantissaZero(x
->mantissa
))
1477 SetInternalFPFNaN(z
);
1482 case INFINITY_SUBNORMAL
:
1483 case INFINITY_NORMAL
:
1484 SetInternalFPFInfinity(z
, 0);
1485 z
->sign
= x
->sign
^ y
->sign
;
1492 my_memmove((void *)x
,(void *)z
,sizeof(InternalFPF
));
1499 my_memmove((void *)y
,(void *)z
,sizeof(InternalFPF
));
1502 case SUBNORMAL_SUBNORMAL
:
1503 case NORMAL_SUBNORMAL
:
1504 case SUBNORMAL_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
);
1520 SetInternalFPFZero(z
, 0);
1523 if (IsMantissaZero(y
->mantissa
))
1525 SetInternalFPFInfinity(z
, 0);
1530 ** Initialize the result
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
++)
1542 while ((z
->mantissa
[0] & 0x8000) == 0)
1545 ShiftMantLeft1(&carry
, locx
.mantissa
);
1546 ShiftMantLeft1(&carry
, extra_bits
);
1549 ** Time to subtract yet?
1552 for (j
=0; j
<INTERNAL_FPF_PRECISION
; j
++)
1554 if (y
->mantissa
[j
] > extra_bits
[j
])
1559 if (y
->mantissa
[j
] < extra_bits
[j
])
1563 ** Divisor (y) <= dividend (x), subtract
1566 for (j
=(INTERNAL_FPF_PRECISION
-1); j
>=0; j
--)
1571 carry
= 1; /* 1 shifted into quotient */
1573 ShiftMantLeft1(&carry
, z
->mantissa
);
1579 choose_nan(x
, y
, z
, 0);
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
,
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.)
1609 mylong
=(int32
)0-mylong
;
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.
1625 { dest
->type
=IFPF_IS_ZERO
;
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.
1638 myword
=(u16
)((mylong
>> 16) & 0xFFFFL
);
1639 dest
->mantissa
[0]=myword
;
1640 myword
=(u16
)(mylong
& 0xFFFFL
);
1641 dest
->mantissa
[1]=myword
;
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
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
,
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.
1683 my_memcpy(dest
,"NaN",3);
1686 case IFPF_IS_INFINITY
:
1688 my_memcpy(dest
,"+Inf",4);
1690 my_memcpy(dest
,"-Inf",4);
1695 my_memcpy(dest
,"+0",2);
1697 my_memcpy(dest
,"-0",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.
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
1731 { AddSubInternalFPF(1,&locFPFNum
,&IFPF10
,&IFPFComp
);
1732 if(IFPFComp
.sign
==0) break;
1733 MultiplyInternalFPF(&locFPFNum
,&IFPF10
,&IFPFComp
);
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.
1745 AddSubInternalFPF(1,&locFPFNum
,&IFPF10
,&IFPFComp
);
1746 if(IFPFComp
.sign
!=0) break;
1747 DivideInternalFPF(&locFPFNum
,&IFPF10
,&IFPFComp
);
1749 my_memcpy((void *)&locFPFNum
,(void *)&IFPFComp
,sizeof(InternalFPF
));
1753 ** About time to start storing things. First, store the
1756 ccount
=1; /* Init character counter */
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
1776 ** Re-position radix point
1779 while(locFPFNum
.exp
>0)
1782 ShiftMantLeft1(&mycarry
,locFPFNum
.mantissa
);
1783 carryaccum
=(carryaccum
<<1);
1784 if(mycarry
) carryaccum
++;
1788 while(locFPFNum
.exp
<0)
1791 ShiftMantRight1(&mycarry
,locFPFNum
.mantissa
);
1797 { /* Emit decimal point */
1802 { /* Emit a digit */
1803 *dest
++=('0'+carryaccum
);
1807 my_memcpy((void *)&IFPF10
,
1809 sizeof(InternalFPF
));
1811 /* Do multiply via repeated adds */
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
,
1822 sizeof(InternalFPF
));
1827 ** Now move the 'E', the exponent sign, and the exponent
1832 /* sprint is supposed to return an integer, but it caused problems on SunOS
1833 * with the native cc. Hence we force it.
1838 expcount
=- expcount
;
1842 *dest
++ = (char)(expcount
+ '0');
1847 ** All done, go home.
1857 ////////////////////////////////////////////////////////////////////////
1859 void* AllocateMemory ( unsigned long n
, int* p
)
1862 void* r
= (void*) (*serviceFn
)(2,n
);
1866 void FreeMemory ( void* p
, int* zz
)
1877 ** Perform the floating-point emulation routines portion of the
1878 ** CPU benchmark. Returns the operations per second.
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
),
1912 bbase
=(InternalFPF
*)AllocateMemory(locemfloatstruct
->arraysize
*sizeof(InternalFPF
),
1915 cbase
=(InternalFPF
*)AllocateMemory(locemfloatstruct
->arraysize
*sizeof(InternalFPF
),
1919 ** Set up the arrays
1921 SetupCPUEmFloatArrays(abase
,bbase
,cbase
,locemfloatstruct
->arraysize
);
1924 tickcount
=DoEmFloatIteration(abase
,bbase
,cbase
,
1925 locemfloatstruct
->arraysize
,
1928 FreeMemory((void *)abase
,&systemerror
);
1929 FreeMemory((void *)bbase
,&systemerror
);
1930 FreeMemory((void *)cbase
,&systemerror
);
1936 void entry ( HWord(*f
)(HWord
,HWord
) )
1939 vexxx_printf("starting\n");