imulnt.asm 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. TITLE imul.asm
  2. ;; imulnt.asm Copyright (C) Codemist Ltd, 1993-2002
  3. ;;
  4. ;; This code implements Imultiply and Idivide in 80386 (and up) assembly
  5. ;; code. In fact two versions of the functions are provided, one for
  6. ;; the usual "__cdecl" calling conventions (all args passed on the stack)
  7. ;; and one for the Microsoft so-called "fastcall" where two args are passed
  8. ;; in registers. Name conventions permit the two versions to co-exist.
  9. ;;
  10. .386P
  11. if @Version gt 510
  12. .model FLAT
  13. else
  14. _TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
  15. _TEXT ENDS
  16. _DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
  17. _DATA ENDS
  18. CONST SEGMENT DWORD USE32 PUBLIC 'CONST'
  19. CONST ENDS
  20. _BSS SEGMENT DWORD USE32 PUBLIC 'BSS'
  21. _BSS ENDS
  22. _TLS SEGMENT DWORD USE32 PUBLIC 'TLS'
  23. _TLS ENDS
  24. FLAT GROUP _DATA, CONST, _BSS
  25. ASSUME CS: FLAT, DS: FLAT, SS: FLAT
  26. endif
  27. ;
  28. ; unsigned32 Imultiply(unsigned32 *rlow,
  29. ; unsigned32 a, unsigned32 b, unsigned32 c)
  30. ; {
  31. ; /* uns64 is a 64-bit integral type here */
  32. ; uns64 r = (uns64)a*(uns64)b + (uns64)c;
  33. ; *rlow = (unsigned32)(r & 0x7fffffff);
  34. ; return (unsigned32)(r >> 31);
  35. ; }
  36. ;
  37. PUBLIC _Imultiply
  38. _TEXT SEGMENT
  39. _rlow$ = 8
  40. _a$ = 12
  41. _b$ = 16
  42. _c$ = 20
  43. _Imultiply PROC NEAR
  44. mov eax, DWORD PTR _b$[esp-4]
  45. mul DWORD PTR _a$[esp-4]
  46. mov ecx, DWORD PTR _rlow$[esp-4]
  47. add eax, DWORD PTR _c$[esp-4]
  48. adc edx, 0 ; carry into top half
  49. add eax, eax
  50. adc edx, edx
  51. shr eax, 1
  52. mov DWORD PTR [ecx], eax
  53. mov eax, edx
  54. ret 0
  55. nop
  56. nop
  57. _Imultiply ENDP
  58. _TEXT ENDS
  59. ; unsigned32 Idiv10_9(unsigned32 *qp, unsigned32 high, unsigned32 low)
  60. ; {
  61. ; uns64 p = ((uns64)high << 31) | (uns64)low;
  62. ; *qp = (unsigned32)(p / (uns64)1000000000U);
  63. ; return (unsigned32)(p % (uns64)1000000000U);
  64. ; }
  65. ;
  66. PUBLIC _Idiv10_9
  67. _TEXT SEGMENT
  68. _qp$ = 8
  69. _high$ = 12
  70. _low$ = 16
  71. _Idiv10_9 PROC NEAR
  72. mov edx, DWORD PTR _high$[esp-4]
  73. mov eax, DWORD PTR _low$[esp-4]
  74. shl eax, 1
  75. shr edx, 1
  76. rcr eax, 1 ; That glued together 31+31 bits
  77. mov ecx, 1000000000
  78. div ecx
  79. mov ecx, DWORD PTR _qp$[esp-4]
  80. mov DWORD PTR [ecx], eax
  81. mov eax, edx
  82. ret 0
  83. nop
  84. nop
  85. _Idiv10_9 ENDP
  86. _TEXT ENDS
  87. ; unsigned32 Idivide(unsigned32 *qp, unsigned32 a, unsigned32 b, unsigned32 c)
  88. ; {
  89. ; uns64 p = ((uns64)a << 31) | (uns64)b;
  90. ; *qp = (unsigned32)(p / (uns64)c);
  91. ; return (unsigned32)(p % (uns64)c);
  92. ; }
  93. ;
  94. PUBLIC _Idivide
  95. _TEXT SEGMENT
  96. _qp$ = 8
  97. _a$ = 12
  98. _b$ = 16
  99. _c$ = 20
  100. _Idivide PROC NEAR
  101. mov edx, DWORD PTR _high$[esp-4]
  102. mov eax, DWORD PTR _low$[esp-4]
  103. shl eax, 1
  104. shr edx, 1
  105. rcr eax, 1 ; That glued together 31+31 bits
  106. mov ecx, DWORD PTR _c$[esp-4]
  107. div ecx
  108. mov ecx, DWORD PTR _qp$[esp-4]
  109. mov DWORD PTR [ecx], eax
  110. mov eax, edx
  111. ret 0
  112. nop
  113. nop
  114. nop
  115. _Idivide ENDP
  116. ;;
  117. ;; Now for the versions that take args in registers.
  118. ;;
  119. _TEXT ENDS
  120. ;
  121. ; unsigned32 Imultiply(unsigned32 *rlow,
  122. ; unsigned32 a, unsigned32 b, unsigned32 c)
  123. ; {
  124. ; /* uns64 is a 64-bit integral type here */
  125. ; uns64 r = (uns64)a*(uns64)b + (uns64)c;
  126. ; *rlow = (unsigned32)(r & 0x7fffffff);
  127. ; return (unsigned32)(r >> 31);
  128. ; }
  129. ;
  130. PUBLIC @Imultiply@16
  131. _TEXT SEGMENT
  132. @Imultiply@16 PROC NEAR
  133. mov eax, DWORD PTR 4[esp]
  134. mul edx
  135. add eax, DWORD PTR 8[esp]
  136. adc edx, 0 ; carry into top half
  137. add eax, eax
  138. adc edx, edx
  139. shr eax, 1
  140. mov DWORD PTR [ecx], eax
  141. mov eax, edx
  142. ret 8
  143. nop
  144. nop
  145. nop
  146. nop
  147. nop
  148. nop
  149. @Imultiply@16 ENDP
  150. _TEXT ENDS
  151. ; unsigned32 Idiv10_9(unsigned32 *qp, unsigned32 high, unsigned32 low)
  152. ; {
  153. ; uns64 p = ((uns64)high << 31) | (uns64)low;
  154. ; *qp = (unsigned32)(p / (uns64)1000000000U);
  155. ; return (unsigned32)(p % (uns64)1000000000U);
  156. ; }
  157. ;
  158. PUBLIC @Idiv10_9@12
  159. _TEXT SEGMENT
  160. @Idiv10_9@12 PROC NEAR
  161. mov eax, DWORD PTR 4 [esp]
  162. shl eax, 1
  163. shr edx, 1
  164. rcr eax, 1 ; That glued together 31+31 bits
  165. push 1000000000
  166. div DWORD PTR [esp]
  167. mov DWORD PTR [ecx], eax
  168. pop eax
  169. mov eax, edx
  170. ret 4
  171. nop
  172. nop
  173. nop
  174. nop
  175. nop
  176. nop
  177. @Idiv10_9@12 ENDP
  178. _TEXT ENDS
  179. ; unsigned32 Idivide(unsigned32 *qp, unsigned32 a, unsigned32 b, unsigned32 c)
  180. ; {
  181. ; uns64 p = ((uns64)a << 31) | (uns64)b;
  182. ; *qp = (unsigned32)(p / (uns64)c);
  183. ; return (unsigned32)(p % (uns64)c);
  184. ; }
  185. ;
  186. PUBLIC @Idivide@16
  187. _TEXT SEGMENT
  188. @Idivide@16 PROC NEAR
  189. mov eax, DWORD PTR 4 [esp]
  190. shl eax, 1
  191. shr edx, 1
  192. rcr eax, 1 ; That glued together 31+31 bits
  193. div DWORD PTR 8[esp]
  194. mov DWORD PTR [ecx], eax
  195. mov eax, edx
  196. ret 8
  197. nop
  198. nop
  199. nop
  200. @Idivide@16 ENDP
  201. _TEXT ENDS
  202. END