123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- TITLE imul.asm
- ;; imulnt.asm Copyright (C) Codemist Ltd, 1993-2002
- ;;
- ;; This code implements Imultiply and Idivide in 80386 (and up) assembly
- ;; code. In fact two versions of the functions are provided, one for
- ;; the usual "__cdecl" calling conventions (all args passed on the stack)
- ;; and one for the Microsoft so-called "fastcall" where two args are passed
- ;; in registers. Name conventions permit the two versions to co-exist.
- ;;
- .386P
- if @Version gt 510
- .model FLAT
- else
- _TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
- _TEXT ENDS
- _DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
- _DATA ENDS
- CONST SEGMENT DWORD USE32 PUBLIC 'CONST'
- CONST ENDS
- _BSS SEGMENT DWORD USE32 PUBLIC 'BSS'
- _BSS ENDS
- _TLS SEGMENT DWORD USE32 PUBLIC 'TLS'
- _TLS ENDS
- FLAT GROUP _DATA, CONST, _BSS
- ASSUME CS: FLAT, DS: FLAT, SS: FLAT
- endif
- ;
- ; unsigned32 Imultiply(unsigned32 *rlow,
- ; unsigned32 a, unsigned32 b, unsigned32 c)
- ; {
- ; /* uns64 is a 64-bit integral type here */
- ; uns64 r = (uns64)a*(uns64)b + (uns64)c;
- ; *rlow = (unsigned32)(r & 0x7fffffff);
- ; return (unsigned32)(r >> 31);
- ; }
- ;
- PUBLIC _Imultiply
- _TEXT SEGMENT
- _rlow$ = 8
- _a$ = 12
- _b$ = 16
- _c$ = 20
- _Imultiply PROC NEAR
- mov eax, DWORD PTR _b$[esp-4]
- mul DWORD PTR _a$[esp-4]
- mov ecx, DWORD PTR _rlow$[esp-4]
- add eax, DWORD PTR _c$[esp-4]
- adc edx, 0 ; carry into top half
- add eax, eax
- adc edx, edx
- shr eax, 1
- mov DWORD PTR [ecx], eax
- mov eax, edx
- ret 0
- nop
- nop
- _Imultiply ENDP
- _TEXT ENDS
- ; unsigned32 Idiv10_9(unsigned32 *qp, unsigned32 high, unsigned32 low)
- ; {
- ; uns64 p = ((uns64)high << 31) | (uns64)low;
- ; *qp = (unsigned32)(p / (uns64)1000000000U);
- ; return (unsigned32)(p % (uns64)1000000000U);
- ; }
- ;
- PUBLIC _Idiv10_9
- _TEXT SEGMENT
- _qp$ = 8
- _high$ = 12
- _low$ = 16
- _Idiv10_9 PROC NEAR
- mov edx, DWORD PTR _high$[esp-4]
- mov eax, DWORD PTR _low$[esp-4]
- shl eax, 1
- shr edx, 1
- rcr eax, 1 ; That glued together 31+31 bits
- mov ecx, 1000000000
- div ecx
- mov ecx, DWORD PTR _qp$[esp-4]
- mov DWORD PTR [ecx], eax
- mov eax, edx
- ret 0
- nop
- nop
- _Idiv10_9 ENDP
- _TEXT ENDS
- ; unsigned32 Idivide(unsigned32 *qp, unsigned32 a, unsigned32 b, unsigned32 c)
- ; {
- ; uns64 p = ((uns64)a << 31) | (uns64)b;
- ; *qp = (unsigned32)(p / (uns64)c);
- ; return (unsigned32)(p % (uns64)c);
- ; }
- ;
- PUBLIC _Idivide
- _TEXT SEGMENT
- _qp$ = 8
- _a$ = 12
- _b$ = 16
- _c$ = 20
- _Idivide PROC NEAR
- mov edx, DWORD PTR _high$[esp-4]
- mov eax, DWORD PTR _low$[esp-4]
- shl eax, 1
- shr edx, 1
- rcr eax, 1 ; That glued together 31+31 bits
- mov ecx, DWORD PTR _c$[esp-4]
- div ecx
- mov ecx, DWORD PTR _qp$[esp-4]
- mov DWORD PTR [ecx], eax
- mov eax, edx
- ret 0
- nop
- nop
- nop
- _Idivide ENDP
- ;;
- ;; Now for the versions that take args in registers.
- ;;
- _TEXT ENDS
- ;
- ; unsigned32 Imultiply(unsigned32 *rlow,
- ; unsigned32 a, unsigned32 b, unsigned32 c)
- ; {
- ; /* uns64 is a 64-bit integral type here */
- ; uns64 r = (uns64)a*(uns64)b + (uns64)c;
- ; *rlow = (unsigned32)(r & 0x7fffffff);
- ; return (unsigned32)(r >> 31);
- ; }
- ;
- PUBLIC @Imultiply@16
- _TEXT SEGMENT
- @Imultiply@16 PROC NEAR
- mov eax, DWORD PTR 4[esp]
- mul edx
- add eax, DWORD PTR 8[esp]
- adc edx, 0 ; carry into top half
- add eax, eax
- adc edx, edx
- shr eax, 1
- mov DWORD PTR [ecx], eax
- mov eax, edx
- ret 8
- nop
- nop
- nop
- nop
- nop
- nop
- @Imultiply@16 ENDP
- _TEXT ENDS
- ; unsigned32 Idiv10_9(unsigned32 *qp, unsigned32 high, unsigned32 low)
- ; {
- ; uns64 p = ((uns64)high << 31) | (uns64)low;
- ; *qp = (unsigned32)(p / (uns64)1000000000U);
- ; return (unsigned32)(p % (uns64)1000000000U);
- ; }
- ;
- PUBLIC @Idiv10_9@12
- _TEXT SEGMENT
- @Idiv10_9@12 PROC NEAR
- mov eax, DWORD PTR 4 [esp]
- shl eax, 1
- shr edx, 1
- rcr eax, 1 ; That glued together 31+31 bits
- push 1000000000
- div DWORD PTR [esp]
- mov DWORD PTR [ecx], eax
- pop eax
- mov eax, edx
- ret 4
- nop
- nop
- nop
- nop
- nop
- nop
- @Idiv10_9@12 ENDP
- _TEXT ENDS
- ; unsigned32 Idivide(unsigned32 *qp, unsigned32 a, unsigned32 b, unsigned32 c)
- ; {
- ; uns64 p = ((uns64)a << 31) | (uns64)b;
- ; *qp = (unsigned32)(p / (uns64)c);
- ; return (unsigned32)(p % (uns64)c);
- ; }
- ;
- PUBLIC @Idivide@16
- _TEXT SEGMENT
- @Idivide@16 PROC NEAR
- mov eax, DWORD PTR 4 [esp]
- shl eax, 1
- shr edx, 1
- rcr eax, 1 ; That glued together 31+31 bits
- div DWORD PTR 8[esp]
- mov DWORD PTR [ecx], eax
- mov eax, edx
- ret 8
- nop
- nop
- nop
- @Idivide@16 ENDP
- _TEXT ENDS
- END
|