;-------------------------------------------------------------------------- ; divunsigned.s ; ; Copyright (C) 2000-2012, Michael Hope, Philipp Klaus Krause, Marco Bodrato ; ; This library is free software; you can redistribute it and/or modify it ; under the terms of the GNU General Public License as published by the ; Free Software Foundation; either version 2, or (at your option) any ; later version. ; ; This library is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this library; see the file COPYING. If not, write to the ; Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, ; MA 02110-1301, USA. ; ; As a special exception, if you link this library with other files, ; some of which are compiled with SDCC, to produce an executable, ; this library does not by itself cause the resulting executable to ; be covered by the GNU General Public License. This exception does ; not however invalidate any other reasons why the executable file ; might be covered by the GNU General Public License. ;-------------------------------------------------------------------------- ;; Originally from GBDK by Pascal Felber. .area _CODE .globl __divuint .globl __divuchar __divuint: pop af pop hl pop de push de push hl push af jr __divu16 __divuchar: ld hl,#2+1 add hl,sp ld e,(hl) dec hl ld l,(hl) ;; Fall through __divu8:: ld h,#0x00 ld d,h ; Fall through to __divu16 ;; unsigned 16-bit division ;; ;; Entry conditions ;; HL = dividend ;; DE = divisor ;; ;; Exit conditions ;; HL = quotient ;; DE = remainder ;; carry = 0 ;; If divisor is 0, quotient is set to "infinity", i.e HL = 0xFFFF. ;; ;; Register used: AF,B,DE,HL __divu16:: ;; Two algorithms: one assumes divisor <2^7, the second ;; assumes divisor >=2^7; choose the applicable one. ld a,e and a,#0x80 or a,d jr NZ,.morethan7bits ;; Both algorithms "rotate" 24 bits (H,L,A) but roles change. ;; unsigned 16/7-bit division .atmost7bits: ld b,#16 ; bits in dividend and possible quotient ;; Carry cleared by AND/OR, this "0" bit will pass trough HL.[*] adc hl,hl .dvloop7: ;; HL holds both dividend and quotient. While we shift a bit from ;; MSB of dividend, we shift next bit of quotient in from carry. ;; A holds remainder. rla ;; If remainder is >= divisor, next bit of quotient is 1. We try ;; to compute the difference. sub a,e jr NC,.nodrop7 ; Jump if remainder is >= dividend add a,e ; Otherwise, restore remainder ;; The add above sets the carry, because sbc a,e did set it. .nodrop7: ccf ; Complement borrow so 1 indicates a ; successful substraction (this is the ; next bit of quotient) adc hl,hl djnz .dvloop7 ;; Carry now contains the same value it contained before ;; entering .dvloop7[*]: "0" = valid result. ld e,a ; DE = remainder, HL = quotient ret .morethan7bits: ld b,#9 ; at most 9 bits in quotient. ld a,l ; precompute the first 7 shifts, by ld l,h ; doing 8 ld h,#0 rr l ; undoing 1 .dvloop: ;; Shift next bit of quotient into bit 0 of dividend ;; Shift next MSB of dividend into LSB of remainder ;; A 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 adc hl,hl ; HL < 2^(7+9), 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: ccf ; Complement borrow so 1 indicates a ; successful substraction (this is the ; next bit of quotient) rla djnz .dvloop ;; Take care of the ninth quotient bit! after the loop B=0. rl b ; BA = quotient ;; Carry now contains "0" = valid result. ld d,b ld e,a ; DE = quotient, HL = remainder ex de,hl ; HL = quotient, DE = remainder ret