X-Git-Url: https://git.gag.com/?a=blobdiff_plain;ds=sidebyside;f=device%2Flib%2Fz80%2Fdiv.s;h=305cd67ab13a1c39bf6d0f790723b975af3ffe0e;hb=5a1d5e778e85664f4e6657019348b4756b16eacb;hp=c66aca33718fd085a52814c72ba19fb4f3f7c9bd;hpb=f239a9f256f022ade8216daba928e817f2d5f528;p=fw%2Fsdcc diff --git a/device/lib/z80/div.s b/device/lib/z80/div.s index c66aca33..305cd67a 100644 --- a/device/lib/z80/div.s +++ b/device/lib/z80/div.s @@ -1,339 +1,230 @@ - ;; Originally from GBDK by Pascal Felber. - .area _CODE + ;; Originally from GBDK by Pascal Felber. -__divschar_rrx_s:: + .area _CODE + +__divuint_rrx_s:: + pop af + pop hl + pop de + push de + push hl + push af + + jr __divu16 + +__divsuchar_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 + xor a + + jr signexte - ld l,c - ld h,b - - ret - -__modschar_rrx_s:: +__modsuchar_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 + xor a - call .div8 + call signexte - ld l,e - ld h,d - - ret + ex de,hl + ret -__divsint_rrx_s:: - ld hl,#2+3 +__divuschar_rrx_s:: + ld hl,#2+1 + ld d, h 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 a,l ; Sign extend + rlca + sbc a + ld h,a - ld l,e - ld h,d - - ret + jr __div16 - ;; Unsigned -__divuchar_rrx_s:: +__divschar_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 + ;; Fall through +__divschar_rrx_hds:: +__div8:: + ld a,l ; Sign extend + rlca + sbc a +signexte: + ld h,a + ld a,e ; Sign extend + rlca + sbc a + ld d,a + ; Fall through to __div16 + + ;; signed 16-bit division + ;; + ;; 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,BC,DE,HL +__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,h ; Get high byte of dividend + xor d ; Xor with high byte of divisor + 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 + 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 + ;; Divide absolute values +.dodiv: + call __divu16 + jr C,.exit ; Exit if divide by zero + ;; Negate quotient if it is negative + pop af ; recover sign of quotient + jr NC,.dorem ; Jump if quotient is positive + ld b,a + sub a ; Substract quotient from 0 + sub l + ld l,a + sbc a ; Propagate borrow (A=0xFF if borrow) + sub h + ld h,a + ld a,b +.dorem: + ;; Negate remainder if it is negative + rla + ret NC ; 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 +.exit: + pop af +.dividebyzero: + ld h,d ; Divide by zero error: D=E=0 + ld l,e + scf ; Set carry, invalid result ret -__divuint_rrx_s:: - ld hl,#2+3 + ;; Unsigned +__divuchar_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 +__divuchar_rrx_hds:: +__divu8:: + ld h,#0x00 + ld d,h + ; Fall through to divu16 + + ;; 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:: - 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 +__divu16:: + ;; Check for division by zero + ld a,e + or d + jr Z,.dividebyzero ; Branch if divisor is non-zero + ld a,h + ld c,l + ld hl,#0 + ;; Carry was cleared by OR, this "0" bit will pass trough AC.[*] + ld b,#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 + ;; 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 + ;; 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 C, C to A, + ;; A to HL + rl c ; Carry (next bit of quotient) to bit 0 + rla + adc hl,hl ; HL < 32768 before, no carry, ever. + + ;; If remainder is >= divisor, next bit of quotient is 1. We try + ;; to compute the difference. + sbc hl,de + 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: - 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 + ccf ; Complement borrow so 1 indicates a + ; successful substraction (this is the + ; next bit of quotient) + djnz .dvloop + ;; Shift last carry bit into quotient + 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