NAME Math_32_Module
;
PUBLIC Load_16, ?Load_16?byte
PUBLIC Load_32, ?Load_32?byte
PUBLIC Mul_16,  ?Mul_16?byte
PUBLIC Div_16,  ?Div_16?byte
PUBLIC Add_16,  ?Add_16?byte
PUBLIC Sub_16,  ?Sub_16?byte
PUBLIC Add_32,  ?Add_32?byte
PUBLIC Sub_32,  ?Sub_32?byte
PUBLIC Low_16, Mid_16, High_16
;
Math_32_Data  SEGMENT DATA
Math_32_Code  SEGMENT CODE
;
RSEG  Math_32_Data
?Load_16?byte:    DS 2
?Load_32?byte:    DS 4
?Mul_16?byte:     DS 2
?Div_16?byte:     DS 2
?Add_16?byte:     DS 2
?Sub_16?byte:     DS 2
?Add_32?byte:     DS 4
?Sub_32?byte:     DS 4
OP_0:             DS 1
OP_1:             DS 1
OP_2:             DS 1
OP_3:             DS 1
TMP_0:            DS 1
TMP_1:            DS 1
TMP_2:            DS 1
TMP_3:            DS 1
;
RSEG  Math_32_Code

Load_16:
    ;Load the lower 16 bits of the OP registers with the value supplied
    mov    OP_3,#0
    mov    OP_2,#0
    mov    OP_1,?Load_16?byte
    mov    OP_0,?Load_16?byte + 1
    ret

Load_32:
    ;Load all the OP registers with the value supplied
    mov    OP_3,?Load_32?byte
    mov    OP_2,?Load_32?byte + 1
    mov    OP_1,?Load_32?byte + 2
    mov    OP_0,?Load_32?byte + 3
    ret

Low_16:
    ;Return the lower 16 Bits of the OP registers
    mov    R6,OP_1
    mov    R7,OP_0
    ret

Mid_16:
    ;Return the middle 16 Bits of the OP registers
    mov    R6,OP_2
    mov    R7,OP_1
    ret

High_16:
    ;Return the high 16 Bits of the OP registers
    mov    R6,OP_3
    mov    R7,OP_2
    ret

Add_16:
    ;Add the 16 bits supplied by the caller to the OP registers
    clr    c
    mov    a,OP_0
    addc   a,?Add_16?byte + 1  ;low byte first
    mov    OP_0,a
    mov    a,OP_1
    addc   a,?Add_16?byte      ;high byte + carry
    mov    OP_1,a
    mov    a,OP_2
    addc   a,#0                ;propagate carry only
    mov    OP_2,a
    mov    a,OP_3
    addc   a,#0                ;propagate carry only
    mov    OP_3,a
    ret

Add_32:
    ;Add the 32 bits supplied by the caller to the OP registers
    clr    c
    mov    a,OP_0
    addc   a,?Add_32?byte + 3  ;lowest byte first
    mov    OP_0,a
    mov    a,OP_1
    addc   a,?Add_32?byte + 2  ;mid-lowest byte + carry
    mov    OP_1,a
    mov    a,OP_2
    addc   a,?Add_32?byte + 1  ;mid-highest byte + carry
    mov    OP_2,a
    mov    a,OP_3
    addc   a,?Add_32?byte      ;highest byte + carry
    mov    OP_3,a
    ret

Sub_16:
    ;Subtract the 16 bits supplied by the caller from the OP registers
    clr    c
    mov    a,OP_0
    subb   a,?Sub_16?byte + 1  ;low byte first
    mov    OP_0,a
    mov    a,OP_1
    subb   a,?Sub_16?byte      ;high byte + carry
    mov    OP_1,a
    mov    a,OP_2
    subb   a,#0                ;propagate carry only
    mov    OP_2,a
    mov    a,OP_3
    subb   a,#0                ;propagate carry only
    mov    OP_3,a
    ret

Sub_32:
    ;Subtract the 32 bits supplied by the caller from the OP registers
    clr    c
    mov    a,OP_0
    subb   a,?Sub_32?byte + 3  ;lowest byte first
    mov    OP_0,a
    mov    a,OP_1
    subb   a,?Sub_32?byte + 2  ;mid-lowest byte + carry
    mov    OP_1,a
    mov    a,OP_2
    subb   a,?Sub_32?byte + 1  ;mid-highest byte + carry
    mov    OP_2,a
    mov    a,OP_3
    subb   a,?Sub_32?byte      ;highest byte + carry
    mov    OP_3,a
    ret

Mul_16:
    ;Multiply the 32 bit OP with the 16 bit value supplied
    mov    TMP_3,#0            ;clear out upper 16 bits
    mov    TMP_2,#0
    ;Generate the lowest byte of the result
    mov    b,OP_0
    mov    a,?Mul_16?byte + 1
    mul    ab
    mov    TMP_0,a             ;low-order result
    mov    TMP_1,b
    ;Now generate the next higher order byte
    mov    b,OP_1
    mov    a,?Mul_16?byte + 1
    mul    ab
    add    a,TMP_1             ;low-order result
    mov    TMP_1,a             ;  save
    mov    a,b                 ;  get high-order result
    addc   a,TMP_2             ;  include carry from previous operation
    mov    TMP_2,a             ;  save
    jnc    Mul_loop1
    inc    TMP_3               ;propagate carry into TMP_3
Mul_loop1:
    mov    b,OP_0
    mov    a,?Mul_16?byte
    mul    ab
    add    a,TMP_1             ;low-order result
    mov    TMP_1,a             ;  save
    mov    a,b                 ;  get high-order result
    addc   a,TMP_2             ;  include carry from previous operation
    mov    TMP_2,a             ;  save
    jnc    Mul_loop2
    inc    TMP_3               ;propagate carry into TMP_3
Mul_loop2:
    ;Now starting working on the 3rd byte
    mov    b,OP_0
    mov    a,?Mul_16?byte + 1
    mul    ab
    add    a,TMP_2             ;low-order result
    mov    TMP_2,a             ;  save
    mov    a,b                 ;  get high-order result
    addc   a,TMP_3             ;  include carry from previous operation
    mov    TMP_3,a             ;  save
    ; Now the other half
    mov    b,OP_1
    mov    a,?Mul_16?byte
    mul    ab
    add    a,TMP_2             ;low-order result
    mov    TMP_2,a             ;  save
    mov    a,b                 ;  get high-order result
    addc   a,TMP_3             ;  include carry from previous operation
    mov    TMP_3,a             ;  save
    ; Now finish off the highest order byte
    mov    b,OP_3
    mov    a,?Mul_16?byte + 1
    mul    ab
    add    a,TMP_3             ;low-order result
    mov    TMP_3,a             ;  save
    ; Forget about the high-order result, this is only 32 bit math !
    mov    b,OP_2
    mov    a,?Mul_16?byte
    mul    ab
    add    a,TMP_3             ;low-order result
    mov    TMP_3,a
    ; Now we are all done, move the TMP values back into OP
    mov    OP_0,TMP_0
    mov    OP_1,TMP_1
    mov    OP_2,TMP_2
    mov    OP_3,TMP_3
    ret

Div_16:
    ;Devides the 32 bit OP register by the value supplied
    mov    R7,#0
    mov    R6,#0               ;zero out partial remainder
    mov    TMP_0,#0
    mov    TMP_1,#0
    mov    TMP_2,#0
    mov    TMP_3,#0
    mov    R1,?Div_16?byte     ;load divisor
    mov    R0,?Div_16?byte + 1
    mov    R5,#32
    ;This begins the loop
Div_loop:
    call   Shift_D             ;Shift the dividend and return MSB in C
    mov    a,R6                ;shift carry into LSB of partial remainder
    rlc    a
    mov    R6,a
    mov    a,R7
    rlc    a
    mov    R7,a
    ; now test to see if R7:R6 >= R1:R0
    clr    c
    mov    a,R7                ;Subtract R1 from R7 to see if R1 < R7
    subb   a,R1                ; A=R7-R1, carry set if R7<R1
    jc     Cant_sub
    ; at this point R7>R1 or R7=R1
    jnz    Can_Sub             ;jump if R7>R1
    ; if R7=R1, test for R6>=R0
    clr    c
    mov    a,R6
    subb   a,R0                ; A=R6-R0, carry set if R6<R0
    jc     Cant_Sub
Can_Sub:
    ;Subtract the divisor from the partial remainder
    clr    c
    mov    a,R6
    subb   a,R0                ; A=R6-R0
    mov    R6,a
    mov    a,R7
    subb   a,R1                ; A=R7-R1-Borrow
    mov    R7,a
    setb   c                   ; shift a 1 into the quotient
    jmp    Quot
Cant_Sub:
    ;shift a 0 into the quotient
    clr    c
Quot:
    ;shift the carry bit into the quotient
    call   Shift_Q
    ; test for completion
    djnz   R5,Div_loop
    ; Now we are all done, move the TMP values back into OP
    mov    OP_0,TMP_0
    mov    OP_1,TMP_1
    mov    OP_2,TMP_2
    mov    OP_3,TMP_3
    ret

Shift_D:
    ; Shift the dividend one bit to the left and return the MSB in C
    clr    c
    mov    a,OP_0
    rlc    a
    mov    OP_0,a
    mov    a,OP_1
    rlc    a
    mov    OP_1,a
    mov    a,OP_2
    rlc    a
    mov    OP_2,a
    mov    a,OP_3
    rlc    a
    mov    OP_3,a
    ret

Shift_Q:
    ; Shift the quotient one bit to the left and shift the C into LSB
    mov    a,TMP_0
    rlc    a
    mov    TMP_0,a
    mov    a,TMP_1
    rlc    a
    mov    TMP_1,a
    mov    a,TMP_2
    rlc    a
    mov    TMP_2,a
    mov    a,TMP_3
    rlc    a
    mov    TMP_3,a
    ret

end
