1/*
2 * Copyright (c) 2001,2011,2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25/*
26 * As of 3/19/2001, using this module results in no change in runtime
27 * performance compared to using the inline C functions in
28 * giantPort_Generic.h. Examination of the compiled code shows that
29 * the GNU C compiler, when configured for -O2, generates almost
30 * exactly the same code as we have here.
31 * We'll leave this code in, to protect against changes in gcc, changes
32 * in CFLAGS, and to serve as an example for other PPC implementations.
33 */
34
35#if		defined(__ppc__) && defined(__MACH__)
36
37/*********************************************
38
39Add two digits, return sum. Carry bit returned as an out parameter.
40
41giantDigit giantAddDigits(
42	register giantDigit dig1,
43	register giantDigit dig2,
44	register giantDigit *carry)	...RETURNED, 0 or 1
45**********************************************/
46 .text
47	.align 2
48.globl _giantAddDigits
49_giantAddDigits:
50	/*
51	 * dig1  : r3
52	 * dig2  : r4
53	 * carry : r5
54	 * sum   : r6
55	 */
56
57	/* sum = dig1 + dig2 */
58	add	r6, r3, r4;
59
60	/* if((sum < dig1) || (sum < dig2)) */
61	cmplw	cr0,r6,r3
62	blt	L1
63	cmplw	cr0,r6,r4
64	bge	L2
65
66L1:
67	/* *carry = 1; */
68	li	r7,1
69	stw	r7, 0(r5)
70	b	L3
71
72L2:
73	/* else *carry = 0; */
74	li	r7,0
75	stw	r7, 0(r5)
76
77L3:
78	/* return sum in r3 */
79	mr.	r3,r6
80	blr
81
82/*********************************************
83
84Add a single digit value to a double digit accumulator in place.
85Carry out of the MSD of the accumulator is not handled.
86
87void giantAddDouble(
88	giantDigit *accLow,			-- IN/OUT
89	giantDigit *accHigh,		-- IN/OUT
90	giantDigit val);
91**********************************************/
92
93	.align 2
94.globl _giantAddDouble
95_giantAddDouble:
96	/*
97	 * r3 : accLow
98	 * r4 : accHi
99	 * r5 : val
100	 * r6 : sumLo
101	 * r7 : *accLow
102	 */
103
104	/* giantDigit sumLo = *accLow + val; */
105	lwz	r7,0(r3)
106	add	r6,r7,r5
107
108	/* if((sumLo < *accLow) || (sumLo < val)) { */
109	cmplw	cr0,r6,r7
110	blt 	L10
111	cmplw 	cr0,r6,r5
112	bge  	L11
113
114L10:
115	/* (*accHigh)++; */
116	lwz	r7, 0(r4)
117	addi	r7,r7,1
118	stw	r7, 0(r4)
119
120L11:
121	/* *accLow = sumLo; */
122	stw		r6,0(r3)
123	blr
124
125/*****************************************************************************
126
127Subtract a - b, return difference. Borrow bit returned as an out parameter.
128
129giantDigit giantSubDigits(
130	giantDigit a,
131	giantDigit b,
132	giantDigit *borrow)		-- RETURNED, 0 or 1
133
134******************************************************************************/
135
136	.align 2
137.globl _giantSubDigits
138_giantSubDigits:
139
140	/* a  : r3
141	   b  : r4
142	   borrow : r5
143	   diff   : r6 */
144
145	/* giantDigit diff = a - b; */
146	subf	r6, r4, r3;
147
148	/* if(a < b) */
149	cmplw	cr0,r3,r4
150	bge		L20
151
152	/* *borrow = 1; */
153	li       r7,1
154	stw      r7, 0(r5)
155	b        L21
156
157L20:
158	/* else *borrow = 0; */
159	li       r7,0
160	stw      r7, 0(r5)
161
162L21:
163	/* return diff in r3 */
164	mr.      r3,r6
165	blr
166
167/*****************************************************************************
168
169Multiply two digits, return two digits.
170
171void giantMulDigits(
172	giantDigit	dig1,
173	giantDigit	dig2,
174 	giantDigit	*lowProduct,	-- RETURNED, low digit
175	giantDigit	*hiProduct)		-- RETURNED, high digit
176
177******************************************************************************/
178
179	.align 2
180.globl _giantMulDigits
181_giantMulDigits:
182
183	/* r3 : dig1
184	   r4 : dig2
185	   r5 : lowProduct
186	   r6 : hiProduct */
187
188	/* dprod = (unsigned long long)dig1 * (unsigned long long)dig2; */
189	mullw	r7, r3, r4		/* r7 = low(dig1 * dig2) */
190	mulhwu	r8, r3, r4	/* r8 - hi(dig1 * dig2) */
191
192	/* *hiProduct = (giantDigit)(dprod >> GIANT_BITS_PER_DIGIT); */
193	stw	r8, 0(r6)
194
195	/* *lowProduct = (giantDigit)dprod; */
196	stw	r7, 0(r5)
197	blr
198
199
200/*****************************************************************************
201
202Multiply a vector of giantDigits, candVector, by a single giantDigit,
203plierDigit, adding results into prodVector. Returns m.s. digit from
204final multiply; only candLength digits of *prodVector will be written.
205
206giantDigit VectorMultiply(
207	giantDigit plierDigit,
208	giantDigit *candVector,
209	unsigned candLength,
210	giantDigit *prodVector)
211
212******************************************************************************/
213
214/*
215 * Register definitions
216 * Input paramters:
217 */
218#define plierDigit	r3
219#define candVector	r4
220#define candLength 	r5
221#define prodVector	r6
222
223/*
224 * PPC ABI specifies:
225 *    r3..r10 for parameter passing
226 *    r11, r12 volatile (caller saved, we can write)
227 *
228 * We'll use the remainder of the registers normally used for parameter passing
229 * and also the other volatile register for local variables.
230 */
231#define candDex		r7
232#define lastCarry	r8
233#define prodLo		r9
234#define prodHi		r10
235#define scr1		r11
236#define sumLo		r12
237
238	.align 2
239.globl _VectorMultiply
240_VectorMultiply:
241
242    /* giantDigit lastCarry = 0; */
243	li       lastCarry,0
244
245
246	/* for(candDex=0; candDex<candLength; ++candDex) { */
247	li       candDex,0
248	b		L_endLoop
249
250	    /*
251	     * prod = *(candVector++) * plierDigit + *prodVector + lastCarry
252	     */
253L_topLoop:
254		lwz      scr1,0(candVector)				/* *candVector --> scr1 */
255		addi     candVector,candVector,4		/* candVector++ */
256
257		mullw	prodLo,scr1,plierDigit	/* prodLo = low(*candVector * plierDigit) */
258		mulhwu	prodHi,scr1,plierDigit	/* prodHi = high(*candVector * plierDigit) */
259
260	    /* giantAddDouble(&prodLo, &prodHi, *prodVector); */
261		lwz     scr1,0(prodVector)		/* *prodVector --> r9 */
262		add		sumLo,prodLo,scr1		/* prodLo + *prodVector --> sumLo */
263		cmplw	cr0,sumLo,prodLo		/* sumLo < prodLo? */
264		blt		L_carry1
265		cmplw	cr0,sumLo,scr1			/* sumLo < *prodVector? */
266		bge		L_noCar1
267L_carry1:
268		addi	prodHi,prodHi,1			/* prodHi++ */
269L_noCar1:
270		mr.		prodLo,sumLo			/* prodLo := sumLo */
271
272	    /* giantAddDouble(&prodLo, &prodHi, lastCarry); */
273		add		sumLo,sumLo,lastCarry	/* sumLo += lastCarry */
274		cmplw	cr0,sumLo,prodLo		/* sumLo < prodLo? */
275		blt		L_carry2
276		cmplw	cr0,sumLo,lastCarry	/* sumLo < lastCarry? */
277		bge		L_noCar2
278L_carry2:
279		addi	prodHi,prodHi,1			/* prodHi++ */
280L_noCar2:
281		mr.		prodLo,sumLo			/* prodLo := sumLo */
282
283	    /* *(prodVector++) = prodLo; */
284		stw      prodLo,0(prodVector)		/* prodLo --> *prodVector */
285		addi     prodVector,prodVector,4	/* prodVector++ */
286
287	    /* lastCarry = prodHi; */
288		mr.		lastCarry,prodHi
289
290	/* } */
291	addi     candDex,candDex,1			/* candDex++ */
292L_endLoop:
293	cmplw    cr0,candDex,candLength		/* candDex < candLength? */
294	blt      L_topLoop
295
296	/* return lastCarry; */
297	mr.      r3,lastCarry				/* return lastCarry in r3 */
298	blr
299
300#endif	/* defined(__ppc__) && defined(__MACH__) */
301