root/common/lib/libc/arch/m68k/gen/muldi3.S
/*      $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 <machine/asm.h>

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)