1/* 2 * COPYRIGHT: LGPL, see LGPL.txt in the top level directory 3 * PROJECT: ReactOS Win32 subsystem 4 * PURPOSE: FLOATOBJ floating point emulation functions for x86 5 * FILE: win32ss/gdi/eng/i386/floatobj.S 6 * PROGRAMMER: Timo Kreuzer 7 */ 8 9#include <asm.inc> 10 11.code 12/******************************************************************************* 13 * IEEE 754-1985 single precision floating point 14 * 15 * | 31 | 30...23 | 22...0 | 16 * |sign| exponent | fraction | 17 * 18 * mantissa = 1 + (fraction / 2^23) 19 * f = (-1)^sign * mantissa * 2 ^ (exponent - bias) 20 * bias = 127 21 * 22 ******************************************************************************* 23 * win32k x86 floating point emulation 24 * 25 * struct _EFLOAT 26 = { 27 * LONG lMant; 28 * LONG lExp; 29 * }; 30 * 31 * f = (lMant / 0x40000000) * 2 ^ (lExp - 2) 32 * = lMant * 2 ^ (lExp - 32) 33 * 34 ******************************************************************************* 35 * Optimization notes: 36 * 37 * - shld is slow (4 cycles) and not pairable, mov + shl is faster 38 * - esp is used, because it's available earlier 39 * - bsr is very slow on old cpus (up to 72 cycles on a p1) while being much 40 * faster on modern cpus (2-11 cycles). Workarounds using branch trees or 41 * table lookups are of no use nowadays. 42 ******************************************************************************* 43 * Compatibility notes: 44 * - There are issues with very large size values near integer overflow. 45 * Floating point values are behaving different there. This behavior isn't 46 * simulated yet. Difference is < 10^-5 % 47 * - The result of a multiplication can differ from Windows result in the 48 * least significant bit, that is a difference of 1 / 2^30 or ~10^-9 49 ******************************************************************************* 50 * Implementation status: 51 * 52 * FLOATOBJ_SetFloat - implemented, tested 53 * FLOATOBJ_SetLong - implemented, tested 54 * FLOATOBJ_GetFloat - implemented, tested 55 * FLOATOBJ_GetLong - implemented in C 56 * FLOATOBJ_Equal - implemented, tested 57 * FLOATOBJ_EqualLong - implemented 58 * FLOATOBJ_GreaterThan - implemented 59 * FLOATOBJ_GreaterThanLong - wrapper 60 * FLOATOBJ_LessThan - implemented 61 * FLOATOBJ_LessThanLong - wrapper 62 * FLOATOBJ_Neg - implemented 63 * FLOATOBJ_Mul - implemented, tested, optimized 64 * FLOATOBJ_MulFloat - wrapper 65 * FLOATOBJ_MulLong - wrapper, could really need optimization 66 * FLOATOBJ_Div - implemented 67 * FLOATOBJ_DivFloat - wrapper 68 * FLOATOBJ_DivLong - wrapper 69 * FLOATOBJ_Add - implemented, tested 70 * FLOATOBJ_AddFloat - wrapper 71 * FLOATOBJ_AddLong - wrapper 72 * FLOATOBJ_Sub - implemented, tested 73 * FLOATOBJ_SubFloat - wrapper 74 * FLOATOBJ_SubLong - wrapper 75 */ 76 77#define lMant 0 78#define lExp 4 79 80#define PARAM1 8 81#define PARAM2 12 82 83/** Globals **/ 84/* extern const FLOATOBJ gef0; */ 85PUBLIC _gef0 86_gef0: 87 .long 0, 0 88 89/* extern const FLOATOBJ gef1; */ 90PUBLIC _gef1 91_gef1: 92 .long HEX(40000000), HEX(00000002) 93 94/* extern const FLOATOBJ gef2; */ 95PUBLIC _gef2 96_gef2: 97 .long HEX(40000000), HEX(00000003) 98 99/* extern const FLOATOBJ gef16; */ 100PUBLIC _gef16 101_gef16: 102 .long HEX(40000000), HEX(00000006) 103 104/****************************************************************************** 105 * VOID 106 * APIENTRY 107 * FLOATOBJ_SetFloat(IN OUT PFLOATOBJ pf, IN FLOATL f); 108 */ 109_FLOATOBJ_SetFloat@8: 110PUBLIC _FLOATOBJ_SetFloat@8 111 push ebp 112 mov ebp, esp 113 114 mov ecx, [esp + PARAM2] /* Load the float into ecx */ 115 mov eax, ecx /* Copy float to eax for later */ 116 117 test ecx, HEX(7f800000) /* Check for zero exponent - 0 or denormal */ 118 jz SetFloat0 /* If it's all zero, ... */ 119 120 shl ecx, 7 /* Put the bits for the mantissa in place */ 121 122 cdq /* Fill edx with the sign from the FLOATL in eax */ 123 and ecx, HEX(7fffffff) /* Mask out invalid field in the mantissa */ 124 125 shr eax, 23 /* Shift the exponent in eax in place */ 126 or ecx, HEX(40000000) /* Set bit for 1 in the mantissa */ 127 and eax, HEX(0ff) /* Mask out invalid fields in the exponent in eax */ 128 129 xor ecx, edx /* Make use of the sign bit expanded to full edx */ 130 131 sub eax, 125 /* Adjust exonent bias */ 132 133 sub ecx, edx /* Substract -1 or add 1 if sign was set */ 134 135 mov edx, [esp + PARAM1] /* Load pf into edx */ 136 mov [edx + lMant], ecx /* Save back mantissa */ 137 mov [edx + lExp], eax /* Save back exponent */ 138 139 pop ebp /* Return */ 140 ret 8 141 142SetFloat0: 143 mov edx, [esp + PARAM1] /* Load pf into edx */ 144 145 mov dword ptr [edx + lMant], 0 /* Set mantissa and exponent to 0 */ 146 mov dword ptr [edx + lExp], 0 147 148 pop ebp /* Return */ 149 ret 8 150 151 152/******************************************************************************* 153 * LONG 154 * APIENTRY 155 * FLOATOBJ_GetFloat(IN PFLOATOBJ pf); 156 * 157 */ 158_FLOATOBJ_GetFloat@4: 159PUBLIC _FLOATOBJ_GetFloat@4 160 push ebp 161 mov ebp, esp 162 163 mov edx, [esp + PARAM1] /* Load pf into edx */ 164 mov eax, [edx + lMant] /* Load mantissa into eax */ 165 mov ecx, [edx + lExp] /* Load exponent into ecx */ 166 167 cdq /* Calculate abs(mantissa) */ 168 xor eax, edx 169 170 add ecx, 125 171 172 sub eax, edx 173 jz GetFloatRet 174 175 and ecx, HEX(0ff) /* Mask out invalid fields in the exponent */ 176 and eax, HEX(3fffffff) /* Mask out invalid fields in mantissa */ 177 178 shl ecx, 23 /* Shift exponent in place */ 179 shr eax, 7 /* Shift mantissa in place */ 180 181 and edx, HEX(80000000) /* Reduce edx to sign bit only */ 182 183 or eax, ecx /* Set exponent in result */ 184 or eax, edx /* Set sign bit in result */ 185 186GetFloatRet: 187 /* Return */ 188 pop ebp 189 ret 4 190 191 192 193/****************************************************************************** 194 * VOID 195 * APIENTRY 196 * FLOATOBJ_SetLong(OUT PFLOATOBJ pf, IN LONG l); 197 * 198 * Instead of using abs(l), which is 3 + 2 instructions, use a branch. 199 */ 200_FLOATOBJ_SetLong@8: 201PUBLIC _FLOATOBJ_SetLong@8 202 push ebp 203 mov ebp, esp 204 205 mov eax, [esp + PARAM2] /* Load l into eax */ 206 mov edx, [esp + PARAM1] /* Load pf into edx */ 207 208 test eax, eax /* different handling for <0, =0 and >0 */ 209 js SetLongNeg 210 jz SetLong0 211 212 bsr ecx, eax /* Get number of most significant bit aka log2(l) */ 213 mov [edx + lExp], ecx /* Safe log2(l) into exponent */ 214 215 neg ecx /* Calculate necessary shift */ 216 add ecx, 30 217 218 add dword ptr [edx + lExp], 2 /* Adjust exponent */ 219 220 shl eax, cl /* Shift mantissa in place */ 221 mov [edx + lMant], eax /* Save mantissa */ 222 223 pop ebp /* Return */ 224 ret 8 225 226SetLongNeg: 227 neg eax /* Get absolute value of l */ 228 bsr ecx, eax /* Get number of most significant bit aka log2(l) */ 229 neg eax /* Back to negative */ 230 231 mov [edx + lExp], ecx /* Safe log2(-l) into exponent */ 232 233 neg ecx /* Calculate necessary shift */ 234 add ecx, 30 235 236 add dword ptr [edx + lExp], 2 /* Adjust exponent */ 237 238 shl eax, cl /* Shift mantissa in place */ 239 mov [edx + lMant], eax /* Save mantissa */ 240 241 pop ebp /* Return */ 242 ret 8 243 244SetLong0: 245 mov dword ptr [edx + lMant], 0 /* Set mantissa and exponent to 0 */ 246 mov dword ptr [edx + lExp], 0 247 248 pop ebp /* Return */ 249 ret 8 250 251 252/****************************************************************************** 253 * BOOL 254 * APIENTRY 255 * FLOATOBJ_Equal(IN PFLOATOBJ pf1, IN PFLOATOBJ pf2); 256 */ 257_FLOATOBJ_Equal@8: 258PUBLIC _FLOATOBJ_Equal@8 259 push ebp 260 mov ebp, esp 261 262 mov ecx, [esp + PARAM1] /* Load pf1 into ecx */ 263 mov eax, [esp + PARAM2] /* Load pf2 into ecx */ 264 265 mov edx, [ecx + lExp] /* Get float1 in ecx, edx */ 266 mov ecx, [ecx + lMant] 267 268 sub edx, [eax + lExp] /* Calculate diference to float2 */ 269 sub ecx, [eax + lMant] 270 271 or edx, ecx /* Combine */ 272 273 mov eax, 0 /* Set eax if combination is 0 */ 274 setz al 275 276 pop ebp /* Return */ 277 ret 8 278 279 280/****************************************************************************** 281 * BOOL 282 * APIENTRY 283 * FLOATOBJ_EqualLong(IN PFLOATOBJ pf, IN LONG l); 284 */ 285_FLOATOBJ_EqualLong@8: 286PUBLIC _FLOATOBJ_EqualLong@8 287 push ebp 288 mov ebp, esp 289 290 mov eax, [esp + PARAM1] /* Load pf into eax */ 291 mov ecx, 32 /* Load (32 - lExp) into ecx */ 292 sub ecx, [eax + lExp] 293 mov edx, [eax + lMant] /* Load mantissa into edx */ 294 sar edx, cl /* Signed shift mantissa according to exponent */ 295 shl edx, cl /* Shift the mantissa back */ 296 cmp edx, [eax + lMant] /* Check whether bits were killed by shifting */ 297 jnz EqualLongFalse /* We have truncated the mantissa, return 0 */ 298 299 sar edx, cl /* Shift the mantissa again */ 300 xor eax, eax /* Set return value ... */ 301 cmp edx, [esp + PARAM2] /* TRUE if shifted mantissa equals the LONG */ 302 setz al 303 304 pop ebp /* Return */ 305 ret 8 306 307EqualLongFalse: 308 xor eax, eax /* Return FALSE */ 309 pop ebp 310 ret 8 311 312 313/****************************************************************************** 314 * BOOL 315 * APIENTRY 316 * FLOATOBJ_GreaterThan(IN PFLOATOBJ pf, IN PFLOATOBJ pf1); 317 * 318 */ 319_FLOATOBJ_GreaterThan@8: 320PUBLIC _FLOATOBJ_GreaterThan@8 321 push ebp 322 mov ebp, esp 323 324 mov eax, [ebp + PARAM1] /* Load pointer to efloat1 in eax */ 325 mov edx, [ebp + PARAM2] /* Load pointer to efloat2 in edx */ 326 327 mov ecx, [eax + lMant] /* Load mantissa1 in ecx */ 328 mov edx, [edx + lMant] /* Load mantissa2 in edx */ 329 330 sar ecx, 31 /* Calculate sign(lMant1) in ecx */ 331 sar edx, 31 /* Calculate sign(lMant2) in edx */ 332 333 cmp ecx, edx /* Branch if both have the same sign */ 334 je GreaterThan_2 335 336 /* Mantissae have different sign */ 337 mov eax, 0 /* Return (sign(lMant1) > sign(lMant2)) */ 338 setg al 339 pop ebp 340 ret 8 341 342GreaterThan_2: 343 /* Mantissae have the same sign */ 344 345 mov edx, [ebp + PARAM2] /* Reload pointer to float2 in edx */ 346 test ecx, ecx /* Branch if sign is negative */ 347 js GreaterThan_neg 348 349 /* Both mantissae are positive or 0 */ 350 351 or ecx, [edx + lMant] /* Branch if one mantissa is 0 */ 352 jz GreaterThan_pos2 353 354 /* Both mantissae are positive */ 355 356 mov ecx, [eax + lExp] /* Branch if exponents are equal */ 357 cmp ecx, [edx + lExp] 358 je GreaterThan_pos2 359 360 mov eax, 0 /* Return (lExp1 > lExp2) */ 361 setg al 362 pop ebp 363 ret 8 364 365GreaterThan_pos2: 366 /* Exponents are equal or one mantissa is 0 */ 367 368 mov ecx, [eax + lMant] /* Return (lMant1 > lMant2) */ 369 cmp ecx, [edx + lMant] 370 mov eax, 0 371 setg al 372 pop ebp 373 ret 8 374 375GreaterThan_neg: 376 /* Both mantissae are negative */ 377 378 mov ecx, [eax + lExp] /* Branch if exponents are equal */ 379 cmp ecx, [edx + lExp] 380 je GreaterThan_neg2 381 382 /* Both mantissae negative, exponents are different */ 383 384 mov eax, 0 /* Return (lExp1 < lExp2) */ 385 setl al 386 pop ebp 387 ret 8 388 389GreaterThan_neg2: 390 /* Both mantissae negative, exponents are equal */ 391 392 mov ecx, [eax + lMant] /* Return (lMant1 < lMant2) */ 393 cmp ecx, [edx + lMant] 394 mov eax, 0 395 setl al 396 pop ebp 397 ret 8 398 399 400 401/****************************************************************************** 402 * VOID 403 * APIENTRY 404 * FLOATOBJ_GreaterThanLong(IN OUT PFLOATOBJ pf, IN LONG l); 405 * 406 * Currently implemented as a wrapper around FLOATOBJ_SetLong and 407 * LOATOBJ_GreaterThan 408 */ 409_FLOATOBJ_GreaterThanLong@8: 410PUBLIC _FLOATOBJ_GreaterThanLong@8 411 push ebp 412 mov ebp, esp 413 414 sub esp, 8 /* Make room for a FLOATOBJ on the stack */ 415 mov eax, [ebp + PARAM2] /* Load LONG into eax */ 416 417 lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */ 418 419 push eax /* Push LONG on the stack */ 420 push ecx /* Push pointer to local FLOATOBJ on the stack */ 421 call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */ 422 423 lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */ 424 push ecx 425 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ 426 call _FLOATOBJ_GreaterThan@8 /* Compare */ 427 428 mov esp, ebp /* Cleanup and return */ 429 pop ebp 430 ret 8 431 432 433/****************************************************************************** 434 * BOOL 435 * APIENTRY 436 * FLOATOBJ_LessThan(IN PFLOATOBJ pf, IN PFLOATOBJ pf1); 437 * 438 */ 439_FLOATOBJ_LessThan@8: 440PUBLIC _FLOATOBJ_LessThan@8 441 push ebp 442 mov ebp, esp 443 444 mov eax, [ebp + PARAM1] /* Load pointer to floats in eax and edx */ 445 mov edx, [ebp + PARAM2] 446 447 mov ecx, [eax + lMant] /* Load mantissae in ecx and edx */ 448 mov edx, [edx + lMant] 449 450 sar ecx, 31 /* Calculate sign(lMant1) and sign(lMant2) */ 451 sar edx, 31 452 453 cmp ecx, edx /* Branch if both have the same sign */ 454 je LessThan_2 455 456 /* Mantissae have different sign */ 457 458 mov eax, 0 /* Return (sign(lMant1) < sign(lMant2)) */ 459 setl al 460 pop ebp 461 ret 8 462 463LessThan_2: 464 /* Mantissae have the same sign */ 465 466 467 mov edx, [ebp + PARAM2] /* Reload pointer to float2 in edx */ 468 469 test ecx, ecx /* Branch if sign is negative */ 470 js LessThan_neg 471 472 /* Both mantissae are positive or 0 */ 473 474 or ecx, [edx + lMant] /* Branch if one mantissa is 0 */ 475 jz LessThan_pos2 476 477 /* Both mantissae are positive */ 478 479 mov ecx, [eax + lExp] /* Branch if exponents are equal */ 480 cmp ecx, [edx + lExp] 481 je LessThan_pos2 482 483 mov eax, 0 /* Return (lExp1 < lExp2) */ 484 setl al 485 pop ebp 486 ret 8 487 488LessThan_pos2: 489 /* Exponents are equal or one mantissa is 0 */ 490 491 mov ecx, [eax + lMant] /* Return (lMant1 < lMant2) */ 492 cmp ecx, [edx + lMant] 493 mov eax, 0 494 setl al 495 pop ebp 496 ret 8 497 498LessThan_neg: 499 /* Both mantissae are negative */ 500 501 mov ecx, [eax + lExp] /* Branch if exponents are equal */ 502 cmp ecx, [edx + lExp] 503 je LessThan_neg2 504 505 /* Both mantissae negative, exponents are different */ 506 507 mov eax, 0 /* Return (lExp1 > lExp2) */ 508 setg al 509 pop ebp 510 ret 8 511 512LessThan_neg2: 513 /* Both mantissae negative, exponents are equal */ 514 515 mov ecx, [eax + lMant] /* Return (lMant1 > lMant2) */ 516 cmp ecx, [edx + lMant] 517 mov eax, 0 518 setg al 519 pop ebp 520 ret 8 521 522 523/****************************************************************************** 524 * VOID 525 * APIENTRY 526 * FLOATOBJ_LessThanLong(IN OUT PFLOATOBJ pf, IN LONG l); 527 * 528 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_LessThan 529 */ 530_FLOATOBJ_LessThanLong@8: 531PUBLIC _FLOATOBJ_LessThanLong@8 532 push ebp 533 mov ebp, esp 534 535 sub esp, 8 /* Make room for a FLOATOBJ on the stack */ 536 mov eax, [ebp + PARAM2] /* Load LONG into eax */ 537 538 lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */ 539 push eax /* Push LONG on the stack */ 540 push ecx /* Push pointer to local FLOATOBJ on the stack */ 541 call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */ 542 543 lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */ 544 push ecx 545 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ 546 call _FLOATOBJ_LessThan@8 /* Compare */ 547 548 mov esp, ebp /* Cleanup and return */ 549 pop ebp 550 ret 8 551 552 553 554/****************************************************************************** 555 * VOID 556 * APIENTRY 557 * FLOATOBJ_Mul(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2); 558 * 559 * (mant1 * 2^exp1) * (mant2 * 2^exp2) = (mant1 * mant2) * 2^(exp1 + exp2) 560 * or mant = mant1 * mant2 and exp = exp1 + exp2 561 * No special handling for 0, where mantissa is 0 562 */ 563_FLOATOBJ_Mul@8: 564PUBLIC _FLOATOBJ_Mul@8 565 push ebp 566 mov ebp, esp 567 568 mov edx, [esp + PARAM1] /* Load pf1 into edx */ 569 mov ecx, [esp + PARAM2] /* Load pf2 into ecx */ 570 mov eax, [ecx + lMant] /* Load mantissa2 into eax */ 571 mov ecx, [ecx + lExp] /* Load exponent2 into ecx */ 572 573 imul dword ptr [edx + lMant] /* Multiply eax with mantissa 1 */ 574 575 test edx, edx /* Special handling for result < 0 */ 576 js MulNeg 577 578 shl edx, 2 /* Get new mantissa from bits 30 to 62 */ 579 shr eax, 30 /* of edx:eax into edx */ 580 or eax, edx 581 582 mov edx, ecx /* Need ecx for the shift, safe exp2 to free edx */ 583 mov ecx, 0 /* Check for highest bit */ 584 sets cl 585 shr eax, cl /* Normalize mantissa in eax */ 586 587 jz Mul0 /* All 0? */ 588 589 lea edx, [edx + ecx -2] /* Normalize exponent in edx */ 590 591 592 mov ecx, [esp + PARAM1] /* Load pf1 into ecx */ 593 mov [ecx + lMant], eax /* Save back mantissa */ 594 add [ecx + lExp], edx /* Save back exponent */ 595 596 pop ebp /* Return */ 597 ret 8 598 599MulNeg: 600 601 shl edx, 2 /* Get new mantissa from bits 30 to 62 */ 602 shr eax, 30 /* of edx:eax into edx */ 603 or eax, edx 604 605 mov edx, ecx /* Need ecx for the shift, safe exp2 to free edx */ 606 607 mov ecx, 0 /* Check for highest bit */ 608 setns cl 609 shr eax, cl /* Normalize mantissa in eax */ 610 611 jz Mul0 /* All 0? */ 612 613 614 lea edx, [edx + ecx -2] /* Normalize exponent in edx */ 615 or eax, HEX(80000000) /* Set sign bit */ 616 617 mov ecx, [esp + PARAM1] /* Load pf1 into ecx */ 618 mov [ecx + lMant], eax /* Save back mantissa */ 619 add [ecx + lExp], edx /* Save back exponent */ 620 621 pop ebp /* Return */ 622 ret 8 623 624Mul0: 625 mov ecx, [esp + PARAM1] /* Load pf1 into ecx */ 626 mov [ecx + lMant], eax /* Store 0 in mantissa */ 627 mov [ecx + lExp], eax /* Store 0 in exponent */ 628 629 pop ebp /* Return */ 630 ret 8 631 632 633/****************************************************************************** 634 * VOID 635 * APIENTRY 636 * FLOATOBJ_MulFloat(IN OUT PFLOATOBJ pf, IN FLOATL f); 637 * 638 * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Mul 639 */ 640_FLOATOBJ_MulFloat@8: 641PUBLIC _FLOATOBJ_MulFloat@8 642 push ebp 643 mov ebp, esp 644 645 sub esp, 8 /* Make room for a FLOATOBJ on the stack */ 646 mov eax, [ebp + PARAM2] /* Load f into eax */ 647 lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */ 648 push eax /* Push f on the stack */ 649 push ecx /* Push pointer to local FLOATOBJ on the stack */ 650 call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */ 651 652 lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */ 653 push ecx 654 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ 655 call _FLOATOBJ_Mul@8 /* Multiply */ 656 657 mov esp, ebp /* Cleanup and return */ 658 pop ebp 659 ret 8 660 661 662/****************************************************************************** 663 * VOID 664 * APIENTRY 665 * FLOATOBJ_MulLong(IN OUT PFLOATOBJ pf, IN LONG l); 666 * 667 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Mul 668 */ 669_FLOATOBJ_MulLong@8: 670PUBLIC _FLOATOBJ_MulLong@8 671 push ebp 672 mov ebp, esp 673 674 sub esp, 8 /* Make room for a FLOATOBJ on the stack */ 675 mov eax, [ebp + PARAM2] /* Load l into eax */ 676 lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */ 677 push eax /* Push l on the stack */ 678 push ecx /* Push pointer to local FLOATOBJ on the stack */ 679 call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */ 680 681 lea ecx, [ebp -8] /* Push pointer to local FLOATOBJ on the stack */ 682 push ecx 683 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ 684 call _FLOATOBJ_Mul@8 /* Multiply */ 685 686 mov esp, ebp /* Cleanup and return */ 687 pop ebp 688 ret 8 689 690 691/******************************************************************************* 692 * VOID 693 * APIENTRY 694 * FLOATOBJ_Div(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2); 695 * 696 */ 697_FLOATOBJ_Div@8: 698PUBLIC _FLOATOBJ_Div@8 699 push ebp 700 mov ebp, esp 701 push ebx 702 703 mov eax, [ebp + PARAM2] /* Load lMant2 into eax */ 704 mov eax, [eax + lMant] 705 706 cdq /* Calculate abs(lMant2) */ 707 xor eax, edx 708 sub eax, edx 709 jz DivError /* Divide by zero error! */ 710 711 mov ebx, edx /* Copy sign(lMant2) to ebx */ 712 mov ecx, eax /* Copy abs(lMant2) to ecx */ 713 714 mov eax, [ebp + PARAM1] /* Load lMant1 into eax */ 715 mov eax, [eax + lMant] 716 717 cdq /* Calculate abs(lMant1) */ 718 xor eax, edx 719 sub eax, edx 720 721 jz Div0 /* Dividend is 0? */ 722 723 xor ebx, edx /* combine both signs in ebx */ 724 725 mov edx, eax /* Prepare edx:eax for integer divide */ 726 xor eax, eax 727 shr edx, 1 728 div ecx /* Do an unsigned divide */ 729 730 xor ecx, ecx /* Adjust result */ 731 test eax, HEX(80000000) 732 setnz cl 733 shr eax, cl 734 735 xor eax, ebx /* Correct the result's sign */ 736 sub eax, ebx 737 738 mov edx, [ebp + PARAM1] /* Load pf1 into edx */ 739 mov [edx + lMant], eax /* Safe back the mantissa */ 740 mov ebx, [ebp + PARAM2] /* Load pf2 into ebx */ 741 sub ecx, [ebx + lExp] /* Calculate exponent offset */ 742 inc ecx 743 add [edx + lExp], ecx /* Safe back exponent */ 744 745 pop ebx /* Return */ 746 pop ebp 747 ret 8 748 749DivError: 750Div0: 751 mov edx, [ebp + PARAM1] /* Load pf into edx */ 752 mov [edx + lMant], eax /* Store 0 in mantissa */ 753 mov [edx + lExp], eax /* Store 0 in exponent */ 754 755 pop ebx /* Return */ 756 pop ebp 757 ret 8 758 759 760/****************************************************************************** 761 * VOID 762 * APIENTRY 763 * FLOATOBJ_DivFloat(IN OUT PFLOATOBJ pf, IN FLOATL f); 764 * 765 * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Div 766 */ 767_FLOATOBJ_DivFloat@8: 768PUBLIC _FLOATOBJ_DivFloat@8 769 push ebp 770 mov ebp, esp 771 sub esp, 8 /* Make room for a FLOATOBJ on the stack */ 772 773 mov eax, [ebp + PARAM2] /* Load f into eax */ 774 lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */ 775 push eax /* Push f on the stack */ 776 push ecx /* Push pointer to local FLOATOBJ on the stack */ 777 call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */ 778 779 lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */ 780 push ecx 781 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ 782 call _FLOATOBJ_Div@8 /* Divide */ 783 784 mov esp, ebp /* Cleanup and return */ 785 pop ebp 786 ret 8 787 788 789/****************************************************************************** 790 * VOID 791 * APIENTRY 792 * FLOATOBJ_DivLong(IN OUT PFLOATOBJ pf, IN LONG l); 793 * 794 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Div 795 */ 796_FLOATOBJ_DivLong@8: 797PUBLIC _FLOATOBJ_DivLong@8 798 push ebp 799 mov ebp, esp 800 sub esp, 8 /* Make room for a FLOATOBJ on the stack */ 801 802 mov eax, [ebp + PARAM2] /* Load l into eax */ 803 lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */ 804 push eax /* Push l on the stack */ 805 push ecx /* Push pointer to local FLOATOBJ on the stack */ 806 call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */ 807 808 lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */ 809 push ecx 810 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ 811 call _FLOATOBJ_Div@8 /* Divide */ 812 813 mov esp, ebp /* Cleanup and return */ 814 pop ebp 815 ret 8 816 817/******************************************************************************* 818 * VOID 819 * APIENTRY 820 * FLOATOBJ_Add(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2); 821 * 822 */ 823_FLOATOBJ_Add@8: 824PUBLIC _FLOATOBJ_Add@8 825 push ebp 826 mov ebp, esp 827 push ebx 828 829 mov eax, [ebp + PARAM1] /* Load pointer to pf1 in eax */ 830 mov ebx, [ebp + PARAM2] /* Load pointer to pf2 in ebx */ 831 832 mov ecx, [eax + lExp] /* Load float1 in (eax,ecx) */ 833 mov edx, [ebx + lExp] 834 mov eax, [eax + lMant] /* Load float2 in (ebx,edx) */ 835 mov ebx, [ebx + lMant] 836 837 cmp ecx, edx /* Check which one has the bigger lExp */ 838 jl Add2 839 840 sub ecx, edx /* Calculate lExp1 - lExp2 */ 841 sar eax, 1 /* Shift both mantissae 1 bit right */ 842 sar ebx, 1 843 sar ebx, cl /* Shift lMant2 according to exponent difference */ 844 845 add eax, ebx /* Add the manrissae */ 846 jz AddIs0 847 848 cdq /* Calculate abs(mantissa) */ 849 xor eax, edx 850 sub eax, edx 851 852 bsr ecx, eax /* Find most significant bit */ 853 neg ecx /* and calculate needed normalize shift */ 854 add ecx, 30 855 shl eax, cl 856 dec ecx 857 858 xor eax, edx /* Go back to original sign */ 859 sub eax, edx 860 861 mov edx, [ebp + PARAM1] /* Reload pointer to float1 */ 862 863 pop ebx 864 865 mov dword ptr [edx + lMant], eax /* Safe mantissa */ 866 sub [edx + lExp], ecx /* Adjust exponent */ 867 868 pop ebp /* Return */ 869 ret 8 870 871Add2: 872 sub edx, ecx /* Calculate lExp2 - lExp1 and put it into ecx */ 873 mov ecx, edx 874 875 sar ebx, 1 /* Shift both mantissae 1 bit right */ 876 sar eax, 1 877 sar eax, cl /* Shift lMant2 according to exponent difference */ 878 879 add eax, ebx /* Add the manrissae */ 880 jz AddIs0 881 882 mov ebx, [ebp + PARAM1] /* Reload pointer to float1 */ 883 add [ebx + lExp], ecx /* Adjust exponent part 1 */ 884 885 cdq /* Calculate abs(mantissa) */ 886 xor eax, edx 887 sub eax, edx 888 889 bsr ecx, eax /* Find most significant bit */ 890 neg ecx /* and calculate needed normalize shift */ 891 add ecx, 30 892 shl eax, cl 893 dec ecx 894 895 xor eax, edx /* Go back to original sign */ 896 sub eax, edx 897 898 mov dword ptr [ebx + lMant], eax /* Safe mantissa and adjust exponent */ 899 sub [ebx + lExp], ecx 900 901 pop ebx /* Return */ 902 pop ebp 903 ret 8 904 905AddIs0: 906 /* Mantissa is 0, so float to (0,0) */ 907 mov eax, [ebp + PARAM1] 908 pop ebx 909 mov dword ptr [eax + lMant], 0 910 mov dword ptr [eax + lExp], 0 911 pop ebp 912 ret 8 913 914/****************************************************************************** 915 * VOID 916 * APIENTRY 917 * FLOATOBJ_AddFloat(IN OUT PFLOATOBJ pf, IN FLOATL f); 918 * 919 * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Add 920 */ 921_FLOATOBJ_AddFloat@8: 922PUBLIC _FLOATOBJ_AddFloat@8 923 push ebp 924 mov ebp, esp 925 sub esp, 8 /* Make room for a FLOATOBJ on the stack */ 926 927 mov eax, [ebp + PARAM2] /* Load f into eax */ 928 lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */ 929 push eax /* Push f on the stack */ 930 push ecx /* Push pointer to local FLOATOBJ on the stack */ 931 call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */ 932 933 lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */ 934 push ecx 935 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ 936 call _FLOATOBJ_Add@8 /* Add */ 937 938 mov esp, ebp /* Cleanup and return */ 939 pop ebp 940 ret 8 941 942 943/****************************************************************************** 944 * VOID 945 * APIENTRY 946 * FLOATOBJ_AddLong(IN OUT PFLOATOBJ pf, IN LONG l); 947 * 948 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Add 949 */ 950_FLOATOBJ_AddLong@8: 951PUBLIC _FLOATOBJ_AddLong@8 952 push ebp 953 mov ebp, esp 954 sub esp, 8 /* Make room for a FLOATOBJ on the stack */ 955 956 mov eax, [ebp + PARAM2] /* Load l into eax */ 957 lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */ 958 push eax /* Push l on the stack */ 959 push ecx /* Push pointer to local FLOATOBJ on the stack */ 960 call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */ 961 962 lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */ 963 push ecx 964 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ 965 call _FLOATOBJ_Add@8 /* Add */ 966 967 mov esp, ebp /* Cleanup and return */ 968 pop ebp 969 ret 8 970 971/******************************************************************************* 972 * VOID 973 * APIENTRY 974 * FLOATOBJ_Sub(IN OUT PFLOATOBJ pf, IN PFLOATOBJ pf1); 975 * 976 */ 977_FLOATOBJ_Sub@8: 978PUBLIC _FLOATOBJ_Sub@8 979 push ebp 980 mov ebp, esp 981 push ebx 982 983 mov eax, [ebp + PARAM1] /* Load pointer to floats in eax and ebx */ 984 mov ebx, [ebp + PARAM2] 985 986 mov ecx, [eax + lExp] /* Load float1 in (eax,ecx) and float2 in (ebx,edx) */ 987 mov edx, [ebx + lExp] 988 mov eax, [eax + lMant] 989 mov ebx, [ebx + lMant] 990 991 cmp ecx, edx /* Check which one has the bigger lExp */ 992 jl Sub2 993 994 sub ecx, edx /* Calculate lExp1 - lExp2 */ 995 sar eax, 1 /* Shift both mantissae 1 bit right */ 996 sar ebx, 1 997 sar ebx, cl /* Shift lMant2 according to exponent difference */ 998 999 sub eax, ebx /* Substract the manrissae */ 1000 jz SubIs0 1001 1002 cdq /* Calculate abs(mantissa) */ 1003 xor eax, edx 1004 sub eax, edx 1005 1006 bsr ecx, eax /* Find most significant bit */ 1007 neg ecx /* and calculate needed normalize shift */ 1008 add ecx, 30 1009 shl eax, cl 1010 dec ecx 1011 1012 xor eax, edx /* Go back to original sign */ 1013 sub eax, edx 1014 1015 mov edx, [ebp + PARAM1] /* Reload pointer to float1 */ 1016 1017 pop ebx 1018 1019 mov dword ptr [edx + lMant], eax /* Safe mantissa and adjust exponent */ 1020 sub [edx + lExp], ecx 1021 1022 pop ebp 1023 ret 8 1024 1025Sub2: 1026 sub edx, ecx /* Calculate lExp2 - lExp1 and put it into ecx */ 1027 mov ecx, edx 1028 1029 sar ebx, 1 /* Shift both mantissae 1 bit right */ 1030 sar eax, 1 1031 sar eax, cl /* Shift lMant2 according to exponent difference */ 1032 1033 sub eax, ebx /* Substract the manrissae */ 1034 jz AddIs0 1035 1036 mov ebx, [ebp + PARAM1] /* Reload pointer to float1 */ 1037 add [ebx + lExp], ecx /* Adjust exponent part 1 */ 1038 1039 cdq /* Calculate abs(mantissa) */ 1040 xor eax, edx 1041 sub eax, edx 1042 1043 bsr ecx, eax /* Find most significant bit */ 1044 neg ecx /* and calculate needed normalize shift */ 1045 add ecx, 30 1046 shl eax, cl 1047 dec ecx 1048 1049 xor eax, edx /* Go back to original sign */ 1050 sub eax, edx 1051 1052 mov dword ptr [ebx + lMant], eax /* Safe mantissa */ 1053 sub [ebx + lExp], ecx /* Adjust exponent */ 1054 1055 pop ebx /* Return */ 1056 pop ebp 1057 ret 8 1058 1059SubIs0: 1060 /* Mantissa is 0, so float to (0,0) */ 1061 mov eax, [ebp + PARAM1] 1062 pop ebx 1063 mov dword ptr [eax + lMant], 0 1064 mov dword ptr [eax + lExp], 0 1065 pop ebp 1066 ret 8 1067/****************************************************************************** 1068 * VOID 1069 * APIENTRY 1070 * FLOATOBJ_SubFloat(IN OUT PFLOATOBJ pf, IN FLOATL f); 1071 * 1072 * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Sub 1073 */ 1074_FLOATOBJ_SubFloat@8: 1075PUBLIC _FLOATOBJ_SubFloat@8 1076 push ebp 1077 mov ebp, esp 1078 sub esp, 8 /* Make room for a FLOATOBJ on the stack */ 1079 1080 mov eax, [ebp + PARAM2] /* Load f into eax */ 1081 lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */ 1082 push eax /* Push f on the stack */ 1083 push ecx /* Push pointer to local FLOATOBJ on the stack */ 1084 call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */ 1085 1086 lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */ 1087 push ecx 1088 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ 1089 call _FLOATOBJ_Sub@8 /* Substract */ 1090 1091 mov esp, ebp /* Cleanup and return */ 1092 pop ebp 1093 ret 8 1094 1095 1096/****************************************************************************** 1097 * VOID 1098 * APIENTRY 1099 * FLOATOBJ_SubLong(IN OUT PFLOATOBJ pf, IN LONG l); 1100 * 1101 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Sub 1102 */ 1103_FLOATOBJ_SubLong@8: 1104PUBLIC _FLOATOBJ_SubLong@8 1105 push ebp 1106 mov ebp, esp 1107 sub esp, 8 /* Make room for a FLOATOBJ on the stack */ 1108 1109 mov eax, [ebp + PARAM2] /* Load l into eax */ 1110 lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */ 1111 push eax /* Push l on the stack */ 1112 push ecx /* Push pointer to local FLOATOBJ on the stack */ 1113 call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */ 1114 1115 lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */ 1116 push ecx 1117 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ 1118 call _FLOATOBJ_Sub@8 /* Substract */ 1119 1120 mov esp, ebp /* Cleanup and return */ 1121 pop ebp 1122 ret 8 1123 1124 1125/******************************************************************************* 1126 * VOID 1127 * APIENTRY 1128 * FLOATOBJ_Neg(IN OUT PFLOATOBJ pf); 1129 * 1130 */ 1131_FLOATOBJ_Neg@4: 1132PUBLIC _FLOATOBJ_Neg@4 1133 push ebp 1134 mov ebp, esp 1135 1136 mov ecx, [esp + PARAM1] /* Load pf into ecx */ 1137 neg dword ptr [ecx + lMant] /* Negate lMant1 */ 1138 1139 pop ebp /* Return */ 1140 ret 4 1141 1142END 1143/* EOF */ 1144