;=============================================================
; File:    GCD.asm
; Purpose: Find the greatest common divisor of two integers.
;          Show how to use the stack to transmit parameters.
;          Show how to create a recursive procedure.
;=============================================================

include 'emu8086.inc'

       org  100h ; set location counter to 100h

       jmp  CodeStart

DataStart:

prompt   db  13, 10, "Next number> ", 0 
newline  db  13, 10, 0
maxMsg   db  13, 10, "The GCD is ", 0
fini     db  13, 10, 13, 10, "Fini", 13, 10, 0
numA     dw  ?
numB     dw  ?
numGCD   dw  0

CodeStart:
       mov  si, offset prompt    ; prompt for number
       call print_string
       call scan_num             ; get next number
       cmp  cx, 0
       je   EndProg              ; zero indicates quit
       mov  numA, cx

       mov  si, offset prompt    ; prompt for number
       call print_string
       call scan_num             ; get next number
       cmp  cx, 0
       je   EndProg              ; zero indicates quit
       mov  numB, cx

       mov  ax, numA             ; push A and B 
       push ax                   ; onto the stack
       mov  ax, numB
       push ax
       call GCD                  ; call the GCD routine
       mov  numGCD, ax           ; retrieve the result
       
       mov  si, offset maxMsg    ; display "The GCD is"
       call print_string

       mov  ax, numGCD           ; display GCD value
       call print_num
       
       mov  si, offset newline   ; issue newline
       call print_string
       
       jmp  CodeStart            ; go back for more
                     
EndProg:
       mov  si, offset fini      ; display "Fini"
       call print_string

       ret                       ; return to caller


; GCD(a,b) takes a and b from the stack and 
; returns the greatest common divisor in AX.
;
; int gcd(int a, int b)  =  Euclidean Algorithm for GCD
;    int r = a % b
;    if (r == 0)
;	   return b
;    return gcd(b, r)


GCD    PROC
       pop  cx                   ; save return address in CX
       mov  dx, 0                ; put dividend in DX:AX
       pop  bx                   ; get B, divisor
       pop  ax                   ; get A, dividend
       div  bx                   ; divide A / B; remainder in DX
       cmp  dx, 0
       je   ReturnB

       push cx                   ; save return address on stack       
       push bx                   ; push B onto stack
       push dx                   ; push remainder onto stack
       call GCD
                                 ; ax now contains the GCD
       ret                       ; return to caller

ReturnB:
       mov  ax, bx               ; copy B (answer) into AX
       push cx                   ; push return address onto stack
       ret                       ; return to caller
GCD    ENDP

DEFINE_PRINT_STRING
DEFINE_SCAN_NUM
DEFINE_PRINT_NUM
DEFINE_PRINT_NUM_UNS
