; Listing 8-3
;
; 128-bit by 128-bit division

        option  casemap:none

nl          =       10

            .const
ttlStr      byte    "Listing 8-3", 0
fmtStr1     byte    "quotient  = "
            byte    "%08x_%08x_%08x_%08x"
            byte    nl, 0
            
fmtStr2     byte    "remainder = "
            byte    "%08x_%08x_%08x_%08x"
            byte    nl, 0
            
fmtStr3     byte    "quotient (2)  = "
            byte    "%08x_%08x_%08x_%08x"
            byte    nl, 0
            
            
             .data

; op1 is a 128-bit value. Initial values were chosen
; to make it easy to verify result.

op1         oword   2222eeeeccccaaaa8888666644440000h            
op2         oword   2
op3         oword   11117777666655554444333322220000h
result      oword   ?
remain      oword   ?

            .code
            externdef printf:proc
            
; Return program title to C++ program:

            public  getTitle
getTitle    proc
            lea     rax, ttlStr
            ret
getTitle    endp


; div128-
;
; This procedure does a general 128/128 division operation 
; using the following algorithm (all variables are assumed 
; to be 128-bit objects):
;
; Quotient := Dividend;
; Remainder := 0;
; for i := 1 to NumberBits do
; 
;  Remainder:Quotient := Remainder:Quotient SHL 1;
;  if Remainder >= Divisor then
; 
;      Remainder := Remainder - Divisor;
;      Quotient := Quotient + 1;
; 
;  endif
; endfor
;
; Data passed:
;
; 128-bit dividend, by reference in RCX
; 128-bit divisor, by reference in RDX
;
; Data returned:
;
; Pointer to 128-bit quotient in R8
; Pointer to 128-bit remainder in R9 

div128      proc
remainder   equ     <[rbp-16]>
dividend    equ     <[rbp-32]>
quotient    equ     <[rbp-32]>      ;Aliased to dividend
divisor     equ     <[rbp-48]>

            push    rbp
            mov     rbp, rsp
            sub     rsp, 48
            
            push    rax
            push    rcx
            
            xor     rax, rax        ;Initialize remainder to 0
            mov     remainder, rax
            mov     remainder[8], rax
            
; Copy the dividend to local storage

            mov     rax, [rcx]
            mov     dividend, rax
            mov     rax, [rcx+8]
            mov     dividend[8], rax
            
; Copy the divisor to local storage

            mov     rax, [rdx]
            mov     divisor, rax
            mov     rax, [rdx+8]
            mov     divisor[8], rax
            
            
            mov     cl, 128           ;Count off bits in cl

; Compute Remainder:Quotient := Remainder:Quotient SHL 1:

repeatLp:   shl     qword ptr dividend[0], 1  ;256-bit extended
            rcl     qword ptr dividend[8], 1  ; precision shift
            rcl     qword ptr remainder[0], 1 ; though remainder
            rcl     qword ptr remainder[8], 1       

; Do a 128-bit comparison to see if the remainder
; is greater than or equal to the divisor.

            mov     rax, remainder[8]
            cmp     rax, divisor[8]
            ja      isGE
            jb      notGE
            
            mov     rax, remainder
            cmp     rax, divisor
            ja      isGE
            jb      notGE
            
; Remainder := Remainder - Divisor

isGE:       mov     rax, divisor
            sub     remainder, rax
            mov     rax, divisor[8]
            sub     remainder[8], rax

; Quotient := Quotient + 1;


            add     qword ptr quotient, 1
            adc     qword ptr quotient[8], 0

notGE:      dec     cl
            jnz     repeatLp


; Okay, copy the quotient (left in the Dividend variable)
; and the remainder to their return locations.
    
            mov     rax, quotient[0]
            mov     [r8], rax
            mov     rax, quotient[8]
            mov     [r8][8], rax
            
            mov     rax, remainder[0]
            mov     [r9], rax
            mov     rax, remainder[8]
            mov     [r9][8], rax


            pop     rcx
            pop     rax
            leave
            ret
                        
div128      endp





            
; Here is the "asmMain" function.

        
            public  asmMain
asmMain     proc
            push    rbp
            mov     rbp, rsp
            sub     rsp, 64         ;Shadow storage
            

; Test the div128 function:

            lea     rcx, op1
            lea     rdx, op2
            lea     r8, result
            lea     r9, remain
            call    div128
                        
; Print the results:

            lea     rcx, fmtStr1
            mov     edx, dword ptr result[12]
            mov     r8d, dword ptr result[8]
            mov     r9d, dword ptr result[4]
            mov     eax, dword ptr result[0]
            mov     [rsp+32], rax
            call    printf
                

            lea     rcx, fmtStr2
            mov     edx, dword ptr remain[12]
            mov     r8d, dword ptr remain[8]
            mov     r9d, dword ptr remain[4]
            mov     eax, dword ptr remain[0]
            mov     [rsp+32], rax
            call    printf
                
            
; Test the div128 function:

            lea     rcx, op1
            lea     rdx, op3
            lea     r8, result
            lea     r9, remain
            call    div128
                        
; Print the results:

            lea     rcx, fmtStr3
            mov     edx, dword ptr result[12]
            mov     r8d, dword ptr result[8]
            mov     r9d, dword ptr result[4]
            mov     eax, dword ptr result[0]
            mov     [rsp+32], rax
            call    printf
                

            lea     rcx, fmtStr2
            mov     edx, dword ptr remain[12]
            mov     r8d, dword ptr remain[8]
            mov     r9d, dword ptr remain[4]
            mov     eax, dword ptr remain[0]
            mov     [rsp+32], rax
            call    printf
                
            
            leave
            ret     ;Returns to caller
        
asmMain     endp
            end