X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=device%2Flib%2Fz80%2Fdiv.s;h=305cd67ab13a1c39bf6d0f790723b975af3ffe0e;hb=5a1d5e778e85664f4e6657019348b4756b16eacb;hp=e64aa07b9fe4e9d70ce36011fe97a184f9a190df;hpb=2109a06030f5d8dcb7412a67cf61315e6f69a427;p=fw%2Fsdcc diff --git a/device/lib/z80/div.s b/device/lib/z80/div.s index e64aa07b..305cd67a 100644 --- a/device/lib/z80/div.s +++ b/device/lib/z80/div.s @@ -2,48 +2,15 @@ .area _CODE - ;; 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 - __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 + pop af + pop hl + pop de + push de + push hl + push af - ret + jr __divu16 __divsuchar_rrx_s:: ld hl,#2+1 @@ -51,15 +18,10 @@ __divsuchar_rrx_s:: ld e,(hl) dec hl - ld c,(hl) - ld b, #0 - - call signexte - - ld l,c - ld h,b + ld l,(hl) + xor a - ret + jr signexte __modsuchar_rrx_s:: ld hl,#2+1 @@ -67,113 +29,115 @@ __modsuchar_rrx_s:: ld e,(hl) dec hl - ld c,(hl) - ld b, #0 + ld l,(hl) + xor a call signexte - ld l,e - ld h,d - + ex de,hl ret __divuschar_rrx_s:: ld hl,#2+1 + ld d, h add hl,sp ld e,(hl) - ld d, #0 dec hl - ld c,(hl) + ld l,(hl) - ld a,c ; Sign extend + ld a,l ; Sign extend rlca sbc a - ld b,a + ld h,a - call __div16 + jr __div16 - ld l,c - ld h,b +__divschar_rrx_s:: + ld hl,#2+1 + add hl,sp - ret + ld e,(hl) + dec hl + ld l,(hl) + ;; Fall through +__divschar_rrx_hds:: __div8:: -.mod8:: - ld a,c ; Sign extend + 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 - ;; 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 +__divsint_rrx_hds:: __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 - push af ; Save as sign of remainder + ld a,h ; Get high byte of dividend xor d ; Xor with high byte of divisor - push af ; 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 - jr 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 - jr 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 jr C,.exit ; Exit if divide by zero ;; Negate quotient if it is negative pop af ; recover sign of quotient - and #0x80 - jr Z,.dorem ; Jump if quotient is positive + 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 - pop af ; recover sign of remainder - 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 @@ -183,78 +147,84 @@ __div16:: ret .exit: pop af - pop af + +.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:: -.modu8:: - ld b,#0x00 - ld d,b + 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:: __divu16:: -.modu16:: ;; Check for division by zero ld a,e or d - jr 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) - jr C,.drop ; Jump if remainder is >= dividend - pop hl ; Otherwise, restore remainder - jr .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 -