                ; by Soji Yamakawa 2017/10/24
                ; Division 32-bit / 32-bit signed integers
                EXPORT  DIV32_NUMER
                EXPORT  DIV32_DENOM
                EXPORT  DIV32
                EXPORT  UDIV32

DIV32_NUMER     RZB     4       ; Input Numerator,   Output Remainder
DIV32_NUM_HI    EQU     DIV32_NUMER
DIV32_NUM_LO    EQU     DIV32_NUMER+2
DIV32_DENOM     RZB     4       ; Input Denominator, Output Quotient
DIV32_DEN_HI    EQU     DIV32_DENOM
DIV32_DEN_LO    EQU     DIV32_DENOM+2

DIV32_REM_HI    EQU     DIV32_NUM_HI
DIV32_REM_LO    EQU     DIV32_NUM_LO
DIV32_SUM       EQU     DIV32_DENOM
DIV32_SUM_HI    EQU     DIV32_SUM
DIV32_SUM_LO    EQU     DIV32_SUM+2

DIV32           PSHS    A,B,X,Y,U

                LDD     DIV32_DEN_HI,PCR
                STA     DIV32_SIGN_DEN,PCR
                BPL     DIV32_DEN_SIGN_SET

                COMA
                COMB
                STD     DIV32_DEN_HI,PCR
                LDD     DIV32_DEN_LO,PCR
                COMA
                COMB
                ADDD    #1
                STD     DIV32_DEN_LO,PCR
                BCC     DIV32_DEN_SIGN_SET
                ; Added 1, Carry set -> D=0
                INCB
                ADDD    DIV32_DEN_HI,PCR
                STD     DIV32_DEN_HI,PCR
DIV32_DEN_SIGN_SET

                LDD     DIV32_NUM_HI,PCR
                STA     DIV32_SIGN_NUM,PCR
                BPL     DIV32_NUM_SIGN_SET

                COMA
                COMB
                STD     DIV32_NUM_HI,PCR
                LDD     DIV32_NUM_LO,PCR
                COMA
                COMB
                ADDD    #1
                STD     DIV32_NUM_LO,PCR
                BCC     DIV32_NUM_SIGN_SET
                ; Added 1, Carry set -> D=0
                INCB
                ADDD    DIV32_NUM_HI,PCR
                STD     DIV32_NUM_HI,PCR
DIV32_NUM_SIGN_SET

                BSR     UDIV32

                LDA     DIV32_SIGN_NUM,PCR
                BPL     DIV32_REM_SIGN_SET
                LDX     #0

                LDD     DIV32_REM_LO,PCR
                COMA
                COMB
                ADDD    #1
                STD     DIV32_REM_LO,PCR
                LDB     #0  ; CLRB will also clear Carry flag :-P
                ROLB
                ABX
                LDD     DIV32_REM_HI,PCR
                COMA
                COMB
                LEAX    D,X
                STX     DIV32_REM_HI,PCR
                LDA     #-1 ; This is dealing with NUM<0 case.
DIV32_REM_SIGN_SET

                EORA    DIV32_SIGN_DEN,PCR
                BPL     DIV32_QUO_SIGN_SET
                LDX     #0

                LDD     DIV32_SUM_LO,PCR
                COMA
                COMB
                ADDD    #1
                STD     DIV32_SUM_LO,PCR
                LDB     #0  ; CLRB will also clear Carry flag :-P
                ROLB
                ABX
                LDD     DIV32_SUM_HI,PCR
                COMA
                COMB
                LEAX    D,X
                STX     DIV32_SUM_HI,PCR
DIV32_QUO_SIGN_SET

                PULS    A,B,X,Y,U,PC


DIV32_SCALED    RZB     4
DIV32_SCA_HI    EQU     DIV32_SCALED
DIV32_SCA_LO    EQU     DIV32_SCALED+2
DIV32_SIGN      RZB     2
DIV32_SIGN_NUM  EQU     DIV32_SIGN
DIV32_SIGN_DEN  EQU     DIV32_SIGN+1

UDIV32          PSHS    A,B,X,Y,U

                LDD     DIV32_DEN_HI,PCR
                STD     DIV32_SCA_HI,PCR
                LDD     DIV32_DEN_LO,PCR
                STD     DIV32_SCA_LO,PCR

                LDD     #1
                STD     DIV32_MUL_LO,PCR
                LDX     #0
                STX     DIV32_MUL_HI,PCR
                STX     DIV32_SUM_LO,PCR

                LDD     DIV32_REM_HI,PCR
                LDU     DIV32_REM_LO,PCR

UDIV32_UPSHIFTLOOP
                CMPD    DIV32_SCA_HI,PCR
                BLO     UDIV32_UPSHIFTEND
                BHI     UDIV32_UPSHIFT
                CMPU    DIV32_SCA_LO,PCR
                BLO     UDIV32_UPSHIFTEND
UDIV32_UPSHIFT
                LSL     DIV32_SCA_LO+1,PCR
                ROL     DIV32_SCA_LO  ,PCR
                ROL     DIV32_SCA_HI+1,PCR
                ROL     DIV32_SCA_HI  ,PCR

                LSL     DIV32_MUL_LO+1,PCR
                ROL     DIV32_MUL_LO  ,PCR
                ROL     DIV32_MUL_HI+1,PCR
                ROL     DIV32_MUL_HI  ,PCR

                BPL     UDIV32_UPSHIFTLOOP
UDIV32_UPSHIFTEND

                ; X must be kept zero to this line.
                ; X serves as DIV32_SUM_HI
                ; Y serves as DIV32_SUM_LO

                LDY     #0

UDIV32_LOOP     LDD     DIV32_REM_HI,PCR
                BEQ     UDIV32_LAST16_CLEAR_SCA_HI
                CMPD    DIV32_SCA_HI,PCR
                BLO     UDIV32_DONTADD
                BHI     UDIV32_ADD
                LDD     DIV32_REM_LO,PCR
                CMPD    DIV32_SCA_LO,PCR
                BLO     UDIV32_DONTADD

UDIV32_ADD      
                ; Adding MUL to SUM is nothing more than OR operation 
                ; because only one bit of MUL is on, and that bit is off
                ; in the SUM before addition.
                ; Therefore, no worry of carry from Y to X.
                LDD     DIV32_MUL_LO,PCR
                LEAY    D,Y
DIV32_MUL_HIM2  LEAX    $7FFF,X ; $7FFF is replaced with MUL_HI
DIV32_MUL_HI    EQU     DIV32_MUL_HIM2+2

                LDD     DIV32_REM_LO,PCR
                SUBD    DIV32_SCA_LO,PCR
                STD     DIV32_REM_LO,PCR
                LDD     DIV32_REM_HI,PCR
                SBCB    DIV32_SCA_HI+1,PCR
                SBCA    DIV32_SCA_HI,PCR
                STD     DIV32_REM_HI,PCR

UDIV32_DONTADD  LSR     DIV32_SCA_HI  ,PCR
                ROR     DIV32_SCA_HI+1,PCR
                ROR     DIV32_SCA_LO  ,PCR
                ROR     DIV32_SCA_LO+1,PCR

                LSR     DIV32_MUL_HI  ,PCR
                ROR     DIV32_MUL_HI+1,PCR
                ROR     DIV32_MUL_LO  ,PCR
                ROR     DIV32_MUL_LO+1,PCR

                BCC     UDIV32_LOOP
                BRA     UDIV32_LOOPEND


UDIV32_LAST16_CLEAR_SCA_HI
UDIV32_LAST16_CLEAR_SCA_HI_LOOP
                LDD     DIV32_SCA_HI,PCR
                ORA     DIV32_MUL_HI,PCR    ; Just in case
                ORB     DIV32_MUL_HI+1,PCR  ; Just in case
                CMPD    #0
                BEQ     UDIV32_LAST16_LOOP_IN

                LSR     DIV32_SCA_HI  ,PCR
                ROR     DIV32_SCA_HI+1,PCR
                ROR     DIV32_SCA_LO  ,PCR
                ROR     DIV32_SCA_LO+1,PCR

                LSR     DIV32_MUL_HI  ,PCR
                ROR     DIV32_MUL_HI+1,PCR
                ROR     DIV32_MUL_LO  ,PCR
                ROR     DIV32_MUL_LO+1,PCR

                BCC     UDIV32_LAST16_CLEAR_SCA_HI_LOOP
                BRA     UDIV32_LOOPEND


UDIV32_LAST16_LOOP_IN
                LDD     DIV32_REM_LO,PCR
UDIV32_LAST16_LOOP
                CMPD    DIV32_SCA_LO,PCR
                BLO     UDIV32_LAST16_DONTADD

                ; Adding MUL to SUM is nothing more than OR operation 
                ; because only one bit of MUL is on, and that bit is off
                ; in the SUM before addition.
                ; Therefore, no worry of carry from Y to X.
DIV32_MUL_LOM2  LEAY    $7FFF,Y ; $7FFF is replaced with MUL_LO
DIV32_MUL_LO    EQU     DIV32_MUL_LOM2+2
                SUBD    DIV32_SCA_LO,PCR

UDIV32_LAST16_DONTADD   
                LSR     DIV32_SCA_LO  ,PCR
                ROR     DIV32_SCA_LO+1,PCR

                LSR     DIV32_MUL_LO  ,PCR
                ROR     DIV32_MUL_LO+1,PCR

                BCC     UDIV32_LAST16_LOOP

                STD     DIV32_REM_LO,PCR


UDIV32_LOOPEND  STY     DIV32_SUM_LO,PCR
                STX     DIV32_SUM_HI,PCR

                PULS    A,B,X,Y,U,PC
