xref: /netbsd-src/common/lib/libc/arch/m68k/gen/muldi3.S (revision 97690669791023668350378835254001c39bf94d)
1/*	$NetBSD: muldi3.S,v 1.2 2020/05/31 12:37:07 rin Exp $	*/
2
3/*
4 * Copyright (c) 2020 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Rin Okuyama.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <machine/asm.h>
33
34RCSID("$NetBSD: muldi3.S,v 1.2 2020/05/31 12:37:07 rin Exp $")
35
36| int64_t __muldi3(int64_t X, int64_t Y);
37|
38| * Return lower 64bit of (X * Y) into %d0:%d1.
39|
40| * Intended for 68060:
41|   - GCC does not emit __muldi3() for 68020-40, that have 32 * 32 --> 64 mulul.
42|   - mulsl (and moveml) are not implemented for 68010.
43|
44| * Notation:
45|   - H32:L32 --> higher:lower 32bit of variable
46|   - H:L     --> higher:lower 16bit of variable/register
47
48#ifdef __mc68010__
49#error "not for 68010"
50#endif
51
52#define X_H32 (4 * 4)
53#define X_L32 (X_H32 + 4)
54#define Y_H32 (X_L32 + 4)
55#define Y_L32 (Y_H32 + 4)
56
57ENTRY(__muldi3)
58	moveml	%d2-%d4, -(%sp)	| push %d2-%d4
59
60| First, calculate (X_L32 * Y_L32) as a 64bit integer.
61
62	movel	X_L32(%sp), %a0	| save X_L32
63	movel	Y_L32(%sp), %a1	| save Y_L32
64
65	movel	%a0, %d2	| prepare for X_L32(H) in L
66	movel	%a1, %d3	| prepare for Y_L32(H) in L
67
68	movel	%a0, %d4	| X_L32(L) in L
69	movel	%a1, %d1	| Y_L32(L) in L
70	movel	%a0, %d0	| X_L32(L) in L
71
72	swap	%d2		| X_L32(H) in L
73	swap	%d3 		| Y_L32(H) in L
74
75	muluw	%d1, %d4	| A = X_L32(L) * Y_L32(L)
76	muluw	%d2, %d1	| B = X_L32(H) * Y_L32(L)
77	muluw	%d3, %d2	| C = X_L32(H) * Y_L32(H)
78	muluw	%d0, %d3	| D = X_L32(L) * Y_L32(H)
79
80	movel	%d4, %d0	| extract A(H)
81	clrw	%d0
82	swap	%d0
83
84	addl	%d0, %d1	| B += A(H) (no carry; max 0xffff0000)
85
86	addl	%d3, %d1	| B += D
87	bccs	1f		| if (carry)
88	addil	#0x10000, %d2	| 	C += 0x10000
89
901:	swap	%d1		| B(H) <--> B(L)
91
92| (%d0), (%d1), %d2 = C, %d3 = free, %d4 = A
93
94	clrl	%d3		| extract B(H)
95	movew	%d1, %d3
96
97	movew	%d4, %d1	| %d1 = (B(L) << 16) + A(L)
98
99	addl	%d3, %d2	| C += B(H)
100
101| We have (X_L32 * Y_L32) in %d2:%d1. Lower 32bit was completed.
102| Add (X_L32 * Y_H32 + X_H32 * Y_L32) to higher 32bit.
103|
104| (%d0), (%d1), %d2 = C, %d3 = free, %d4 = free
105
106	movel	%a0, %d0	| restore X_L32
107	movel	%a1, %d3	| restore Y_L32
108	mulsl	Y_H32(%sp), %d0	| E = X_L32 * Y_H32
109	mulsl	X_H32(%sp), %d3 | F = X_H32 * Y_L32
110	addl	%d2, %d0	| E += C
111	addl	%d3, %d0	| %d0 = E + F
112
113	moveml	(%sp)+, %d2-%d4	| pop %d2-%d4
114	rts
115END(__muldi3)
116