Blame | Last modification | View Log | Download
;--------------------------------------------------------------------------
; 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