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