/* $NetBSD: udivsi3.S,v 1.1 2002/03/26 22:49:33 fredette Exp $ */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Matthew Fredette. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #if defined(LIBC_SCCS) && !defined(lint) RCSID("$NetBSD: udivsi3.S,v 1.1 2002/03/26 22:49:33 fredette Exp $"); #endif /* LIBC_SCCS and not lint */ ENTRY(__udivsi3) movel %d2, %sp@- | save %d2 movel %sp@(12), %d0 | load divisor movel %sp@(8), %d1 | load dividend | first, we divide the divisor and dividend by two until | the divisor fits into 16 bits: 1: cmpil #0x10000, %d0 bcs 2f lsrl #1, %d0 lsrl #1, %d1 bra 1b 2: | now we can do the divide. to avoid overflow, we have to | do the divide in two parts, high and low, and add the | results together: movew %d1, %d2 | save low(dividend) clrw %d1 swap %d1 | %d1 = dividend >> 16 divuw %d0, %d1 | do the high divide moveal %d1, %a1 | save high divide result movew %d2, %d1 | concat(remainder, low(dividend)) divuw %d0, %d1 | do the low divide movel %a1, %d0 | recover high divide result swap %d0 clrw %d0 | %d0 = finished high divide result andil #0xffff, %d1 | %d1 = finished low divide result addl %d1, %d0 | %d0 = quotient guess | the quotient we have so far is only a guess. the divide we | did above was really the divide of some dividendB by some | divisorB, where the following hold: | | (dividend - divisor) <= dividendB <= dividend | (divisor / 2) < divisorB <= divisor | | so our guess quotient cannot be less than our real desired | quotient. however, it might be one too big. | | to adjust this quotient, we multiply it by the original | divisor and subtract the result from the original dividend. | if the result is nonnegative, our guessed quotient was | correct, and the subtraction result is our remainder. | if the result is negative, our guessed quotient was one | too big, and the subtraction result plus the original | divisor is our remainder. | | as in mulsi3, we have to do the multiply in stages to avoid | overflow: movel %sp@(12), %d2 | load divisor swap %d2 movel %d0, %d1 muluw %d2, %d1 | high(divisor) * low(guess) moveal %d1, %a1 | save high(divisor) * low(guess) swap %d2 movel %d0, %d1 swap %d1 muluw %d2, %d1 | low(divisor) * high(guess) addl %a1, %d1 swap %d1 clrw %d1 | %d1 = finished high multiply result moveal %d2, %a1 | save original divisor muluw %d0, %d2 | low(guess) * low(divisor) addl %d1, %d2 | %d2 = guess * divisor movel %sp@(8), %d1 | load original dividend subl %d2, %d1 | subtract bcc 3f subql #1, %d0 | adjust quotient addl %a1, %d1 | adjust remainder 3: movel %sp@+, %d2 | restore %d2 rts