	;; Originally from GBDK by Pascal Felber.
	.area	_CODE

__divschar_rrx_s::       
        ld      hl,#2+1
        add     hl,sp
        
        ld      e,(hl)
        dec     hl
        ld      l,(hl)
        
        ;; Fall through
__divschar_rrx_hds::
        ld      c,l
        
        call    .div8

	ld	l,c
        ld      h,b
        	
	ret
	
__modschar_rrx_s::       
        ld      hl,#2+1
        add     hl,sp
        
        ld      e,(hl)
        dec     hl
        ld      l,(hl)
        
        ;; Fall through
__modschar_rrx_hds::
        ld      c,l

       	call	.div8

	ld	l,e
        ld      h,d
        	
	ret

__divsint_rrx_s::        
        ld      hl,#2+3
        add     hl,sp
        
        ld      d,(hl)
        dec     hl
        ld      e,(hl)
        dec     hl
        ld      a,(hl)
        dec     hl
        ld      l,(hl)
        ld      h,a
        
        ;; Fall through
__divsint_rrx_hds::
	ld	b,h
	ld	c,l

	call	.div16

	ld	l,c
	ld	h,b
	
	ret
	
__modsint_rrx_s::
        ld      hl,#2+3
        add     hl,sp
        
        ld      d,(hl)
        dec     hl
        ld      e,(hl)
        dec     hl
        ld      a,(hl)
        dec     hl
        ld      l,(hl)
        ld      h,a

        ;; Fall through
__modsint_rrx_hds::
	ld	b,h
	ld	c,l

	call	.div16

	ld	l,e
	ld	h,d
	
	ret

	;; Unsigned
__divuchar_rrx_s::       
        ld      hl,#2+1
        add     hl,sp
        
        ld      e,(hl)
        dec     hl
        ld      l,(hl)
        
        ;; Fall through
__divuchar_rrx_hds::
        ld      c,l
	call	.divu8

	ld	l,c
        ld      h,b
        
	ret
	
__moduchar_rrx_s::       
        ld      hl,#2+1
        add     hl,sp
        
        ld      e,(hl)
        dec     hl
        ld      l,(hl)
        
        ;; Fall through
__moduchar_rrx_hds::
        ld      c,l
	call	.divu8

	ld	l,e
        ld      h,d

        ret

__divuint_rrx_s::                
        ld      hl,#2+3
        add     hl,sp
        
        ld      d,(hl)
        dec     hl
        ld      e,(hl)
        dec     hl
        ld      a,(hl)
        dec     hl
        ld      l,(hl)
        ld      h,a

        ;; Fall through
__divuint_rrx_hds::
	ld	b,h
	ld	c,l
	call	.divu16

	ld	l,c
	ld	h,b
	
	ret
	
__moduint_rrx_s::                
        ld      hl,#2+3
        add     hl,sp
        
        ld      d,(hl)
        dec     hl
        ld      e,(hl)
        dec     hl
        ld      a,(hl)
        dec     hl
        ld      l,(hl)
        ld      h,a
        ;; Fall through
        
__moduint_rrx_hds::
	ld	b,h
	ld	c,l

	call	.divu16

	ld	l,e
	ld	h,d
	
	ret
	
.div8::
.mod8::
	LD	A,C		; Sign extend
	RLCA
	SBC	A
	LD	B,A
	LD	A,E		; Sign extend
	RLCA
	SBC	A
	LD	D,A

	; Fall through to .div16
	
	;; 16-bit division
	;; 
	;; Entry conditions
	;;   BC = dividend
	;;   DE = divisor
	;; 
	;; Exit conditions
	;;   BC = quotient
	;;   DE = remainder
	;;   If divisor is non-zero, carry=0
	;;   If divisor is 0, carry=1 and both quotient and remainder are 0
	;;
	;; Register used: AF,BC,DE,HL
.div16::
.mod16::
	;; Determine sign of quotient by xor-ing high bytes of dividend
	;;  and divisor. Quotient is positive if signs are the same, negative
	;;  if signs are different
	;; Remainder has same sign as dividend
	LD	A,B		; Get high byte of dividend
	LD	(.srem),A	; Save as sign of remainder
	XOR	D		; Xor with high byte of divisor
	LD	(.squot),A	; Save sign of quotient
	;; Take absolute value of divisor
	BIT	7,D
	jp	Z,.chkde	; Jump if divisor is positive
	SUB	A		; Substract divisor from 0
	SUB	E
	LD	E,A
	SBC	A		; Propagate borrow (A=0xFF if borrow)
	SUB	D
	LD	D,A
	;; Take absolute value of dividend
.chkde:
	BIT	7,B
	jp	Z,.dodiv	; Jump if dividend is positive
	SUB	A		; Substract dividend from 0
	SUB	C
	LD	C,A
	SBC	A		; Propagate borrow (A=0xFF if borrow)
	SUB	B
	LD	B,A
	;; Divide absolute values
.dodiv:
	CALL	.divu16
	RET	C		; Exit if divide by zero
	;; Negate quotient if it is negative
	LD	A,(.squot)
	AND	#0x80
	jp	Z,.dorem	; Jump if quotient is positive
	SUB	A		; Substract quotient from 0
	SUB	C
	LD	C,A
	SBC	A		; Propagate borrow (A=0xFF if borrow)
	SUB	B
	LD	B,A
.dorem:
	;; Negate remainder if it is negative
	LD	A,(.srem)
	AND	#0x80
	RET	Z		; Return if remainder is positive
	SUB	A		; Substract remainder from 0
	SUB	E
	LD	E,A
	SBC	A		; Propagate remainder (A=0xFF if borrow)
	SUB	D
	LD	D,A
	RET

.divu8::
.modu8::
	LD	B,#0x00
	LD	D,B
	; Fall through to divu16

.divu16::
.modu16::
	;; Check for division by zero
	LD	A,E
	OR	D
	jp	NZ,.divide	; Branch if divisor is non-zero
	LD	BC,#0x00	; Divide by zero error
	LD	D,B
	LD	E,C
	SCF			; Set carry, invalid result
	RET
.divide:
	ld	hl,#0
;	LD	L,C		; L = low byte of dividend/quotient
;	LD	H,B		; H = high byte of dividend/quotient
;	LD	BC,#0x00	; BC = remainder
	OR	A		; Clear carry to start
	ex	af,af
	LD	A,#16		; 16 bits in dividend
.dvloop:
	;; Shift next bit of quotient into bit 0 of dividend
	;; Shift next MSB of dividend into LSB of remainder
	;; BC holds both dividend and quotient. While we shift a bit from
	;;  MSB of dividend, we shift next bit of quotient in from carry
	;; HL holds remainder
	;; Do a 32-bit left shift, shifting carry to L, L to H,
	;;  H to C, C to B
	ex	af,af'
	RL	C		; Carry (next bit of quotient) to bit 0
	RL	B		; Clears carry since BC was 0
	adc	hl,hl		

	;; If remainder is >= divisor, next bit of quotient is 1. This
	;;  bit goes to carry
	PUSH	HL		; Save current remainder
	sbc	hl,de
;	LD	A,C		; Substract divisor from remainder
;	SBC	E
;	LD	C,A
;	LD	A,B
;	SBC	D
;	LD	B,A
	CCF			; Complement borrow so 1 indicates a
				;  successful substraction (this is the
				;  next bit of quotient)
	jp	C,.drop		; Jump if remainder is >= dividend
	POP	HL		; Otherwise, restore remainder
	jp	.nodrop
.drop:
	INC	SP
	INC	SP
.nodrop:
	ex	af,af'
	DEC	A		; DEC does not affect carry flag
	jp	NZ,.dvloop
	ex	af,af'
	;; Shift last carry bit into quotient
	LD	D,H		; DE = remainder
	LD	E,L
	RL	C		; Carry to L
;	LD	C,L		; C = low byte of quotient
	RL	B
;	LD	B,H		; B = high byte of quotient
	OR	A		; Clear carry, valid result
	RET

	.area	_BSS

.srem:
	.ds 0x01		; Sign of quotient
.squot:
	.ds 0x01		; Sign of remainder
.dcnt:
	.ds 0x01		; Counter for division
