Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

252 lines
5.9 KiB

  1. page ,132
  2. subttl emfdiv.asm - Division
  3. ;***
  4. ;emfdiv.asm - Division
  5. ;
  6. ; Copyright (c) 1986-89, Microsoft Corporation
  7. ;
  8. ;Purpose:
  9. ; Division
  10. ;
  11. ; This Module contains Proprietary Information of Microsoft
  12. ; Corporation and should be treated as Confidential.
  13. ;
  14. ;Revision History:
  15. ; See emulator.hst
  16. ;
  17. ;*******************************************************************************
  18. ;-----------------------------------------;
  19. ; ;
  20. ; Division ;
  21. ; ;
  22. ;-----------------------------------------;
  23. ProfBegin FDIV
  24. RDBRQQ: ; Routine Div Both must see if we have two singles.
  25. if fastSP
  26. MOV BX,DX
  27. XOR BX,Single + 256*Single
  28. TEST BX,Single + 256*Single
  29. JNZ RDDRQQ
  30. MOV bx,offset TDSRQQ
  31. JMP [bx]
  32. endif ;fastSP
  33. pub RDDRQQ ; Routine Division Double
  34. ; Now we have
  35. ; SI --> numerator , AX - Expon , DL - Sign
  36. ; DI --> denominator , CX - Expon , DH - Sign
  37. if fastSP
  38. CALL CoerceToDouble ; insure that both args are double
  39. endif ;fastSP
  40. STC ; exponent will be difference - 1
  41. SBB AX,CX ; compute result exponent
  42. ; AH has the (tentative) true exponent of the result. It is correct if the
  43. ; result does not need normalizing. If normalizing is required, then this
  44. ; must be incremented to give the correct result exponent
  45. XOR DH,DL ; Compute sign
  46. PUSH ebp
  47. PUSH edx ; Save sign
  48. PUSH esi
  49. PUSH edi
  50. ADD esi,6
  51. ADD edi,6
  52. MOV ecx,4
  53. STD
  54. REP CMPS word ptr [esi],word ptr [edi] ; compare numerator mantissa
  55. CLD ; with denominator mantissa
  56. POP edi
  57. POP esi
  58. PUSHF ; save the flags from the compare
  59. MOV BP,AX ; save the exponent
  60. LODS word ptr [esi] ; Load up numerator
  61. MOV CX,AX
  62. LODS word ptr [esi]
  63. MOV BX,AX
  64. LODS word ptr [esi]
  65. MOV DX,AX
  66. LODS word ptr [esi]
  67. XCHG AX,DX
  68. ; Move divisor to DAC so we can get at it easily.
  69. MOV esi,edi ; Move divisor to DAC
  70. MOV edi,offset DAC
  71. ifdef i386
  72. MOVSD
  73. MOVSD
  74. else
  75. MOVSW
  76. MOVSW
  77. MOVSW
  78. MOVSW
  79. endif
  80. ; Now we're all set:
  81. ; DX:AX:BX:CX has dividend
  82. ; DAC has divisor (in normal format)
  83. ; Both are 64 bits with zeros and have implied bit set.
  84. ; Top of stack has sign and tentative exponent.
  85. XOR DI,DI
  86. POPF ; numerator mantissa < denominator?
  87. ; 80286 errata for POPF shouldn't
  88. ; apply because interrupts should be
  89. ; turned on in this context
  90. JB short DivNoShift ; if so bypass numerator shift
  91. SHR DX,1 ; Make sure dividend is smaller than divisor
  92. RCR AX,1 ; by dividing it by two
  93. RCR BX,1
  94. RCR CX,1
  95. RCR DI,1
  96. INC BP ; increment result exponent
  97. pub DivNoShift
  98. PUSH ebp ; save result exponent
  99. MOV [REMLSW],DI ; Save lsb of remainder
  100. CALL DIV16 ; Get a quotient digit
  101. PUSH edi
  102. MOV [REMLSW],0 ; Turn off the shifted bit
  103. CALL DIV16
  104. PUSH edi
  105. CALL DIV16
  106. PUSH edi
  107. CALL DIV16
  108. MOV BP,8001H ; turn round and sticky on
  109. SHL CX,1
  110. RCL BX,1
  111. RCL AX,1
  112. RCL DX,1 ; multiply remainder by 2
  113. JC short BPset ; if overflow, then round,sticky valid
  114. MOV esi,offset DAC
  115. CMP DX,[esi+6]
  116. JNE short RemainderNotHalf
  117. CMP AX,[esi+4]
  118. JNE short RemainderNotHalf
  119. CMP BX,[esi+2]
  120. JNE short RemainderNotHalf
  121. CMP CX,[esi] ; compare 2*remainder with denominator
  122. ;Observe, oh wondering one, how you can assume the result of this last
  123. ;compare is not equality. Use the following notation: n=numerator,
  124. ;d=denominator,q=quotient,r=remainder,b=base(2^64 here). If
  125. ;initially we had n < d then there was no shift and we will find q and r
  126. ;so that q*d+r=n*b, if initially we had n >= d then there was a shift and
  127. ;we will find q and r so that q*d+r=n*b/2. If we have equality here
  128. ;then r=d/2 ==> n={possibly 2*}(2*q+1)*d/(2*b), since this can only
  129. ;be integral if d is a multiple of b, but by definition b/2 <= d < b, we
  130. ;have a contradiction. Equality is thus impossible at this point.
  131. pub RemainderNotHalf ; if 2*remainder > denominator
  132. JAE short BPset ; then round and sticky are valid
  133. OR AX,DX
  134. OR AX,CX
  135. OR AX,BX
  136. OR AL,AH ; otherwise or sticky bits into AL
  137. XOR AH,AH ; clear round bit
  138. MOV BP,AX ; move round and sticky into BP
  139. pub BPset
  140. MOV DX,DI ; get low 16 bits into proper location
  141. POP ecx
  142. POP ebx
  143. POP edi
  144. POP esi ; Now restore exponent
  145. JMP ROUND ; Result is normalized, round it
  146. ; Remainder in DX:AX:BX:CX:REMLSW
  147. pub DIV16
  148. MOV SI,[DAC+6] ; Get high word of divisor
  149. XOR DI,DI ; Initialize quotient digit to zero
  150. CMP DX,SI ; Will we overflow?
  151. JAE MAXQUO ; If so, go handle special
  152. OR DX,DX ; Is dividend small?
  153. JNZ short DDIV
  154. CMP SI,AX ; Will divisor fit at all?
  155. JA short ZERQUO ; No - quotient is zero
  156. pub DDIV
  157. DIV SI ; AX is our digit "guess"
  158. PUSH edx ; Save remainder -
  159. PUSH ebx ; top 32 bits
  160. XCHG AX,DI ; Quotient digit in DI
  161. XOR BP,BP ; Initialize quotient * divisor
  162. MOV SI,BP
  163. MOV AX,[DAC]
  164. OR AX,AX ; If zero, save multiply time
  165. JZ short REM2
  166. MUL DI ; Begin computing quotient * divisor
  167. MOV SI,DX
  168. pub REM2
  169. PUSH eax ; Save lowest word of quotient * divisor
  170. MOV AX,[DAC+2]
  171. OR AX,AX
  172. JZ short REM3
  173. MUL DI
  174. ADD SI,AX
  175. ADC BP,DX
  176. pub REM3
  177. MOV AX,[DAC+4]
  178. OR AX,AX
  179. JZ short REM4
  180. MUL DI
  181. ADD BP,AX
  182. ADC DX,0
  183. XCHG AX,DX
  184. ; Remainder - Quotient * divisor
  185. ; [SP+4]:[SP+2]:CX:REMLSW - AX:BP:SI:[SP]
  186. pub REM4
  187. MOV DX,[REMLSW] ; Low word of remainder
  188. POP ebx ; Recover lowest word of quotient * divisor
  189. SUB DX,BX
  190. SBB CX,SI
  191. POP ebx
  192. SBB BX,BP
  193. POP ebp ; Remainder from DIV
  194. SBB BP,AX
  195. XCHG AX,BP
  196. pub ZERQUO ; Remainder in AX:BX:CX:DX
  197. XCHG AX,DX
  198. XCHG AX,CX
  199. XCHG AX,BX
  200. JNC short DRET ; Remainder in DX:AX:BX:CX
  201. pub RESTORE
  202. DEC DI ; Drop quotient since it didn't fit
  203. ADD CX,[DAC] ; Add divisor back in until remainder goes +
  204. ADC BX,[DAC+2]
  205. ADC AX,[DAC+4]
  206. ADC DX,[DAC+6]
  207. JNC RESTORE ; Loop is performed at most twice
  208. pub DRET
  209. RET
  210. pub MAXQUO
  211. DEC DI ; DI=FFFF=2**16-1, DX:AX:BX:CX is remainder,
  212. SUB CX,[DAC] ; DX = [DAC+6], d = divisor = [DAC]
  213. SBB BX,[DAC+2]
  214. SBB AX,[DAC+4] ; subtract 2^16*d from DX:AX:BX:CX:0000H
  215. ADD CX,[DAC+2] ; (DX-[DAC+6] = 0 is implied)
  216. ADC BX,[DAC+4]
  217. ADC AX,DX ; add high 48 bits of d to AX:BX:CX:0000H
  218. MOV DX,[DAC] ; add low 16 bits of d to zero giving DX
  219. CMC ; DI should be FFFEH if no carry from add
  220. JMP ZERQUO
  221. ProfEnd FDIV