; DIVIDE
; Divide one 16-bit number into another, returning the 16-bit result and 
; the remainder. Upon entry, the top of the division fraction (the dividend)
; must be in topH and topL, and the bottom (divisor) in btmH and btmL. 
; If division by zero is attempted, the routine will return immediately with 
; the error code of 0FFh in w. Otherwise, it will perform the division, leaving 
; the remainder in topH and topL and the result (quotient) in qH and qL. 
; Upon return from a successful division, w contains 0. 

; Device data and reset vector
        device  pic16c55,xt_osc,wdt_off,protect_off
        reset   start

        org     8
topH    ds      1       ; MSB of top of fraction. 
topL    ds      1       ; LSB of top of fraction. 
btmH    ds      1       ; MSB of bottom of fraction.
btmL    ds      1       ; LSB of bottom of fraction.
qH      ds      1       ; MSB of quotient. 
qL      ds      1       ; LSB of quotient. 
count   ds      1       ; temporary counter
index   ds      1       ; temporary counter

        org     0
start   mov     !rb,#0  ; Set to outputs to display
        mov     !rc,#0  ; results on LEDs. 
        mov     topH,#33h       ; Problem: divide
        mov     topL,#0Ah       ; 330Ah by 00A3h. 
        mov     btmH,#0h        
        mov     btmL,#0A3h
        call    divide
        mov     rb,qL   ; Display quotient in binary
        mov     rc,qH   ; on LEDs connected to rb and rc. 
        jmp     $       ; Endless loop

Divide  mov     w,btmH  ; Check for division by 0.
        OR      w,btmL
        snz
        retw    255     ; Error code= 255: return. 
        mov     count,#1        ; Otherwise, initialize variables
        clr     index   ; for the division. 
        clr     qH
        clr     qL

:sh_loop        jb      btmH.7,:d1      ; Shift divisor left
        clc             ; until msb is in 
        rl      btmL    ; btmH.7. 
        rl      btmH    ; count = no. of shifts+1. 
        inc     count   
        jmp     :sh_loop
:d1     clc
        rl      qL      ; Shift quotient left.
        rl      qH
        sub     topL,btmL       ; top = top - btm. 
        jc      :d2     ; If top - btm < 0 then 
        sub     topH,#1 ; top = top + btm
        jc      :d2     ; The idea is to do the 
        inc     topH    ; the subtraction and comparison
        add     topL,btmL       ; (top > btm?) in one step. 
        goto    :reentr ; Then, if btm > top, undo
:d2     sub     topH,btmH       ; the subtraction by adding
        sc              ; top and btm back together
        goto    :less
        setb    qL.0
:reentr clc
        rr      btmH
        rr      btmL
        djnz    count,:d1
        ret             ; Return w/ remainder in top
                        ; and result in q. 
:less   ADD     topL,btmL       ; btm > top, so 
        snc             ; undo the subtraction by
        inc     topH    ; adding them back together. 
        ADD     topH,btmH
        goto    :reentr

