[WIN32SS] Improve the FILE header section. Brought to you by Adam Stachowicz. CORE...
[reactos.git] / reactos / win32ss / gdi / eng / i386 / floatobj.S
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; */
86 PUBLIC _gef0
87 _gef0:
88 .long 0, 0
89
90 /* extern const FLOATOBJ gef1; */
91 PUBLIC _gef1
92 _gef1:
93 .long HEX(40000000), HEX(00000002)
94
95 /* extern const FLOATOBJ gef16; */
96 PUBLIC _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:
106 PUBLIC _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
138 SetFloat0:
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:
155 PUBLIC _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
182 GetFloatRet:
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:
197 PUBLIC _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
222 SetLongNeg:
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
240 SetLong0:
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:
255 PUBLIC _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
270 GetLong2:
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:
282 PUBLIC _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:
310 PUBLIC _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
331 EqualLongFalse:
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:
344 PUBLIC _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
366 GreaterThan_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
389 GreaterThan_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
399 GreaterThan_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
413 GreaterThan_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:
434 PUBLIC _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:
464 PUBLIC _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
487 LessThan_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
512 LessThan_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
522 LessThan_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
536 LessThan_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:
555 PUBLIC _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:
588 PUBLIC _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
623 MulNeg:
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
648 Mul0:
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:
665 PUBLIC _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:
694 PUBLIC _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:
722 PUBLIC _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
773 DivError:
774 Div0:
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:
792 PUBLIC _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:
821 PUBLIC _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:
849 PUBLIC _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
896 Add2:
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
930 AddIs0:
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:
948 PUBLIC _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:
977 PUBLIC _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:
1005 PUBLIC _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
1052 Sub2:
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
1086 SubIs0:
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:
1103 PUBLIC _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:
1132 PUBLIC _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:
1160 PUBLIC _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
1170 END
1171 /* EOF */