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.

349 lines
9.5 KiB

  1. page ,132
  2. ;---------------------------Module-Header-------------------------------;
  3. ; Module Name: MATH.ASM
  4. ;
  5. ; Contains FIXED point math routines.
  6. ;
  7. ; Created: Sun 30-Aug-1987 19:28:30
  8. ; Author: Charles Whitmer [chuckwh]
  9. ;
  10. ; Copyright (c) 1987 Microsoft Corporation
  11. ;-----------------------------------------------------------------------;
  12. ?WIN = 0
  13. ?PLM = 1
  14. ?NODATA = 0
  15. ?DF=1
  16. PMODE=1
  17. .xlist
  18. include cmacros.inc
  19. ; include windows.inc
  20. include timer.inc
  21. .list
  22. UQUAD struc
  23. uq0 dw ?
  24. uq1 dw ?
  25. uq2 dw ?
  26. uq3 dw ?
  27. UQUAD ends
  28. ; The following structure should be used to access high and low
  29. ; words of a DWORD. This means that "word ptr foo[2]" -> "foo.hi".
  30. LONG struc
  31. lo dw ?
  32. hi dw ?
  33. LONG ends
  34. sBegin Code286
  35. assumes cs,Code286
  36. assumes ds,nothing
  37. assumes es,nothing
  38. ;---------------------------Public-Routine------------------------------;
  39. ; qdiv
  40. ;
  41. ; This is an extended precision divide routine which is intended to
  42. ; emulate the 80386 64 bit/32 bit DIV instruction. We don't have the
  43. ; 32 bit registers to work with, but we pack the arguments and results
  44. ; into what registers we do have. We will divide two unsigned numbers
  45. ; and return the quotient and remainder. We will do INT 0 for overflow,
  46. ; just like the 80386 microcode. This should ease conversion later.
  47. ;
  48. ; Entry:
  49. ; DX:CX:BX:AX = UQUAD Numerator
  50. ; SI:DI = ULONG Denominator
  51. ; Returns:
  52. ; DX:AX = quotient
  53. ; CX:BX = remainder
  54. ; Registers Destroyed:
  55. ; none
  56. ; History:
  57. ; Tue 26-Jan-1988 00:02:09 -by- Charles Whitmer [chuckwh]
  58. ; Wrote it.
  59. ;-----------------------------------------------------------------------;
  60. assumes ds,nothing
  61. assumes es,nothing
  62. cProc qdiv,<PUBLIC,NEAR>,<si,di>
  63. localQ uqNumerator
  64. localD ulDenominator
  65. localD ulQuotient
  66. localW cShift
  67. cBegin
  68. ; stuff the quad word into local memory
  69. mov uqNumerator.uq0,ax
  70. mov uqNumerator.uq1,bx
  71. mov uqNumerator.uq2,cx
  72. mov uqNumerator.uq3,dx
  73. ; check for a zero Numerator
  74. or ax,bx
  75. or ax,cx
  76. or ax,dx
  77. jz qdiv_exit_relay ; quotient = remainder = 0
  78. ; handle the special case when the denominator lives in the low word
  79. or si,si
  80. jnz not_that_special
  81. ; calculate (DX=0):CX:BX:uqNumerator.uq0 / (SI=0):DI
  82. cmp di,1 ; separate out the trivial case
  83. jz div_by_one
  84. xchg dx,cx ; CX = remainder.hi = 0
  85. mov ax,bx
  86. div di
  87. mov bx,ax ; BX = quotient.hi
  88. mov ax,uqNumerator.uq0
  89. div di ; AX = quotient.lo
  90. xchg bx,dx ; DX = quotient.hi, BX = remainder.lo
  91. ifdef WIMP
  92. or ax,ax ; clear OF
  93. endif
  94. qdiv_exit_relay:
  95. jmp qdiv_exit
  96. ; calculate (DX=0):(CX=0):BX:uqNumerator.uq0 / (SI=0):(DI=1)
  97. div_by_one:
  98. xchg dx,bx ; DX = quotient.hi, BX = remainder.lo = 0
  99. mov ax,uqNumerator.uq0 ; AX = quotient.lo
  100. jmp qdiv_exit
  101. not_that_special:
  102. ; handle the special case when the denominator lives in the high word
  103. or di,di
  104. jnz not_this_special_either
  105. ; calculate DX:CX:BX:uqNumerator.uq0 / SI:(DI=0)
  106. cmp si,1 ; separate out the trivial case
  107. jz div_by_10000h
  108. mov ax,cx
  109. div si
  110. mov cx,ax ; CX = quotient.hi
  111. mov ax,bx
  112. div si ; AX = quotient.lo
  113. xchg cx,dx ; DX = quotient.hi, CX = remainder.hi
  114. mov bx,uqNumerator.uq0 ; BX = remainder.lo
  115. ifdef WIMP
  116. or ax,ax ; clear OF
  117. endif
  118. jmp qdiv_exit
  119. ; calculate (DX=0):CX:BX:uqNumerator.uq0 / (SI=1):(DI=0)
  120. div_by_10000h:
  121. xchg cx,dx ; DX = quotient.hi, CX = remainder.hi = 0
  122. mov ax,bx ; AX = quotient.lo
  123. mov bx,uqNumerator.uq0 ; BX = remainder.lo
  124. jmp qdiv_exit
  125. not_this_special_either:
  126. ; normalize the denominator
  127. mov dx,si
  128. mov ax,di
  129. call ulNormalize ; DX:AX = normalized denominator
  130. mov cShift,cx ; CX < 16
  131. mov ulDenominator.lo,ax
  132. mov ulDenominator.hi,dx
  133. ; shift the Numerator by the same amount
  134. jcxz numerator_is_shifted
  135. mov si,-1
  136. shl si,cl
  137. not si ; SI = mask
  138. mov bx,uqNumerator.uq3
  139. shl bx,cl
  140. mov ax,uqNumerator.uq2
  141. rol ax,cl
  142. mov di,si
  143. and di,ax
  144. or bx,di
  145. mov uqNumerator.uq3,bx
  146. xor ax,di
  147. mov bx,uqNumerator.uq1
  148. rol bx,cl
  149. mov di,si
  150. and di,bx
  151. or ax,di
  152. mov uqNumerator.uq2,ax
  153. xor bx,di
  154. mov ax,uqNumerator.uq0
  155. rol ax,cl
  156. mov di,si
  157. and di,ax
  158. or bx,di
  159. mov uqNumerator.uq1,bx
  160. xor ax,di
  161. mov uqNumerator.uq0,ax
  162. numerator_is_shifted:
  163. ; set up registers for division
  164. mov dx,uqNumerator.uq3
  165. mov ax,uqNumerator.uq2
  166. mov di,uqNumerator.uq1
  167. mov cx,ulDenominator.hi
  168. mov bx,ulDenominator.lo
  169. ; check for case when Denominator has only 16 bits
  170. or bx,bx
  171. jnz must_do_long_division
  172. div cx
  173. mov si,ax
  174. mov ax,uqNumerator.uq1
  175. div cx
  176. xchg si,dx ; DX:AX = quotient
  177. mov di,uqNumerator.uq0 ; SI:DI = remainder (shifted)
  178. jmp short unshift_remainder
  179. must_do_long_division:
  180. ; do the long division, part IZ@NL@%
  181. cmp dx,cx ; we only know that DX:AX < CX:BX!
  182. jb first_division_is_safe
  183. mov ulQuotient.hi,0 ; i.e. 10000h, our guess is too big
  184. mov si,ax
  185. sub si,bx ; ... remainder is negative
  186. jmp short first_adjuster
  187. first_division_is_safe:
  188. div cx
  189. mov ulQuotient.hi,ax
  190. mov si,dx
  191. mul bx ; fix remainder for low order term
  192. sub di,ax
  193. sbb si,dx
  194. jnc first_adjuster_done ; The remainder is UNSIGNED! We have
  195. first_adjuster: ; to use the carry flag to keep track
  196. dec ulQuotient.hi ; of the sign. The adjuster loop
  197. add di,bx ; watches for a change to the carry
  198. adc si,cx ; flag which would indicate a sign
  199. jnc first_adjuster ; change IF we had more bits to keep
  200. first_adjuster_done: ; a sign in.
  201. ; do the long division, part II
  202. mov dx,si
  203. mov ax,di
  204. mov di,uqNumerator.uq0
  205. cmp dx,cx ; we only know that DX:AX < CX:BX!
  206. jb second_division_is_safe
  207. mov ulQuotient.lo,0 ; i.e. 10000h, our guess is too big
  208. mov si,ax
  209. sub si,bx ; ... remainder is negative
  210. jmp short second_adjuster
  211. second_division_is_safe:
  212. div cx
  213. mov ulQuotient.lo,ax
  214. mov si,dx
  215. mul bx ; fix remainder for low order term
  216. sub di,ax
  217. sbb si,dx
  218. jnc second_adjuster_done
  219. second_adjuster:
  220. dec ulQuotient.lo
  221. add di,bx
  222. adc si,cx
  223. jnc second_adjuster
  224. second_adjuster_done:
  225. mov ax,ulQuotient.lo
  226. mov dx,ulQuotient.hi
  227. ; unshift the remainder in SI:DI
  228. unshift_remainder:
  229. mov cx,cShift
  230. jcxz remainder_unshifted
  231. mov bx,-1
  232. shr bx,cl
  233. not bx
  234. shr di,cl
  235. ror si,cl
  236. and bx,si
  237. or di,bx
  238. xor si,bx
  239. remainder_unshifted:
  240. mov cx,si
  241. mov bx,di
  242. ifdef WIMP
  243. or ax,ax ; clear OF
  244. endif
  245. qdiv_exit:
  246. cEnd
  247. ;---------------------------Public-Routine------------------------------;
  248. ; ulNormalize
  249. ;
  250. ; Normalizes a ULONG so that the highest order bit is 1. Returns the
  251. ; number of shifts done. Also returns ZF=1 if the ULONG was zero.
  252. ;
  253. ; Entry:
  254. ; DX:AX = ULONG
  255. ; Returns:
  256. ; DX:AX = normalized ULONG
  257. ; CX = shift count
  258. ; ZF = 1 if the ULONG is zero, 0 otherwise
  259. ; Registers Destroyed:
  260. ; none
  261. ; History:
  262. ; Mon 25-Jan-1988 22:07:03 -by- Charles Whitmer [chuckwh]
  263. ; Wrote it.
  264. ;-----------------------------------------------------------------------;
  265. assumes ds,nothing
  266. assumes es,nothing
  267. cProc ulNormalize,<PUBLIC,NEAR>
  268. cBegin
  269. ; shift by words
  270. xor cx,cx
  271. or dx,dx
  272. js ulNormalize_exit
  273. jnz top_word_ok
  274. xchg ax,dx
  275. or dx,dx
  276. jz ulNormalize_exit ; the zero exit
  277. mov cl,16
  278. js ulNormalize_exit
  279. top_word_ok:
  280. ; shift by bytes
  281. or dh,dh
  282. jnz top_byte_ok
  283. xchg dh,dl
  284. xchg dl,ah
  285. xchg ah,al
  286. add cl,8
  287. or dh,dh
  288. js ulNormalize_exit
  289. top_byte_ok:
  290. ; do the rest by bits
  291. next_byte:
  292. inc cx
  293. add ax,ax
  294. adc dx,dx
  295. jns next_byte
  296. ulNormalize_exit:
  297. cEnd
  298. sEnd
  299. end