1#------------------------------------------------------------------------------
2#
3# Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
4# This program and the accompanying materials
5# are licensed and made available under the terms and conditions of the BSD License
6# which accompanies this distribution.  The full text of the license may be found at
7# http://opensource.org/licenses/bsd-license.php.
8#
9# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11#
12# Module Name:
13#
14#   DivU64x64Remainder.S
15#
16# Abstract:
17#
18#   Calculate the quotient of a 64-bit integer by a 64-bit integer and returns
19#   both the quotient and the remainder
20#
21#------------------------------------------------------------------------------
22
23ASM_GLOBAL ASM_PFX(InternalMathDivRemU64x32), ASM_PFX(InternalMathDivRemU64x64)
24
25#------------------------------------------------------------------------------
26# UINT64
27# EFIAPI
28# InternalMathDivRemU64x64 (
29#   IN      UINT64                    Dividend,
30#   IN      UINT64                    Divisor,
31#   OUT     UINT64                    *Remainder    OPTIONAL
32#   );
33#------------------------------------------------------------------------------
34ASM_PFX(InternalMathDivRemU64x64):
35    movl    16(%esp), %ecx              # ecx <- divisor[32..63]
36    testl   %ecx, %ecx
37    jnz     Hard                        # call _@DivRemU64x64 if Divisor > 2^32
38    movl    20(%esp), %ecx
39    jecxz   L1
40    andl     $0, 4(%ecx)                # zero high dword of remainder
41    movl    %ecx, 16(%esp)              # set up stack frame to match DivRemU64x32
42L1:
43    jmp     ASM_PFX(InternalMathDivRemU64x32)
44Hard:
45    push    %ebx
46    push    %esi
47    push    %edi
48    mov     20(%esp), %edx
49    mov     16(%esp), %eax              # edx:eax <- dividend
50    movl    %edx, %edi
51    movl    %eax, %esi                  # edi:esi <- dividend
52    mov     24(%esp), %ebx              # ecx:ebx <- divisor
53L2:
54    shrl    %edx
55    rcrl    $1, %eax
56    shrdl   $1, %ecx, %ebx
57    shrl    %ecx
58    jnz     L2
59    divl    %ebx
60    movl    %eax, %ebx                  # ebx <- quotient
61    movl    28(%esp), %ecx              # ecx <- high dword of divisor
62    mull    24(%esp)                    # edx:eax <- quotient * divisor[0..31]
63    imull   %ebx, %ecx                  # ecx <- quotient * divisor[32..63]
64    addl    %ecx, %edx                  # edx <- (quotient * divisor)[32..63]
65    mov     32(%esp), %ecx              # ecx <- addr for Remainder
66    jc      TooLarge                    # product > 2^64
67    cmpl    %edx, %edi                  # compare high 32 bits
68    ja      Correct
69    jb      TooLarge                    # product > dividend
70    cmpl    %eax, %esi
71    jae     Correct                     # product <= dividend
72TooLarge:
73    decl    %ebx                        # adjust quotient by -1
74    jecxz   Return                      # return if Remainder == NULL
75    sub     24(%esp), %eax
76    sbb     28(%esp), %edx              # edx:eax <- (quotient - 1) * divisor
77Correct:
78    jecxz   Return
79    subl    %eax, %esi
80    sbbl    %edx, %edi                  # edi:esi <- remainder
81    movl    %esi, (%ecx)
82    movl    %edi, 4(%ecx)
83Return:
84    movl    %ebx, %eax                  # eax <- quotient
85    xorl    %edx, %edx                  # quotient is 32 bits long
86    pop     %edi
87    pop     %esi
88    pop     %ebx
89    ret
90