X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=device%2Flib%2Fz80%2Fdiv.s;h=f0574eb506e80cd759fce009c8d1bea0ca130ce5;hb=d55072f68fcf3718b20b1a2c86058b01157bd189;hp=5917c24acb81349e0d86686087b2bc3f257ae9c4;hpb=404dbf4e0b144d60a2e106ef2b32cab556436f62;p=fw%2Fsdcc diff --git a/device/lib/z80/div.s b/device/lib/z80/div.s index 5917c24a..f0574eb5 100644 --- a/device/lib/z80/div.s +++ b/device/lib/z80/div.s @@ -1,318 +1,231 @@ - ;; Originally from GBDK by Pascal Felber. - .area _CODE - -__divschar:: - push de - push bc - push ix - ld ix,#0 - add ix,sp - - ld c,8(ix) - ld e,9(ix) - call .div8 - - ld l,c - - pop ix - pop bc - pop de - ret - -__modschar:: - push de - push bc - push ix - ld ix,#0 - add ix,sp - - ld c,8(ix) - ld e,9(ix) - call .div8 - - ld l,e - - pop ix - pop bc - pop de - ret - -__divsint:: - push de - push bc - push ix - ld ix,#0 - add ix,sp - - ld c,8(ix) - ld b,9(ix) - ld e,10(ix) - ld d,11(ix) - call .div16 - - ld l,c - ld h,b - - pop ix - pop bc - pop de - ret - -__modsint:: - push de - push bc - push ix - ld ix,#0 - add ix,sp - - ld c,8(ix) - ld b,9(ix) - ld e,10(ix) - ld d,11(ix) - call .div16 - - ld l,e - ld h,d - - pop ix - pop bc - pop de - ret - - ;; Unsigned -__divuchar:: - push de - push bc - push ix - ld ix,#0 - add ix,sp - - ld c,8(ix) - ld e,9(ix) - call .divu8 - - ld l,c - - pop ix - pop bc - pop de - ret - -__moduchar:: - push de - push bc - push ix - ld ix,#0 - add ix,sp - - ld c,8(ix) - ld e,9(ix) - call .divu8 - - ld l,e - - pop ix - pop bc - pop de - ret - -__divuint:: - push de - push bc - push ix - ld ix,#0 - add ix,sp - - ld c,8(ix) - ld b,9(ix) - ld e,10(ix) - ld d,11(ix) - call .divu16 - - ld l,c - ld h,b - - pop ix - pop bc - pop de - ret - -__moduint:: - push de - push bc - push ix - ld ix,#0 - add ix,sp - - ld c,8(ix) - ld b,9(ix) - ld e,10(ix) - ld d,11(ix) - call .divu16 - - ld l,e - ld h,d - - pop ix - pop bc - pop de - 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 - JR 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 + ;; Originally from GBDK by Pascal Felber. + + .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) + xor a + + jr signexte + +__modsuchar_rrx_s:: + ld hl,#2+1 + add hl,sp + + ld e,(hl) + dec hl + ld l,(hl) + xor a + + call signexte + + ex de,hl + ret + +__divuschar_rrx_s:: + ld hl,#2+1 + add hl,sp + + ld e,(hl) + ld d, #0 + dec hl + ld l,(hl) + + ld a,l ; Sign extend + rlca + sbc a + ld h,a + + jr __div16 + +__divschar_rrx_s:: + ld hl,#2+1 + add hl,sp + + ld e,(hl) + dec hl + ld l,(hl) + + ;; 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,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 + 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 - RET C ; Exit if divide by zero - ;; Negate quotient if it is negative - LD A,(.squot) - AND #0x80 - JR 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 + 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 - 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 - 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: - 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 - LD A,#16 ; 16 bits in dividend + ;; 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 + + ;; 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 + + ;; 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 + 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 - LD (.dcnt),A - RL L ; Carry (next bit of quotient) to bit 0 - RL H ; Shift remaining bytes - RL C - RL B ; Clears carry since BC was 0 - ;; If remainder is >= divisor, next bit of quotient is 1. This - ;; bit goes to carry - PUSH BC ; Save current remainder - 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) - JR C,.drop ; Jump if remainder is >= dividend - POP BC ; Otherwise, restore remainder - JR .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: - LD A,(.dcnt) - DEC A ; DEC does not affect carry flag - JR NZ,.dvloop - ;; Shift last carry bit into quotient - LD D,B ; DE = remainder - LD E,C - RL L ; Carry to L - LD C,L ; C = low byte of quotient - RL H - LD B,H ; B = high byte of quotient - OR A ; Clear carry, valid result - RET - - .area _BSS + 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 -.srem: - .ds 0x01 ; Sign of quotient -.squot: - .ds 0x01 ; Sign of remainder -.dcnt: - .ds 0x01 ; Counter for division