OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
MsvcMath32.c
Go to the documentation of this file.
1
8/* Came from https://gist.github.com/mmozeiko/6a365d6c483fc721b63a#file-win32_crt_math-cpp */
9
10#ifdef _M_IX86 // use this file only for 32-bit architecture
11
12#define CRT_LOWORD(x) dword ptr [x+0]
13#define CRT_HIWORD(x) dword ptr [x+4]
14
15 __declspec(naked) void _alldiv()
16 {
17 #define DVND esp + 16 // stack address of dividend (a)
18 #define DVSR esp + 24 // stack address of divisor (b)
19
20 __asm
21 {
22 push edi
23 push esi
24 push ebx
25
26; Determine sign of the result (edi = 0 if result is positive, non-zero
27; otherwise) and make operands positive.
28
29 xor edi,edi ; result sign assumed positive
30
31 mov eax,CRT_HIWORD(DVND) ; hi word of a
32 or eax,eax ; test to see if signed
33 jge short L1 ; skip rest if a is already positive
34 inc edi ; complement result sign flag
35 mov edx,CRT_LOWORD(DVND) ; lo word of a
36 neg eax ; make a positive
37 neg edx
38 sbb eax,0
39 mov CRT_HIWORD(DVND),eax ; save positive value
40 mov CRT_LOWORD(DVND),edx
41L1:
42 mov eax,CRT_HIWORD(DVSR) ; hi word of b
43 or eax,eax ; test to see if signed
44 jge short L2 ; skip rest if b is already positive
45 inc edi ; complement the result sign flag
46 mov edx,CRT_LOWORD(DVSR) ; lo word of a
47 neg eax ; make b positive
48 neg edx
49 sbb eax,0
50 mov CRT_HIWORD(DVSR),eax ; save positive value
51 mov CRT_LOWORD(DVSR),edx
52L2:
53
54;
55; Now do the divide. First look to see if the divisor is less than 4194304K.
56; If so, then we can use a simple algorithm with word divides, otherwise
57; things get a little more complex.
58;
59; NOTE - eax currently contains the high order word of DVSR
60;
61
62 or eax,eax ; check to see if divisor < 4194304K
63 jnz short L3 ; nope, gotta do this the hard way
64 mov ecx,CRT_LOWORD(DVSR) ; load divisor
65 mov eax,CRT_HIWORD(DVND) ; load high word of dividend
66 xor edx,edx
67 div ecx ; eax <- high order bits of quotient
68 mov ebx,eax ; save high bits of quotient
69 mov eax,CRT_LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend
70 div ecx ; eax <- low order bits of quotient
71 mov edx,ebx ; edx:eax <- quotient
72 jmp short L4 ; set sign, restore stack and return
73
74;
75; Here we do it the hard way. Remember, eax contains the high word of DVSR
76;
77
78L3:
79 mov ebx,eax ; ebx:ecx <- divisor
80 mov ecx,CRT_LOWORD(DVSR)
81 mov edx,CRT_HIWORD(DVND) ; edx:eax <- dividend
82 mov eax,CRT_LOWORD(DVND)
83L5:
84 shr ebx,1 ; shift divisor right one bit
85 rcr ecx,1
86 shr edx,1 ; shift dividend right one bit
87 rcr eax,1
88 or ebx,ebx
89 jnz short L5 ; loop until divisor < 4194304K
90 div ecx ; now divide, ignore remainder
91 mov esi,eax ; save quotient
92
93;
94; We may be off by one, so to check, we will multiply the quotient
95; by the divisor and check the result against the orignal dividend
96; Note that we must also check for overflow, which can occur if the
97; dividend is close to 2**64 and the quotient is off by 1.
98;
99
100 mul CRT_HIWORD(DVSR) ; QUOT * CRT_HIWORD(DVSR)
101 mov ecx,eax
102 mov eax,CRT_LOWORD(DVSR)
103 mul esi ; QUOT * CRT_LOWORD(DVSR)
104 add edx,ecx ; EDX:EAX = QUOT * DVSR
105 jc short L6 ; carry means Quotient is off by 1
106
107;
108; do long compare here between original dividend and the result of the
109; multiply in edx:eax. If original is larger or equal, we are ok, otherwise
110; subtract one (1) from the quotient.
111;
112
113 cmp edx,CRT_HIWORD(DVND) ; compare hi words of result and original
114 ja short L6 ; if result > original, do subtract
115 jb short L7 ; if result < original, we are ok
116 cmp eax,CRT_LOWORD(DVND) ; hi words are equal, compare lo words
117 jbe short L7 ; if less or equal we are ok, else subtract
118L6:
119 dec esi ; subtract 1 from quotient
120L7:
121 xor edx,edx ; edx:eax <- quotient
122 mov eax,esi
123
124;
125; Just the cleanup left to do. edx:eax contains the quotient. Set the sign
126; according to the save value, cleanup the stack, and return.
127;
128
129L4:
130 dec edi ; check to see if result is negative
131 jnz short L8 ; if EDI == 0, result should be negative
132 neg edx ; otherwise, negate the result
133 neg eax
134 sbb edx,0
135
136;
137; Restore the saved registers and return.
138;
139
140L8:
141 pop ebx
142 pop esi
143 pop edi
144
145 ret 16
146 }
147
148 #undef DVND
149 #undef DVSR
150 }
151
152 __declspec(naked) void _alldvrm()
153 {
154 #define DVND esp + 16 // stack address of dividend (a)
155 #define DVSR esp + 24 // stack address of divisor (b)
156
157 __asm
158 {
159 push edi
160 push esi
161 push ebp
162
163; Determine sign of the quotient (edi = 0 if result is positive, non-zero
164; otherwise) and make operands positive.
165; Sign of the remainder is kept in ebp.
166
167 xor edi,edi ; result sign assumed positive
168 xor ebp,ebp ; result sign assumed positive
169
170 mov eax,CRT_HIWORD(DVND) ; hi word of a
171 or eax,eax ; test to see if signed
172 jge short L1 ; skip rest if a is already positive
173 inc edi ; complement result sign flag
174 inc ebp ; complement result sign flag
175 mov edx,CRT_LOWORD(DVND) ; lo word of a
176 neg eax ; make a positive
177 neg edx
178 sbb eax,0
179 mov CRT_HIWORD(DVND),eax ; save positive value
180 mov CRT_LOWORD(DVND),edx
181L1:
182 mov eax,CRT_HIWORD(DVSR) ; hi word of b
183 or eax,eax ; test to see if signed
184 jge short L2 ; skip rest if b is already positive
185 inc edi ; complement the result sign flag
186 mov edx,CRT_LOWORD(DVSR) ; lo word of a
187 neg eax ; make b positive
188 neg edx
189 sbb eax,0
190 mov CRT_HIWORD(DVSR),eax ; save positive value
191 mov CRT_LOWORD(DVSR),edx
192L2:
193
194;
195; Now do the divide. First look to see if the divisor is less than 4194304K.
196; If so, then we can use a simple algorithm with word divides, otherwise
197; things get a little more complex.
198;
199; NOTE - eax currently contains the high order word of DVSR
200;
201
202 or eax,eax ; check to see if divisor < 4194304K
203 jnz short L3 ; nope, gotta do this the hard way
204 mov ecx,CRT_LOWORD(DVSR) ; load divisor
205 mov eax,CRT_HIWORD(DVND) ; load high word of dividend
206 xor edx,edx
207 div ecx ; eax <- high order bits of quotient
208 mov ebx,eax ; save high bits of quotient
209 mov eax,CRT_LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend
210 div ecx ; eax <- low order bits of quotient
211 mov esi,eax ; ebx:esi <- quotient
212;
213; Now we need to do a multiply so that we can compute the remainder.
214;
215 mov eax,ebx ; set up high word of quotient
216 mul CRT_LOWORD(DVSR) ; CRT_HIWORD(QUOT) * DVSR
217 mov ecx,eax ; save the result in ecx
218 mov eax,esi ; set up low word of quotient
219 mul CRT_LOWORD(DVSR) ; CRT_LOWORD(QUOT) * DVSR
220 add edx,ecx ; EDX:EAX = QUOT * DVSR
221 jmp short L4 ; complete remainder calculation
222
223;
224; Here we do it the hard way. Remember, eax contains the high word of DVSR
225;
226
227L3:
228 mov ebx,eax ; ebx:ecx <- divisor
229 mov ecx,CRT_LOWORD(DVSR)
230 mov edx,CRT_HIWORD(DVND) ; edx:eax <- dividend
231 mov eax,CRT_LOWORD(DVND)
232L5:
233 shr ebx,1 ; shift divisor right one bit
234 rcr ecx,1
235 shr edx,1 ; shift dividend right one bit
236 rcr eax,1
237 or ebx,ebx
238 jnz short L5 ; loop until divisor < 4194304K
239 div ecx ; now divide, ignore remainder
240 mov esi,eax ; save quotient
241
242;
243; We may be off by one, so to check, we will multiply the quotient
244; by the divisor and check the result against the orignal dividend
245; Note that we must also check for overflow, which can occur if the
246; dividend is close to 2**64 and the quotient is off by 1.
247;
248
249 mul CRT_HIWORD(DVSR) ; QUOT * CRT_HIWORD(DVSR)
250 mov ecx,eax
251 mov eax,CRT_LOWORD(DVSR)
252 mul esi ; QUOT * CRT_LOWORD(DVSR)
253 add edx,ecx ; EDX:EAX = QUOT * DVSR
254 jc short L6 ; carry means Quotient is off by 1
255
256;
257; do long compare here between original dividend and the result of the
258; multiply in edx:eax. If original is larger or equal, we are ok, otherwise
259; subtract one (1) from the quotient.
260;
261
262 cmp edx,CRT_HIWORD(DVND) ; compare hi words of result and original
263 ja short L6 ; if result > original, do subtract
264 jb short L7 ; if result < original, we are ok
265 cmp eax,CRT_LOWORD(DVND) ; hi words are equal, compare lo words
266 jbe short L7 ; if less or equal we are ok, else subtract
267L6:
268 dec esi ; subtract 1 from quotient
269 sub eax,CRT_LOWORD(DVSR) ; subtract divisor from result
270 sbb edx,CRT_HIWORD(DVSR)
271L7:
272 xor ebx,ebx ; ebx:esi <- quotient
273
274L4:
275;
276; Calculate remainder by subtracting the result from the original dividend.
277; Since the result is already in a register, we will do the subtract in the
278; opposite direction and negate the result if necessary.
279;
280
281 sub eax,CRT_LOWORD(DVND) ; subtract dividend from result
282 sbb edx,CRT_HIWORD(DVND)
283
284;
285; Now check the result sign flag to see if the result is supposed to be positive
286; or negative. It is currently negated (because we subtracted in the 'wrong'
287; direction), so if the sign flag is set we are done, otherwise we must negate
288; the result to make it positive again.
289;
290
291 dec ebp ; check result sign flag
292 jns short L9 ; result is ok, set up the quotient
293 neg edx ; otherwise, negate the result
294 neg eax
295 sbb edx,0
296
297;
298; Now we need to get the quotient into edx:eax and the remainder into ebx:ecx.
299;
300L9:
301 mov ecx,edx
302 mov edx,ebx
303 mov ebx,ecx
304 mov ecx,eax
305 mov eax,esi
306
307;
308; Just the cleanup left to do. edx:eax contains the quotient. Set the sign
309; according to the save value, cleanup the stack, and return.
310;
311
312 dec edi ; check to see if result is negative
313 jnz short L8 ; if EDI == 0, result should be negative
314 neg edx ; otherwise, negate the result
315 neg eax
316 sbb edx,0
317
318;
319; Restore the saved registers and return.
320;
321
322L8:
323 pop ebp
324 pop esi
325 pop edi
326
327 ret 16
328 }
329
330 #undef DVND
331 #undef DVSR
332 }
333
334 __declspec(naked) void _allmul()
335 {
336 #define A esp + 8 // stack address of a
337 #define B esp + 16 // stack address of b
338
339 __asm
340 {
341 push ebx
342
343 mov eax,CRT_HIWORD(A)
344 mov ecx,CRT_LOWORD(B)
345 mul ecx ;eax has AHI, ecx has BLO, so AHI * BLO
346 mov ebx,eax ;save result
347
348 mov eax,CRT_LOWORD(A)
349 mul CRT_HIWORD(B) ;ALO * BHI
350 add ebx,eax ;ebx = ((ALO * BHI) + (AHI * BLO))
351
352 mov eax,CRT_LOWORD(A) ;ecx = BLO
353 mul ecx ;so edx:eax = ALO*BLO
354 add edx,ebx ;now edx has all the LO*HI stuff
355
356 pop ebx
357
358 ret 16 ; callee restores the stack
359 }
360
361 #undef A
362 #undef B
363 }
364
365 __declspec(naked) void _allrem()
366 {
367 #define DVND esp + 12 // stack address of dividend (a)
368 #define DVSR esp + 20 // stack address of divisor (b)
369
370 __asm
371 {
372 push ebx
373 push edi
374
375
376; Determine sign of the result (edi = 0 if result is positive, non-zero
377; otherwise) and make operands positive.
378
379 xor edi,edi ; result sign assumed positive
380
381 mov eax,CRT_HIWORD(DVND) ; hi word of a
382 or eax,eax ; test to see if signed
383 jge short L1 ; skip rest if a is already positive
384 inc edi ; complement result sign flag bit
385 mov edx,CRT_LOWORD(DVND) ; lo word of a
386 neg eax ; make a positive
387 neg edx
388 sbb eax,0
389 mov CRT_HIWORD(DVND),eax ; save positive value
390 mov CRT_LOWORD(DVND),edx
391L1:
392 mov eax,CRT_HIWORD(DVSR) ; hi word of b
393 or eax,eax ; test to see if signed
394 jge short L2 ; skip rest if b is already positive
395 mov edx,CRT_LOWORD(DVSR) ; lo word of b
396 neg eax ; make b positive
397 neg edx
398 sbb eax,0
399 mov CRT_HIWORD(DVSR),eax ; save positive value
400 mov CRT_LOWORD(DVSR),edx
401L2:
402
403;
404; Now do the divide. First look to see if the divisor is less than 4194304K.
405; If so, then we can use a simple algorithm with word divides, otherwise
406; things get a little more complex.
407;
408; NOTE - eax currently contains the high order word of DVSR
409;
410
411 or eax,eax ; check to see if divisor < 4194304K
412 jnz short L3 ; nope, gotta do this the hard way
413 mov ecx,CRT_LOWORD(DVSR) ; load divisor
414 mov eax,CRT_HIWORD(DVND) ; load high word of dividend
415 xor edx,edx
416 div ecx ; edx <- remainder
417 mov eax,CRT_LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend
418 div ecx ; edx <- final remainder
419 mov eax,edx ; edx:eax <- remainder
420 xor edx,edx
421 dec edi ; check result sign flag
422 jns short L4 ; negate result, restore stack and return
423 jmp short L8 ; result sign ok, restore stack and return
424
425;
426; Here we do it the hard way. Remember, eax contains the high word of DVSR
427;
428
429L3:
430 mov ebx,eax ; ebx:ecx <- divisor
431 mov ecx,CRT_LOWORD(DVSR)
432 mov edx,CRT_HIWORD(DVND) ; edx:eax <- dividend
433 mov eax,CRT_LOWORD(DVND)
434L5:
435 shr ebx,1 ; shift divisor right one bit
436 rcr ecx,1
437 shr edx,1 ; shift dividend right one bit
438 rcr eax,1
439 or ebx,ebx
440 jnz short L5 ; loop until divisor < 4194304K
441 div ecx ; now divide, ignore remainder
442
443;
444; We may be off by one, so to check, we will multiply the quotient
445; by the divisor and check the result against the orignal dividend
446; Note that we must also check for overflow, which can occur if the
447; dividend is close to 2**64 and the quotient is off by 1.
448;
449
450 mov ecx,eax ; save a copy of quotient in ECX
451 mul CRT_HIWORD(DVSR)
452 xchg ecx,eax ; save product, get quotient in EAX
453 mul CRT_LOWORD(DVSR)
454 add edx,ecx ; EDX:EAX = QUOT * DVSR
455 jc short L6 ; carry means Quotient is off by 1
456
457;
458; do long compare here between original dividend and the result of the
459; multiply in edx:eax. If original is larger or equal, we are ok, otherwise
460; subtract the original divisor from the result.
461;
462
463 cmp edx,CRT_HIWORD(DVND) ; compare hi words of result and original
464 ja short L6 ; if result > original, do subtract
465 jb short L7 ; if result < original, we are ok
466 cmp eax,CRT_LOWORD(DVND) ; hi words are equal, compare lo words
467 jbe short L7 ; if less or equal we are ok, else subtract
468L6:
469 sub eax,CRT_LOWORD(DVSR) ; subtract divisor from result
470 sbb edx,CRT_HIWORD(DVSR)
471L7:
472
473;
474; Calculate remainder by subtracting the result from the original dividend.
475; Since the result is already in a register, we will do the subtract in the
476; opposite direction and negate the result if necessary.
477;
478
479 sub eax,CRT_LOWORD(DVND) ; subtract dividend from result
480 sbb edx,CRT_HIWORD(DVND)
481
482;
483; Now check the result sign flag to see if the result is supposed to be positive
484; or negative. It is currently negated (because we subtracted in the 'wrong'
485; direction), so if the sign flag is set we are done, otherwise we must negate
486; the result to make it positive again.
487;
488
489 dec edi ; check result sign flag
490 jns short L8 ; result is ok, restore stack and return
491L4:
492 neg edx ; otherwise, negate the result
493 neg eax
494 sbb edx,0
495
496;
497; Just the cleanup left to do. edx:eax contains the quotient.
498; Restore the saved registers and return.
499;
500
501L8:
502 pop edi
503 pop ebx
504
505 ret 16
506 }
507
508 #undef DVND
509 #undef DVSR
510 }
511
512 __declspec(naked) void _allshl()
513 {
514 __asm
515 {
516;
517; Handle shifts of 64 or more bits (all get 0)
518;
519 cmp cl, 64
520 jae short RETZERO
521
522;
523; Handle shifts of between 0 and 31 bits
524;
525 cmp cl, 32
526 jae short MORE32
527 shld edx,eax,cl
528 shl eax,cl
529 ret
530
531;
532; Handle shifts of between 32 and 63 bits
533;
534MORE32:
535 mov edx,eax
536 xor eax,eax
537 and cl,31
538 shl edx,cl
539 ret
540
541;
542; return 0 in edx:eax
543;
544RETZERO:
545 xor eax,eax
546 xor edx,edx
547 ret
548 }
549 }
550
551 __declspec(naked) void _allshr()
552 {
553 __asm
554 {
555;
556; Handle shifts of 64 bits or more (if shifting 64 bits or more, the result
557; depends only on the high order bit of edx).
558;
559 cmp cl,64
560 jae short RETSIGN
561
562;
563; Handle shifts of between 0 and 31 bits
564;
565 cmp cl, 32
566 jae short MORE32
567 shrd eax,edx,cl
568 sar edx,cl
569 ret
570
571;
572; Handle shifts of between 32 and 63 bits
573;
574MORE32:
575 mov eax,edx
576 sar edx,31
577 and cl,31
578 sar eax,cl
579 ret
580
581;
582; Return double precision 0 or -1, depending on the sign of edx
583;
584RETSIGN:
585 sar edx,31
586 mov eax,edx
587 ret
588 }
589 }
590
591 __declspec(naked) void _aulldiv()
592 {
593 #define DVND esp + 12 // stack address of dividend (a)
594 #define DVSR esp + 20 // stack address of divisor (b)
595
596 __asm
597 {
598 push ebx
599 push esi
600
601;
602; Now do the divide. First look to see if the divisor is less than 4194304K.
603; If so, then we can use a simple algorithm with word divides, otherwise
604; things get a little more complex.
605;
606
607 mov eax,CRT_HIWORD(DVSR) ; check to see if divisor < 4194304K
608 or eax,eax
609 jnz short L1 ; nope, gotta do this the hard way
610 mov ecx,CRT_LOWORD(DVSR) ; load divisor
611 mov eax,CRT_HIWORD(DVND) ; load high word of dividend
612 xor edx,edx
613 div ecx ; get high order bits of quotient
614 mov ebx,eax ; save high bits of quotient
615 mov eax,CRT_LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend
616 div ecx ; get low order bits of quotient
617 mov edx,ebx ; edx:eax <- quotient hi:quotient lo
618 jmp short L2 ; restore stack and return
619
620;
621; Here we do it the hard way. Remember, eax contains DVSRHI
622;
623
624L1:
625 mov ecx,eax ; ecx:ebx <- divisor
626 mov ebx,CRT_LOWORD(DVSR)
627 mov edx,CRT_HIWORD(DVND) ; edx:eax <- dividend
628 mov eax,CRT_LOWORD(DVND)
629L3:
630 shr ecx,1 ; shift divisor right one bit; hi bit <- 0
631 rcr ebx,1
632 shr edx,1 ; shift dividend right one bit; hi bit <- 0
633 rcr eax,1
634 or ecx,ecx
635 jnz short L3 ; loop until divisor < 4194304K
636 div ebx ; now divide, ignore remainder
637 mov esi,eax ; save quotient
638
639;
640; We may be off by one, so to check, we will multiply the quotient
641; by the divisor and check the result against the orignal dividend
642; Note that we must also check for overflow, which can occur if the
643; dividend is close to 2**64 and the quotient is off by 1.
644;
645
646 mul CRT_HIWORD(DVSR) ; QUOT * CRT_HIWORD(DVSR)
647 mov ecx,eax
648 mov eax,CRT_LOWORD(DVSR)
649 mul esi ; QUOT * CRT_LOWORD(DVSR)
650 add edx,ecx ; EDX:EAX = QUOT * DVSR
651 jc short L4 ; carry means Quotient is off by 1
652
653;
654; do long compare here between original dividend and the result of the
655; multiply in edx:eax. If original is larger or equal, we are ok, otherwise
656; subtract one (1) from the quotient.
657;
658
659 cmp edx,CRT_HIWORD(DVND) ; compare hi words of result and original
660 ja short L4 ; if result > original, do subtract
661 jb short L5 ; if result < original, we are ok
662 cmp eax,CRT_LOWORD(DVND) ; hi words are equal, compare lo words
663 jbe short L5 ; if less or equal we are ok, else subtract
664L4:
665 dec esi ; subtract 1 from quotient
666L5:
667 xor edx,edx ; edx:eax <- quotient
668 mov eax,esi
669
670;
671; Just the cleanup left to do. edx:eax contains the quotient.
672; Restore the saved registers and return.
673;
674
675L2:
676
677 pop esi
678 pop ebx
679
680 ret 16
681 }
682
683 #undef DVND
684 #undef DVSR
685 }
686
687 __declspec(naked) void _aulldvrm()
688 {
689 #define DVND esp + 8 // stack address of dividend (a)
690 #define DVSR esp + 16 // stack address of divisor (b)
691
692 __asm
693 {
694 push esi
695
696;
697; Now do the divide. First look to see if the divisor is less than 4194304K.
698; If so, then we can use a simple algorithm with word divides, otherwise
699; things get a little more complex.
700;
701
702 mov eax,CRT_HIWORD(DVSR) ; check to see if divisor < 4194304K
703 or eax,eax
704 jnz short L1 ; nope, gotta do this the hard way
705 mov ecx,CRT_LOWORD(DVSR) ; load divisor
706 mov eax,CRT_HIWORD(DVND) ; load high word of dividend
707 xor edx,edx
708 div ecx ; get high order bits of quotient
709 mov ebx,eax ; save high bits of quotient
710 mov eax,CRT_LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend
711 div ecx ; get low order bits of quotient
712 mov esi,eax ; ebx:esi <- quotient
713
714;
715; Now we need to do a multiply so that we can compute the remainder.
716;
717 mov eax,ebx ; set up high word of quotient
718 mul CRT_LOWORD(DVSR) ; CRT_HIWORD(QUOT) * DVSR
719 mov ecx,eax ; save the result in ecx
720 mov eax,esi ; set up low word of quotient
721 mul CRT_LOWORD(DVSR) ; CRT_LOWORD(QUOT) * DVSR
722 add edx,ecx ; EDX:EAX = QUOT * DVSR
723 jmp short L2 ; complete remainder calculation
724
725;
726; Here we do it the hard way. Remember, eax contains DVSRHI
727;
728
729L1:
730 mov ecx,eax ; ecx:ebx <- divisor
731 mov ebx,CRT_LOWORD(DVSR)
732 mov edx,CRT_HIWORD(DVND) ; edx:eax <- dividend
733 mov eax,CRT_LOWORD(DVND)
734L3:
735 shr ecx,1 ; shift divisor right one bit; hi bit <- 0
736 rcr ebx,1
737 shr edx,1 ; shift dividend right one bit; hi bit <- 0
738 rcr eax,1
739 or ecx,ecx
740 jnz short L3 ; loop until divisor < 4194304K
741 div ebx ; now divide, ignore remainder
742 mov esi,eax ; save quotient
743
744;
745; We may be off by one, so to check, we will multiply the quotient
746; by the divisor and check the result against the orignal dividend
747; Note that we must also check for overflow, which can occur if the
748; dividend is close to 2**64 and the quotient is off by 1.
749;
750
751 mul CRT_HIWORD(DVSR) ; QUOT * CRT_HIWORD(DVSR)
752 mov ecx,eax
753 mov eax,CRT_LOWORD(DVSR)
754 mul esi ; QUOT * CRT_LOWORD(DVSR)
755 add edx,ecx ; EDX:EAX = QUOT * DVSR
756 jc short L4 ; carry means Quotient is off by 1
757
758;
759; do long compare here between original dividend and the result of the
760; multiply in edx:eax. If original is larger or equal, we are ok, otherwise
761; subtract one (1) from the quotient.
762;
763
764 cmp edx,CRT_HIWORD(DVND) ; compare hi words of result and original
765 ja short L4 ; if result > original, do subtract
766 jb short L5 ; if result < original, we are ok
767 cmp eax,CRT_LOWORD(DVND) ; hi words are equal, compare lo words
768 jbe short L5 ; if less or equal we are ok, else subtract
769L4:
770 dec esi ; subtract 1 from quotient
771 sub eax,CRT_LOWORD(DVSR) ; subtract divisor from result
772 sbb edx,CRT_HIWORD(DVSR)
773L5:
774 xor ebx,ebx ; ebx:esi <- quotient
775
776L2:
777;
778; Calculate remainder by subtracting the result from the original dividend.
779; Since the result is already in a register, we will do the subtract in the
780; opposite direction and negate the result.
781;
782
783 sub eax,CRT_LOWORD(DVND) ; subtract dividend from result
784 sbb edx,CRT_HIWORD(DVND)
785 neg edx ; otherwise, negate the result
786 neg eax
787 sbb edx,0
788
789;
790; Now we need to get the quotient into edx:eax and the remainder into ebx:ecx.
791;
792 mov ecx,edx
793 mov edx,ebx
794 mov ebx,ecx
795 mov ecx,eax
796 mov eax,esi
797;
798; Just the cleanup left to do. edx:eax contains the quotient.
799; Restore the saved registers and return.
800;
801
802 pop esi
803
804 ret 16
805 }
806
807 #undef DVND
808 #undef DVSR
809 }
810
811 __declspec(naked) void _aullrem()
812 {
813 #define DVND esp + 8 // stack address of dividend (a)
814 #define DVSR esp + 16 // stack address of divisor (b)
815
816 __asm
817 {
818 push ebx
819
820; Now do the divide. First look to see if the divisor is less than 4194304K.
821; If so, then we can use a simple algorithm with word divides, otherwise
822; things get a little more complex.
823;
824
825 mov eax,CRT_HIWORD(DVSR) ; check to see if divisor < 4194304K
826 or eax,eax
827 jnz short L1 ; nope, gotta do this the hard way
828 mov ecx,CRT_LOWORD(DVSR) ; load divisor
829 mov eax,CRT_HIWORD(DVND) ; load high word of dividend
830 xor edx,edx
831 div ecx ; edx <- remainder, eax <- quotient
832 mov eax,CRT_LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend
833 div ecx ; edx <- final remainder
834 mov eax,edx ; edx:eax <- remainder
835 xor edx,edx
836 jmp short L2 ; restore stack and return
837
838;
839; Here we do it the hard way. Remember, eax contains DVSRHI
840;
841
842L1:
843 mov ecx,eax ; ecx:ebx <- divisor
844 mov ebx,CRT_LOWORD(DVSR)
845 mov edx,CRT_HIWORD(DVND) ; edx:eax <- dividend
846 mov eax,CRT_LOWORD(DVND)
847L3:
848 shr ecx,1 ; shift divisor right one bit; hi bit <- 0
849 rcr ebx,1
850 shr edx,1 ; shift dividend right one bit; hi bit <- 0
851 rcr eax,1
852 or ecx,ecx
853 jnz short L3 ; loop until divisor < 4194304K
854 div ebx ; now divide, ignore remainder
855
856;
857; We may be off by one, so to check, we will multiply the quotient
858; by the divisor and check the result against the orignal dividend
859; Note that we must also check for overflow, which can occur if the
860; dividend is close to 2**64 and the quotient is off by 1.
861;
862
863 mov ecx,eax ; save a copy of quotient in ECX
864 mul CRT_HIWORD(DVSR)
865 xchg ecx,eax ; put partial product in ECX, get quotient in EAX
866 mul CRT_LOWORD(DVSR)
867 add edx,ecx ; EDX:EAX = QUOT * DVSR
868 jc short L4 ; carry means Quotient is off by 1
869
870;
871; do long compare here between original dividend and the result of the
872; multiply in edx:eax. If original is larger or equal, we're ok, otherwise
873; subtract the original divisor from the result.
874;
875
876 cmp edx,CRT_HIWORD(DVND) ; compare hi words of result and original
877 ja short L4 ; if result > original, do subtract
878 jb short L5 ; if result < original, we're ok
879 cmp eax,CRT_LOWORD(DVND) ; hi words are equal, compare lo words
880 jbe short L5 ; if less or equal we're ok, else subtract
881L4:
882 sub eax,CRT_LOWORD(DVSR) ; subtract divisor from result
883 sbb edx,CRT_HIWORD(DVSR)
884L5:
885
886;
887; Calculate remainder by subtracting the result from the original dividend.
888; Since the result is already in a register, we will perform the subtract in
889; the opposite direction and negate the result to make it positive.
890;
891
892 sub eax,CRT_LOWORD(DVND) ; subtract original dividend from result
893 sbb edx,CRT_HIWORD(DVND)
894 neg edx ; and negate it
895 neg eax
896 sbb edx,0
897
898;
899; Just the cleanup left to do. dx:ax contains the remainder.
900; Restore the saved registers and return.
901;
902
903L2:
904
905 pop ebx
906
907 ret 16
908 }
909
910 #undef DVND
911 #undef DVSR
912 }
913
914 __declspec(naked) void _aullshr()
915 {
916 __asm
917 {
918 cmp cl,64
919 jae short RETZERO
920
921;
922; Handle shifts of between 0 and 31 bits
923;
924 cmp cl, 32
925 jae short MORE32
926 shrd eax,edx,cl
927 shr edx,cl
928 ret
929
930;
931; Handle shifts of between 32 and 63 bits
932;
933MORE32:
934 mov eax,edx
935 xor edx,edx
936 and cl,31
937 shr eax,cl
938 ret
939
940;
941; return 0 in edx:eax
942;
943RETZERO:
944 xor eax,eax
945 xor edx,edx
946 ret
947 }
948 }
949
950#undef CRT_LOWORD
951#undef CRT_HIWORD
952
953#endif
UINT8 value
APPLE_EVENT_HANDLE Handle
Definition OcTypingLib.h:45