xref: /freebsd/crypto/openssl/crypto/bn/asm/ppc.pl (revision b00ab754)
1#!/usr/bin/env perl
2#
3# Implemented as a Perl wrapper as we want to support several different
4# architectures with single file. We pick up the target based on the
5# file name we are asked to generate.
6#
7# It should be noted though that this perl code is nothing like
8# <openssl>/crypto/perlasm/x86*. In this case perl is used pretty much
9# as pre-processor to cover for platform differences in name decoration,
10# linker tables, 32-/64-bit instruction sets...
11#
12# As you might know there're several PowerPC ABI in use. Most notably
13# Linux and AIX use different 32-bit ABIs. Good news are that these ABIs
14# are similar enough to implement leaf(!) functions, which would be ABI
15# neutral. And that's what you find here: ABI neutral leaf functions.
16# In case you wonder what that is...
17#
18#       AIX performance
19#
20#	MEASUREMENTS WITH cc ON a 200 MhZ PowerPC 604e.
21#
22#	The following is the performance of 32-bit compiler
23#	generated code:
24#
25#	OpenSSL 0.9.6c 21 dec 2001
26#	built on: Tue Jun 11 11:06:51 EDT 2002
27#	options:bn(64,32) ...
28#compiler: cc -DTHREADS  -DAIX -DB_ENDIAN -DBN_LLONG -O3
29#                  sign    verify    sign/s verify/s
30#rsa  512 bits   0.0098s   0.0009s    102.0   1170.6
31#rsa 1024 bits   0.0507s   0.0026s     19.7    387.5
32#rsa 2048 bits   0.3036s   0.0085s      3.3    117.1
33#rsa 4096 bits   2.0040s   0.0299s      0.5     33.4
34#dsa  512 bits   0.0087s   0.0106s    114.3     94.5
35#dsa 1024 bits   0.0256s   0.0313s     39.0     32.0
36#
37#	Same bechmark with this assembler code:
38#
39#rsa  512 bits   0.0056s   0.0005s    178.6   2049.2
40#rsa 1024 bits   0.0283s   0.0015s     35.3    674.1
41#rsa 2048 bits   0.1744s   0.0050s      5.7    201.2
42#rsa 4096 bits   1.1644s   0.0179s      0.9     55.7
43#dsa  512 bits   0.0052s   0.0062s    191.6    162.0
44#dsa 1024 bits   0.0149s   0.0180s     67.0     55.5
45#
46#	Number of operations increases by at almost 75%
47#
48#	Here are performance numbers for 64-bit compiler
49#	generated code:
50#
51#	OpenSSL 0.9.6g [engine] 9 Aug 2002
52#	built on: Fri Apr 18 16:59:20 EDT 2003
53#	options:bn(64,64) ...
54#	compiler: cc -DTHREADS -D_REENTRANT -q64 -DB_ENDIAN -O3
55#                  sign    verify    sign/s verify/s
56#rsa  512 bits   0.0028s   0.0003s    357.1   3844.4
57#rsa 1024 bits   0.0148s   0.0008s     67.5   1239.7
58#rsa 2048 bits   0.0963s   0.0028s     10.4    353.0
59#rsa 4096 bits   0.6538s   0.0102s      1.5     98.1
60#dsa  512 bits   0.0026s   0.0032s    382.5    313.7
61#dsa 1024 bits   0.0081s   0.0099s    122.8    100.6
62#
63#	Same benchmark with this assembler code:
64#
65#rsa  512 bits   0.0020s   0.0002s    510.4   6273.7
66#rsa 1024 bits   0.0088s   0.0005s    114.1   2128.3
67#rsa 2048 bits   0.0540s   0.0016s     18.5    622.5
68#rsa 4096 bits   0.3700s   0.0058s      2.7    171.0
69#dsa  512 bits   0.0016s   0.0020s    610.7    507.1
70#dsa 1024 bits   0.0047s   0.0058s    212.5    173.2
71#
72#	Again, performance increases by at about 75%
73#
74#       Mac OS X, Apple G5 1.8GHz (Note this is 32 bit code)
75#       OpenSSL 0.9.7c 30 Sep 2003
76#
77#       Original code.
78#
79#rsa  512 bits   0.0011s   0.0001s    906.1  11012.5
80#rsa 1024 bits   0.0060s   0.0003s    166.6   3363.1
81#rsa 2048 bits   0.0370s   0.0010s     27.1    982.4
82#rsa 4096 bits   0.2426s   0.0036s      4.1    280.4
83#dsa  512 bits   0.0010s   0.0012s   1038.1    841.5
84#dsa 1024 bits   0.0030s   0.0037s    329.6    269.7
85#dsa 2048 bits   0.0101s   0.0127s     98.9     78.6
86#
87#       Same benchmark with this assembler code:
88#
89#rsa  512 bits   0.0007s   0.0001s   1416.2  16645.9
90#rsa 1024 bits   0.0036s   0.0002s    274.4   5380.6
91#rsa 2048 bits   0.0222s   0.0006s     45.1   1589.5
92#rsa 4096 bits   0.1469s   0.0022s      6.8    449.6
93#dsa  512 bits   0.0006s   0.0007s   1664.2   1376.2
94#dsa 1024 bits   0.0018s   0.0023s    545.0    442.2
95#dsa 2048 bits   0.0061s   0.0075s    163.5    132.8
96#
97#        Performance increase of ~60%
98#
99#	If you have comments or suggestions to improve code send
100#	me a note at schari@us.ibm.com
101#
102
103$flavour = shift;
104
105if ($flavour =~ /32/) {
106	$BITS=	32;
107	$BNSZ=	$BITS/8;
108	$ISA=	"\"ppc\"";
109
110	$LD=	"lwz";		# load
111	$LDU=	"lwzu";		# load and update
112	$ST=	"stw";		# store
113	$STU=	"stwu";		# store and update
114	$UMULL=	"mullw";	# unsigned multiply low
115	$UMULH=	"mulhwu";	# unsigned multiply high
116	$UDIV=	"divwu";	# unsigned divide
117	$UCMPI=	"cmplwi";	# unsigned compare with immediate
118	$UCMP=	"cmplw";	# unsigned compare
119	$CNTLZ=	"cntlzw";	# count leading zeros
120	$SHL=	"slw";		# shift left
121	$SHR=	"srw";		# unsigned shift right
122	$SHRI=	"srwi";		# unsigned shift right by immediate
123	$SHLI=	"slwi";		# shift left by immediate
124	$CLRU=	"clrlwi";	# clear upper bits
125	$INSR=	"insrwi";	# insert right
126	$ROTL=	"rotlwi";	# rotate left by immediate
127	$TR=	"tw";		# conditional trap
128} elsif ($flavour =~ /64/) {
129	$BITS=	64;
130	$BNSZ=	$BITS/8;
131	$ISA=	"\"ppc64\"";
132
133	# same as above, but 64-bit mnemonics...
134	$LD=	"ld";		# load
135	$LDU=	"ldu";		# load and update
136	$ST=	"std";		# store
137	$STU=	"stdu";		# store and update
138	$UMULL=	"mulld";	# unsigned multiply low
139	$UMULH=	"mulhdu";	# unsigned multiply high
140	$UDIV=	"divdu";	# unsigned divide
141	$UCMPI=	"cmpldi";	# unsigned compare with immediate
142	$UCMP=	"cmpld";	# unsigned compare
143	$CNTLZ=	"cntlzd";	# count leading zeros
144	$SHL=	"sld";		# shift left
145	$SHR=	"srd";		# unsigned shift right
146	$SHRI=	"srdi";		# unsigned shift right by immediate
147	$SHLI=	"sldi";		# shift left by immediate
148	$CLRU=	"clrldi";	# clear upper bits
149	$INSR=	"insrdi";	# insert right
150	$ROTL=	"rotldi";	# rotate left by immediate
151	$TR=	"td";		# conditional trap
152} else { die "nonsense $flavour"; }
153
154$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
155( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
156( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
157die "can't locate ppc-xlate.pl";
158
159open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
160
161$data=<<EOF;
162#--------------------------------------------------------------------
163#
164#
165#
166#
167#	File:		ppc32.s
168#
169#	Created by:	Suresh Chari
170#			IBM Thomas J. Watson Research Library
171#			Hawthorne, NY
172#
173#
174#	Description:	Optimized assembly routines for OpenSSL crypto
175#			on the 32 bitPowerPC platform.
176#
177#
178#	Version History
179#
180#	2. Fixed bn_add,bn_sub and bn_div_words, added comments,
181#	   cleaned up code. Also made a single version which can
182#	   be used for both the AIX and Linux compilers. See NOTE
183#	   below.
184#				12/05/03		Suresh Chari
185#			(with lots of help from)        Andy Polyakov
186##
187#	1. Initial version	10/20/02		Suresh Chari
188#
189#
190#	The following file works for the xlc,cc
191#	and gcc compilers.
192#
193#	NOTE:	To get the file to link correctly with the gcc compiler
194#	        you have to change the names of the routines and remove
195#		the first .(dot) character. This should automatically
196#		be done in the build process.
197#
198#	Hand optimized assembly code for the following routines
199#
200#	bn_sqr_comba4
201#	bn_sqr_comba8
202#	bn_mul_comba4
203#	bn_mul_comba8
204#	bn_sub_words
205#	bn_add_words
206#	bn_div_words
207#	bn_sqr_words
208#	bn_mul_words
209#	bn_mul_add_words
210#
211#	NOTE:	It is possible to optimize this code more for
212#	specific PowerPC or Power architectures. On the Northstar
213#	architecture the optimizations in this file do
214#	 NOT provide much improvement.
215#
216#	If you have comments or suggestions to improve code send
217#	me a note at schari\@us.ibm.com
218#
219#--------------------------------------------------------------------------
220#
221#	Defines to be used in the assembly code.
222#
223#.set r0,0	# we use it as storage for value of 0
224#.set SP,1	# preserved
225#.set RTOC,2	# preserved
226#.set r3,3	# 1st argument/return value
227#.set r4,4	# 2nd argument/volatile register
228#.set r5,5	# 3rd argument/volatile register
229#.set r6,6	# ...
230#.set r7,7
231#.set r8,8
232#.set r9,9
233#.set r10,10
234#.set r11,11
235#.set r12,12
236#.set r13,13	# not used, nor any other "below" it...
237
238#	Declare function names to be global
239#	NOTE:	For gcc these names MUST be changed to remove
240#	        the first . i.e. for example change ".bn_sqr_comba4"
241#		to "bn_sqr_comba4". This should be automatically done
242#		in the build.
243
244	.globl	.bn_sqr_comba4
245	.globl	.bn_sqr_comba8
246	.globl	.bn_mul_comba4
247	.globl	.bn_mul_comba8
248	.globl	.bn_sub_words
249	.globl	.bn_add_words
250	.globl	.bn_div_words
251	.globl	.bn_sqr_words
252	.globl	.bn_mul_words
253	.globl	.bn_mul_add_words
254
255# .text section
256
257	.machine	"any"
258
259#
260#	NOTE:	The following label name should be changed to
261#		"bn_sqr_comba4" i.e. remove the first dot
262#		for the gcc compiler. This should be automatically
263#		done in the build
264#
265
266.align	4
267.bn_sqr_comba4:
268#
269# Optimized version of bn_sqr_comba4.
270#
271# void bn_sqr_comba4(BN_ULONG *r, BN_ULONG *a)
272# r3 contains r
273# r4 contains a
274#
275# Freely use registers r5,r6,r7,r8,r9,r10,r11 as follows:
276#
277# r5,r6 are the two BN_ULONGs being multiplied.
278# r7,r8 are the results of the 32x32 giving 64 bit multiply.
279# r9,r10, r11 are the equivalents of c1,c2, c3.
280# Here's the assembly
281#
282#
283	xor		r0,r0,r0		# set r0 = 0. Used in the addze
284						# instructions below
285
286						#sqr_add_c(a,0,c1,c2,c3)
287	$LD		r5,`0*$BNSZ`(r4)
288	$UMULL		r9,r5,r5
289	$UMULH		r10,r5,r5		#in first iteration. No need
290						#to add since c1=c2=c3=0.
291						# Note c3(r11) is NOT set to 0
292						# but will be.
293
294	$ST		r9,`0*$BNSZ`(r3)	# r[0]=c1;
295						# sqr_add_c2(a,1,0,c2,c3,c1);
296	$LD		r6,`1*$BNSZ`(r4)
297	$UMULL		r7,r5,r6
298	$UMULH		r8,r5,r6
299
300	addc		r7,r7,r7		# compute (r7,r8)=2*(r7,r8)
301	adde		r8,r8,r8
302	addze		r9,r0			# catch carry if any.
303						# r9= r0(=0) and carry
304
305	addc		r10,r7,r10		# now add to temp result.
306	addze		r11,r8                  # r8 added to r11 which is 0
307	addze		r9,r9
308
309	$ST		r10,`1*$BNSZ`(r3)	#r[1]=c2;
310						#sqr_add_c(a,1,c3,c1,c2)
311	$UMULL		r7,r6,r6
312	$UMULH		r8,r6,r6
313	addc		r11,r7,r11
314	adde		r9,r8,r9
315	addze		r10,r0
316						#sqr_add_c2(a,2,0,c3,c1,c2)
317	$LD		r6,`2*$BNSZ`(r4)
318	$UMULL		r7,r5,r6
319	$UMULH		r8,r5,r6
320
321	addc		r7,r7,r7
322	adde		r8,r8,r8
323	addze		r10,r10
324
325	addc		r11,r7,r11
326	adde		r9,r8,r9
327	addze		r10,r10
328	$ST		r11,`2*$BNSZ`(r3)	#r[2]=c3
329						#sqr_add_c2(a,3,0,c1,c2,c3);
330	$LD		r6,`3*$BNSZ`(r4)
331	$UMULL		r7,r5,r6
332	$UMULH		r8,r5,r6
333	addc		r7,r7,r7
334	adde		r8,r8,r8
335	addze		r11,r0
336
337	addc		r9,r7,r9
338	adde		r10,r8,r10
339	addze		r11,r11
340						#sqr_add_c2(a,2,1,c1,c2,c3);
341	$LD		r5,`1*$BNSZ`(r4)
342	$LD		r6,`2*$BNSZ`(r4)
343	$UMULL		r7,r5,r6
344	$UMULH		r8,r5,r6
345
346	addc		r7,r7,r7
347	adde		r8,r8,r8
348	addze		r11,r11
349	addc		r9,r7,r9
350	adde		r10,r8,r10
351	addze		r11,r11
352	$ST		r9,`3*$BNSZ`(r3)	#r[3]=c1
353						#sqr_add_c(a,2,c2,c3,c1);
354	$UMULL		r7,r6,r6
355	$UMULH		r8,r6,r6
356	addc		r10,r7,r10
357	adde		r11,r8,r11
358	addze		r9,r0
359						#sqr_add_c2(a,3,1,c2,c3,c1);
360	$LD		r6,`3*$BNSZ`(r4)
361	$UMULL		r7,r5,r6
362	$UMULH		r8,r5,r6
363	addc		r7,r7,r7
364	adde		r8,r8,r8
365	addze		r9,r9
366
367	addc		r10,r7,r10
368	adde		r11,r8,r11
369	addze		r9,r9
370	$ST		r10,`4*$BNSZ`(r3)	#r[4]=c2
371						#sqr_add_c2(a,3,2,c3,c1,c2);
372	$LD		r5,`2*$BNSZ`(r4)
373	$UMULL		r7,r5,r6
374	$UMULH		r8,r5,r6
375	addc		r7,r7,r7
376	adde		r8,r8,r8
377	addze		r10,r0
378
379	addc		r11,r7,r11
380	adde		r9,r8,r9
381	addze		r10,r10
382	$ST		r11,`5*$BNSZ`(r3)	#r[5] = c3
383						#sqr_add_c(a,3,c1,c2,c3);
384	$UMULL		r7,r6,r6
385	$UMULH		r8,r6,r6
386	addc		r9,r7,r9
387	adde		r10,r8,r10
388
389	$ST		r9,`6*$BNSZ`(r3)	#r[6]=c1
390	$ST		r10,`7*$BNSZ`(r3)	#r[7]=c2
391	blr
392	.long	0
393	.byte	0,12,0x14,0,0,0,2,0
394	.long	0
395.size	.bn_sqr_comba4,.-.bn_sqr_comba4
396
397#
398#	NOTE:	The following label name should be changed to
399#		"bn_sqr_comba8" i.e. remove the first dot
400#		for the gcc compiler. This should be automatically
401#		done in the build
402#
403
404.align	4
405.bn_sqr_comba8:
406#
407# This is an optimized version of the bn_sqr_comba8 routine.
408# Tightly uses the adde instruction
409#
410#
411# void bn_sqr_comba8(BN_ULONG *r, BN_ULONG *a)
412# r3 contains r
413# r4 contains a
414#
415# Freely use registers r5,r6,r7,r8,r9,r10,r11 as follows:
416#
417# r5,r6 are the two BN_ULONGs being multiplied.
418# r7,r8 are the results of the 32x32 giving 64 bit multiply.
419# r9,r10, r11 are the equivalents of c1,c2, c3.
420#
421# Possible optimization of loading all 8 longs of a into registers
422# doesnt provide any speedup
423#
424
425	xor		r0,r0,r0		#set r0 = 0.Used in addze
426						#instructions below.
427
428						#sqr_add_c(a,0,c1,c2,c3);
429	$LD		r5,`0*$BNSZ`(r4)
430	$UMULL		r9,r5,r5		#1st iteration:	no carries.
431	$UMULH		r10,r5,r5
432	$ST		r9,`0*$BNSZ`(r3)	# r[0]=c1;
433						#sqr_add_c2(a,1,0,c2,c3,c1);
434	$LD		r6,`1*$BNSZ`(r4)
435	$UMULL		r7,r5,r6
436	$UMULH		r8,r5,r6
437
438	addc		r10,r7,r10		#add the two register number
439	adde		r11,r8,r0 		# (r8,r7) to the three register
440	addze		r9,r0			# number (r9,r11,r10).NOTE:r0=0
441
442	addc		r10,r7,r10		#add the two register number
443	adde		r11,r8,r11 		# (r8,r7) to the three register
444	addze		r9,r9			# number (r9,r11,r10).
445
446	$ST		r10,`1*$BNSZ`(r3)	# r[1]=c2
447
448						#sqr_add_c(a,1,c3,c1,c2);
449	$UMULL		r7,r6,r6
450	$UMULH		r8,r6,r6
451	addc		r11,r7,r11
452	adde		r9,r8,r9
453	addze		r10,r0
454						#sqr_add_c2(a,2,0,c3,c1,c2);
455	$LD		r6,`2*$BNSZ`(r4)
456	$UMULL		r7,r5,r6
457	$UMULH		r8,r5,r6
458
459	addc		r11,r7,r11
460	adde		r9,r8,r9
461	addze		r10,r10
462
463	addc		r11,r7,r11
464	adde		r9,r8,r9
465	addze		r10,r10
466
467	$ST		r11,`2*$BNSZ`(r3)	#r[2]=c3
468						#sqr_add_c2(a,3,0,c1,c2,c3);
469	$LD		r6,`3*$BNSZ`(r4)	#r6 = a[3]. r5 is already a[0].
470	$UMULL		r7,r5,r6
471	$UMULH		r8,r5,r6
472
473	addc		r9,r7,r9
474	adde		r10,r8,r10
475	addze		r11,r0
476
477	addc		r9,r7,r9
478	adde		r10,r8,r10
479	addze		r11,r11
480						#sqr_add_c2(a,2,1,c1,c2,c3);
481	$LD		r5,`1*$BNSZ`(r4)
482	$LD		r6,`2*$BNSZ`(r4)
483	$UMULL		r7,r5,r6
484	$UMULH		r8,r5,r6
485
486	addc		r9,r7,r9
487	adde		r10,r8,r10
488	addze		r11,r11
489
490	addc		r9,r7,r9
491	adde		r10,r8,r10
492	addze		r11,r11
493
494	$ST		r9,`3*$BNSZ`(r3)	#r[3]=c1;
495						#sqr_add_c(a,2,c2,c3,c1);
496	$UMULL		r7,r6,r6
497	$UMULH		r8,r6,r6
498
499	addc		r10,r7,r10
500	adde		r11,r8,r11
501	addze		r9,r0
502						#sqr_add_c2(a,3,1,c2,c3,c1);
503	$LD		r6,`3*$BNSZ`(r4)
504	$UMULL		r7,r5,r6
505	$UMULH		r8,r5,r6
506
507	addc		r10,r7,r10
508	adde		r11,r8,r11
509	addze		r9,r9
510
511	addc		r10,r7,r10
512	adde		r11,r8,r11
513	addze		r9,r9
514						#sqr_add_c2(a,4,0,c2,c3,c1);
515	$LD		r5,`0*$BNSZ`(r4)
516	$LD		r6,`4*$BNSZ`(r4)
517	$UMULL		r7,r5,r6
518	$UMULH		r8,r5,r6
519
520	addc		r10,r7,r10
521	adde		r11,r8,r11
522	addze		r9,r9
523
524	addc		r10,r7,r10
525	adde		r11,r8,r11
526	addze		r9,r9
527	$ST		r10,`4*$BNSZ`(r3)	#r[4]=c2;
528						#sqr_add_c2(a,5,0,c3,c1,c2);
529	$LD		r6,`5*$BNSZ`(r4)
530	$UMULL		r7,r5,r6
531	$UMULH		r8,r5,r6
532
533	addc		r11,r7,r11
534	adde		r9,r8,r9
535	addze		r10,r0
536
537	addc		r11,r7,r11
538	adde		r9,r8,r9
539	addze		r10,r10
540						#sqr_add_c2(a,4,1,c3,c1,c2);
541	$LD		r5,`1*$BNSZ`(r4)
542	$LD		r6,`4*$BNSZ`(r4)
543	$UMULL		r7,r5,r6
544	$UMULH		r8,r5,r6
545
546	addc		r11,r7,r11
547	adde		r9,r8,r9
548	addze		r10,r10
549
550	addc		r11,r7,r11
551	adde		r9,r8,r9
552	addze		r10,r10
553						#sqr_add_c2(a,3,2,c3,c1,c2);
554	$LD		r5,`2*$BNSZ`(r4)
555	$LD		r6,`3*$BNSZ`(r4)
556	$UMULL		r7,r5,r6
557	$UMULH		r8,r5,r6
558
559	addc		r11,r7,r11
560	adde		r9,r8,r9
561	addze		r10,r10
562
563	addc		r11,r7,r11
564	adde		r9,r8,r9
565	addze		r10,r10
566	$ST		r11,`5*$BNSZ`(r3)	#r[5]=c3;
567						#sqr_add_c(a,3,c1,c2,c3);
568	$UMULL		r7,r6,r6
569	$UMULH		r8,r6,r6
570	addc		r9,r7,r9
571	adde		r10,r8,r10
572	addze		r11,r0
573						#sqr_add_c2(a,4,2,c1,c2,c3);
574	$LD		r6,`4*$BNSZ`(r4)
575	$UMULL		r7,r5,r6
576	$UMULH		r8,r5,r6
577
578	addc		r9,r7,r9
579	adde		r10,r8,r10
580	addze		r11,r11
581
582	addc		r9,r7,r9
583	adde		r10,r8,r10
584	addze		r11,r11
585						#sqr_add_c2(a,5,1,c1,c2,c3);
586	$LD		r5,`1*$BNSZ`(r4)
587	$LD		r6,`5*$BNSZ`(r4)
588	$UMULL		r7,r5,r6
589	$UMULH		r8,r5,r6
590
591	addc		r9,r7,r9
592	adde		r10,r8,r10
593	addze		r11,r11
594
595	addc		r9,r7,r9
596	adde		r10,r8,r10
597	addze		r11,r11
598						#sqr_add_c2(a,6,0,c1,c2,c3);
599	$LD		r5,`0*$BNSZ`(r4)
600	$LD		r6,`6*$BNSZ`(r4)
601	$UMULL		r7,r5,r6
602	$UMULH		r8,r5,r6
603	addc		r9,r7,r9
604	adde		r10,r8,r10
605	addze		r11,r11
606	addc		r9,r7,r9
607	adde		r10,r8,r10
608	addze		r11,r11
609	$ST		r9,`6*$BNSZ`(r3)	#r[6]=c1;
610						#sqr_add_c2(a,7,0,c2,c3,c1);
611	$LD		r6,`7*$BNSZ`(r4)
612	$UMULL		r7,r5,r6
613	$UMULH		r8,r5,r6
614
615	addc		r10,r7,r10
616	adde		r11,r8,r11
617	addze		r9,r0
618	addc		r10,r7,r10
619	adde		r11,r8,r11
620	addze		r9,r9
621						#sqr_add_c2(a,6,1,c2,c3,c1);
622	$LD		r5,`1*$BNSZ`(r4)
623	$LD		r6,`6*$BNSZ`(r4)
624	$UMULL		r7,r5,r6
625	$UMULH		r8,r5,r6
626
627	addc		r10,r7,r10
628	adde		r11,r8,r11
629	addze		r9,r9
630	addc		r10,r7,r10
631	adde		r11,r8,r11
632	addze		r9,r9
633						#sqr_add_c2(a,5,2,c2,c3,c1);
634	$LD		r5,`2*$BNSZ`(r4)
635	$LD		r6,`5*$BNSZ`(r4)
636	$UMULL		r7,r5,r6
637	$UMULH		r8,r5,r6
638	addc		r10,r7,r10
639	adde		r11,r8,r11
640	addze		r9,r9
641	addc		r10,r7,r10
642	adde		r11,r8,r11
643	addze		r9,r9
644						#sqr_add_c2(a,4,3,c2,c3,c1);
645	$LD		r5,`3*$BNSZ`(r4)
646	$LD		r6,`4*$BNSZ`(r4)
647	$UMULL		r7,r5,r6
648	$UMULH		r8,r5,r6
649
650	addc		r10,r7,r10
651	adde		r11,r8,r11
652	addze		r9,r9
653	addc		r10,r7,r10
654	adde		r11,r8,r11
655	addze		r9,r9
656	$ST		r10,`7*$BNSZ`(r3)	#r[7]=c2;
657						#sqr_add_c(a,4,c3,c1,c2);
658	$UMULL		r7,r6,r6
659	$UMULH		r8,r6,r6
660	addc		r11,r7,r11
661	adde		r9,r8,r9
662	addze		r10,r0
663						#sqr_add_c2(a,5,3,c3,c1,c2);
664	$LD		r6,`5*$BNSZ`(r4)
665	$UMULL		r7,r5,r6
666	$UMULH		r8,r5,r6
667	addc		r11,r7,r11
668	adde		r9,r8,r9
669	addze		r10,r10
670	addc		r11,r7,r11
671	adde		r9,r8,r9
672	addze		r10,r10
673						#sqr_add_c2(a,6,2,c3,c1,c2);
674	$LD		r5,`2*$BNSZ`(r4)
675	$LD		r6,`6*$BNSZ`(r4)
676	$UMULL		r7,r5,r6
677	$UMULH		r8,r5,r6
678	addc		r11,r7,r11
679	adde		r9,r8,r9
680	addze		r10,r10
681
682	addc		r11,r7,r11
683	adde		r9,r8,r9
684	addze		r10,r10
685						#sqr_add_c2(a,7,1,c3,c1,c2);
686	$LD		r5,`1*$BNSZ`(r4)
687	$LD		r6,`7*$BNSZ`(r4)
688	$UMULL		r7,r5,r6
689	$UMULH		r8,r5,r6
690	addc		r11,r7,r11
691	adde		r9,r8,r9
692	addze		r10,r10
693	addc		r11,r7,r11
694	adde		r9,r8,r9
695	addze		r10,r10
696	$ST		r11,`8*$BNSZ`(r3)	#r[8]=c3;
697						#sqr_add_c2(a,7,2,c1,c2,c3);
698	$LD		r5,`2*$BNSZ`(r4)
699	$UMULL		r7,r5,r6
700	$UMULH		r8,r5,r6
701
702	addc		r9,r7,r9
703	adde		r10,r8,r10
704	addze		r11,r0
705	addc		r9,r7,r9
706	adde		r10,r8,r10
707	addze		r11,r11
708						#sqr_add_c2(a,6,3,c1,c2,c3);
709	$LD		r5,`3*$BNSZ`(r4)
710	$LD		r6,`6*$BNSZ`(r4)
711	$UMULL		r7,r5,r6
712	$UMULH		r8,r5,r6
713	addc		r9,r7,r9
714	adde		r10,r8,r10
715	addze		r11,r11
716	addc		r9,r7,r9
717	adde		r10,r8,r10
718	addze		r11,r11
719						#sqr_add_c2(a,5,4,c1,c2,c3);
720	$LD		r5,`4*$BNSZ`(r4)
721	$LD		r6,`5*$BNSZ`(r4)
722	$UMULL		r7,r5,r6
723	$UMULH		r8,r5,r6
724	addc		r9,r7,r9
725	adde		r10,r8,r10
726	addze		r11,r11
727	addc		r9,r7,r9
728	adde		r10,r8,r10
729	addze		r11,r11
730	$ST		r9,`9*$BNSZ`(r3)	#r[9]=c1;
731						#sqr_add_c(a,5,c2,c3,c1);
732	$UMULL		r7,r6,r6
733	$UMULH		r8,r6,r6
734	addc		r10,r7,r10
735	adde		r11,r8,r11
736	addze		r9,r0
737						#sqr_add_c2(a,6,4,c2,c3,c1);
738	$LD		r6,`6*$BNSZ`(r4)
739	$UMULL		r7,r5,r6
740	$UMULH		r8,r5,r6
741	addc		r10,r7,r10
742	adde		r11,r8,r11
743	addze		r9,r9
744	addc		r10,r7,r10
745	adde		r11,r8,r11
746	addze		r9,r9
747						#sqr_add_c2(a,7,3,c2,c3,c1);
748	$LD		r5,`3*$BNSZ`(r4)
749	$LD		r6,`7*$BNSZ`(r4)
750	$UMULL		r7,r5,r6
751	$UMULH		r8,r5,r6
752	addc		r10,r7,r10
753	adde		r11,r8,r11
754	addze		r9,r9
755	addc		r10,r7,r10
756	adde		r11,r8,r11
757	addze		r9,r9
758	$ST		r10,`10*$BNSZ`(r3)	#r[10]=c2;
759						#sqr_add_c2(a,7,4,c3,c1,c2);
760	$LD		r5,`4*$BNSZ`(r4)
761	$UMULL		r7,r5,r6
762	$UMULH		r8,r5,r6
763	addc		r11,r7,r11
764	adde		r9,r8,r9
765	addze		r10,r0
766	addc		r11,r7,r11
767	adde		r9,r8,r9
768	addze		r10,r10
769						#sqr_add_c2(a,6,5,c3,c1,c2);
770	$LD		r5,`5*$BNSZ`(r4)
771	$LD		r6,`6*$BNSZ`(r4)
772	$UMULL		r7,r5,r6
773	$UMULH		r8,r5,r6
774	addc		r11,r7,r11
775	adde		r9,r8,r9
776	addze		r10,r10
777	addc		r11,r7,r11
778	adde		r9,r8,r9
779	addze		r10,r10
780	$ST		r11,`11*$BNSZ`(r3)	#r[11]=c3;
781						#sqr_add_c(a,6,c1,c2,c3);
782	$UMULL		r7,r6,r6
783	$UMULH		r8,r6,r6
784	addc		r9,r7,r9
785	adde		r10,r8,r10
786	addze		r11,r0
787						#sqr_add_c2(a,7,5,c1,c2,c3)
788	$LD		r6,`7*$BNSZ`(r4)
789	$UMULL		r7,r5,r6
790	$UMULH		r8,r5,r6
791	addc		r9,r7,r9
792	adde		r10,r8,r10
793	addze		r11,r11
794	addc		r9,r7,r9
795	adde		r10,r8,r10
796	addze		r11,r11
797	$ST		r9,`12*$BNSZ`(r3)	#r[12]=c1;
798
799						#sqr_add_c2(a,7,6,c2,c3,c1)
800	$LD		r5,`6*$BNSZ`(r4)
801	$UMULL		r7,r5,r6
802	$UMULH		r8,r5,r6
803	addc		r10,r7,r10
804	adde		r11,r8,r11
805	addze		r9,r0
806	addc		r10,r7,r10
807	adde		r11,r8,r11
808	addze		r9,r9
809	$ST		r10,`13*$BNSZ`(r3)	#r[13]=c2;
810						#sqr_add_c(a,7,c3,c1,c2);
811	$UMULL		r7,r6,r6
812	$UMULH		r8,r6,r6
813	addc		r11,r7,r11
814	adde		r9,r8,r9
815	$ST		r11,`14*$BNSZ`(r3)	#r[14]=c3;
816	$ST		r9, `15*$BNSZ`(r3)	#r[15]=c1;
817
818
819	blr
820	.long	0
821	.byte	0,12,0x14,0,0,0,2,0
822	.long	0
823.size	.bn_sqr_comba8,.-.bn_sqr_comba8
824
825#
826#	NOTE:	The following label name should be changed to
827#		"bn_mul_comba4" i.e. remove the first dot
828#		for the gcc compiler. This should be automatically
829#		done in the build
830#
831
832.align	4
833.bn_mul_comba4:
834#
835# This is an optimized version of the bn_mul_comba4 routine.
836#
837# void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
838# r3 contains r
839# r4 contains a
840# r5 contains b
841# r6, r7 are the 2 BN_ULONGs being multiplied.
842# r8, r9 are the results of the 32x32 giving 64 multiply.
843# r10, r11, r12 are the equivalents of c1, c2, and c3.
844#
845	xor	r0,r0,r0		#r0=0. Used in addze below.
846					#mul_add_c(a[0],b[0],c1,c2,c3);
847	$LD	r6,`0*$BNSZ`(r4)
848	$LD	r7,`0*$BNSZ`(r5)
849	$UMULL	r10,r6,r7
850	$UMULH	r11,r6,r7
851	$ST	r10,`0*$BNSZ`(r3)	#r[0]=c1
852					#mul_add_c(a[0],b[1],c2,c3,c1);
853	$LD	r7,`1*$BNSZ`(r5)
854	$UMULL	r8,r6,r7
855	$UMULH	r9,r6,r7
856	addc	r11,r8,r11
857	adde	r12,r9,r0
858	addze	r10,r0
859					#mul_add_c(a[1],b[0],c2,c3,c1);
860	$LD	r6, `1*$BNSZ`(r4)
861	$LD	r7, `0*$BNSZ`(r5)
862	$UMULL	r8,r6,r7
863	$UMULH	r9,r6,r7
864	addc	r11,r8,r11
865	adde	r12,r9,r12
866	addze	r10,r10
867	$ST	r11,`1*$BNSZ`(r3)	#r[1]=c2
868					#mul_add_c(a[2],b[0],c3,c1,c2);
869	$LD	r6,`2*$BNSZ`(r4)
870	$UMULL	r8,r6,r7
871	$UMULH	r9,r6,r7
872	addc	r12,r8,r12
873	adde	r10,r9,r10
874	addze	r11,r0
875					#mul_add_c(a[1],b[1],c3,c1,c2);
876	$LD	r6,`1*$BNSZ`(r4)
877	$LD	r7,`1*$BNSZ`(r5)
878	$UMULL	r8,r6,r7
879	$UMULH	r9,r6,r7
880	addc	r12,r8,r12
881	adde	r10,r9,r10
882	addze	r11,r11
883					#mul_add_c(a[0],b[2],c3,c1,c2);
884	$LD	r6,`0*$BNSZ`(r4)
885	$LD	r7,`2*$BNSZ`(r5)
886	$UMULL	r8,r6,r7
887	$UMULH	r9,r6,r7
888	addc	r12,r8,r12
889	adde	r10,r9,r10
890	addze	r11,r11
891	$ST	r12,`2*$BNSZ`(r3)	#r[2]=c3
892					#mul_add_c(a[0],b[3],c1,c2,c3);
893	$LD	r7,`3*$BNSZ`(r5)
894	$UMULL	r8,r6,r7
895	$UMULH	r9,r6,r7
896	addc	r10,r8,r10
897	adde	r11,r9,r11
898	addze	r12,r0
899					#mul_add_c(a[1],b[2],c1,c2,c3);
900	$LD	r6,`1*$BNSZ`(r4)
901	$LD	r7,`2*$BNSZ`(r5)
902	$UMULL	r8,r6,r7
903	$UMULH	r9,r6,r7
904	addc	r10,r8,r10
905	adde	r11,r9,r11
906	addze	r12,r12
907					#mul_add_c(a[2],b[1],c1,c2,c3);
908	$LD	r6,`2*$BNSZ`(r4)
909	$LD	r7,`1*$BNSZ`(r5)
910	$UMULL	r8,r6,r7
911	$UMULH	r9,r6,r7
912	addc	r10,r8,r10
913	adde	r11,r9,r11
914	addze	r12,r12
915					#mul_add_c(a[3],b[0],c1,c2,c3);
916	$LD	r6,`3*$BNSZ`(r4)
917	$LD	r7,`0*$BNSZ`(r5)
918	$UMULL	r8,r6,r7
919	$UMULH	r9,r6,r7
920	addc	r10,r8,r10
921	adde	r11,r9,r11
922	addze	r12,r12
923	$ST	r10,`3*$BNSZ`(r3)	#r[3]=c1
924					#mul_add_c(a[3],b[1],c2,c3,c1);
925	$LD	r7,`1*$BNSZ`(r5)
926	$UMULL	r8,r6,r7
927	$UMULH	r9,r6,r7
928	addc	r11,r8,r11
929	adde	r12,r9,r12
930	addze	r10,r0
931					#mul_add_c(a[2],b[2],c2,c3,c1);
932	$LD	r6,`2*$BNSZ`(r4)
933	$LD	r7,`2*$BNSZ`(r5)
934	$UMULL	r8,r6,r7
935	$UMULH	r9,r6,r7
936	addc	r11,r8,r11
937	adde	r12,r9,r12
938	addze	r10,r10
939					#mul_add_c(a[1],b[3],c2,c3,c1);
940	$LD	r6,`1*$BNSZ`(r4)
941	$LD	r7,`3*$BNSZ`(r5)
942	$UMULL	r8,r6,r7
943	$UMULH	r9,r6,r7
944	addc	r11,r8,r11
945	adde	r12,r9,r12
946	addze	r10,r10
947	$ST	r11,`4*$BNSZ`(r3)	#r[4]=c2
948					#mul_add_c(a[2],b[3],c3,c1,c2);
949	$LD	r6,`2*$BNSZ`(r4)
950	$UMULL	r8,r6,r7
951	$UMULH	r9,r6,r7
952	addc	r12,r8,r12
953	adde	r10,r9,r10
954	addze	r11,r0
955					#mul_add_c(a[3],b[2],c3,c1,c2);
956	$LD	r6,`3*$BNSZ`(r4)
957	$LD	r7,`2*$BNSZ`(r5)
958	$UMULL	r8,r6,r7
959	$UMULH	r9,r6,r7
960	addc	r12,r8,r12
961	adde	r10,r9,r10
962	addze	r11,r11
963	$ST	r12,`5*$BNSZ`(r3)	#r[5]=c3
964					#mul_add_c(a[3],b[3],c1,c2,c3);
965	$LD	r7,`3*$BNSZ`(r5)
966	$UMULL	r8,r6,r7
967	$UMULH	r9,r6,r7
968	addc	r10,r8,r10
969	adde	r11,r9,r11
970
971	$ST	r10,`6*$BNSZ`(r3)	#r[6]=c1
972	$ST	r11,`7*$BNSZ`(r3)	#r[7]=c2
973	blr
974	.long	0
975	.byte	0,12,0x14,0,0,0,3,0
976	.long	0
977.size	.bn_mul_comba4,.-.bn_mul_comba4
978
979#
980#	NOTE:	The following label name should be changed to
981#		"bn_mul_comba8" i.e. remove the first dot
982#		for the gcc compiler. This should be automatically
983#		done in the build
984#
985
986.align	4
987.bn_mul_comba8:
988#
989# Optimized version of the bn_mul_comba8 routine.
990#
991# void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
992# r3 contains r
993# r4 contains a
994# r5 contains b
995# r6, r7 are the 2 BN_ULONGs being multiplied.
996# r8, r9 are the results of the 32x32 giving 64 multiply.
997# r10, r11, r12 are the equivalents of c1, c2, and c3.
998#
999	xor	r0,r0,r0		#r0=0. Used in addze below.
1000
1001					#mul_add_c(a[0],b[0],c1,c2,c3);
1002	$LD	r6,`0*$BNSZ`(r4)	#a[0]
1003	$LD	r7,`0*$BNSZ`(r5)	#b[0]
1004	$UMULL	r10,r6,r7
1005	$UMULH	r11,r6,r7
1006	$ST	r10,`0*$BNSZ`(r3)	#r[0]=c1;
1007					#mul_add_c(a[0],b[1],c2,c3,c1);
1008	$LD	r7,`1*$BNSZ`(r5)
1009	$UMULL	r8,r6,r7
1010	$UMULH	r9,r6,r7
1011	addc	r11,r11,r8
1012	addze	r12,r9			# since we didnt set r12 to zero before.
1013	addze	r10,r0
1014					#mul_add_c(a[1],b[0],c2,c3,c1);
1015	$LD	r6,`1*$BNSZ`(r4)
1016	$LD	r7,`0*$BNSZ`(r5)
1017	$UMULL	r8,r6,r7
1018	$UMULH	r9,r6,r7
1019	addc	r11,r11,r8
1020	adde	r12,r12,r9
1021	addze	r10,r10
1022	$ST	r11,`1*$BNSZ`(r3)	#r[1]=c2;
1023					#mul_add_c(a[2],b[0],c3,c1,c2);
1024	$LD	r6,`2*$BNSZ`(r4)
1025	$UMULL	r8,r6,r7
1026	$UMULH	r9,r6,r7
1027	addc	r12,r12,r8
1028	adde	r10,r10,r9
1029	addze	r11,r0
1030					#mul_add_c(a[1],b[1],c3,c1,c2);
1031	$LD	r6,`1*$BNSZ`(r4)
1032	$LD	r7,`1*$BNSZ`(r5)
1033	$UMULL	r8,r6,r7
1034	$UMULH	r9,r6,r7
1035	addc	r12,r12,r8
1036	adde	r10,r10,r9
1037	addze	r11,r11
1038					#mul_add_c(a[0],b[2],c3,c1,c2);
1039	$LD	r6,`0*$BNSZ`(r4)
1040	$LD	r7,`2*$BNSZ`(r5)
1041	$UMULL	r8,r6,r7
1042	$UMULH	r9,r6,r7
1043	addc	r12,r12,r8
1044	adde	r10,r10,r9
1045	addze	r11,r11
1046	$ST	r12,`2*$BNSZ`(r3)	#r[2]=c3;
1047					#mul_add_c(a[0],b[3],c1,c2,c3);
1048	$LD	r7,`3*$BNSZ`(r5)
1049	$UMULL	r8,r6,r7
1050	$UMULH	r9,r6,r7
1051	addc	r10,r10,r8
1052	adde	r11,r11,r9
1053	addze	r12,r0
1054					#mul_add_c(a[1],b[2],c1,c2,c3);
1055	$LD	r6,`1*$BNSZ`(r4)
1056	$LD	r7,`2*$BNSZ`(r5)
1057	$UMULL	r8,r6,r7
1058	$UMULH	r9,r6,r7
1059	addc	r10,r10,r8
1060	adde	r11,r11,r9
1061	addze	r12,r12
1062
1063					#mul_add_c(a[2],b[1],c1,c2,c3);
1064	$LD	r6,`2*$BNSZ`(r4)
1065	$LD	r7,`1*$BNSZ`(r5)
1066	$UMULL	r8,r6,r7
1067	$UMULH	r9,r6,r7
1068	addc	r10,r10,r8
1069	adde	r11,r11,r9
1070	addze	r12,r12
1071					#mul_add_c(a[3],b[0],c1,c2,c3);
1072	$LD	r6,`3*$BNSZ`(r4)
1073	$LD	r7,`0*$BNSZ`(r5)
1074	$UMULL	r8,r6,r7
1075	$UMULH	r9,r6,r7
1076	addc	r10,r10,r8
1077	adde	r11,r11,r9
1078	addze	r12,r12
1079	$ST	r10,`3*$BNSZ`(r3)	#r[3]=c1;
1080					#mul_add_c(a[4],b[0],c2,c3,c1);
1081	$LD	r6,`4*$BNSZ`(r4)
1082	$UMULL	r8,r6,r7
1083	$UMULH	r9,r6,r7
1084	addc	r11,r11,r8
1085	adde	r12,r12,r9
1086	addze	r10,r0
1087					#mul_add_c(a[3],b[1],c2,c3,c1);
1088	$LD	r6,`3*$BNSZ`(r4)
1089	$LD	r7,`1*$BNSZ`(r5)
1090	$UMULL	r8,r6,r7
1091	$UMULH	r9,r6,r7
1092	addc	r11,r11,r8
1093	adde	r12,r12,r9
1094	addze	r10,r10
1095					#mul_add_c(a[2],b[2],c2,c3,c1);
1096	$LD	r6,`2*$BNSZ`(r4)
1097	$LD	r7,`2*$BNSZ`(r5)
1098	$UMULL	r8,r6,r7
1099	$UMULH	r9,r6,r7
1100	addc	r11,r11,r8
1101	adde	r12,r12,r9
1102	addze	r10,r10
1103					#mul_add_c(a[1],b[3],c2,c3,c1);
1104	$LD	r6,`1*$BNSZ`(r4)
1105	$LD	r7,`3*$BNSZ`(r5)
1106	$UMULL	r8,r6,r7
1107	$UMULH	r9,r6,r7
1108	addc	r11,r11,r8
1109	adde	r12,r12,r9
1110	addze	r10,r10
1111					#mul_add_c(a[0],b[4],c2,c3,c1);
1112	$LD	r6,`0*$BNSZ`(r4)
1113	$LD	r7,`4*$BNSZ`(r5)
1114	$UMULL	r8,r6,r7
1115	$UMULH	r9,r6,r7
1116	addc	r11,r11,r8
1117	adde	r12,r12,r9
1118	addze	r10,r10
1119	$ST	r11,`4*$BNSZ`(r3)	#r[4]=c2;
1120					#mul_add_c(a[0],b[5],c3,c1,c2);
1121	$LD	r7,`5*$BNSZ`(r5)
1122	$UMULL	r8,r6,r7
1123	$UMULH	r9,r6,r7
1124	addc	r12,r12,r8
1125	adde	r10,r10,r9
1126	addze	r11,r0
1127					#mul_add_c(a[1],b[4],c3,c1,c2);
1128	$LD	r6,`1*$BNSZ`(r4)
1129	$LD	r7,`4*$BNSZ`(r5)
1130	$UMULL	r8,r6,r7
1131	$UMULH	r9,r6,r7
1132	addc	r12,r12,r8
1133	adde	r10,r10,r9
1134	addze	r11,r11
1135					#mul_add_c(a[2],b[3],c3,c1,c2);
1136	$LD	r6,`2*$BNSZ`(r4)
1137	$LD	r7,`3*$BNSZ`(r5)
1138	$UMULL	r8,r6,r7
1139	$UMULH	r9,r6,r7
1140	addc	r12,r12,r8
1141	adde	r10,r10,r9
1142	addze	r11,r11
1143					#mul_add_c(a[3],b[2],c3,c1,c2);
1144	$LD	r6,`3*$BNSZ`(r4)
1145	$LD	r7,`2*$BNSZ`(r5)
1146	$UMULL	r8,r6,r7
1147	$UMULH	r9,r6,r7
1148	addc	r12,r12,r8
1149	adde	r10,r10,r9
1150	addze	r11,r11
1151					#mul_add_c(a[4],b[1],c3,c1,c2);
1152	$LD	r6,`4*$BNSZ`(r4)
1153	$LD	r7,`1*$BNSZ`(r5)
1154	$UMULL	r8,r6,r7
1155	$UMULH	r9,r6,r7
1156	addc	r12,r12,r8
1157	adde	r10,r10,r9
1158	addze	r11,r11
1159					#mul_add_c(a[5],b[0],c3,c1,c2);
1160	$LD	r6,`5*$BNSZ`(r4)
1161	$LD	r7,`0*$BNSZ`(r5)
1162	$UMULL	r8,r6,r7
1163	$UMULH	r9,r6,r7
1164	addc	r12,r12,r8
1165	adde	r10,r10,r9
1166	addze	r11,r11
1167	$ST	r12,`5*$BNSZ`(r3)	#r[5]=c3;
1168					#mul_add_c(a[6],b[0],c1,c2,c3);
1169	$LD	r6,`6*$BNSZ`(r4)
1170	$UMULL	r8,r6,r7
1171	$UMULH	r9,r6,r7
1172	addc	r10,r10,r8
1173	adde	r11,r11,r9
1174	addze	r12,r0
1175					#mul_add_c(a[5],b[1],c1,c2,c3);
1176	$LD	r6,`5*$BNSZ`(r4)
1177	$LD	r7,`1*$BNSZ`(r5)
1178	$UMULL	r8,r6,r7
1179	$UMULH	r9,r6,r7
1180	addc	r10,r10,r8
1181	adde	r11,r11,r9
1182	addze	r12,r12
1183					#mul_add_c(a[4],b[2],c1,c2,c3);
1184	$LD	r6,`4*$BNSZ`(r4)
1185	$LD	r7,`2*$BNSZ`(r5)
1186	$UMULL	r8,r6,r7
1187	$UMULH	r9,r6,r7
1188	addc	r10,r10,r8
1189	adde	r11,r11,r9
1190	addze	r12,r12
1191					#mul_add_c(a[3],b[3],c1,c2,c3);
1192	$LD	r6,`3*$BNSZ`(r4)
1193	$LD	r7,`3*$BNSZ`(r5)
1194	$UMULL	r8,r6,r7
1195	$UMULH	r9,r6,r7
1196	addc	r10,r10,r8
1197	adde	r11,r11,r9
1198	addze	r12,r12
1199					#mul_add_c(a[2],b[4],c1,c2,c3);
1200	$LD	r6,`2*$BNSZ`(r4)
1201	$LD	r7,`4*$BNSZ`(r5)
1202	$UMULL	r8,r6,r7
1203	$UMULH	r9,r6,r7
1204	addc	r10,r10,r8
1205	adde	r11,r11,r9
1206	addze	r12,r12
1207					#mul_add_c(a[1],b[5],c1,c2,c3);
1208	$LD	r6,`1*$BNSZ`(r4)
1209	$LD	r7,`5*$BNSZ`(r5)
1210	$UMULL	r8,r6,r7
1211	$UMULH	r9,r6,r7
1212	addc	r10,r10,r8
1213	adde	r11,r11,r9
1214	addze	r12,r12
1215					#mul_add_c(a[0],b[6],c1,c2,c3);
1216	$LD	r6,`0*$BNSZ`(r4)
1217	$LD	r7,`6*$BNSZ`(r5)
1218	$UMULL	r8,r6,r7
1219	$UMULH	r9,r6,r7
1220	addc	r10,r10,r8
1221	adde	r11,r11,r9
1222	addze	r12,r12
1223	$ST	r10,`6*$BNSZ`(r3)	#r[6]=c1;
1224					#mul_add_c(a[0],b[7],c2,c3,c1);
1225	$LD	r7,`7*$BNSZ`(r5)
1226	$UMULL	r8,r6,r7
1227	$UMULH	r9,r6,r7
1228	addc	r11,r11,r8
1229	adde	r12,r12,r9
1230	addze	r10,r0
1231					#mul_add_c(a[1],b[6],c2,c3,c1);
1232	$LD	r6,`1*$BNSZ`(r4)
1233	$LD	r7,`6*$BNSZ`(r5)
1234	$UMULL	r8,r6,r7
1235	$UMULH	r9,r6,r7
1236	addc	r11,r11,r8
1237	adde	r12,r12,r9
1238	addze	r10,r10
1239					#mul_add_c(a[2],b[5],c2,c3,c1);
1240	$LD	r6,`2*$BNSZ`(r4)
1241	$LD	r7,`5*$BNSZ`(r5)
1242	$UMULL	r8,r6,r7
1243	$UMULH	r9,r6,r7
1244	addc	r11,r11,r8
1245	adde	r12,r12,r9
1246	addze	r10,r10
1247					#mul_add_c(a[3],b[4],c2,c3,c1);
1248	$LD	r6,`3*$BNSZ`(r4)
1249	$LD	r7,`4*$BNSZ`(r5)
1250	$UMULL	r8,r6,r7
1251	$UMULH	r9,r6,r7
1252	addc	r11,r11,r8
1253	adde	r12,r12,r9
1254	addze	r10,r10
1255					#mul_add_c(a[4],b[3],c2,c3,c1);
1256	$LD	r6,`4*$BNSZ`(r4)
1257	$LD	r7,`3*$BNSZ`(r5)
1258	$UMULL	r8,r6,r7
1259	$UMULH	r9,r6,r7
1260	addc	r11,r11,r8
1261	adde	r12,r12,r9
1262	addze	r10,r10
1263					#mul_add_c(a[5],b[2],c2,c3,c1);
1264	$LD	r6,`5*$BNSZ`(r4)
1265	$LD	r7,`2*$BNSZ`(r5)
1266	$UMULL	r8,r6,r7
1267	$UMULH	r9,r6,r7
1268	addc	r11,r11,r8
1269	adde	r12,r12,r9
1270	addze	r10,r10
1271					#mul_add_c(a[6],b[1],c2,c3,c1);
1272	$LD	r6,`6*$BNSZ`(r4)
1273	$LD	r7,`1*$BNSZ`(r5)
1274	$UMULL	r8,r6,r7
1275	$UMULH	r9,r6,r7
1276	addc	r11,r11,r8
1277	adde	r12,r12,r9
1278	addze	r10,r10
1279					#mul_add_c(a[7],b[0],c2,c3,c1);
1280	$LD	r6,`7*$BNSZ`(r4)
1281	$LD	r7,`0*$BNSZ`(r5)
1282	$UMULL	r8,r6,r7
1283	$UMULH	r9,r6,r7
1284	addc	r11,r11,r8
1285	adde	r12,r12,r9
1286	addze	r10,r10
1287	$ST	r11,`7*$BNSZ`(r3)	#r[7]=c2;
1288					#mul_add_c(a[7],b[1],c3,c1,c2);
1289	$LD	r7,`1*$BNSZ`(r5)
1290	$UMULL	r8,r6,r7
1291	$UMULH	r9,r6,r7
1292	addc	r12,r12,r8
1293	adde	r10,r10,r9
1294	addze	r11,r0
1295					#mul_add_c(a[6],b[2],c3,c1,c2);
1296	$LD	r6,`6*$BNSZ`(r4)
1297	$LD	r7,`2*$BNSZ`(r5)
1298	$UMULL	r8,r6,r7
1299	$UMULH	r9,r6,r7
1300	addc	r12,r12,r8
1301	adde	r10,r10,r9
1302	addze	r11,r11
1303					#mul_add_c(a[5],b[3],c3,c1,c2);
1304	$LD	r6,`5*$BNSZ`(r4)
1305	$LD	r7,`3*$BNSZ`(r5)
1306	$UMULL	r8,r6,r7
1307	$UMULH	r9,r6,r7
1308	addc	r12,r12,r8
1309	adde	r10,r10,r9
1310	addze	r11,r11
1311					#mul_add_c(a[4],b[4],c3,c1,c2);
1312	$LD	r6,`4*$BNSZ`(r4)
1313	$LD	r7,`4*$BNSZ`(r5)
1314	$UMULL	r8,r6,r7
1315	$UMULH	r9,r6,r7
1316	addc	r12,r12,r8
1317	adde	r10,r10,r9
1318	addze	r11,r11
1319					#mul_add_c(a[3],b[5],c3,c1,c2);
1320	$LD	r6,`3*$BNSZ`(r4)
1321	$LD	r7,`5*$BNSZ`(r5)
1322	$UMULL	r8,r6,r7
1323	$UMULH	r9,r6,r7
1324	addc	r12,r12,r8
1325	adde	r10,r10,r9
1326	addze	r11,r11
1327					#mul_add_c(a[2],b[6],c3,c1,c2);
1328	$LD	r6,`2*$BNSZ`(r4)
1329	$LD	r7,`6*$BNSZ`(r5)
1330	$UMULL	r8,r6,r7
1331	$UMULH	r9,r6,r7
1332	addc	r12,r12,r8
1333	adde	r10,r10,r9
1334	addze	r11,r11
1335					#mul_add_c(a[1],b[7],c3,c1,c2);
1336	$LD	r6,`1*$BNSZ`(r4)
1337	$LD	r7,`7*$BNSZ`(r5)
1338	$UMULL	r8,r6,r7
1339	$UMULH	r9,r6,r7
1340	addc	r12,r12,r8
1341	adde	r10,r10,r9
1342	addze	r11,r11
1343	$ST	r12,`8*$BNSZ`(r3)	#r[8]=c3;
1344					#mul_add_c(a[2],b[7],c1,c2,c3);
1345	$LD	r6,`2*$BNSZ`(r4)
1346	$UMULL	r8,r6,r7
1347	$UMULH	r9,r6,r7
1348	addc	r10,r10,r8
1349	adde	r11,r11,r9
1350	addze	r12,r0
1351					#mul_add_c(a[3],b[6],c1,c2,c3);
1352	$LD	r6,`3*$BNSZ`(r4)
1353	$LD	r7,`6*$BNSZ`(r5)
1354	$UMULL	r8,r6,r7
1355	$UMULH	r9,r6,r7
1356	addc	r10,r10,r8
1357	adde	r11,r11,r9
1358	addze	r12,r12
1359					#mul_add_c(a[4],b[5],c1,c2,c3);
1360	$LD	r6,`4*$BNSZ`(r4)
1361	$LD	r7,`5*$BNSZ`(r5)
1362	$UMULL	r8,r6,r7
1363	$UMULH	r9,r6,r7
1364	addc	r10,r10,r8
1365	adde	r11,r11,r9
1366	addze	r12,r12
1367					#mul_add_c(a[5],b[4],c1,c2,c3);
1368	$LD	r6,`5*$BNSZ`(r4)
1369	$LD	r7,`4*$BNSZ`(r5)
1370	$UMULL	r8,r6,r7
1371	$UMULH	r9,r6,r7
1372	addc	r10,r10,r8
1373	adde	r11,r11,r9
1374	addze	r12,r12
1375					#mul_add_c(a[6],b[3],c1,c2,c3);
1376	$LD	r6,`6*$BNSZ`(r4)
1377	$LD	r7,`3*$BNSZ`(r5)
1378	$UMULL	r8,r6,r7
1379	$UMULH	r9,r6,r7
1380	addc	r10,r10,r8
1381	adde	r11,r11,r9
1382	addze	r12,r12
1383					#mul_add_c(a[7],b[2],c1,c2,c3);
1384	$LD	r6,`7*$BNSZ`(r4)
1385	$LD	r7,`2*$BNSZ`(r5)
1386	$UMULL	r8,r6,r7
1387	$UMULH	r9,r6,r7
1388	addc	r10,r10,r8
1389	adde	r11,r11,r9
1390	addze	r12,r12
1391	$ST	r10,`9*$BNSZ`(r3)	#r[9]=c1;
1392					#mul_add_c(a[7],b[3],c2,c3,c1);
1393	$LD	r7,`3*$BNSZ`(r5)
1394	$UMULL	r8,r6,r7
1395	$UMULH	r9,r6,r7
1396	addc	r11,r11,r8
1397	adde	r12,r12,r9
1398	addze	r10,r0
1399					#mul_add_c(a[6],b[4],c2,c3,c1);
1400	$LD	r6,`6*$BNSZ`(r4)
1401	$LD	r7,`4*$BNSZ`(r5)
1402	$UMULL	r8,r6,r7
1403	$UMULH	r9,r6,r7
1404	addc	r11,r11,r8
1405	adde	r12,r12,r9
1406	addze	r10,r10
1407					#mul_add_c(a[5],b[5],c2,c3,c1);
1408	$LD	r6,`5*$BNSZ`(r4)
1409	$LD	r7,`5*$BNSZ`(r5)
1410	$UMULL	r8,r6,r7
1411	$UMULH	r9,r6,r7
1412	addc	r11,r11,r8
1413	adde	r12,r12,r9
1414	addze	r10,r10
1415					#mul_add_c(a[4],b[6],c2,c3,c1);
1416	$LD	r6,`4*$BNSZ`(r4)
1417	$LD	r7,`6*$BNSZ`(r5)
1418	$UMULL	r8,r6,r7
1419	$UMULH	r9,r6,r7
1420	addc	r11,r11,r8
1421	adde	r12,r12,r9
1422	addze	r10,r10
1423					#mul_add_c(a[3],b[7],c2,c3,c1);
1424	$LD	r6,`3*$BNSZ`(r4)
1425	$LD	r7,`7*$BNSZ`(r5)
1426	$UMULL	r8,r6,r7
1427	$UMULH	r9,r6,r7
1428	addc	r11,r11,r8
1429	adde	r12,r12,r9
1430	addze	r10,r10
1431	$ST	r11,`10*$BNSZ`(r3)	#r[10]=c2;
1432					#mul_add_c(a[4],b[7],c3,c1,c2);
1433	$LD	r6,`4*$BNSZ`(r4)
1434	$UMULL	r8,r6,r7
1435	$UMULH	r9,r6,r7
1436	addc	r12,r12,r8
1437	adde	r10,r10,r9
1438	addze	r11,r0
1439					#mul_add_c(a[5],b[6],c3,c1,c2);
1440	$LD	r6,`5*$BNSZ`(r4)
1441	$LD	r7,`6*$BNSZ`(r5)
1442	$UMULL	r8,r6,r7
1443	$UMULH	r9,r6,r7
1444	addc	r12,r12,r8
1445	adde	r10,r10,r9
1446	addze	r11,r11
1447					#mul_add_c(a[6],b[5],c3,c1,c2);
1448	$LD	r6,`6*$BNSZ`(r4)
1449	$LD	r7,`5*$BNSZ`(r5)
1450	$UMULL	r8,r6,r7
1451	$UMULH	r9,r6,r7
1452	addc	r12,r12,r8
1453	adde	r10,r10,r9
1454	addze	r11,r11
1455					#mul_add_c(a[7],b[4],c3,c1,c2);
1456	$LD	r6,`7*$BNSZ`(r4)
1457	$LD	r7,`4*$BNSZ`(r5)
1458	$UMULL	r8,r6,r7
1459	$UMULH	r9,r6,r7
1460	addc	r12,r12,r8
1461	adde	r10,r10,r9
1462	addze	r11,r11
1463	$ST	r12,`11*$BNSZ`(r3)	#r[11]=c3;
1464					#mul_add_c(a[7],b[5],c1,c2,c3);
1465	$LD	r7,`5*$BNSZ`(r5)
1466	$UMULL	r8,r6,r7
1467	$UMULH	r9,r6,r7
1468	addc	r10,r10,r8
1469	adde	r11,r11,r9
1470	addze	r12,r0
1471					#mul_add_c(a[6],b[6],c1,c2,c3);
1472	$LD	r6,`6*$BNSZ`(r4)
1473	$LD	r7,`6*$BNSZ`(r5)
1474	$UMULL	r8,r6,r7
1475	$UMULH	r9,r6,r7
1476	addc	r10,r10,r8
1477	adde	r11,r11,r9
1478	addze	r12,r12
1479					#mul_add_c(a[5],b[7],c1,c2,c3);
1480	$LD	r6,`5*$BNSZ`(r4)
1481	$LD	r7,`7*$BNSZ`(r5)
1482	$UMULL	r8,r6,r7
1483	$UMULH	r9,r6,r7
1484	addc	r10,r10,r8
1485	adde	r11,r11,r9
1486	addze	r12,r12
1487	$ST	r10,`12*$BNSZ`(r3)	#r[12]=c1;
1488					#mul_add_c(a[6],b[7],c2,c3,c1);
1489	$LD	r6,`6*$BNSZ`(r4)
1490	$UMULL	r8,r6,r7
1491	$UMULH	r9,r6,r7
1492	addc	r11,r11,r8
1493	adde	r12,r12,r9
1494	addze	r10,r0
1495					#mul_add_c(a[7],b[6],c2,c3,c1);
1496	$LD	r6,`7*$BNSZ`(r4)
1497	$LD	r7,`6*$BNSZ`(r5)
1498	$UMULL	r8,r6,r7
1499	$UMULH	r9,r6,r7
1500	addc	r11,r11,r8
1501	adde	r12,r12,r9
1502	addze	r10,r10
1503	$ST	r11,`13*$BNSZ`(r3)	#r[13]=c2;
1504					#mul_add_c(a[7],b[7],c3,c1,c2);
1505	$LD	r7,`7*$BNSZ`(r5)
1506	$UMULL	r8,r6,r7
1507	$UMULH	r9,r6,r7
1508	addc	r12,r12,r8
1509	adde	r10,r10,r9
1510	$ST	r12,`14*$BNSZ`(r3)	#r[14]=c3;
1511	$ST	r10,`15*$BNSZ`(r3)	#r[15]=c1;
1512	blr
1513	.long	0
1514	.byte	0,12,0x14,0,0,0,3,0
1515	.long	0
1516.size	.bn_mul_comba8,.-.bn_mul_comba8
1517
1518#
1519#	NOTE:	The following label name should be changed to
1520#		"bn_sub_words" i.e. remove the first dot
1521#		for the gcc compiler. This should be automatically
1522#		done in the build
1523#
1524#
1525.align	4
1526.bn_sub_words:
1527#
1528#	Handcoded version of bn_sub_words
1529#
1530#BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
1531#
1532#	r3 = r
1533#	r4 = a
1534#	r5 = b
1535#	r6 = n
1536#
1537#       Note:	No loop unrolling done since this is not a performance
1538#               critical loop.
1539
1540	xor	r0,r0,r0	#set r0 = 0
1541#
1542#	check for r6 = 0 AND set carry bit.
1543#
1544	subfc.	r7,r0,r6        # If r6 is 0 then result is 0.
1545				# if r6 > 0 then result !=0
1546				# In either case carry bit is set.
1547	beq	Lppcasm_sub_adios
1548	addi	r4,r4,-$BNSZ
1549	addi	r3,r3,-$BNSZ
1550	addi	r5,r5,-$BNSZ
1551	mtctr	r6
1552Lppcasm_sub_mainloop:
1553	$LDU	r7,$BNSZ(r4)
1554	$LDU	r8,$BNSZ(r5)
1555	subfe	r6,r8,r7	# r6 = r7+carry bit + onescomplement(r8)
1556				# if carry = 1 this is r7-r8. Else it
1557				# is r7-r8 -1 as we need.
1558	$STU	r6,$BNSZ(r3)
1559	bdnz	Lppcasm_sub_mainloop
1560Lppcasm_sub_adios:
1561	subfze	r3,r0		# if carry bit is set then r3 = 0 else -1
1562	andi.	r3,r3,1         # keep only last bit.
1563	blr
1564	.long	0
1565	.byte	0,12,0x14,0,0,0,4,0
1566	.long	0
1567.size	.bn_sub_words,.-.bn_sub_words
1568
1569#
1570#	NOTE:	The following label name should be changed to
1571#		"bn_add_words" i.e. remove the first dot
1572#		for the gcc compiler. This should be automatically
1573#		done in the build
1574#
1575
1576.align	4
1577.bn_add_words:
1578#
1579#	Handcoded version of bn_add_words
1580#
1581#BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
1582#
1583#	r3 = r
1584#	r4 = a
1585#	r5 = b
1586#	r6 = n
1587#
1588#       Note:	No loop unrolling done since this is not a performance
1589#               critical loop.
1590
1591	xor	r0,r0,r0
1592#
1593#	check for r6 = 0. Is this needed?
1594#
1595	addic.	r6,r6,0		#test r6 and clear carry bit.
1596	beq	Lppcasm_add_adios
1597	addi	r4,r4,-$BNSZ
1598	addi	r3,r3,-$BNSZ
1599	addi	r5,r5,-$BNSZ
1600	mtctr	r6
1601Lppcasm_add_mainloop:
1602	$LDU	r7,$BNSZ(r4)
1603	$LDU	r8,$BNSZ(r5)
1604	adde	r8,r7,r8
1605	$STU	r8,$BNSZ(r3)
1606	bdnz	Lppcasm_add_mainloop
1607Lppcasm_add_adios:
1608	addze	r3,r0			#return carry bit.
1609	blr
1610	.long	0
1611	.byte	0,12,0x14,0,0,0,4,0
1612	.long	0
1613.size	.bn_add_words,.-.bn_add_words
1614
1615#
1616#	NOTE:	The following label name should be changed to
1617#		"bn_div_words" i.e. remove the first dot
1618#		for the gcc compiler. This should be automatically
1619#		done in the build
1620#
1621
1622.align	4
1623.bn_div_words:
1624#
1625#	This is a cleaned up version of code generated by
1626#	the AIX compiler. The only optimization is to use
1627#	the PPC instruction to count leading zeros instead
1628#	of call to num_bits_word. Since this was compiled
1629#	only at level -O2 we can possibly squeeze it more?
1630#
1631#	r3 = h
1632#	r4 = l
1633#	r5 = d
1634
1635	$UCMPI	0,r5,0			# compare r5 and 0
1636	bne	Lppcasm_div1		# proceed if d!=0
1637	li	r3,-1			# d=0 return -1
1638	blr
1639Lppcasm_div1:
1640	xor	r0,r0,r0		#r0=0
1641	li	r8,$BITS
1642	$CNTLZ.	r7,r5			#r7 = num leading 0s in d.
1643	beq	Lppcasm_div2		#proceed if no leading zeros
1644	subf	r8,r7,r8		#r8 = BN_num_bits_word(d)
1645	$SHR.	r9,r3,r8		#are there any bits above r8'th?
1646	$TR	16,r9,r0		#if there're, signal to dump core...
1647Lppcasm_div2:
1648	$UCMP	0,r3,r5			#h>=d?
1649	blt	Lppcasm_div3		#goto Lppcasm_div3 if not
1650	subf	r3,r5,r3		#h-=d ;
1651Lppcasm_div3:				#r7 = BN_BITS2-i. so r7=i
1652	cmpi	0,0,r7,0		# is (i == 0)?
1653	beq	Lppcasm_div4
1654	$SHL	r3,r3,r7		# h = (h<< i)
1655	$SHR	r8,r4,r8		# r8 = (l >> BN_BITS2 -i)
1656	$SHL	r5,r5,r7		# d<<=i
1657	or	r3,r3,r8		# h = (h<<i)|(l>>(BN_BITS2-i))
1658	$SHL	r4,r4,r7		# l <<=i
1659Lppcasm_div4:
1660	$SHRI	r9,r5,`$BITS/2`		# r9 = dh
1661					# dl will be computed when needed
1662					# as it saves registers.
1663	li	r6,2			#r6=2
1664	mtctr	r6			#counter will be in count.
1665Lppcasm_divouterloop:
1666	$SHRI	r8,r3,`$BITS/2`		#r8 = (h>>BN_BITS4)
1667	$SHRI	r11,r4,`$BITS/2`	#r11= (l&BN_MASK2h)>>BN_BITS4
1668					# compute here for innerloop.
1669	$UCMP	0,r8,r9			# is (h>>BN_BITS4)==dh
1670	bne	Lppcasm_div5		# goto Lppcasm_div5 if not
1671
1672	li	r8,-1
1673	$CLRU	r8,r8,`$BITS/2`		#q = BN_MASK2l
1674	b	Lppcasm_div6
1675Lppcasm_div5:
1676	$UDIV	r8,r3,r9		#q = h/dh
1677Lppcasm_div6:
1678	$UMULL	r12,r9,r8		#th = q*dh
1679	$CLRU	r10,r5,`$BITS/2`	#r10=dl
1680	$UMULL	r6,r8,r10		#tl = q*dl
1681
1682Lppcasm_divinnerloop:
1683	subf	r10,r12,r3		#t = h -th
1684	$SHRI	r7,r10,`$BITS/2`	#r7= (t &BN_MASK2H), sort of...
1685	addic.	r7,r7,0			#test if r7 == 0. used below.
1686					# now want to compute
1687					# r7 = (t<<BN_BITS4)|((l&BN_MASK2h)>>BN_BITS4)
1688					# the following 2 instructions do that
1689	$SHLI	r7,r10,`$BITS/2`	# r7 = (t<<BN_BITS4)
1690	or	r7,r7,r11		# r7|=((l&BN_MASK2h)>>BN_BITS4)
1691	$UCMP	cr1,r6,r7		# compare (tl <= r7)
1692	bne	Lppcasm_divinnerexit
1693	ble	cr1,Lppcasm_divinnerexit
1694	addi	r8,r8,-1		#q--
1695	subf	r12,r9,r12		#th -=dh
1696	$CLRU	r10,r5,`$BITS/2`	#r10=dl. t is no longer needed in loop.
1697	subf	r6,r10,r6		#tl -=dl
1698	b	Lppcasm_divinnerloop
1699Lppcasm_divinnerexit:
1700	$SHRI	r10,r6,`$BITS/2`	#t=(tl>>BN_BITS4)
1701	$SHLI	r11,r6,`$BITS/2`	#tl=(tl<<BN_BITS4)&BN_MASK2h;
1702	$UCMP	cr1,r4,r11		# compare l and tl
1703	add	r12,r12,r10		# th+=t
1704	bge	cr1,Lppcasm_div7	# if (l>=tl) goto Lppcasm_div7
1705	addi	r12,r12,1		# th++
1706Lppcasm_div7:
1707	subf	r11,r11,r4		#r11=l-tl
1708	$UCMP	cr1,r3,r12		#compare h and th
1709	bge	cr1,Lppcasm_div8	#if (h>=th) goto Lppcasm_div8
1710	addi	r8,r8,-1		# q--
1711	add	r3,r5,r3		# h+=d
1712Lppcasm_div8:
1713	subf	r12,r12,r3		#r12 = h-th
1714	$SHLI	r4,r11,`$BITS/2`	#l=(l&BN_MASK2l)<<BN_BITS4
1715					# want to compute
1716					# h = ((h<<BN_BITS4)|(l>>BN_BITS4))&BN_MASK2
1717					# the following 2 instructions will do this.
1718	$INSR	r11,r12,`$BITS/2`,`$BITS/2`	# r11 is the value we want rotated $BITS/2.
1719	$ROTL	r3,r11,`$BITS/2`	# rotate by $BITS/2 and store in r3
1720	bdz	Lppcasm_div9		#if (count==0) break ;
1721	$SHLI	r0,r8,`$BITS/2`		#ret =q<<BN_BITS4
1722	b	Lppcasm_divouterloop
1723Lppcasm_div9:
1724	or	r3,r8,r0
1725	blr
1726	.long	0
1727	.byte	0,12,0x14,0,0,0,3,0
1728	.long	0
1729.size	.bn_div_words,.-.bn_div_words
1730
1731#
1732#	NOTE:	The following label name should be changed to
1733#		"bn_sqr_words" i.e. remove the first dot
1734#		for the gcc compiler. This should be automatically
1735#		done in the build
1736#
1737.align	4
1738.bn_sqr_words:
1739#
1740#	Optimized version of bn_sqr_words
1741#
1742#	void bn_sqr_words(BN_ULONG *r, BN_ULONG *a, int n)
1743#
1744#	r3 = r
1745#	r4 = a
1746#	r5 = n
1747#
1748#	r6 = a[i].
1749#	r7,r8 = product.
1750#
1751#	No unrolling done here. Not performance critical.
1752
1753	addic.	r5,r5,0			#test r5.
1754	beq	Lppcasm_sqr_adios
1755	addi	r4,r4,-$BNSZ
1756	addi	r3,r3,-$BNSZ
1757	mtctr	r5
1758Lppcasm_sqr_mainloop:
1759					#sqr(r[0],r[1],a[0]);
1760	$LDU	r6,$BNSZ(r4)
1761	$UMULL	r7,r6,r6
1762	$UMULH  r8,r6,r6
1763	$STU	r7,$BNSZ(r3)
1764	$STU	r8,$BNSZ(r3)
1765	bdnz	Lppcasm_sqr_mainloop
1766Lppcasm_sqr_adios:
1767	blr
1768	.long	0
1769	.byte	0,12,0x14,0,0,0,3,0
1770	.long	0
1771.size	.bn_sqr_words,.-.bn_sqr_words
1772
1773#
1774#	NOTE:	The following label name should be changed to
1775#		"bn_mul_words" i.e. remove the first dot
1776#		for the gcc compiler. This should be automatically
1777#		done in the build
1778#
1779
1780.align	4
1781.bn_mul_words:
1782#
1783# BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
1784#
1785# r3 = rp
1786# r4 = ap
1787# r5 = num
1788# r6 = w
1789	xor	r0,r0,r0
1790	xor	r12,r12,r12		# used for carry
1791	rlwinm.	r7,r5,30,2,31		# num >> 2
1792	beq	Lppcasm_mw_REM
1793	mtctr	r7
1794Lppcasm_mw_LOOP:
1795					#mul(rp[0],ap[0],w,c1);
1796	$LD	r8,`0*$BNSZ`(r4)
1797	$UMULL	r9,r6,r8
1798	$UMULH  r10,r6,r8
1799	addc	r9,r9,r12
1800	#addze	r10,r10			#carry is NOT ignored.
1801					#will be taken care of
1802					#in second spin below
1803					#using adde.
1804	$ST	r9,`0*$BNSZ`(r3)
1805					#mul(rp[1],ap[1],w,c1);
1806	$LD	r8,`1*$BNSZ`(r4)
1807	$UMULL	r11,r6,r8
1808	$UMULH  r12,r6,r8
1809	adde	r11,r11,r10
1810	#addze	r12,r12
1811	$ST	r11,`1*$BNSZ`(r3)
1812					#mul(rp[2],ap[2],w,c1);
1813	$LD	r8,`2*$BNSZ`(r4)
1814	$UMULL	r9,r6,r8
1815	$UMULH  r10,r6,r8
1816	adde	r9,r9,r12
1817	#addze	r10,r10
1818	$ST	r9,`2*$BNSZ`(r3)
1819					#mul_add(rp[3],ap[3],w,c1);
1820	$LD	r8,`3*$BNSZ`(r4)
1821	$UMULL	r11,r6,r8
1822	$UMULH  r12,r6,r8
1823	adde	r11,r11,r10
1824	addze	r12,r12			#this spin we collect carry into
1825					#r12
1826	$ST	r11,`3*$BNSZ`(r3)
1827
1828	addi	r3,r3,`4*$BNSZ`
1829	addi	r4,r4,`4*$BNSZ`
1830	bdnz	Lppcasm_mw_LOOP
1831
1832Lppcasm_mw_REM:
1833	andi.	r5,r5,0x3
1834	beq	Lppcasm_mw_OVER
1835					#mul(rp[0],ap[0],w,c1);
1836	$LD	r8,`0*$BNSZ`(r4)
1837	$UMULL	r9,r6,r8
1838	$UMULH  r10,r6,r8
1839	addc	r9,r9,r12
1840	addze	r10,r10
1841	$ST	r9,`0*$BNSZ`(r3)
1842	addi	r12,r10,0
1843
1844	addi	r5,r5,-1
1845	cmpli	0,0,r5,0
1846	beq	Lppcasm_mw_OVER
1847
1848
1849					#mul(rp[1],ap[1],w,c1);
1850	$LD	r8,`1*$BNSZ`(r4)
1851	$UMULL	r9,r6,r8
1852	$UMULH  r10,r6,r8
1853	addc	r9,r9,r12
1854	addze	r10,r10
1855	$ST	r9,`1*$BNSZ`(r3)
1856	addi	r12,r10,0
1857
1858	addi	r5,r5,-1
1859	cmpli	0,0,r5,0
1860	beq	Lppcasm_mw_OVER
1861
1862					#mul_add(rp[2],ap[2],w,c1);
1863	$LD	r8,`2*$BNSZ`(r4)
1864	$UMULL	r9,r6,r8
1865	$UMULH  r10,r6,r8
1866	addc	r9,r9,r12
1867	addze	r10,r10
1868	$ST	r9,`2*$BNSZ`(r3)
1869	addi	r12,r10,0
1870
1871Lppcasm_mw_OVER:
1872	addi	r3,r12,0
1873	blr
1874	.long	0
1875	.byte	0,12,0x14,0,0,0,4,0
1876	.long	0
1877.size	bn_mul_words,.-bn_mul_words
1878
1879#
1880#	NOTE:	The following label name should be changed to
1881#		"bn_mul_add_words" i.e. remove the first dot
1882#		for the gcc compiler. This should be automatically
1883#		done in the build
1884#
1885
1886.align	4
1887.bn_mul_add_words:
1888#
1889# BN_ULONG bn_mul_add_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
1890#
1891# r3 = rp
1892# r4 = ap
1893# r5 = num
1894# r6 = w
1895#
1896# empirical evidence suggests that unrolled version performs best!!
1897#
1898	xor	r0,r0,r0		#r0 = 0
1899	xor	r12,r12,r12  		#r12 = 0 . used for carry
1900	rlwinm.	r7,r5,30,2,31		# num >> 2
1901	beq	Lppcasm_maw_leftover	# if (num < 4) go LPPCASM_maw_leftover
1902	mtctr	r7
1903Lppcasm_maw_mainloop:
1904					#mul_add(rp[0],ap[0],w,c1);
1905	$LD	r8,`0*$BNSZ`(r4)
1906	$LD	r11,`0*$BNSZ`(r3)
1907	$UMULL	r9,r6,r8
1908	$UMULH  r10,r6,r8
1909	addc	r9,r9,r12		#r12 is carry.
1910	addze	r10,r10
1911	addc	r9,r9,r11
1912	#addze	r10,r10
1913					#the above instruction addze
1914					#is NOT needed. Carry will NOT
1915					#be ignored. It's not affected
1916					#by multiply and will be collected
1917					#in the next spin
1918	$ST	r9,`0*$BNSZ`(r3)
1919
1920					#mul_add(rp[1],ap[1],w,c1);
1921	$LD	r8,`1*$BNSZ`(r4)
1922	$LD	r9,`1*$BNSZ`(r3)
1923	$UMULL	r11,r6,r8
1924	$UMULH  r12,r6,r8
1925	adde	r11,r11,r10		#r10 is carry.
1926	addze	r12,r12
1927	addc	r11,r11,r9
1928	#addze	r12,r12
1929	$ST	r11,`1*$BNSZ`(r3)
1930
1931					#mul_add(rp[2],ap[2],w,c1);
1932	$LD	r8,`2*$BNSZ`(r4)
1933	$UMULL	r9,r6,r8
1934	$LD	r11,`2*$BNSZ`(r3)
1935	$UMULH  r10,r6,r8
1936	adde	r9,r9,r12
1937	addze	r10,r10
1938	addc	r9,r9,r11
1939	#addze	r10,r10
1940	$ST	r9,`2*$BNSZ`(r3)
1941
1942					#mul_add(rp[3],ap[3],w,c1);
1943	$LD	r8,`3*$BNSZ`(r4)
1944	$UMULL	r11,r6,r8
1945	$LD	r9,`3*$BNSZ`(r3)
1946	$UMULH  r12,r6,r8
1947	adde	r11,r11,r10
1948	addze	r12,r12
1949	addc	r11,r11,r9
1950	addze	r12,r12
1951	$ST	r11,`3*$BNSZ`(r3)
1952	addi	r3,r3,`4*$BNSZ`
1953	addi	r4,r4,`4*$BNSZ`
1954	bdnz	Lppcasm_maw_mainloop
1955
1956Lppcasm_maw_leftover:
1957	andi.	r5,r5,0x3
1958	beq	Lppcasm_maw_adios
1959	addi	r3,r3,-$BNSZ
1960	addi	r4,r4,-$BNSZ
1961					#mul_add(rp[0],ap[0],w,c1);
1962	mtctr	r5
1963	$LDU	r8,$BNSZ(r4)
1964	$UMULL	r9,r6,r8
1965	$UMULH  r10,r6,r8
1966	$LDU	r11,$BNSZ(r3)
1967	addc	r9,r9,r11
1968	addze	r10,r10
1969	addc	r9,r9,r12
1970	addze	r12,r10
1971	$ST	r9,0(r3)
1972
1973	bdz	Lppcasm_maw_adios
1974					#mul_add(rp[1],ap[1],w,c1);
1975	$LDU	r8,$BNSZ(r4)
1976	$UMULL	r9,r6,r8
1977	$UMULH  r10,r6,r8
1978	$LDU	r11,$BNSZ(r3)
1979	addc	r9,r9,r11
1980	addze	r10,r10
1981	addc	r9,r9,r12
1982	addze	r12,r10
1983	$ST	r9,0(r3)
1984
1985	bdz	Lppcasm_maw_adios
1986					#mul_add(rp[2],ap[2],w,c1);
1987	$LDU	r8,$BNSZ(r4)
1988	$UMULL	r9,r6,r8
1989	$UMULH  r10,r6,r8
1990	$LDU	r11,$BNSZ(r3)
1991	addc	r9,r9,r11
1992	addze	r10,r10
1993	addc	r9,r9,r12
1994	addze	r12,r10
1995	$ST	r9,0(r3)
1996
1997Lppcasm_maw_adios:
1998	addi	r3,r12,0
1999	blr
2000	.long	0
2001	.byte	0,12,0x14,0,0,0,4,0
2002	.long	0
2003.size	.bn_mul_add_words,.-.bn_mul_add_words
2004	.align	4
2005EOF
2006$data =~ s/\`([^\`]*)\`/eval $1/gem;
2007print $data;
2008close STDOUT;
2009