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.

916 lines
24 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. .286
  16. .xlist
  17. include cmacros.inc
  18. include windows.inc
  19. .list
  20. externA __WinFlags
  21. UQUAD struc
  22. uq0 dw ?
  23. uq1 dw ?
  24. uq2 dw ?
  25. uq3 dw ?
  26. UQUAD ends
  27. ; The following two equates are just used as shorthand
  28. ; for the "word ptr" and "byte ptr" overrides.
  29. wptr equ word ptr
  30. bptr equ byte ptr
  31. ; The following structure should be used to access high and low
  32. ; words of a DWORD. This means that "word ptr foo[2]" -> "foo.hi".
  33. LONG struc
  34. lo dw ?
  35. hi dw ?
  36. LONG ends
  37. EAXtoDXAX macro
  38. shld edx,eax,16 ; move HIWORD(eax) to dx
  39. endm
  40. DXAXtoEAX macro
  41. ror eax,16 ; xchg HIWORD(eax) and LOWORD(eax)
  42. shrd eax,edx,16 ; move LOWORD(edx) to HIWORD(eax)
  43. endm
  44. neg32 macro hi, lo
  45. neg lo
  46. adc hi,0 ; carry set unless lo zero
  47. neg hi
  48. endm
  49. ifndef SEGNAME
  50. SEGNAME equ <_TEXT>
  51. endif
  52. createSeg %SEGNAME, CodeSeg, word, public, CODE
  53. sBegin CodeSeg
  54. assumes cs,CodeSeg
  55. assumes ds,nothing
  56. assumes es,nothing
  57. ;---------------------------Public-Routine------------------------------;
  58. ; long muldiv32(long, long, long)
  59. ;
  60. ; multiples two 32 bit values and then divides the result by a third
  61. ; 32 bit value with full 64 bit presision
  62. ;
  63. ; lResult = (lNumber * lNumerator) / lDenominator with correct rounding
  64. ;
  65. ; Entry:
  66. ; lNumber = number to multiply by nNumerator
  67. ; lNumerator = number to multiply by nNumber
  68. ; lDenominator = number to divide the multiplication result by.
  69. ;
  70. ; Returns:
  71. ; DX:AX = result of multiplication and division.
  72. ;
  73. ; Error Returns:
  74. ; none
  75. ; Registers Preserved:
  76. ; DS,ES,SI,DI
  77. ; History:
  78. ; Fri 05-Oct-1990 -by- Rob Williams [Robwi]
  79. ; Behavior consistent with MulDiv16 routine (signed, no int 0 on overflow)
  80. ; Stole muldiv16 psuedocode
  81. ;
  82. ; Wed 14-June-1990 -by- Todd Laney [ToddLa]
  83. ; converted it to 386/286 code. (by checking __WinFlags)
  84. ;
  85. ; Tue 08-May-1990 -by- Rob Williams [Robwi]
  86. ; Wrote it.
  87. ;
  88. ;----------------------------Pseudo-Code--------------------------------;
  89. ; long FAR PASCAL muldiv32(long, long, long)
  90. ; long l;
  91. ; long Numer;
  92. ; long Denom;
  93. ; {
  94. ;
  95. ; Sign = sign of Denom; // Sign will keep track of final sign //
  96. ;
  97. ;
  98. ; if (Denom < 0)
  99. ; {
  100. ; negate Denom; // make sure Denom is positive //
  101. ; }
  102. ;
  103. ; if (l < 0)
  104. ; {
  105. ; negate l; // make sure l is positive //
  106. ; }
  107. ;
  108. ; make Sign reflect any sign change;
  109. ;
  110. ;
  111. ; if (Numer < 0)
  112. ; {
  113. ; negate Numer; // make sure Numer is positive //
  114. ; }
  115. ;
  116. ; make Sign reflect any sign change;
  117. ;
  118. ; Numer *= l;
  119. ; Numer += (Denom/2); // adjust for rounding //
  120. ;
  121. ; if (overflow) // check for overflow, and handle divide by zero //
  122. ; {
  123. ; jump to md5;
  124. ; }
  125. ;
  126. ; result = Numer/Denom;
  127. ;
  128. ; if (overflow) // check again to see if overflow occured //
  129. ; {
  130. ; jump to md5;
  131. ; }
  132. ;
  133. ; if (Sign is negative) // put sign on the result //
  134. ; {
  135. ; negate result;
  136. ; }
  137. ;
  138. ;md6:
  139. ; return(result);
  140. ;
  141. ;md5:
  142. ; DX = 7FFF; // indicate overflow by //
  143. ; AX = 0xFFFF // return largest integer //
  144. ; if (Sign is negative)
  145. ; {
  146. ; DX = 0x8000; // with correct sign //
  147. ; AX = 0x0000;
  148. ; }
  149. ;
  150. ; jump to md6;
  151. ; }
  152. ;-----------------------------------------------------------------------;
  153. assumes ds,nothing
  154. assumes es,nothing
  155. cProc muldiv32,<PUBLIC,FAR,NODATA,NONWIN>,<>
  156. ; ParmD lNumber
  157. ; ParmD lNumerator
  158. ; ParmD lDenominator
  159. cBegin <nogen>
  160. mov ax,__WinFlags
  161. test ax,WF_CPU286+WF_CPU086+WF_CPU186
  162. jz md32_1
  163. jmp NEAR PTR muldiv32_286
  164. md32_1:
  165. errn$ muldiv32_386
  166. cEnd <nogen>
  167. cProc muldiv32_386,<PUBLIC,FAR,NODATA,NONWIN>,<>
  168. ParmD lNumber
  169. ParmD lNumerator
  170. ParmD lDenominator
  171. cBegin
  172. .386
  173. mov ebx,lDenominator ; get the demoninator
  174. mov ecx,ebx ; ECX holds the final sign in hiword
  175. or ebx,ebx ; ensure the denominator is positive
  176. jns md386_1
  177. neg ebx
  178. md386_1:
  179. mov eax,lNumber ; get the long we are multiplying
  180. xor ecx,eax ; make ECX reflect any sign change
  181. or eax,eax ; ensure the long is positive
  182. jns md386_2
  183. neg eax
  184. md386_2:
  185. mov edx,lNumerator ; get the numerator
  186. xor ecx,edx ; make ECX reflect any sign change
  187. or edx,edx ; ensure the numerator is positive
  188. jns md386_3
  189. neg edx
  190. md386_3:
  191. mul edx ; multiply
  192. mov cx,bx ; get half of the demoninator to adjust for rounding
  193. sar ebx,1
  194. add eax,ebx ; adjust for possible rounding error
  195. adc edx,0 ; this is really a long addition
  196. sal ebx,1 ; restore the demoninator
  197. or bx,cx ; fix bottom bit
  198. cmp edx,ebx ; check for overflow
  199. jae md386_5 ; (ae handles /0 case)
  200. div ebx ; divide
  201. or eax,eax ; If sign is set, then overflow occured
  202. js md386_5 ; Overflow.
  203. or ecx,ecx ; put the sign on the result
  204. jns md386_6
  205. neg eax
  206. md386_6:
  207. EAXtoDXAX ; convert eax to dx:ax for 16 bit programs
  208. .286
  209. cEnd
  210. .386
  211. md386_5:
  212. mov eax,7FFFFFFFh ; return the largest integer
  213. or ecx,ecx ; with the correct sign
  214. jns md386_6
  215. not eax
  216. jmp md386_6
  217. .286
  218. cProc muldiv32_286,<PUBLIC,FAR,NODATA,NONWIN>,<di,si>
  219. ParmD lNumber
  220. ParmD lNumerator
  221. ParmD lDenominator
  222. LocalW wSign
  223. cBegin
  224. mov dx,lDenominator.hi ; get the demoninator
  225. mov si,dx ; SI holds the final sign
  226. or dx,dx ; ensure the denominator is positive
  227. jns md286_1
  228. neg32 dx, lDenominator.lo
  229. mov lDenominator.hi, dx
  230. md286_1:
  231. mov ax,lNumber.lo ; get the long we are multiplying
  232. mov dx,lNumber.hi
  233. xor si,dx ; make ECX reflect any sign change
  234. or dx,dx ; ensure the long is positive
  235. jns md286_2
  236. neg32 dx, ax
  237. md286_2:
  238. mov bx,lNumerator.lo ; get the numerator
  239. mov cx,lNumerator.hi ; get the numerator
  240. xor si,cx ; make ECX reflect any sign change
  241. or cx,cx ; ensure the numerator is positive
  242. jns md286_3
  243. neg32 cx, bx
  244. md286_3:
  245. mov wSign, si ; save sign
  246. call dmul ; multiply (result in dx:cx:bx:ax)
  247. mov si, lDenominator.hi
  248. mov di, lDenominator.lo
  249. sar si, 1 ; get half of the demoninator
  250. rcr di, 1 ; to adjust for rounding
  251. add ax, di ; adjust for possible rounding error
  252. adc bx, si
  253. adc cx, 0
  254. adc dx, 0 ; this is really a long addition
  255. sal di, 1 ; restore the demoninator
  256. rcl si, 1
  257. or di, lDenominator.lo ; fix bottom bit
  258. cmp dx, si ; begin overflow check (unsigned for div 0 check)
  259. ja md286_5 ; overflow
  260. jb md286_7 ; no overflow
  261. cmp cx, di
  262. jae md286_5 ; overflow
  263. md286_7:
  264. call qdiv ; DX:AX is quotient
  265. or dx,dx ; If sign is set, then overflow occured
  266. js md286_5 ; Overflow.
  267. mov cx, wSign
  268. or cx,cx ; put the sign on the result
  269. jns md286_6
  270. neg32 dx,ax
  271. md286_6:
  272. cEnd
  273. md286_5:
  274. mov cx, wSign
  275. mov ax, 0FFFFh ; return the largest integer
  276. mov dx, 7FFFh
  277. or cx, cx ; with the correct sign
  278. jns md286_6
  279. not dx
  280. not ax
  281. jmp md286_6
  282. ;---------------------------Public-Routine------------------------------;
  283. ; idmul
  284. ;
  285. ; This is an extended precision multiply routine, intended to emulate
  286. ; 80386 imul instruction.
  287. ;
  288. ; Entry:
  289. ; DX:AX = LONG
  290. ; CX:BX = LONG
  291. ; Returns:
  292. ; DX:CX:BX:AX = QUAD product
  293. ; Registers Destroyed:
  294. ; none
  295. ; History:
  296. ; Tue 26-Jan-1988 23:47:02 -by- Charles Whitmer [chuckwh]
  297. ; Wrote it.
  298. ;-----------------------------------------------------------------------;
  299. assumes ds,nothing
  300. assumes es,nothing
  301. cProc idmul,<PUBLIC,NEAR>,<si,di>
  302. localQ qTemp
  303. cBegin
  304. ; put one argument in safe registers
  305. mov si,dx
  306. mov di,ax
  307. ; do the low order unsigned product
  308. mul bx
  309. mov qTemp.uq0,ax
  310. mov qTemp.uq1,dx
  311. ; do the high order signed product
  312. mov ax,si
  313. imul cx
  314. mov qTemp.uq2,ax
  315. mov qTemp.uq3,dx
  316. ; do a mixed product
  317. mov ax,si
  318. cwd
  319. and dx,bx
  320. sub qTemp.uq2,dx ; adjust for sign bit
  321. sbb qTemp.uq3,0
  322. mul bx
  323. add qTemp.uq1,ax
  324. adc qTemp.uq2,dx
  325. adc qTemp.uq3,0
  326. ; do the other mixed product
  327. mov ax,cx
  328. cwd
  329. and dx,di
  330. sub qTemp.uq2,dx
  331. sbb qTemp.uq3,0
  332. mul di
  333. ; pick up the answer
  334. mov bx,ax
  335. mov cx,dx
  336. xor dx,dx
  337. mov ax,qTemp.uq0
  338. add bx,qTemp.uq1
  339. adc cx,qTemp.uq2
  340. adc dx,qTemp.uq3
  341. cEnd
  342. ;---------------------------Public-Routine------------------------------;
  343. ; dmul
  344. ;
  345. ; This is an extended precision multiply routine, intended to emulate
  346. ; 80386 mul instruction.
  347. ;
  348. ; Entry:
  349. ; DX:AX = LONG
  350. ; CX:BX = LONG
  351. ; Returns:
  352. ; DX:CX:BX:AX = QUAD product
  353. ; Registers Destroyed:
  354. ; none
  355. ; History:
  356. ; Tue 02-Feb-1988 10:50:44 -by- Charles Whitmer [chuckwh]
  357. ; Copied from idmul and modified.
  358. ;-----------------------------------------------------------------------;
  359. assumes ds,nothing
  360. assumes es,nothing
  361. cProc dmul,<PUBLIC,NEAR>,<si,di>
  362. localQ qTemp
  363. cBegin
  364. ; put one argument in safe registers
  365. mov si,dx
  366. mov di,ax
  367. ; do the low order product
  368. mul bx
  369. mov qTemp.uq0,ax
  370. mov qTemp.uq1,dx
  371. ; do the high order product
  372. mov ax,si
  373. mul cx
  374. mov qTemp.uq2,ax
  375. mov qTemp.uq3,dx
  376. ; do a mixed product
  377. mov ax,si
  378. mul bx
  379. add qTemp.uq1,ax
  380. adc qTemp.uq2,dx
  381. adc qTemp.uq3,0
  382. ; do the other mixed product
  383. mov ax,cx
  384. mul di
  385. ; pick up the answer
  386. mov bx,ax
  387. mov cx,dx
  388. xor dx,dx
  389. mov ax,qTemp.uq0
  390. add bx,qTemp.uq1
  391. adc cx,qTemp.uq2
  392. adc dx,qTemp.uq3
  393. cEnd
  394. ;---------------------------Public-Routine------------------------------;
  395. ; iqdiv
  396. ;
  397. ; This is an extended precision divide routine which is intended to
  398. ; emulate the 80386 64 bit/32 bit IDIV instruction. We don't have the
  399. ; 32 bit registers to work with, but we pack the arguments and results
  400. ; into what registers we do have. We will divide two signed numbers
  401. ; and return the quotient and remainder. We will do INT 0 for overflow,
  402. ; just like the 80386 microcode. This should ease conversion later.
  403. ;
  404. ; This routine just keeps track of the signs and calls qdiv to do the
  405. ; real work.
  406. ;
  407. ; Entry:
  408. ; DX:CX:BX:AX = QUAD Numerator
  409. ; SI:DI = LONG Denominator
  410. ; Returns:
  411. ; DX:AX = quotient
  412. ; CX:BX = remainder
  413. ; Registers Destroyed:
  414. ; DI,SI
  415. ; History:
  416. ; Tue 26-Jan-1988 02:49:19 -by- Charles Whitmer [chuckwh]
  417. ; Wrote it.
  418. ;-----------------------------------------------------------------------;
  419. WIMP equ 1
  420. IQDIV_RESULT_SIGN equ 1
  421. IQDIV_REM_SIGN equ 2
  422. assumes ds,nothing
  423. assumes es,nothing
  424. cProc iqdiv,<PUBLIC,NEAR>
  425. localB flags
  426. cBegin
  427. mov flags,0
  428. ; take the absolute value of the denominator
  429. or si,si
  430. jns denominator_is_cool
  431. xor flags,IQDIV_RESULT_SIGN
  432. neg di
  433. adc si,0
  434. neg si
  435. denominator_is_cool:
  436. ; take the absolute value of the denominator
  437. or dx,dx
  438. jns numerator_is_cool
  439. xor flags,IQDIV_RESULT_SIGN + IQDIV_REM_SIGN
  440. not ax
  441. not bx
  442. not cx
  443. not dx
  444. add ax,1
  445. adc bx,0
  446. adc cx,0
  447. adc dx,0
  448. numerator_is_cool:
  449. ; do the unsigned division
  450. call qdiv
  451. ifdef WIMP
  452. jo iqdiv_exit
  453. endif
  454. ; check for overflow
  455. or dx,dx
  456. jns have_a_bit_to_spare
  457. ifdef WIMP
  458. mov ax,8000h
  459. dec ah
  460. jmp short iqdiv_exit
  461. else
  462. int 0 ; You're toast, Jack!
  463. endif
  464. have_a_bit_to_spare:
  465. ; negate the result, if required
  466. test flags,IQDIV_RESULT_SIGN
  467. jz result_is_done
  468. neg ax
  469. adc dx,0
  470. neg dx
  471. result_is_done:
  472. ; negate the remainder, if required
  473. test flags,IQDIV_REM_SIGN
  474. jz remainder_is_done
  475. neg bx
  476. adc cx,0
  477. neg cx
  478. remainder_is_done:
  479. iqdiv_exit:
  480. cEnd
  481. ;---------------------------Public-Routine------------------------------;
  482. ; qdiv
  483. ;
  484. ; This is an extended precision divide routine which is intended to
  485. ; emulate the 80386 64 bit/32 bit DIV instruction. We don't have the
  486. ; 32 bit registers to work with, but we pack the arguments and results
  487. ; into what registers we do have. We will divide two unsigned numbers
  488. ; and return the quotient and remainder. We will do INT 0 for overflow,
  489. ; just like the 80386 microcode. This should ease conversion later.
  490. ;
  491. ; Entry:
  492. ; DX:CX:BX:AX = UQUAD Numerator
  493. ; SI:DI = ULONG Denominator
  494. ; Returns:
  495. ; DX:AX = quotient
  496. ; CX:BX = remainder
  497. ; Registers Destroyed:
  498. ; none
  499. ; History:
  500. ; Tue 26-Jan-1988 00:02:09 -by- Charles Whitmer [chuckwh]
  501. ; Wrote it.
  502. ;-----------------------------------------------------------------------;
  503. assumes ds,nothing
  504. assumes es,nothing
  505. cProc qdiv,<PUBLIC,NEAR>,<si,di>
  506. localQ uqNumerator
  507. localD ulDenominator
  508. localD ulQuotient
  509. localW cShift
  510. cBegin
  511. ; stuff the quad word into local memory
  512. mov uqNumerator.uq0,ax
  513. mov uqNumerator.uq1,bx
  514. mov uqNumerator.uq2,cx
  515. mov uqNumerator.uq3,dx
  516. ; check for overflow
  517. qdiv_restart:
  518. cmp si,dx
  519. ja qdiv_no_overflow
  520. jb qdiv_overflow
  521. cmp di,cx
  522. ja qdiv_no_overflow
  523. qdiv_overflow:
  524. ifdef WIMP
  525. mov ax,8000h
  526. dec ah
  527. jmp qdiv_exit
  528. else
  529. int 0 ; You're toast, Jack!
  530. jmp qdiv_restart
  531. endif
  532. qdiv_no_overflow:
  533. ; check for a zero Numerator
  534. or ax,bx
  535. or ax,cx
  536. or ax,dx
  537. jz qdiv_exit_relay ; quotient = remainder = 0
  538. ; handle the special case when the denominator lives in the low word
  539. or si,si
  540. jnz not_that_special
  541. ; calculate (DX=0):CX:BX:uqNumerator.uq0 / (SI=0):DI
  542. cmp di,1 ; separate out the trivial case
  543. jz div_by_one
  544. xchg dx,cx ; CX = remainder.hi = 0
  545. mov ax,bx
  546. div di
  547. mov bx,ax ; BX = quotient.hi
  548. mov ax,uqNumerator.uq0
  549. div di ; AX = quotient.lo
  550. xchg bx,dx ; DX = quotient.hi, BX = remainder.lo
  551. ifdef WIMP
  552. or ax,ax ; clear OF
  553. endif
  554. qdiv_exit_relay:
  555. jmp qdiv_exit
  556. ; calculate (DX=0):(CX=0):BX:uqNumerator.uq0 / (SI=0):(DI=1)
  557. div_by_one:
  558. xchg dx,bx ; DX = quotient.hi, BX = remainder.lo = 0
  559. mov ax,uqNumerator.uq0 ; AX = quotient.lo
  560. jmp qdiv_exit
  561. not_that_special:
  562. ; handle the special case when the denominator lives in the high word
  563. or di,di
  564. jnz not_this_special_either
  565. ; calculate DX:CX:BX:uqNumerator.uq0 / SI:(DI=0)
  566. cmp si,1 ; separate out the trivial case
  567. jz div_by_10000h
  568. mov ax,cx
  569. div si
  570. mov cx,ax ; CX = quotient.hi
  571. mov ax,bx
  572. div si ; AX = quotient.lo
  573. xchg cx,dx ; DX = quotient.hi, CX = remainder.hi
  574. mov bx,uqNumerator.uq0 ; BX = remainder.lo
  575. ifdef WIMP
  576. or ax,ax ; clear OF
  577. endif
  578. jmp qdiv_exit
  579. ; calculate (DX=0):CX:BX:uqNumerator.uq0 / (SI=1):(DI=0)
  580. div_by_10000h:
  581. xchg cx,dx ; DX = quotient.hi, CX = remainder.hi = 0
  582. mov ax,bx ; AX = quotient.lo
  583. mov bx,uqNumerator.uq0 ; BX = remainder.lo
  584. jmp qdiv_exit
  585. not_this_special_either:
  586. ; normalize the denominator
  587. mov dx,si
  588. mov ax,di
  589. call ulNormalize ; DX:AX = normalized denominator
  590. mov cShift,cx ; CX < 16
  591. mov ulDenominator.lo,ax
  592. mov ulDenominator.hi,dx
  593. ; shift the Numerator by the same amount
  594. jcxz numerator_is_shifted
  595. mov si,-1
  596. shl si,cl
  597. not si ; SI = mask
  598. mov bx,uqNumerator.uq3
  599. shl bx,cl
  600. mov ax,uqNumerator.uq2
  601. rol ax,cl
  602. mov di,si
  603. and di,ax
  604. or bx,di
  605. mov uqNumerator.uq3,bx
  606. xor ax,di
  607. mov bx,uqNumerator.uq1
  608. rol bx,cl
  609. mov di,si
  610. and di,bx
  611. or ax,di
  612. mov uqNumerator.uq2,ax
  613. xor bx,di
  614. mov ax,uqNumerator.uq0
  615. rol ax,cl
  616. mov di,si
  617. and di,ax
  618. or bx,di
  619. mov uqNumerator.uq1,bx
  620. xor ax,di
  621. mov uqNumerator.uq0,ax
  622. numerator_is_shifted:
  623. ; set up registers for division
  624. mov dx,uqNumerator.uq3
  625. mov ax,uqNumerator.uq2
  626. mov di,uqNumerator.uq1
  627. mov cx,ulDenominator.hi
  628. mov bx,ulDenominator.lo
  629. ; check for case when Denominator has only 16 bits
  630. or bx,bx
  631. jnz must_do_long_division
  632. div cx
  633. mov si,ax
  634. mov ax,uqNumerator.uq1
  635. div cx
  636. xchg si,dx ; DX:AX = quotient
  637. mov di,uqNumerator.uq0 ; SI:DI = remainder (shifted)
  638. jmp short unshift_remainder
  639. must_do_long_division:
  640. ; do the long division, part IZ@NL@%
  641. cmp dx,cx ; we only know that DX:AX < CX:BX!
  642. jb first_division_is_safe
  643. mov ulQuotient.hi,0 ; i.e. 10000h, our guess is too big
  644. mov si,ax
  645. sub si,bx ; ... remainder is negative
  646. jmp short first_adjuster
  647. first_division_is_safe:
  648. div cx
  649. mov ulQuotient.hi,ax
  650. mov si,dx
  651. mul bx ; fix remainder for low order term
  652. sub di,ax
  653. sbb si,dx
  654. jnc first_adjuster_done ; The remainder is UNSIGNED! We have
  655. first_adjuster: ; to use the carry flag to keep track
  656. dec ulQuotient.hi ; of the sign. The adjuster loop
  657. add di,bx ; watches for a change to the carry
  658. adc si,cx ; flag which would indicate a sign
  659. jnc first_adjuster ; change IF we had more bits to keep
  660. first_adjuster_done: ; a sign in.
  661. ; do the long division, part II
  662. mov dx,si
  663. mov ax,di
  664. mov di,uqNumerator.uq0
  665. cmp dx,cx ; we only know that DX:AX < CX:BX!
  666. jb second_division_is_safe
  667. mov ulQuotient.lo,0 ; i.e. 10000h, our guess is too big
  668. mov si,ax
  669. sub si,bx ; ... remainder is negative
  670. jmp short second_adjuster
  671. second_division_is_safe:
  672. div cx
  673. mov ulQuotient.lo,ax
  674. mov si,dx
  675. mul bx ; fix remainder for low order term
  676. sub di,ax
  677. sbb si,dx
  678. jnc second_adjuster_done
  679. second_adjuster:
  680. dec ulQuotient.lo
  681. add di,bx
  682. adc si,cx
  683. jnc second_adjuster
  684. second_adjuster_done:
  685. mov ax,ulQuotient.lo
  686. mov dx,ulQuotient.hi
  687. ; unshift the remainder in SI:DI
  688. unshift_remainder:
  689. mov cx,cShift
  690. jcxz remainder_unshifted
  691. mov bx,-1
  692. shr bx,cl
  693. not bx
  694. shr di,cl
  695. ror si,cl
  696. and bx,si
  697. or di,bx
  698. xor si,bx
  699. remainder_unshifted:
  700. mov cx,si
  701. mov bx,di
  702. ifdef WIMP
  703. or ax,ax ; clear OF
  704. endif
  705. qdiv_exit:
  706. cEnd
  707. ;---------------------------Public-Routine------------------------------;
  708. ; ulNormalize
  709. ;
  710. ; Normalizes a ULONG so that the highest order bit is 1. Returns the
  711. ; number of shifts done. Also returns ZF=1 if the ULONG was zero.
  712. ;
  713. ; Entry:
  714. ; DX:AX = ULONG
  715. ; Returns:
  716. ; DX:AX = normalized ULONG
  717. ; CX = shift count
  718. ; ZF = 1 if the ULONG is zero, 0 otherwise
  719. ; Registers Destroyed:
  720. ; none
  721. ; History:
  722. ; Mon 25-Jan-1988 22:07:03 -by- Charles Whitmer [chuckwh]
  723. ; Wrote it.
  724. ;-----------------------------------------------------------------------;
  725. assumes ds,nothing
  726. assumes es,nothing
  727. cProc ulNormalize,<PUBLIC,NEAR>
  728. cBegin
  729. ; shift by words
  730. xor cx,cx
  731. or dx,dx
  732. js ulNormalize_exit
  733. jnz top_word_ok
  734. xchg ax,dx
  735. or dx,dx
  736. jz ulNormalize_exit ; the zero exit
  737. mov cl,16
  738. js ulNormalize_exit
  739. top_word_ok:
  740. ; shift by bytes
  741. or dh,dh
  742. jnz top_byte_ok
  743. xchg dh,dl
  744. xchg dl,ah
  745. xchg ah,al
  746. add cl,8
  747. or dh,dh
  748. js ulNormalize_exit
  749. top_byte_ok:
  750. ; do the rest by bits
  751. inc cx
  752. add ax,ax
  753. adc dx,dx
  754. js ulNormalize_exit
  755. inc cx
  756. add ax,ax
  757. adc dx,dx
  758. js ulNormalize_exit
  759. inc cx
  760. add ax,ax
  761. adc dx,dx
  762. js ulNormalize_exit
  763. inc cx
  764. add ax,ax
  765. adc dx,dx
  766. js ulNormalize_exit
  767. inc cx
  768. add ax,ax
  769. adc dx,dx
  770. js ulNormalize_exit
  771. inc cx
  772. add ax,ax
  773. adc dx,dx
  774. js ulNormalize_exit
  775. inc cx
  776. add ax,ax
  777. adc dx,dx
  778. ulNormalize_exit:
  779. cEnd
  780. sEnd CodeSeg
  781. end
  782.