/* $NetBSD: muldi3.S,v 1.2 2020/05/31 12:37:07 rin Exp $ */ /* * Copyright (c) 2020 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Rin Okuyama. * * 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. * * 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 RCSID("$NetBSD: muldi3.S,v 1.2 2020/05/31 12:37:07 rin Exp $") | int64_t __muldi3(int64_t X, int64_t Y); | | * Return lower 64bit of (X * Y) into %d0:%d1. | | * Intended for 68060: | - GCC does not emit __muldi3() for 68020-40, that have 32 * 32 --> 64 mulul. | - mulsl (and moveml) are not implemented for 68010. | | * Notation: | - H32:L32 --> higher:lower 32bit of variable | - H:L --> higher:lower 16bit of variable/register #ifdef __mc68010__ #error "not for 68010" #endif #define X_H32 (4 * 4) #define X_L32 (X_H32 + 4) #define Y_H32 (X_L32 + 4) #define Y_L32 (Y_H32 + 4) ENTRY(__muldi3) moveml %d2-%d4, -(%sp) | push %d2-%d4 | First, calculate (X_L32 * Y_L32) as a 64bit integer. movel X_L32(%sp), %a0 | save X_L32 movel Y_L32(%sp), %a1 | save Y_L32 movel %a0, %d2 | prepare for X_L32(H) in L movel %a1, %d3 | prepare for Y_L32(H) in L movel %a0, %d4 | X_L32(L) in L movel %a1, %d1 | Y_L32(L) in L movel %a0, %d0 | X_L32(L) in L swap %d2 | X_L32(H) in L swap %d3 | Y_L32(H) in L muluw %d1, %d4 | A = X_L32(L) * Y_L32(L) muluw %d2, %d1 | B = X_L32(H) * Y_L32(L) muluw %d3, %d2 | C = X_L32(H) * Y_L32(H) muluw %d0, %d3 | D = X_L32(L) * Y_L32(H) movel %d4, %d0 | extract A(H) clrw %d0 swap %d0 addl %d0, %d1 | B += A(H) (no carry; max 0xffff0000) addl %d3, %d1 | B += D bccs 1f | if (carry) addil #0x10000, %d2 | C += 0x10000 1: swap %d1 | B(H) <--> B(L) | (%d0), (%d1), %d2 = C, %d3 = free, %d4 = A clrl %d3 | extract B(H) movew %d1, %d3 movew %d4, %d1 | %d1 = (B(L) << 16) + A(L) addl %d3, %d2 | C += B(H) | We have (X_L32 * Y_L32) in %d2:%d1. Lower 32bit was completed. | Add (X_L32 * Y_H32 + X_H32 * Y_L32) to higher 32bit. | | (%d0), (%d1), %d2 = C, %d3 = free, %d4 = free movel %a0, %d0 | restore X_L32 movel %a1, %d3 | restore Y_L32 mulsl Y_H32(%sp), %d0 | E = X_L32 * Y_H32 mulsl X_H32(%sp), %d3 | F = X_H32 * Y_L32 addl %d2, %d0 | E += C addl %d3, %d0 | %d0 = E + F moveml (%sp)+, %d2-%d4 | pop %d2-%d4 rts END(__muldi3)