;本程式來源http://www.wgmarshall.freeserve.co.uk/8051Math.asm
;*****************************************************************
;*                                                               *
;*     Integer Maths Subroutines for the 8051 microcontroller    *
;*                    W.G.Marshall 2005 Vsn 1.2                  *
;*                                                               *
;*****************************************************************

; All parameters in user-set register bank
; DIV32 requires the use of register bank 1 as well

               BSEG

SignX:         dbit     1
SignY:         dbit     1   

;=================================================================
; subroutine Cr0
; 8-Bit 2's Complement -> magnitude / Sign Bit Conversion
;
; input:     r0 = signed byte
;
; output:    r0 = magnitude
;            Bit SignX = sign (SignX is set if r0 is a negative number)
;
; alters:    
;=================================================================

Cr0:           xch      a, r0          ; read X into accumulator
               clr      SignX          ; clear sign flag
               jnb      acc.7, Cr0a    ; X is negative if bit 7 is 1
               cpl      a              ; X negative, find abs value
               inc      a              ; X = complement(X)+1
               setb     SignX          ; set sign flag
Cr0a:          xch      a, r0          ; save magnitude
               ret

;=================================================================
; subroutine Cr1
; 8-Bit 2's Complement -> magnitude / Sign Bit Conversion
;
; input:     r1 = signed byte
;
; output:    r1 = magnitude
;            Bit SignY = sign (SignY is set if r1 is a negative number)
;
; alters:    
;=================================================================

Cr1:           xch      a, r1          ; read Y into accumulator
               clr      SignY          ; clear sign flag
               jnb      acc.7, Cr1a    ; Y is negative if bit 7 is 1
               cpl      a              ; Y negative, find abs value
               inc      a              ; Y = complement(Y)+1
               setb     SignY          ; set sign flag
Cr1a:          xch      a, r1          ; save magnitude
               ret


;===================================================================
; subroutine Cr0r1
; 16-Bit 2's Complement -> magnitude / Sign Bit Conversion
;
; input:    r1, r0 = signed word
;
; output:   r1, r0 = magnitude
;           Bit SignX = sign (SignX is set if negative number)
;
; alters:   C
;===================================================================

Cr0r1:         xch     a, r1
               clr     SignX           ; clear sign flag
               jnb     acc.7, C0a      ; high byte negative?
               setb    SignX           ; set sign flag
               xch     a, r0           ; number is negative
               cpl     a               ; complement
               add     a, #1           ; and add +1
               xch     a, r0           ; get MS byte
               cpl     a               ; complement
               addc    a, #0
C0a:           xch     a, r1
               ret


;====================================================================
; subroutine Cr2r3
; 16-Bit 2's Complement -> magnitude / Sign Bit Conversion
;
; input:    r3, r2 = signed word
;
; output:   r3, r2 = magnitude
;           Bit SignY = sign (SignY is set if negative number)
;
; alters:   acc, C
;====================================================================

Cr2r3:         mov     a, r3
               clr     SignY           ; clear sign flag
               jnb     acc.7, C1a      ; high byte negative?
               setb    SignY           ; set sign flag
               xch     a, r2           ; number is negative
               cpl     a               ; complement
               add     a, #1           ; and add +1
               xch     a, r2           ; get MS byte
               cpl     a               ; complement
               addc    a, #0
               mov     r3, a
C1a:           ret


;====================================================================
; subroutine Cr4r5
; 16-Bit 2's Complement -> magnitude / Sign Bit Conversion
;
; input:    r5, r4 = signed word
;
; output:   r5, r4 = magnitude
;           Bit SignY = sign (SignY is set if negative number)
;
; alters:   acc, C
;====================================================================

Cr4r5:         mov     a, r5
               clr     SignY           ; clear sign flag
               jnb     acc.7, C4a      ; high byte negative?
               setb    SignY           ; set sign flag
               xch     a, r4           ; number is negative
               cpl     a               ; complement
               add     a, #1           ; and add +1
               xch     a, r4           ; get MS byte
               cpl     a               ; complement
               addc    a, #0
               mov     r5, a
C4a:           ret


;====================================================================
; subroutine Cr0r3
; 32-Bit 2's Complement -> magnitude / Sign Bit Conversion
;
; input:    r3, r2, r1, r0 = signed word
;
; output:   r3, r2, r1, r0 = magnitude
;           Bit SignX = sign (SignX is set if negative number)
;
; alters:   acc
;====================================================================

Cr0r3:         mov     a, r3
               clr     SignX
               jnb     acc.7, C2a      ; negative if bit 7 is 1
               setb    SignX           ; set sign flag
               mov     a, r0           ; number is negative
               cpl     a               ; complement
               add     a, #1           ; and add +1
               mov     r0, a 
               mov     a, r1           ; get next byte
               cpl     a               ; complement
               addc    a, #0
               mov     r1,a
               mov     a, r2           ; get next byte
               cpl     a               ; complement
               addc    a, #0
               mov     r2,a
               mov     a, r3           ; get next byte
               cpl     a               ; complement
               addc    a, #0
               mov     r3, a
C2a:           ret


;==================================================================
; subroutine Mr0
; 8-Bit magnitude / Sign Bit -> 2's Complement Conversion
;
; input:    r0 = magnitude
;           Bits SignX & SignY = sign bits of operands X and Y
;           (set if negative)
;
; output:   r0 = signed byte
;
; alters:   
;==================================================================

Mr0:           jb      SignX, Mr0b     ; test X sign
               jb      SignY, Mr0a     ; test Y sign
               ret

Mr0b:          jnb     SignY, Mr0a
               ret

Mr0a:          xch     a, r0           ; if r0 negative, get abs value
               cpl     a               ; complement magnitude of X
               inc     a               ; r0 = complement(r0)+1
               xch     a, r0           ; save in 2's complement
               ret                     ; done


;====================================================================
; subroutine Mr0r1
; 16-Bit magnitude / Sign Bit -> 2's Complement Conversion
;
; input:    r1, r0 = magnitude
;           Bits SignX & SignY = sign bits of operands X and Y
;           (set if negative)
;
; output:   r1, r0 = signed word
;
; alters:   C
;====================================================================

Mr0r1:         jb      SignX, Mr0r1b   ; test X sign
               jb      SignY, Mr0r1a   ; test Y sign
               ret

Mr0r1b:        jnb     SignY, Mr0r1a
               ret

Mr0r1a:        xch     a, r0           ; negate number
               cpl     a               ; complement
               add     a, #1           ; and add +1
               xch     a, r0 
               xch     a, r1           ; get next byte
               cpl     a               ; complement
               addc    a, #0
               xch     a, r1
               ret


;====================================================================
; subroutine Mr0r3
; 32-Bit magnitude / Sign Bit -> 2's Complement Conversion
;
; input:    r3, r2, r1, r0 = magnitude
;           Bits SignX & SignY = sign bits of operands X and Y
;           (set if negative)
;
; output:   r3, r2, r1, r0 = signed word
;
; alters:   acc, C
;====================================================================

Mr0r3:         jb      SignX, Mr0r3b   ; test X sign
               jb      SignY, Mr0r3a   ; test Y sign
               ret

Mr0r3b:        jnb     SignY, Mr0r3a
               ret

Mr0r3a:        mov     a, r0           ; negate number
               cpl     a               ; complement
               add     a, #1           ; and add +1
               mov     r0, a 
               mov     a, r1           ; get next byte
               cpl     a               ; complement
               addc    a, #0
               mov     r1, a
               mov     a, r2           ; get next byte
               cpl     a               ; complement
               addc    a, #0
               mov     r2, a
               mov     a, r3           ; get next byte
               cpl     a               ; complement
               addc    a, #0
               mov     r3, a
               ret                     ; done


;====================================================================
; subroutine CONV816
; 8-bit Signed number to 16-Bit Signed number conversion
;
; input:     r0 = X
;
; output:    r1, r0 = X with sign extended to 16 bits
;
; alters:
;====================================================================

CONV816:       xch    A, r0
               mov    r1, #0
               jnb    acc.7, Pos
               dec    r1
Pos:           xch    a, r0
               ret


;====================================================================
; subroutine MAG16
; 16-Bit Signed number to Magnitude conversion
;
; input:     r1, r0 = X
;
; output:    r1, r0 = |X|
;
; alters:    C
;====================================================================

MAG16:         xch    a, r1            ; high byte into accumulator
               jnb    acc.7, Mag1      ; exit if positive
               xch    a, r0            ; number is negative
               cpl    a                ; complement
               add    a, #1            ; add +1
               xch    a, r0            ; get MS byte
               cpl    a                ; complement
               addc   a, #0
Mag1:          xch    a, r1
               ret


;====================================================================
; subroutine NEG16
; 16-Bit Negate
;
; input:     r1, r0 = X
;
; output:    r1, r0 = -X
;
; alters:    C
;====================================================================

NEG16:         xch    a, r0
               cpl    a                ; complement
               add    a, #1            ; add +1
               xch    a, r0
               xch    a, r1            ; get MS byte
               cpl    a                ; complement
               addc   a, #0
               xch    a, r1
               ret


;====================================================================
; subroutine LADD8
; 8-Bit Signed (2's Complement) Addition with Limiter
;
; input:     r0 = X
;            r1 = Y
;
; output:    r0 = signed sum S = X + Y
;            80h < S < 7Fh
;
; alters:    C, OV
;====================================================================

LADD8:         xch     a, r0           ; load X into acc
               add     a, r1           ; add Y
               jnb     OV, PosLim8     ; Exit if no overflow
               mov     a, #7fh
               jnc     PosLim8         ; Max positive?
               add     a, #01h         ; Limit to max negative
PosLim8:       xch     a, r0
               ret


;====================================================================
; subroutine ADD16
; 16-Bit Signed (2's Complement) Addition
;
; input:     r1, r0 = X
;            r3, r2 = Y
;
; output:    r1, r0 = signed sum S = X + Y
;            SignX is set if the result has a carry out
;            SignY is set if the result is out of range
;
; alters:    C, OV
;====================================================================

ADD16:         xch     a, r0           ; load X low byte into acc
               add     a, r2           ; add Y low byte
               xch     a, r0           ; put result in Z low byte
               xch     a, r1           ; load X high byte into acc
               addc    a, r3           ; add Y high byte with carry
               xch     a, r1           ; save result in Z high byte
               mov     SignX, C        ; SignX = Carry flag
               mov     C, OV
               mov     SignY, C        ; SignY = Overflow flag
               ret


;====================================================================
; subroutine LADD16
; 16-Bit Signed (2's Complement) Addition with Limiter
;
; input:     r1, r0 = X
;            r3, r2 = Y
;
; output:    r1, r0 = signed sum S = X + Y
;            8000h < Z < 7FFFh
;
; alters:    C, OV
;====================================================================

LADD16:        call    ADD16
               jnb     SignY, NoOver   ; Exit if no overflow
               jnb     SignX, PosLim
               mov     r0, #00h        ; Limit to max negative
               mov     r1, #80h
               ret

PosLim:        mov     r0, #0FFh       ; Limit to max positive
               mov     r1, #7fh
NoOver:        ret
     

;====================================================================
; subroutine ADD32
; 32-Bit Signed (2's Complement) Addition
;
; input:     r3, r2, r1, r0 = X
;            r7, r6, r5, r4 = Y
;
; output:    r3, r2, r1, r0 = signed sum S = X + Y
;            SignX is set if the result has a carry out
;            SignY is set if the result is out of range
;
; alters:    C, OV
;====================================================================

ADD32:         xch     a, r0           ; load X low byte into acc
               add     a, r4           ; add Y low byte
               xch     a, r0           ; save result
               xch     a, r1           ; load X next byte into acc
               addc    a, r5           ; add Y next byte with carry
               xch     a, r1           ; save result
               xch     a, r2           ; load X next byte into acc
               addc    a, r6           ; add Y next byte
               xch     a, r2           ; save result
               xch     a, r3           ; load X high byte into acc
               addc    a, r7           ; add Y high byte with carry
               xch     a, r3
               mov     SignX, C        ; SignX = Carry flag
               mov     C, OV
               mov     SignY, C        ; SignY = Overflow flag
               ret


;====================================================================
; subroutine SUB16
; 16-Bit Signed (2's Complement) Subtraction
;
; input:     r1, r0 = X
;            r3, r2 = Y
;
; output:    r1, r0 = signed difference D = X - Y
;            Carry C is set if the result (D) is out of range.
;
; alters:    acc, C, OV
;====================================================================

SUB16:         mov     a, r0           ; load X low byte into acc
               clr     C               ; clear carry flag
               subb    a, r2           ; subract Y low byte
               mov     r0, a           ; put result in Z low byte
               mov     a, r1           ; load X high into accumulator
               subb    a, r3           ; subtract Y high with borrow
               mov     r1, a           ; save result in Z high byte
               mov     C, OV
               ret


;====================================================================
; subroutine SUB32
; 32-Bit Signed (2's Complement) subtraction
;
; input:     r3, r2, r1, r0 = X
;            r7, r6, r5, r4 = Y
;
; output:    r3, r2, r1, r0 = signed difference D = X - Y
;            Carry C is set if the result (D) is out of range.
;
; alters:    acc, C, OV
;====================================================================

SUB32:         mov     a, r0           ; load X low byte into acc
               clr     C               ; clear carry flag
               subb    a, r4           ; subract Y low byte
               mov     r0, a           ; put result in Z low byte
               mov     a, r1           ; repeat with other bytes...
               subb    a, r5
               mov     r1, a
               mov     a, r2
               subb    a, r6
               mov     r2, a
               mov     a, r3
               subb    a, r7
               mov     r3, a
               mov     C, OV           ; set C if external borrow
               ret


;==================================================================
; subroutine MUL8
; 8-Bit x 8-Bit to 16-Bit Product Signed Multiply
; 2's Complement format
;
; input:    r0 = multiplicand X
;           r1 = multiplier Y
;
; output:   r1, r0 = product P = X x Y.
;           
; calls:    UMUL8, Cr0, Cr1, Mr0r1
;
; alters:   C, Bits SignX & SignY
;==================================================================

MUL8:          acall   Cr0             ; 2's comp -> Mag/Sign
               acall   Cr1             ; 2's comp -> Mag/Sign
               acall   UMUL8
               acall   Mr0r1           ; Mag/Sign -> 2's Comp
               ret


;==================================================================
; subroutine UMUL8
; 8-Bit x 8-Bit to 16-Bit Product Unsigned Multiply
;
; input:    r0 = multiplicand X
;           r1 = multiplier Y
;
; output:   r1, r0 = product P = X x Y.
;
; alters:
;==================================================================

UMUL8:         push    b
               xch     a, r0           ; read X and ...
               mov     b, r1           ; ... Y
               mul     ab              ; multiply X and Y
               mov     r1, b           ; save result high ...
               xch     a, r0           ; ... and low
               pop     b
               ret


;====================================================================
; subroutine MUL816
; 8-Bit x 16-Bit to 32-Bit Product signed Multiply
; 2's Complement format
;
; input:    r0 = multiplicand X
;           r3, r2 = multiplier Y
;
; output:   r3, r2, r1, r0 = product P = X x Y (r3 = sign extension)
;
; calls:    Cr0, Cr2r3, Mr0r3
;
; alters:   acc, C, r4, Bits SignX & SignY
;====================================================================

MUL816:        push    b
               acall   Cr0             ; 2's comp -> Mag/Sign
               acall   Cr2r3           ; 2's comp -> Mag/Sign
               mov     a, r0           ; load X into acc
               mov     b, r2           ; load Y low into B
               mul     ab              ; multiply
               xch     a, r0           ; save X*YL low, reload X
               mov     r4, b           ; temp save X*YL high
               mov     b, r3           ; load Y high into B
               mul     ab              ; multiply
               add     a, r4           ; add X*YL high and X*YH low
               mov     r1, a           ; save result
               clr     a
               addc    a, b            ; X*YH high + 0 + carry flag
               mov     r2, a           ; save result
               mov     r3, #0          ; MS result = 0
               acall   Mr0r3           ; Mag/Sign -> 2's Comp
               pop     b
               ret


;====================================================================
; subroutine MUL16
; 16-Bit x 16-Bit to 32-Bit Product Signed Multiply
; 2's Complement format
;
; input:    r1, r0 = multiplicand X
;           r3, r2 = multiplier Y
;
; output:   r3, r2, r1, r0 = product P = X x Y
;
; calls:    UMUL16, Cr0r1, Cr2r3, Mr0r3
;
; alters:   acc, C, Bits SignX & SignY
;====================================================================

MUL16:         acall   Cr0r1           ; 2's comp -> Mag/Sign
               acall   Cr2r3           ; 2's comp -> Mag/Sign
               acall   UMUL16
               acall   Mr0r3           ; Mag/Sign -> 2's Comp
               ret


;====================================================================
; subroutine UMUL16
; 16-Bit x 16-Bit to 32-Bit Product Unsigned Multiply
;
; input:    r1, r0 = multiplicand X
;           r3, r2 = multiplier Y
;
; output:   r3, r2, r1, r0 = product P = X x Y
;
; alters:   acc, C
;====================================================================

UMUL16:        push    b
               push    dpl
               push    dph
               mov     a, r0
               mov     b, r2
               mul     ab              ; multiply XL x YL
               mov     dpl, b          ; temp save XLYL h
               xch     a, r0           ; save XLYL l, reload XL
               mov     b, r3
               mul     ab              ; multiply XL x YH
               add     a, dpl
               mov     dpl, a          ; temp save XLYH l + XLYL h
               clr     a
               addc    a, b
               mov     dph, a          ; temp save XLYH h + C
               mov     a, r2
               mov     b, r1
               mul     ab              ; multiply XH x YL
               add     a, dpl
               mov     dpl, a          ; save XLYH l + XLYL h + XHYL l
               mov     a, dph
               addc    a, b            ; (XLYH h + C) + XHYL h
               mov     dph, a
               mov     f0, C           ; save intermediate carry
               mov     a, r3
               mov     b, r1
               mul     ab              ; multiply XH x YH
               add     a, dph          ; (XLYH h + C) + XHYL h + XHYH l
               mov     r2, a
               clr     a
               addc    a, b            ; XHYH h + C
               mov     C, f0           ; retrieve intermediate carry
               addc    a, #0
               mov     r3, a
               mov     r1, dpl
               pop     dph
               pop     dpl
               pop     b
               ret


;====================================================================
; subroutine MAC16
; 16-Bit x 16-Bit to 32-Bit Product signed Multiply-Accumulate
; 2's Complement format
;
; input:    r1, r0 = multiplicand X
;           r3, r2 = multiplier Y
;           r7, r6, r5, r4 = 32-bit accumulator Ar
;
; output:   r7, r6, r5, r4 = accumulated result Ar =  Ar + (X x Y)
;           r3, r2, r1, r0 = multiply result M = X x Y
;           Carry C set if overflow
;
; calls:    MUL16
;
; alters:   acc, C, Bits SignX & SignY
;====================================================================

MAC16:         acall  MUL16
               mov    A, r4
               add    A, r0
               mov    r4, A
               mov    A, r5
               addc   A, r1
               mov    r5, A
               mov    A, r6
               addc   A, r2
               mov    r6, A
               mov    A, r7
               addc   A, r3
               mov    r7, A
               mov    C, OV
               ret


;===============================================================
; subroutine DIV8
; 8-Bit / 8-Bit to 8-Bit Quotient & Remainder signed Divide
; 2's Complement Format
;
; input:    r0 = Dividend X
;           r1 = Divisor Y
;
; output:   r0 = quotient Q of division Q = X / Y
;           r1 = remainder 
;           
; calls:    Cr0, Cr1, Mr0
;
; alters:   acc, C, Bits SignX & SignY
;===============================================================

DIV8:          acall   Cr0             ; 2's comp -> Mag/Sign
               acall   Cr1             ; 2's comp -> Mag/Sign
               acall   UDIV8
               acall   Mr0             ; Mag/Sign -> 2's Comp
               ret


;===============================================================
; subroutine UDIV8
; 8-Bit / 8-Bit to 8-Bit Quotient & Remainder Unsigned Divide
;
; input:    r0 = Dividend X
;           r1 = Divisor Y
;
; output:   r0 = quotient Q of division Q = X / Y
;           r1 = remainder 
;           ;
; alters:   acc, C
;===============================================================

UDIV8:         push    b
               mov     a, r0           ; read X and ...
               mov     b, r1           ; ... Y
               div     ab              ; divide X and Y
               mov     r0, a           ; save result quotient
               mov     r1, b           ; save remainder
               pop     b
               ret


;====================================================================
; subroutine DIV16
; 16-Bit / 16-Bit to 16-Bit Quotient & remainder signed Divide
; 2's Complement Format
;
; input:    r1, r0 = Dividend X
;           r3, r2 = Divisor Y
;
; output:   r1, r0 = quotient Q of division Q = X / Y
;           r3, r2 = remainder 
;           Carry C is set if Y = 0, i.e. divide by 0 attempted
;
; calls:    UDIV16, Cr0r1, Cr2r3, Mr0r1
;
; alters:   acc, r4, r5, r6, r7, flags, Bits SignX & SignY
;====================================================================

DIV16:         mov     a, r3           ; get divisor high byte
               orl     a, r2           ; OR with low byte
               jnz     div_OK          ; divisor OK if not 0
               setb    C               ; else, overflow
               ret

div_OK:        push    dpl
               push    dph
               push    b
               acall   Cr0r1           ; 2's comp -> Mag/Sign
               acall   Cr2r3           ; 2's comp -> Mag/Sign
               acall   UDIV16
               acall   Mr0r1           ; Mag/Sign -> 2's Comp
               clr     C
               pop     b
               pop     dph
               pop     dpl
               ret                     ; done


;====================================================================
; subroutine UDIV16
; 16-Bit / 16-Bit to 16-Bit Quotient & Remainder Unsigned Divide
;
; input:    r1, r0 = Dividend X
;           r3, r2 = Divisor Y
;
; output:   r1, r0 = quotient Q of division Q = X / Y
;           r3, r2 = remainder 
;
; alters:   acc, B, dpl, dph, r4, r5, r6, r7, flags
;====================================================================

UDIV16:        mov     r7, #0          ; clear partial remainder
               mov     r6, #0
               mov     B, #16          ; set loop count

div_loop:      clr     C               ; clear carry flag
               mov     a, r0           ; shift the highest bit of
               rlc     a               ; the dividend into...
               mov     r0, a
               mov     a, r1
               rlc     a
               mov     r1, a
               mov     a, r6           ; ... the lowest bit of the
               rlc     a               ; partial remainder
               mov     r6, a
               mov     a, r7
               rlc     a
               mov     r7, a
               mov     a, r6           ; trial subtract divisor
               clr     C               ; from partial remainder
               subb    a, r2
               mov     dpl, a
               mov     a, r7
               subb    a, r3
               mov     dph, a
               cpl     C               ; complement external borrow
               jnc     div_1           ; update partial remainder if
                                       ; borrow
               mov     r7, dph         ; update partial remainder
               mov     r6, dpl
div_1:         mov     a, r4           ; shift result bit into partial
               rlc     a               ; quotient
               mov     r4, a
               mov     a, r5
               rlc     a
               mov     r5, a
               djnz    B, div_loop
               mov     a, r5           ; put quotient in r0, and r1
               mov     r1, a
               mov     a, r4
               mov     r0, a
               mov     a, r7           ; get remainder, saved before the
               mov     r3, a           ; last subtraction
               mov     a, r6
               mov     r2, a
               ret


;====================================================================
; subroutine DIV32
; 32-Bit / 16-Bit to 32-Bit Quotient & remainder signed Divide
; 2's Complement Format
;
; input:    r3, r2, r1, r0 = Dividend X
;           r5, r4 = Divisor Y
;
; output:   r3, r2, r1, r0 = quotient Q of division Q = X / Y
;           r7, r6, r5, r4 = remainder
;           Carry C is set if Y = 0, i.e. divide by 0 attempted
;
; calls:    UDIV32, Cr0r3, Cr4r5, Mr0r3
;
; alters:   acc, flags, Bits SignX & SignY
;====================================================================

DIV32:         mov     a, r4           ; get divisor high byte
               orl     a, r5           ; OR with low byte
               jnz     div32_OK        ; divisor OK if not 0
               setb    C               ; else, overflow
               ret

div32_OK:      acall   Cr0r3           ; 2's comp -> Mag/Sign
               acall   Cr4r5           ; 2's comp -> Mag/Sign
               acall   UDIV32
               acall   Mr0r3           ; Mag/Sign -> 2's Comp
               clr     C               ; divisor is not 0
               ret                     ; done


;====================================================================
; subroutine UDIV32
; 32-Bit / 16-Bit to 32-Bit Quotient & Remainder Unsigned Divide
;
; input:    r3, r2, r1, r0 = Dividend X
;           r5, r4 = Divisor Y
;
; output:   r3, r2, r1, r0 = quotient Q of division Q = X / Y
;           r7, r6, r5, r4 = remainder
;;
; alters:   acc, flags
;====================================================================

UDIV32:        push    08H             ; Save Register Bank 1
               push    09H
               push    0AH
               push    0BH
               push    0CH
               push    0DH
               push    0EH
               push    0FH
               push    dpl
               push    dph
               push    B
               push    psw
               setb    RS0             ; Select Register Bank 1
               clr     RS1
               mov     r7, #0          ; clear partial remainder
               mov     r6, #0
               mov     r5, #0          
               mov     r4, #0
               mov     B, #32          ; set loop count

div_lp32:      pop     psw
               clr     C               ; clear carry flag
               mov     a, r0           ; shift the highest bit of the
               rlc     a               ; dividend into...
               mov     r0, a
               mov     a, r1
               rlc     a
               mov     r1, a
               mov     a, r2
               rlc     a
               mov     r2, a
               mov     a, r3
               rlc     a
               mov     r3, a
               push    psw
               setb    RS0             ; Select Register Bank 1
               clr     RS1
               mov     a, r4           ; ... the lowest bit of the
               rlc     a               ; partial remainder
               mov     r4, a
               mov     a, r5
               rlc     a
               mov     r5, a
               mov     a, r6
               rlc     a
               mov     r6, a
               mov     a, r7
               rlc     a
               mov     r7, a
               mov     a, r4           ; trial subtract divisor from
               pop     psw             ; partial remainder
               clr     C 
               subb    a, r4
               mov     dpl, a
               mov     a, 0DH
               subb    a, r5
               mov     dph, a
               mov     a, 0EH
               subb    a, #0
               mov     r6, a
               mov     a, 0FH
               subb    a, #0
               mov     r7, a
               cpl     C               ; complement external borrow
               jnc     div_321         ; update partial remainder if
                                       ; borrow
               mov     0FH, r7         ; update partial remainder
               mov     0EH, r6
               mov     0DH, dph
               mov     0CH, dpl
div_321:       push    psw
               setb    RS0             ; Select Register Bank 1
               clr     RS1
               mov     a, r0           ; shift result bit into partial
               rlc     a               ; quotient
               mov     r0, a
               mov     a, r1
               rlc     a
               mov     r1, a
               mov     a, r2
               rlc     a
               mov     r2, a
               mov     a, r3
               rlc     a
               mov     r3, a
               djnz    B, div_lp32

               pop     psw
               mov     r7, 0FH         ; retrieve remainder, saved
               mov     r6, 0EH         ; before the last subtraction
               mov     r5, 0DH
               mov     r4, 0CH
               mov     r3, 0BH         ; retrieve quotient
               mov     r2, 0AH
               mov     r1, 09H
               mov     r0, 08H
               pop     B
               pop     dph
               pop     dpl
               pop     0FH             ; Retrieve Register Bank 1
               pop     0EH
               pop     0DH
               pop     0CH
               pop     0BH
               pop     0AH
               pop     09H
               pop     08H
               ret


;====================================================================
; subroutine MULDIV
; 16-Bit x 16-Bit to 32-Bit Product Signed Multiply followed by
; 32-Bit / 16-Bit to 32-Bit Quotient & remainder signed Divide
; 2's Complement Format
;
; input:    r1, r0 = multiplicand X
;           r3, r2 = multiplier Y
;           r5, r4 = divisor Z
;
; output:   r3, r2, r1, r0 = quotient Q of division Q = (X x Y) / Z
;           r7, r6, r5, r4 = remainder
;           Carry C is set if Z = 0, i.e. divide by 0 attempted
;
; calls:    UMUL16, UDIV32, Cr0r1, Cr2r3, Cr4r5, Mr0r3
;
; alters:   acc, flags, Bits SignX & SignY
;====================================================================

MULDIV:        mov     a, r4           ; get divisor high byte
               orl     a, r5           ; OR with low byte
               jnz     muld_OK         ; divisor OK if not 0
               setb    C               ; else, overflow
               ret

muld_OK:       lcall   Cr0r1           ; 2's comp -> Mag/Sign
               lcall   Cr2r3           ; 2's comp -> Mag/Sign
               lcall   UMUL16
               jb      SignX, divn1      ; test X sign
divn:          lcall   Cr4r5           ; 2's comp -> Mag/Sign
               lcall   UDIV32
               lcall   Mr0r3           ; Mag/Sign -> 2's Comp
               clr     C               ; divisor is not 0
               ret

divn1:         jbc     SignY, divn       ; test Y sign
               setb    SignY
               sjmp    divn


;====================================================================
; subroutine MACD16
; 16-Bit x 16-Bit to 32-Bit Product signed Multiply-Accumulate
; with table data and data move.
; y(n) = x(n)*h0 + x(n-1)*h1 + x(n-2)*h2 + ......
; Note: Assumes shared program/data space. i.e. PSEN and RD are OR-ed
; together on the board.
; 2's Complement format
;
; input:    B = No. of 16-bit data items in tables (max 63)
;           DPTR --> New Input data (e.g. from ADC)
;           DPTR+2 --> Base of Data Table (x)
;           DPTR+128 --> Base of Multiplier Table (h)
;
; output:   r7, r6, r5, r4 = 32-bit accumulated result
;
; calls:    MUL16
;
; alters:   acc, flags, Bits SignX & 22H
;====================================================================

MACD16:        mov    r4, #0           ; Clear Accumulator
               mov    r5, #0
               mov    r6, #0
               mov    r7, #0

               movx   a, @DPTR
               push   acc              ; Save XNEWL
               inc    DPTR
               movx   a, @DPTR
               push   acc              ; Save XNEWH
               inc    DPTR

Macd1:         movx   a, @DPTR         ; Get x(n)L
               mov    r0, a
               push   acc              ; Save x(n)L
               mov    a, #80H
               movc   a, @a+DPTR       ; Get h(n)L
               mov    r2, a
               inc    DPTR
               movx   a, @DPTR         ; Get x(n)H
               mov    r1, a
               push   acc              ; Save x(n)H
               mov    a, #80H
               movc   a, @a+DPTR       ; Get h(n)H
               mov    r3, a
               lcall  MUL16            ; Do Multiply...
               mov    A, r4            ; then Accumulate..
               add    A, r0
               mov    r4, A
               mov    A, r5
               addc   A, r1
               mov    r5, A
               mov    A, r6
               addc   A, r2
               mov    r6, A
               mov    A, r7
               addc   A, r3
               mov    r7, A
               pop    acc              ; Now move x data
               mov    r1, a
               pop    acc
               mov    r0, a
               pop    acc
               mov    r3, a
               pop    acc
               mov    r2, a
               mov    a, r0
               push   acc
               mov    a, r1
               push   acc
               mov    a, r3            ; Move up x(n)H
               movx   @DPTR, a
               mov    a, #0FFH
               add    a, dpl
               mov    dpl, a
               mov    a, #0FFH
               addc   a, dph
               mov    dph, a
               mov    a, r2            ; Move up x(n)L
               movx   @DPTR, a
               inc    DPTR
               inc    DPTR
               djnz   b, Macd1         ; Whole table processed?
               dec    SP
               dec    SP
               ret


;==================================================================
; subroutine DELAY
;
; input:    r0, r1, r2 = delay loop constants, r0 = coarse loop
;==================================================================

DELAY:         push   dpl
               push   dph
               mov    dpl, r1
               mov    dph, r2
Delay1:        mov    r1, dpl
Delay2:        mov    r2, dph
               djnz   r2, $
               djnz   r1, Delay2
               djnz   r0, Delay1
               pop    dph
               pop    dpl
               ret


end


