;       Generic assembler routines that have very little at all
;       to do with fractals.
;

; ---- 32-bit Multiply/Divide Routines (includes 16-bit emulation)
;
;       multiply()
;       divide()
;

DEFAULT REL

;%use smartalign
%include "xfract_a.inc"

; external functions
;
; external data
CEXTERN overflow   ;:DWORD  4 - int

section .bss
alignb  16

sign:                      ; sign flag goes here
        resb   INTSZ

section .text

; =======================================================
;
;       32-bit integer multiply routine with an 'n'-bit shift.
;       Overflow condition returns 0x7fffffffh with overflow = 1;
;
;       long x, y, z, multiply();
;       int n;
;
;       z = multiply(x,y,n)
;

CGLOBAL    multiply ;    x:dword, y:dword, n:dword
;                       [ebp+8], [ebp+12], [ebp+16]
multiply:
align 4
        FRAME   ebx
        mov     eax, dword [ebp + 0x8]         ; load X into EAX
        mov     ebx, dword [ebp + 0xC]         ; load Y into EBX
        mov     ecx, dword [ebp + 0x10]        ; set up the shift
        imul    ebx                     ; do the multiply with Y
        cmp     cl, 32                  ; ugly klooge:  check for 32-bit shift
        jb      short fastm1            ;  < 32 bits:  no problem
        mov     eax, edx                ;  >= 32 bits:  manual shift
        mov     edx, 0                  ; nothing left in edx
        sub     ecx, 32                 ;  ...
fastm1: shrd    eax, edx, cl            ; shift down 'n' bits
        js      fastm3
        sar     edx, cl
        jne     overmf
        jmp     multiplyreturn
fastm3: sar     edx, cl
        inc     edx
        jne     overmf
        jmp     multiplyreturn
overmf:
        mov     eax,07fffffffh          ; overflow value
        mov     dword [overflow],1      ; flag overflow

multiplyreturn:
        UNFRAME ebx
        ret

;multiply        endp


; =======================================================
;
;       32-bit integer divide routine with an 'n'-bit shift.
;       Overflow condition returns 0x7fffffffh with overflow = 1;
;
;       long x, y, z, divide();
;       int n;
;
;       z = divide(x,y,n);      /* z = x / y; */
;

CGLOBAL    divide   ;    x:dword, y:dword, n:dword
;                       [ebp+8], [ebp+12], [ebp+16]
divide:
align 4
        FRAME   ebx
        mov     ecx, 32                 ; set up the shift for later
        sub     ecx, dword [ebp + 0x10] ; (for large shift counts - faster)

        mov     edx, dword [ebp + 0x8]  ; load X into EDX (shifts to EDX:EAX)
        mov     ebx, dword [ebp + 0xC]  ; load Y into EBX

        mov     dword [sign], 0         ; clear out the sign flag
        cmp     edx, 0                  ; is X negative?
        jge     short divides1          ;  nope
        not     dword [sign]            ;  yup.  flip signs
        neg     edx                     ;   ...
divides1:
        cmp     ebx, 0                  ; is Y negative?
        jg      short divides2          ;  nope
        jl      short setsign1
        jmp     overd1                  ; don't divide by zero, set overflow
setsign1:
        not     dword [sign]            ;  yup.  flip signs
        neg     ebx                     ;   ...
divides2:
        mov     eax, 0                  ; clear out the low-order bits
fastd1: cmp     cx, 0                   ; done shifting?
        je      fastd2                  ; yup.
        shr     edx, 1                  ; shift one bit
        rcr     eax, 1                  ;  ...
        loop    fastd1                  ; and try again
fastd2:
        cmp     edx, ebx                ; umm, will the divide blow out?
        jae     overd1                  ;  yup.  better skip it.
        div     ebx                     ; do the divide
        cmp     eax, 0                  ; did the sign flip?
        jl      overd1                  ;  then we overflowed
        cmp     dword [sign], 0         ; is the sign reversed?
        je      short divides3          ;  nope
        neg     eax                     ; flip the sign
divides3:
;        shl     eax, 16
;        shl     eax, 16
;        shld    edx, eax, 16
;        shld    edx, eax, 16
;        mov     eax, edx
        jmp     dividereturn            ; back to common code

overd1:
        mov     eax, 07fffffffh         ; overflow value
        mov     dword [overflow], 1     ; flag overflow

dividereturn:                           ; that's all, folks!
        UNFRAME ebx
        ret
;divide          endp


