home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Multimedia Jumpstart 1.1a / CD_ROM.BIN / develpmt / source / waveconv / muldiv32.asm < prev    next >
Assembly Source File  |  1992-09-12  |  20KB  |  760 lines

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