;; 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
+ .area _CODE
- call .div8
+__divuint_rrx_s::
+ pop af
+ pop hl
+ pop de
+ push de
+ push hl
+ push af
- ld l,c
- ld h,b
+ jr __divu16
- ret
-
-__modschar_rrx_s::
+__divsuchar_rrx_s::
ld hl,#2+1
add hl,sp
ld e,(hl)
dec hl
ld l,(hl)
+ xor a
- ;; 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
+ jr signexte
- ;; Unsigned
-__divuchar_rrx_s::
+__modsuchar_rrx_s::
ld hl,#2+1
add hl,sp
ld e,(hl)
dec hl
ld l,(hl)
+ xor a
- ;; Fall through
-__divuchar_rrx_hds::
- ld c,l
- call .divu8
-
- ld l,c
- ld h,b
+ call signexte
+ ex de,hl
ret
-__moduchar_rrx_s::
+__divuschar_rrx_s::
ld hl,#2+1
+ ld d, h
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 a,l ; Sign extend
+ rlca
+ sbc a
ld h,a
- ;; Fall through
-__divuint_rrx_hds::
- ld b,h
- ld c,l
- call .divu16
-
- ld l,c
- ld h,b
-
- ret
+ jr __div16
-__moduint_rrx_s::
- ld hl,#2+3
+__divschar_rrx_s::
+ ld hl,#2+1
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
+ ;; Fall through
+__divschar_rrx_hds::
+__div8::
+ ld a,l ; Sign extend
rlca
sbc a
- ld b,a
+signexte:
+ ld h,a
ld a,e ; Sign extend
rlca
sbc a
ld d,a
+ ; Fall through to __div16
- ; Fall through to .div16
-
- ;; 16-bit division
+ ;; signed 16-bit division
;;
;; Entry conditions
- ;; BC = dividend
+ ;; HL = dividend
;; DE = divisor
;;
;; Exit conditions
- ;; BC = quotient
+ ;; HL = 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::
+__divsint_rrx_hds::
+__div16::
;; 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
+ ld a,h ; Get high byte of dividend
xor d ; Xor with high byte of divisor
- ld (.squot),a ; Save sign of quotient
+ rla ; Sign of quotient goes into the carry
+ ld a,h ; Get high byte of dividend
+ push af ; Save sign of both quotient and reminder
+
+ ;; Take absolute value of dividend
+ rla
+ jr NC,.chkde ; Jump if dividend is positive
+ sub a ; Substract dividend from 0
+ sub l
+ ld l,a
+ sbc a ; Propagate borrow (A=0xFF if borrow)
+ sub h
+ ld h,a
;; Take absolute value of divisor
+.chkde:
bit 7,d
- jp Z,.chkde ; Jump if divisor is positive
+ jr Z,.dodiv ; 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
+ call __divu16
+ jr C,.exit ; Exit if divide by zero
;; Negate quotient if it is negative
- ld a,(.squot)
- and #0x80
- jp Z,.dorem ; Jump if quotient is positive
+ pop af ; recover sign of quotient
+ jr NC,.dorem ; Jump if quotient is positive
+ ld b,a
sub a ; Substract quotient from 0
- sub c
- ld c,a
+ sub l
+ ld l,a
sbc a ; Propagate borrow (A=0xFF if borrow)
- sub b
- ld b,a
+ sub h
+ ld h,a
+ ld a,b
.dorem:
;; Negate remainder if it is negative
- ld a,(.srem)
- and #0x80
- ret Z ; Return if remainder is positive
+ rla
+ ret NC ; Return if remainder is positive
sub a ; Substract remainder from 0
sub e
ld e,a
sub d
ld d,a
ret
+.exit:
+ pop af
-.divu8::
-.modu8::
- ld b,#0x00
- ld d,b
+.dividebyzero:
+ ld h,d ; Divide by zero error: D=E=0
+ ld l,e
+ scf ; Set carry, invalid result
+ 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::
+__divu8::
+ ld h,#0x00
+ ld d,h
; Fall through to divu16
-.divu16::
-.modu16::
+ ;; unsigned 16-bit division
+ ;; Restructured on April 2009 by Marco Bodrato(http://bodrato.it/ )
+ ;;
+ ;; Entry conditions
+ ;; HL = dividend
+ ;; DE = divisor
+ ;;
+ ;; Exit conditions
+ ;; HL = 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,B,DE,HL
+__divuint_rrx_hds::
+__divu16::
;; 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:
+ jr Z,.dividebyzero ; Branch if divisor is non-zero
+ ld a,h
+ ld c,l
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
+ ;; Carry was cleared by OR, this "0" bit will pass trough AC.[*]
+ ld b,#16 ; 16 bits in dividend
.dvloop:
+ ;; Cleaned up on April 2009 by Marco Bodrato(http://bodrato.it/ )
;; 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
+ ;; AC 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'
+ ;; Do a 32-bit left shift, shifting carry to C, C to A,
+ ;; A to HL
rl c ; Carry (next bit of quotient) to bit 0
- rl b ; Clears carry since BC was 0
- adc hl,hl
+ rla
+ adc hl,hl ; HL < 32768 before, no carry, ever.
- ;; If remainder is >= divisor, next bit of quotient is 1. This
- ;; bit goes to carry
- push hl ; Save current remainder
+ ;; If remainder is >= divisor, next bit of quotient is 1. We try
+ ;; to compute the difference.
sbc hl,de
-; ld a,c ; Substract divisor from remainder
-; sbc e
-; ld c,a
-; ld a,b
-; sbc d
-; ld b,a
+ jr NC,.nodrop ; Jump if remainder is >= dividend
+ add hl,de ; Otherwise, restore remainder
+ ;; The add above sets the carry, because sbc hl,de did set it.
+.nodrop:
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'
+ djnz .dvloop
;; 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
+ rl c ; Carry to C
+ rla
+ ;; Carry now contains the same value it contained before
+ ;; entering .dvloop[*]: "0" = valid result.
+ ld d,a
+ ld e,c ; DE = quotient, HL = remainder
+ ex de,hl ; HL = quotient, DE = remainder
ret
-
- .area _BSS
-
-.srem:
- .ds 0x01 ; Sign of quotient
-.squot:
- .ds 0x01 ; Sign of remainder
-.dcnt:
- .ds 0x01 ; Counter for division