e3a38bd1401392d57f84b75d3413b7bcf3562b44
[openssl.git] / crypto / bn / asm / mips.pl
1 #! /usr/bin/env perl
2 # Copyright 2010-2016 The OpenSSL Project Authors. All Rights Reserved.
3 #
4 # Licensed under the OpenSSL license (the "License").  You may not use
5 # this file except in compliance with the License.  You can obtain a copy
6 # in the file LICENSE in the source distribution or at
7 # https://www.openssl.org/source/license.html
8
9 #
10 # ====================================================================
11 # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
12 # project.
13 #
14 # Rights for redistribution and usage in source and binary forms are
15 # granted according to the OpenSSL license. Warranty of any kind is
16 # disclaimed.
17 # ====================================================================
18
19
20 # July 1999
21 #
22 # This is drop-in MIPS III/IV ISA replacement for crypto/bn/bn_asm.c.
23 #
24 # The module is designed to work with either of the "new" MIPS ABI(5),
25 # namely N32 or N64, offered by IRIX 6.x. It's not ment to work under
26 # IRIX 5.x not only because it doesn't support new ABIs but also
27 # because 5.x kernels put R4x00 CPU into 32-bit mode and all those
28 # 64-bit instructions (daddu, dmultu, etc.) found below gonna only
29 # cause illegal instruction exception:-(
30 #
31 # In addition the code depends on preprocessor flags set up by MIPSpro
32 # compiler driver (either as or cc) and therefore (probably?) can't be
33 # compiled by the GNU assembler. GNU C driver manages fine though...
34 # I mean as long as -mmips-as is specified or is the default option,
35 # because then it simply invokes /usr/bin/as which in turn takes
36 # perfect care of the preprocessor definitions. Another neat feature
37 # offered by the MIPSpro assembler is an optimization pass. This gave
38 # me the opportunity to have the code looking more regular as all those
39 # architecture dependent instruction rescheduling details were left to
40 # the assembler. Cool, huh?
41 #
42 # Performance improvement is astonishing! 'apps/openssl speed rsa dsa'
43 # goes way over 3 times faster!
44 #
45 #                                       <appro@fy.chalmers.se>
46
47 # October 2010
48 #
49 # Adapt the module even for 32-bit ABIs and other OSes. The former was
50 # achieved by mechanical replacement of 64-bit arithmetic instructions
51 # such as dmultu, daddu, etc. with their 32-bit counterparts and
52 # adjusting offsets denoting multiples of BN_ULONG. Above mentioned
53 # >3x performance improvement naturally does not apply to 32-bit code
54 # [because there is no instruction 32-bit compiler can't use], one
55 # has to content with 40-85% improvement depending on benchmark and
56 # key length, more for longer keys.
57
58 $flavour = shift || "o32";
59 while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
60 open STDOUT,">$output";
61
62 if ($flavour =~ /64|n32/i) {
63         $LD="ld";
64         $ST="sd";
65         $MULTU="dmultu";
66         $DIVU="ddivu";
67         $ADDU="daddu";
68         $SUBU="dsubu";
69         $SRL="dsrl";
70         $SLL="dsll";
71         $BNSZ=8;
72         $PTR_ADD="daddu";
73         $PTR_SUB="dsubu";
74         $SZREG=8;
75         $REG_S="sd";
76         $REG_L="ld";
77 } else {
78         $LD="lw";
79         $ST="sw";
80         $MULTU="multu";
81         $DIVU="divu";
82         $ADDU="addu";
83         $SUBU="subu";
84         $SRL="srl";
85         $SLL="sll";
86         $BNSZ=4;
87         $PTR_ADD="addu";
88         $PTR_SUB="subu";
89         $SZREG=4;
90         $REG_S="sw";
91         $REG_L="lw";
92         $code=".set     mips2\n";
93 }
94
95 # Below is N32/64 register layout used in the original module.
96 #
97 ($zero,$at,$v0,$v1)=map("\$$_",(0..3));
98 ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
99 ($t0,$t1,$t2,$t3,$t8,$t9)=map("\$$_",(12..15,24,25));
100 ($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7)=map("\$$_",(16..23));
101 ($gp,$sp,$fp,$ra)=map("\$$_",(28..31));
102 ($ta0,$ta1,$ta2,$ta3)=($a4,$a5,$a6,$a7);
103 #
104 # No special adaptation is required for O32. NUBI on the other hand
105 # is treated by saving/restoring ($v1,$t0..$t3).
106
107 $gp=$v1 if ($flavour =~ /nubi/i);
108
109 $minus4=$v1;
110
111 $code.=<<___;
112 .rdata
113 .asciiz "mips3.s, Version 1.2"
114 .asciiz "MIPS II/III/IV ISA artwork by Andy Polyakov <appro\@fy.chalmers.se>"
115
116 .text
117 .set    noat
118
119 .align  5
120 .globl  bn_mul_add_words
121 .ent    bn_mul_add_words
122 bn_mul_add_words:
123         .set    noreorder
124         bgtz    $a2,bn_mul_add_words_internal
125         move    $v0,$zero
126         jr      $ra
127         move    $a0,$v0
128 .end    bn_mul_add_words
129
130 .align  5
131 .ent    bn_mul_add_words_internal
132 bn_mul_add_words_internal:
133 ___
134 $code.=<<___ if ($flavour =~ /nubi/i);
135         .frame  $sp,6*$SZREG,$ra
136         .mask   0x8000f008,-$SZREG
137         .set    noreorder
138         $PTR_SUB $sp,6*$SZREG
139         $REG_S  $ra,5*$SZREG($sp)
140         $REG_S  $t3,4*$SZREG($sp)
141         $REG_S  $t2,3*$SZREG($sp)
142         $REG_S  $t1,2*$SZREG($sp)
143         $REG_S  $t0,1*$SZREG($sp)
144         $REG_S  $gp,0*$SZREG($sp)
145 ___
146 $code.=<<___;
147         .set    reorder
148         li      $minus4,-4
149         and     $ta0,$a2,$minus4
150         beqz    $ta0,.L_bn_mul_add_words_tail
151
152 .L_bn_mul_add_words_loop:
153         $LD     $t0,0($a1)
154         $MULTU  $t0,$a3
155         $LD     $t1,0($a0)
156         $LD     $t2,$BNSZ($a1)
157         $LD     $t3,$BNSZ($a0)
158         $LD     $ta0,2*$BNSZ($a1)
159         $LD     $ta1,2*$BNSZ($a0)
160         $ADDU   $t1,$v0
161         sltu    $v0,$t1,$v0     # All manuals say it "compares 32-bit
162                                 # values", but it seems to work fine
163                                 # even on 64-bit registers.
164         mflo    $at
165         mfhi    $t0
166         $ADDU   $t1,$at
167         $ADDU   $v0,$t0
168          $MULTU $t2,$a3
169         sltu    $at,$t1,$at
170         $ST     $t1,0($a0)
171         $ADDU   $v0,$at
172
173         $LD     $ta2,3*$BNSZ($a1)
174         $LD     $ta3,3*$BNSZ($a0)
175         $ADDU   $t3,$v0
176         sltu    $v0,$t3,$v0
177         mflo    $at
178         mfhi    $t2
179         $ADDU   $t3,$at
180         $ADDU   $v0,$t2
181          $MULTU $ta0,$a3
182         sltu    $at,$t3,$at
183         $ST     $t3,$BNSZ($a0)
184         $ADDU   $v0,$at
185
186         subu    $a2,4
187         $PTR_ADD $a0,4*$BNSZ
188         $PTR_ADD $a1,4*$BNSZ
189         $ADDU   $ta1,$v0
190         sltu    $v0,$ta1,$v0
191         mflo    $at
192         mfhi    $ta0
193         $ADDU   $ta1,$at
194         $ADDU   $v0,$ta0
195          $MULTU $ta2,$a3
196         sltu    $at,$ta1,$at
197         $ST     $ta1,-2*$BNSZ($a0)
198         $ADDU   $v0,$at
199
200
201         and     $ta0,$a2,$minus4
202         $ADDU   $ta3,$v0
203         sltu    $v0,$ta3,$v0
204         mflo    $at
205         mfhi    $ta2
206         $ADDU   $ta3,$at
207         $ADDU   $v0,$ta2
208         sltu    $at,$ta3,$at
209         $ST     $ta3,-$BNSZ($a0)
210         .set    noreorder
211         bgtz    $ta0,.L_bn_mul_add_words_loop
212         $ADDU   $v0,$at
213
214         beqz    $a2,.L_bn_mul_add_words_return
215         nop
216
217 .L_bn_mul_add_words_tail:
218         .set    reorder
219         $LD     $t0,0($a1)
220         $MULTU  $t0,$a3
221         $LD     $t1,0($a0)
222         subu    $a2,1
223         $ADDU   $t1,$v0
224         sltu    $v0,$t1,$v0
225         mflo    $at
226         mfhi    $t0
227         $ADDU   $t1,$at
228         $ADDU   $v0,$t0
229         sltu    $at,$t1,$at
230         $ST     $t1,0($a0)
231         $ADDU   $v0,$at
232         beqz    $a2,.L_bn_mul_add_words_return
233
234         $LD     $t0,$BNSZ($a1)
235         $MULTU  $t0,$a3
236         $LD     $t1,$BNSZ($a0)
237         subu    $a2,1
238         $ADDU   $t1,$v0
239         sltu    $v0,$t1,$v0
240         mflo    $at
241         mfhi    $t0
242         $ADDU   $t1,$at
243         $ADDU   $v0,$t0
244         sltu    $at,$t1,$at
245         $ST     $t1,$BNSZ($a0)
246         $ADDU   $v0,$at
247         beqz    $a2,.L_bn_mul_add_words_return
248
249         $LD     $t0,2*$BNSZ($a1)
250         $MULTU  $t0,$a3
251         $LD     $t1,2*$BNSZ($a0)
252         $ADDU   $t1,$v0
253         sltu    $v0,$t1,$v0
254         mflo    $at
255         mfhi    $t0
256         $ADDU   $t1,$at
257         $ADDU   $v0,$t0
258         sltu    $at,$t1,$at
259         $ST     $t1,2*$BNSZ($a0)
260         $ADDU   $v0,$at
261
262 .L_bn_mul_add_words_return:
263         .set    noreorder
264 ___
265 $code.=<<___ if ($flavour =~ /nubi/i);
266         $REG_L  $t3,4*$SZREG($sp)
267         $REG_L  $t2,3*$SZREG($sp)
268         $REG_L  $t1,2*$SZREG($sp)
269         $REG_L  $t0,1*$SZREG($sp)
270         $REG_L  $gp,0*$SZREG($sp)
271         $PTR_ADD $sp,6*$SZREG
272 ___
273 $code.=<<___;
274         jr      $ra
275         move    $a0,$v0
276 .end    bn_mul_add_words_internal
277
278 .align  5
279 .globl  bn_mul_words
280 .ent    bn_mul_words
281 bn_mul_words:
282         .set    noreorder
283         bgtz    $a2,bn_mul_words_internal
284         move    $v0,$zero
285         jr      $ra
286         move    $a0,$v0
287 .end    bn_mul_words
288
289 .align  5
290 .ent    bn_mul_words_internal
291 bn_mul_words_internal:
292 ___
293 $code.=<<___ if ($flavour =~ /nubi/i);
294         .frame  $sp,6*$SZREG,$ra
295         .mask   0x8000f008,-$SZREG
296         .set    noreorder
297         $PTR_SUB $sp,6*$SZREG
298         $REG_S  $ra,5*$SZREG($sp)
299         $REG_S  $t3,4*$SZREG($sp)
300         $REG_S  $t2,3*$SZREG($sp)
301         $REG_S  $t1,2*$SZREG($sp)
302         $REG_S  $t0,1*$SZREG($sp)
303         $REG_S  $gp,0*$SZREG($sp)
304 ___
305 $code.=<<___;
306         .set    reorder
307         li      $minus4,-4
308         and     $ta0,$a2,$minus4
309         beqz    $ta0,.L_bn_mul_words_tail
310
311 .L_bn_mul_words_loop:
312         $LD     $t0,0($a1)
313         $MULTU  $t0,$a3
314         $LD     $t2,$BNSZ($a1)
315         $LD     $ta0,2*$BNSZ($a1)
316         $LD     $ta2,3*$BNSZ($a1)
317         mflo    $at
318         mfhi    $t0
319         $ADDU   $v0,$at
320         sltu    $t1,$v0,$at
321          $MULTU $t2,$a3
322         $ST     $v0,0($a0)
323         $ADDU   $v0,$t1,$t0
324
325         subu    $a2,4
326         $PTR_ADD $a0,4*$BNSZ
327         $PTR_ADD $a1,4*$BNSZ
328         mflo    $at
329         mfhi    $t2
330         $ADDU   $v0,$at
331         sltu    $t3,$v0,$at
332          $MULTU $ta0,$a3
333         $ST     $v0,-3*$BNSZ($a0)
334         $ADDU   $v0,$t3,$t2
335
336         mflo    $at
337         mfhi    $ta0
338         $ADDU   $v0,$at
339         sltu    $ta1,$v0,$at
340          $MULTU $ta2,$a3
341         $ST     $v0,-2*$BNSZ($a0)
342         $ADDU   $v0,$ta1,$ta0
343
344         and     $ta0,$a2,$minus4
345         mflo    $at
346         mfhi    $ta2
347         $ADDU   $v0,$at
348         sltu    $ta3,$v0,$at
349         $ST     $v0,-$BNSZ($a0)
350         .set    noreorder
351         bgtz    $ta0,.L_bn_mul_words_loop
352         $ADDU   $v0,$ta3,$ta2
353
354         beqz    $a2,.L_bn_mul_words_return
355         nop
356
357 .L_bn_mul_words_tail:
358         .set    reorder
359         $LD     $t0,0($a1)
360         $MULTU  $t0,$a3
361         subu    $a2,1
362         mflo    $at
363         mfhi    $t0
364         $ADDU   $v0,$at
365         sltu    $t1,$v0,$at
366         $ST     $v0,0($a0)
367         $ADDU   $v0,$t1,$t0
368         beqz    $a2,.L_bn_mul_words_return
369
370         $LD     $t0,$BNSZ($a1)
371         $MULTU  $t0,$a3
372         subu    $a2,1
373         mflo    $at
374         mfhi    $t0
375         $ADDU   $v0,$at
376         sltu    $t1,$v0,$at
377         $ST     $v0,$BNSZ($a0)
378         $ADDU   $v0,$t1,$t0
379         beqz    $a2,.L_bn_mul_words_return
380
381         $LD     $t0,2*$BNSZ($a1)
382         $MULTU  $t0,$a3
383         mflo    $at
384         mfhi    $t0
385         $ADDU   $v0,$at
386         sltu    $t1,$v0,$at
387         $ST     $v0,2*$BNSZ($a0)
388         $ADDU   $v0,$t1,$t0
389
390 .L_bn_mul_words_return:
391         .set    noreorder
392 ___
393 $code.=<<___ if ($flavour =~ /nubi/i);
394         $REG_L  $t3,4*$SZREG($sp)
395         $REG_L  $t2,3*$SZREG($sp)
396         $REG_L  $t1,2*$SZREG($sp)
397         $REG_L  $t0,1*$SZREG($sp)
398         $REG_L  $gp,0*$SZREG($sp)
399         $PTR_ADD $sp,6*$SZREG
400 ___
401 $code.=<<___;
402         jr      $ra
403         move    $a0,$v0
404 .end    bn_mul_words_internal
405
406 .align  5
407 .globl  bn_sqr_words
408 .ent    bn_sqr_words
409 bn_sqr_words:
410         .set    noreorder
411         bgtz    $a2,bn_sqr_words_internal
412         move    $v0,$zero
413         jr      $ra
414         move    $a0,$v0
415 .end    bn_sqr_words
416
417 .align  5
418 .ent    bn_sqr_words_internal
419 bn_sqr_words_internal:
420 ___
421 $code.=<<___ if ($flavour =~ /nubi/i);
422         .frame  $sp,6*$SZREG,$ra
423         .mask   0x8000f008,-$SZREG
424         .set    noreorder
425         $PTR_SUB $sp,6*$SZREG
426         $REG_S  $ra,5*$SZREG($sp)
427         $REG_S  $t3,4*$SZREG($sp)
428         $REG_S  $t2,3*$SZREG($sp)
429         $REG_S  $t1,2*$SZREG($sp)
430         $REG_S  $t0,1*$SZREG($sp)
431         $REG_S  $gp,0*$SZREG($sp)
432 ___
433 $code.=<<___;
434         .set    reorder
435         li      $minus4,-4
436         and     $ta0,$a2,$minus4
437         beqz    $ta0,.L_bn_sqr_words_tail
438
439 .L_bn_sqr_words_loop:
440         $LD     $t0,0($a1)
441         $MULTU  $t0,$t0
442         $LD     $t2,$BNSZ($a1)
443         $LD     $ta0,2*$BNSZ($a1)
444         $LD     $ta2,3*$BNSZ($a1)
445         mflo    $t1
446         mfhi    $t0
447         $ST     $t1,0($a0)
448         $ST     $t0,$BNSZ($a0)
449
450         $MULTU  $t2,$t2
451         subu    $a2,4
452         $PTR_ADD $a0,8*$BNSZ
453         $PTR_ADD $a1,4*$BNSZ
454         mflo    $t3
455         mfhi    $t2
456         $ST     $t3,-6*$BNSZ($a0)
457         $ST     $t2,-5*$BNSZ($a0)
458
459         $MULTU  $ta0,$ta0
460         mflo    $ta1
461         mfhi    $ta0
462         $ST     $ta1,-4*$BNSZ($a0)
463         $ST     $ta0,-3*$BNSZ($a0)
464
465
466         $MULTU  $ta2,$ta2
467         and     $ta0,$a2,$minus4
468         mflo    $ta3
469         mfhi    $ta2
470         $ST     $ta3,-2*$BNSZ($a0)
471
472         .set    noreorder
473         bgtz    $ta0,.L_bn_sqr_words_loop
474         $ST     $ta2,-$BNSZ($a0)
475
476         beqz    $a2,.L_bn_sqr_words_return
477         nop
478
479 .L_bn_sqr_words_tail:
480         .set    reorder
481         $LD     $t0,0($a1)
482         $MULTU  $t0,$t0
483         subu    $a2,1
484         mflo    $t1
485         mfhi    $t0
486         $ST     $t1,0($a0)
487         $ST     $t0,$BNSZ($a0)
488         beqz    $a2,.L_bn_sqr_words_return
489
490         $LD     $t0,$BNSZ($a1)
491         $MULTU  $t0,$t0
492         subu    $a2,1
493         mflo    $t1
494         mfhi    $t0
495         $ST     $t1,2*$BNSZ($a0)
496         $ST     $t0,3*$BNSZ($a0)
497         beqz    $a2,.L_bn_sqr_words_return
498
499         $LD     $t0,2*$BNSZ($a1)
500         $MULTU  $t0,$t0
501         mflo    $t1
502         mfhi    $t0
503         $ST     $t1,4*$BNSZ($a0)
504         $ST     $t0,5*$BNSZ($a0)
505
506 .L_bn_sqr_words_return:
507         .set    noreorder
508 ___
509 $code.=<<___ if ($flavour =~ /nubi/i);
510         $REG_L  $t3,4*$SZREG($sp)
511         $REG_L  $t2,3*$SZREG($sp)
512         $REG_L  $t1,2*$SZREG($sp)
513         $REG_L  $t0,1*$SZREG($sp)
514         $REG_L  $gp,0*$SZREG($sp)
515         $PTR_ADD $sp,6*$SZREG
516 ___
517 $code.=<<___;
518         jr      $ra
519         move    $a0,$v0
520
521 .end    bn_sqr_words_internal
522
523 .align  5
524 .globl  bn_add_words
525 .ent    bn_add_words
526 bn_add_words:
527         .set    noreorder
528         bgtz    $a3,bn_add_words_internal
529         move    $v0,$zero
530         jr      $ra
531         move    $a0,$v0
532 .end    bn_add_words
533
534 .align  5
535 .ent    bn_add_words_internal
536 bn_add_words_internal:
537 ___
538 $code.=<<___ if ($flavour =~ /nubi/i);
539         .frame  $sp,6*$SZREG,$ra
540         .mask   0x8000f008,-$SZREG
541         .set    noreorder
542         $PTR_SUB $sp,6*$SZREG
543         $REG_S  $ra,5*$SZREG($sp)
544         $REG_S  $t3,4*$SZREG($sp)
545         $REG_S  $t2,3*$SZREG($sp)
546         $REG_S  $t1,2*$SZREG($sp)
547         $REG_S  $t0,1*$SZREG($sp)
548         $REG_S  $gp,0*$SZREG($sp)
549 ___
550 $code.=<<___;
551         .set    reorder
552         li      $minus4,-4
553         and     $at,$a3,$minus4
554         beqz    $at,.L_bn_add_words_tail
555
556 .L_bn_add_words_loop:
557         $LD     $t0,0($a1)
558         $LD     $ta0,0($a2)
559         subu    $a3,4
560         $LD     $t1,$BNSZ($a1)
561         and     $at,$a3,$minus4
562         $LD     $t2,2*$BNSZ($a1)
563         $PTR_ADD $a2,4*$BNSZ
564         $LD     $t3,3*$BNSZ($a1)
565         $PTR_ADD $a0,4*$BNSZ
566         $LD     $ta1,-3*$BNSZ($a2)
567         $PTR_ADD $a1,4*$BNSZ
568         $LD     $ta2,-2*$BNSZ($a2)
569         $LD     $ta3,-$BNSZ($a2)
570         $ADDU   $ta0,$t0
571         sltu    $t8,$ta0,$t0
572         $ADDU   $t0,$ta0,$v0
573         sltu    $v0,$t0,$ta0
574         $ST     $t0,-4*$BNSZ($a0)
575         $ADDU   $v0,$t8
576
577         $ADDU   $ta1,$t1
578         sltu    $t9,$ta1,$t1
579         $ADDU   $t1,$ta1,$v0
580         sltu    $v0,$t1,$ta1
581         $ST     $t1,-3*$BNSZ($a0)
582         $ADDU   $v0,$t9
583
584         $ADDU   $ta2,$t2
585         sltu    $t8,$ta2,$t2
586         $ADDU   $t2,$ta2,$v0
587         sltu    $v0,$t2,$ta2
588         $ST     $t2,-2*$BNSZ($a0)
589         $ADDU   $v0,$t8
590         
591         $ADDU   $ta3,$t3
592         sltu    $t9,$ta3,$t3
593         $ADDU   $t3,$ta3,$v0
594         sltu    $v0,$t3,$ta3
595         $ST     $t3,-$BNSZ($a0)
596         
597         .set    noreorder
598         bgtz    $at,.L_bn_add_words_loop
599         $ADDU   $v0,$t9
600
601         beqz    $a3,.L_bn_add_words_return
602         nop
603
604 .L_bn_add_words_tail:
605         .set    reorder
606         $LD     $t0,0($a1)
607         $LD     $ta0,0($a2)
608         $ADDU   $ta0,$t0
609         subu    $a3,1
610         sltu    $t8,$ta0,$t0
611         $ADDU   $t0,$ta0,$v0
612         sltu    $v0,$t0,$ta0
613         $ST     $t0,0($a0)
614         $ADDU   $v0,$t8
615         beqz    $a3,.L_bn_add_words_return
616
617         $LD     $t1,$BNSZ($a1)
618         $LD     $ta1,$BNSZ($a2)
619         $ADDU   $ta1,$t1
620         subu    $a3,1
621         sltu    $t9,$ta1,$t1
622         $ADDU   $t1,$ta1,$v0
623         sltu    $v0,$t1,$ta1
624         $ST     $t1,$BNSZ($a0)
625         $ADDU   $v0,$t9
626         beqz    $a3,.L_bn_add_words_return
627
628         $LD     $t2,2*$BNSZ($a1)
629         $LD     $ta2,2*$BNSZ($a2)
630         $ADDU   $ta2,$t2
631         sltu    $t8,$ta2,$t2
632         $ADDU   $t2,$ta2,$v0
633         sltu    $v0,$t2,$ta2
634         $ST     $t2,2*$BNSZ($a0)
635         $ADDU   $v0,$t8
636
637 .L_bn_add_words_return:
638         .set    noreorder
639 ___
640 $code.=<<___ if ($flavour =~ /nubi/i);
641         $REG_L  $t3,4*$SZREG($sp)
642         $REG_L  $t2,3*$SZREG($sp)
643         $REG_L  $t1,2*$SZREG($sp)
644         $REG_L  $t0,1*$SZREG($sp)
645         $REG_L  $gp,0*$SZREG($sp)
646         $PTR_ADD $sp,6*$SZREG
647 ___
648 $code.=<<___;
649         jr      $ra
650         move    $a0,$v0
651
652 .end    bn_add_words_internal
653
654 .align  5
655 .globl  bn_sub_words
656 .ent    bn_sub_words
657 bn_sub_words:
658         .set    noreorder
659         bgtz    $a3,bn_sub_words_internal
660         move    $v0,$zero
661         jr      $ra
662         move    $a0,$zero
663 .end    bn_sub_words
664
665 .align  5
666 .ent    bn_sub_words_internal
667 bn_sub_words_internal:
668 ___
669 $code.=<<___ if ($flavour =~ /nubi/i);
670         .frame  $sp,6*$SZREG,$ra
671         .mask   0x8000f008,-$SZREG
672         .set    noreorder
673         $PTR_SUB $sp,6*$SZREG
674         $REG_S  $ra,5*$SZREG($sp)
675         $REG_S  $t3,4*$SZREG($sp)
676         $REG_S  $t2,3*$SZREG($sp)
677         $REG_S  $t1,2*$SZREG($sp)
678         $REG_S  $t0,1*$SZREG($sp)
679         $REG_S  $gp,0*$SZREG($sp)
680 ___
681 $code.=<<___;
682         .set    reorder
683         li      $minus4,-4
684         and     $at,$a3,$minus4
685         beqz    $at,.L_bn_sub_words_tail
686
687 .L_bn_sub_words_loop:
688         $LD     $t0,0($a1)
689         $LD     $ta0,0($a2)
690         subu    $a3,4
691         $LD     $t1,$BNSZ($a1)
692         and     $at,$a3,$minus4
693         $LD     $t2,2*$BNSZ($a1)
694         $PTR_ADD $a2,4*$BNSZ
695         $LD     $t3,3*$BNSZ($a1)
696         $PTR_ADD $a0,4*$BNSZ
697         $LD     $ta1,-3*$BNSZ($a2)
698         $PTR_ADD $a1,4*$BNSZ
699         $LD     $ta2,-2*$BNSZ($a2)
700         $LD     $ta3,-$BNSZ($a2)
701         sltu    $t8,$t0,$ta0
702         $SUBU   $ta0,$t0,$ta0
703         $SUBU   $t0,$ta0,$v0
704         sgtu    $v0,$t0,$ta0
705         $ST     $t0,-4*$BNSZ($a0)
706         $ADDU   $v0,$t8
707
708         sltu    $t9,$t1,$ta1
709         $SUBU   $ta1,$t1,$ta1
710         $SUBU   $t1,$ta1,$v0
711         sgtu    $v0,$t1,$ta1
712         $ST     $t1,-3*$BNSZ($a0)
713         $ADDU   $v0,$t9
714
715
716         sltu    $t8,$t2,$ta2
717         $SUBU   $ta2,$t2,$ta2
718         $SUBU   $t2,$ta2,$v0
719         sgtu    $v0,$t2,$ta2
720         $ST     $t2,-2*$BNSZ($a0)
721         $ADDU   $v0,$t8
722
723         sltu    $t9,$t3,$ta3
724         $SUBU   $ta3,$t3,$ta3
725         $SUBU   $t3,$ta3,$v0
726         sgtu    $v0,$t3,$ta3
727         $ST     $t3,-$BNSZ($a0)
728
729         .set    noreorder
730         bgtz    $at,.L_bn_sub_words_loop
731         $ADDU   $v0,$t9
732
733         beqz    $a3,.L_bn_sub_words_return
734         nop
735
736 .L_bn_sub_words_tail:
737         .set    reorder
738         $LD     $t0,0($a1)
739         $LD     $ta0,0($a2)
740         subu    $a3,1
741         sltu    $t8,$t0,$ta0
742         $SUBU   $ta0,$t0,$ta0
743         $SUBU   $t0,$ta0,$v0
744         sgtu    $v0,$t0,$ta0
745         $ST     $t0,0($a0)
746         $ADDU   $v0,$t8
747         beqz    $a3,.L_bn_sub_words_return
748
749         $LD     $t1,$BNSZ($a1)
750         subu    $a3,1
751         $LD     $ta1,$BNSZ($a2)
752         sltu    $t9,$t1,$ta1
753         $SUBU   $ta1,$t1,$ta1
754         $SUBU   $t1,$ta1,$v0
755         sgtu    $v0,$t1,$ta1
756         $ST     $t1,$BNSZ($a0)
757         $ADDU   $v0,$t9
758         beqz    $a3,.L_bn_sub_words_return
759
760         $LD     $t2,2*$BNSZ($a1)
761         $LD     $ta2,2*$BNSZ($a2)
762         sltu    $t8,$t2,$ta2
763         $SUBU   $ta2,$t2,$ta2
764         $SUBU   $t2,$ta2,$v0
765         sgtu    $v0,$t2,$ta2
766         $ST     $t2,2*$BNSZ($a0)
767         $ADDU   $v0,$t8
768
769 .L_bn_sub_words_return:
770         .set    noreorder
771 ___
772 $code.=<<___ if ($flavour =~ /nubi/i);
773         $REG_L  $t3,4*$SZREG($sp)
774         $REG_L  $t2,3*$SZREG($sp)
775         $REG_L  $t1,2*$SZREG($sp)
776         $REG_L  $t0,1*$SZREG($sp)
777         $REG_L  $gp,0*$SZREG($sp)
778         $PTR_ADD $sp,6*$SZREG
779 ___
780 $code.=<<___;
781         jr      $ra
782         move    $a0,$v0
783 .end    bn_sub_words_internal
784
785 .align 5
786 .globl  bn_div_3_words
787 .ent    bn_div_3_words
788 bn_div_3_words:
789         .set    noreorder
790         move    $a3,$a0         # we know that bn_div_words does not
791                                 # touch $a3, $ta2, $ta3 and preserves $a2
792                                 # so that we can save two arguments
793                                 # and return address in registers
794                                 # instead of stack:-)
795                                 
796         $LD     $a0,($a3)
797         move    $ta2,$a1
798         bne     $a0,$a2,bn_div_3_words_internal
799         $LD     $a1,-$BNSZ($a3)
800         li      $v0,-1
801         jr      $ra
802         move    $a0,$v0
803 .end    bn_div_3_words
804
805 .align  5
806 .ent    bn_div_3_words_internal
807 bn_div_3_words_internal:
808 ___
809 $code.=<<___ if ($flavour =~ /nubi/i);
810         .frame  $sp,6*$SZREG,$ra
811         .mask   0x8000f008,-$SZREG
812         .set    noreorder
813         $PTR_SUB $sp,6*$SZREG
814         $REG_S  $ra,5*$SZREG($sp)
815         $REG_S  $t3,4*$SZREG($sp)
816         $REG_S  $t2,3*$SZREG($sp)
817         $REG_S  $t1,2*$SZREG($sp)
818         $REG_S  $t0,1*$SZREG($sp)
819         $REG_S  $gp,0*$SZREG($sp)
820 ___
821 $code.=<<___;
822         .set    reorder
823         move    $ta3,$ra
824         bal     bn_div_words_internal
825         move    $ra,$ta3
826         $MULTU  $ta2,$v0
827         $LD     $t2,-2*$BNSZ($a3)
828         move    $ta0,$zero
829         mfhi    $t1
830         mflo    $t0
831         sltu    $t8,$t1,$a1
832 .L_bn_div_3_words_inner_loop:
833         bnez    $t8,.L_bn_div_3_words_inner_loop_done
834         sgeu    $at,$t2,$t0
835         seq     $t9,$t1,$a1
836         and     $at,$t9
837         sltu    $t3,$t0,$ta2
838         $ADDU   $a1,$a2
839         $SUBU   $t1,$t3
840         $SUBU   $t0,$ta2
841         sltu    $t8,$t1,$a1
842         sltu    $ta0,$a1,$a2
843         or      $t8,$ta0
844         .set    noreorder
845         beqz    $at,.L_bn_div_3_words_inner_loop
846         $SUBU   $v0,1
847         $ADDU   $v0,1
848         .set    reorder
849 .L_bn_div_3_words_inner_loop_done:
850         .set    noreorder
851 ___
852 $code.=<<___ if ($flavour =~ /nubi/i);
853         $REG_L  $t3,4*$SZREG($sp)
854         $REG_L  $t2,3*$SZREG($sp)
855         $REG_L  $t1,2*$SZREG($sp)
856         $REG_L  $t0,1*$SZREG($sp)
857         $REG_L  $gp,0*$SZREG($sp)
858         $PTR_ADD $sp,6*$SZREG
859 ___
860 $code.=<<___;
861         jr      $ra
862         move    $a0,$v0
863 .end    bn_div_3_words_internal
864
865 .align  5
866 .globl  bn_div_words
867 .ent    bn_div_words
868 bn_div_words:
869         .set    noreorder
870         bnez    $a2,bn_div_words_internal
871         li      $v0,-1          # I would rather signal div-by-zero
872                                 # which can be done with 'break 7'
873         jr      $ra
874         move    $a0,$v0
875 .end    bn_div_words
876
877 .align  5
878 .ent    bn_div_words_internal
879 bn_div_words_internal:
880 ___
881 $code.=<<___ if ($flavour =~ /nubi/i);
882         .frame  $sp,6*$SZREG,$ra
883         .mask   0x8000f008,-$SZREG
884         .set    noreorder
885         $PTR_SUB $sp,6*$SZREG
886         $REG_S  $ra,5*$SZREG($sp)
887         $REG_S  $t3,4*$SZREG($sp)
888         $REG_S  $t2,3*$SZREG($sp)
889         $REG_S  $t1,2*$SZREG($sp)
890         $REG_S  $t0,1*$SZREG($sp)
891         $REG_S  $gp,0*$SZREG($sp)
892 ___
893 $code.=<<___;
894         move    $v1,$zero
895         bltz    $a2,.L_bn_div_words_body
896         move    $t9,$v1
897         $SLL    $a2,1
898         bgtz    $a2,.-4
899         addu    $t9,1
900
901         .set    reorder
902         negu    $t1,$t9
903         li      $t2,-1
904         $SLL    $t2,$t1
905         and     $t2,$a0
906         $SRL    $at,$a1,$t1
907         .set    noreorder
908         beqz    $t2,.+12
909         nop
910         break   6               # signal overflow
911         .set    reorder
912         $SLL    $a0,$t9
913         $SLL    $a1,$t9
914         or      $a0,$at
915 ___
916 $QT=$ta0;
917 $HH=$ta1;
918 $DH=$v1;
919 $code.=<<___;
920 .L_bn_div_words_body:
921         $SRL    $DH,$a2,4*$BNSZ # bits
922         sgeu    $at,$a0,$a2
923         .set    noreorder
924         beqz    $at,.+12
925         nop
926         $SUBU   $a0,$a2
927         .set    reorder
928
929         li      $QT,-1
930         $SRL    $HH,$a0,4*$BNSZ # bits
931         $SRL    $QT,4*$BNSZ     # q=0xffffffff
932         beq     $DH,$HH,.L_bn_div_words_skip_div1
933         $DIVU   $zero,$a0,$DH
934         mflo    $QT
935 .L_bn_div_words_skip_div1:
936         $MULTU  $a2,$QT
937         $SLL    $t3,$a0,4*$BNSZ # bits
938         $SRL    $at,$a1,4*$BNSZ # bits
939         or      $t3,$at
940         mflo    $t0
941         mfhi    $t1
942 .L_bn_div_words_inner_loop1:
943         sltu    $t2,$t3,$t0
944         seq     $t8,$HH,$t1
945         sltu    $at,$HH,$t1
946         and     $t2,$t8
947         sltu    $v0,$t0,$a2
948         or      $at,$t2
949         .set    noreorder
950         beqz    $at,.L_bn_div_words_inner_loop1_done
951         $SUBU   $t1,$v0
952         $SUBU   $t0,$a2
953         b       .L_bn_div_words_inner_loop1
954         $SUBU   $QT,1
955         .set    reorder
956 .L_bn_div_words_inner_loop1_done:
957
958         $SLL    $a1,4*$BNSZ     # bits
959         $SUBU   $a0,$t3,$t0
960         $SLL    $v0,$QT,4*$BNSZ # bits
961
962         li      $QT,-1
963         $SRL    $HH,$a0,4*$BNSZ # bits
964         $SRL    $QT,4*$BNSZ     # q=0xffffffff
965         beq     $DH,$HH,.L_bn_div_words_skip_div2
966         $DIVU   $zero,$a0,$DH
967         mflo    $QT
968 .L_bn_div_words_skip_div2:
969         $MULTU  $a2,$QT
970         $SLL    $t3,$a0,4*$BNSZ # bits
971         $SRL    $at,$a1,4*$BNSZ # bits
972         or      $t3,$at
973         mflo    $t0
974         mfhi    $t1
975 .L_bn_div_words_inner_loop2:
976         sltu    $t2,$t3,$t0
977         seq     $t8,$HH,$t1
978         sltu    $at,$HH,$t1
979         and     $t2,$t8
980         sltu    $v1,$t0,$a2
981         or      $at,$t2
982         .set    noreorder
983         beqz    $at,.L_bn_div_words_inner_loop2_done
984         $SUBU   $t1,$v1
985         $SUBU   $t0,$a2
986         b       .L_bn_div_words_inner_loop2
987         $SUBU   $QT,1
988         .set    reorder
989 .L_bn_div_words_inner_loop2_done:
990
991         $SUBU   $a0,$t3,$t0
992         or      $v0,$QT
993         $SRL    $v1,$a0,$t9     # $v1 contains remainder if anybody wants it
994         $SRL    $a2,$t9         # restore $a2
995
996         .set    noreorder
997         move    $a1,$v1
998 ___
999 $code.=<<___ if ($flavour =~ /nubi/i);
1000         $REG_L  $t3,4*$SZREG($sp)
1001         $REG_L  $t2,3*$SZREG($sp)
1002         $REG_L  $t1,2*$SZREG($sp)
1003         $REG_L  $t0,1*$SZREG($sp)
1004         $REG_L  $gp,0*$SZREG($sp)
1005         $PTR_ADD $sp,6*$SZREG
1006 ___
1007 $code.=<<___;
1008         jr      $ra
1009         move    $a0,$v0
1010 .end    bn_div_words_internal
1011 ___
1012 undef $HH; undef $QT; undef $DH;
1013
1014 ($a_0,$a_1,$a_2,$a_3)=($t0,$t1,$t2,$t3);
1015 ($b_0,$b_1,$b_2,$b_3)=($ta0,$ta1,$ta2,$ta3);
1016
1017 ($a_4,$a_5,$a_6,$a_7)=($s0,$s2,$s4,$a1); # once we load a[7], no use for $a1
1018 ($b_4,$b_5,$b_6,$b_7)=($s1,$s3,$s5,$a2); # once we load b[7], no use for $a2
1019
1020 ($t_1,$t_2,$c_1,$c_2,$c_3)=($t8,$t9,$v0,$v1,$a3);
1021
1022 $code.=<<___;
1023
1024 .align  5
1025 .globl  bn_mul_comba8
1026 .ent    bn_mul_comba8
1027 bn_mul_comba8:
1028         .set    noreorder
1029 ___
1030 $code.=<<___ if ($flavour =~ /nubi/i);
1031         .frame  $sp,12*$SZREG,$ra
1032         .mask   0x803ff008,-$SZREG
1033         $PTR_SUB $sp,12*$SZREG
1034         $REG_S  $ra,11*$SZREG($sp)
1035         $REG_S  $s5,10*$SZREG($sp)
1036         $REG_S  $s4,9*$SZREG($sp)
1037         $REG_S  $s3,8*$SZREG($sp)
1038         $REG_S  $s2,7*$SZREG($sp)
1039         $REG_S  $s1,6*$SZREG($sp)
1040         $REG_S  $s0,5*$SZREG($sp)
1041         $REG_S  $t3,4*$SZREG($sp)
1042         $REG_S  $t2,3*$SZREG($sp)
1043         $REG_S  $t1,2*$SZREG($sp)
1044         $REG_S  $t0,1*$SZREG($sp)
1045         $REG_S  $gp,0*$SZREG($sp)
1046 ___
1047 $code.=<<___ if ($flavour !~ /nubi/i);
1048         .frame  $sp,6*$SZREG,$ra
1049         .mask   0x003f0000,-$SZREG
1050         $PTR_SUB $sp,6*$SZREG
1051         $REG_S  $s5,5*$SZREG($sp)
1052         $REG_S  $s4,4*$SZREG($sp)
1053         $REG_S  $s3,3*$SZREG($sp)
1054         $REG_S  $s2,2*$SZREG($sp)
1055         $REG_S  $s1,1*$SZREG($sp)
1056         $REG_S  $s0,0*$SZREG($sp)
1057 ___
1058 $code.=<<___;
1059
1060         .set    reorder
1061         $LD     $a_0,0($a1)     # If compiled with -mips3 option on
1062                                 # R5000 box assembler barks on this
1063                                 # 1ine with "should not have mult/div
1064                                 # as last instruction in bb (R10K
1065                                 # bug)" warning. If anybody out there
1066                                 # has a clue about how to circumvent
1067                                 # this do send me a note.
1068                                 #               <appro\@fy.chalmers.se>
1069
1070         $LD     $b_0,0($a2)
1071         $LD     $a_1,$BNSZ($a1)
1072         $LD     $a_2,2*$BNSZ($a1)
1073         $MULTU  $a_0,$b_0               # mul_add_c(a[0],b[0],c1,c2,c3);
1074         $LD     $a_3,3*$BNSZ($a1)
1075         $LD     $b_1,$BNSZ($a2)
1076         $LD     $b_2,2*$BNSZ($a2)
1077         $LD     $b_3,3*$BNSZ($a2)
1078         mflo    $c_1
1079         mfhi    $c_2
1080
1081         $LD     $a_4,4*$BNSZ($a1)
1082         $LD     $a_5,5*$BNSZ($a1)
1083         $MULTU  $a_0,$b_1               # mul_add_c(a[0],b[1],c2,c3,c1);
1084         $LD     $a_6,6*$BNSZ($a1)
1085         $LD     $a_7,7*$BNSZ($a1)
1086         $LD     $b_4,4*$BNSZ($a2)
1087         $LD     $b_5,5*$BNSZ($a2)
1088         mflo    $t_1
1089         mfhi    $t_2
1090         $ADDU   $c_2,$t_1
1091         sltu    $at,$c_2,$t_1
1092         $MULTU  $a_1,$b_0               # mul_add_c(a[1],b[0],c2,c3,c1);
1093         $ADDU   $c_3,$t_2,$at
1094         $LD     $b_6,6*$BNSZ($a2)
1095         $LD     $b_7,7*$BNSZ($a2)
1096         $ST     $c_1,0($a0)     # r[0]=c1;
1097         mflo    $t_1
1098         mfhi    $t_2
1099         $ADDU   $c_2,$t_1
1100         sltu    $at,$c_2,$t_1
1101          $MULTU $a_2,$b_0               # mul_add_c(a[2],b[0],c3,c1,c2);
1102         $ADDU   $t_2,$at
1103         $ADDU   $c_3,$t_2
1104         sltu    $c_1,$c_3,$t_2
1105         $ST     $c_2,$BNSZ($a0) # r[1]=c2;
1106
1107         mflo    $t_1
1108         mfhi    $t_2
1109         $ADDU   $c_3,$t_1
1110         sltu    $at,$c_3,$t_1
1111         $MULTU  $a_1,$b_1               # mul_add_c(a[1],b[1],c3,c1,c2);
1112         $ADDU   $t_2,$at
1113         $ADDU   $c_1,$t_2
1114         mflo    $t_1
1115         mfhi    $t_2
1116         $ADDU   $c_3,$t_1
1117         sltu    $at,$c_3,$t_1
1118         $MULTU  $a_0,$b_2               # mul_add_c(a[0],b[2],c3,c1,c2);
1119         $ADDU   $t_2,$at
1120         $ADDU   $c_1,$t_2
1121         sltu    $c_2,$c_1,$t_2
1122         mflo    $t_1
1123         mfhi    $t_2
1124         $ADDU   $c_3,$t_1
1125         sltu    $at,$c_3,$t_1
1126          $MULTU $a_0,$b_3               # mul_add_c(a[0],b[3],c1,c2,c3);
1127         $ADDU   $t_2,$at
1128         $ADDU   $c_1,$t_2
1129         sltu    $at,$c_1,$t_2
1130         $ADDU   $c_2,$at
1131         $ST     $c_3,2*$BNSZ($a0)       # r[2]=c3;
1132
1133         mflo    $t_1
1134         mfhi    $t_2
1135         $ADDU   $c_1,$t_1
1136         sltu    $at,$c_1,$t_1
1137         $MULTU  $a_1,$b_2               # mul_add_c(a[1],b[2],c1,c2,c3);
1138         $ADDU   $t_2,$at
1139         $ADDU   $c_2,$t_2
1140         sltu    $c_3,$c_2,$t_2
1141         mflo    $t_1
1142         mfhi    $t_2
1143         $ADDU   $c_1,$t_1
1144         sltu    $at,$c_1,$t_1
1145         $MULTU  $a_2,$b_1               # mul_add_c(a[2],b[1],c1,c2,c3);
1146         $ADDU   $t_2,$at
1147         $ADDU   $c_2,$t_2
1148         sltu    $at,$c_2,$t_2
1149         $ADDU   $c_3,$at
1150         mflo    $t_1
1151         mfhi    $t_2
1152         $ADDU   $c_1,$t_1
1153         sltu    $at,$c_1,$t_1
1154         $MULTU  $a_3,$b_0               # mul_add_c(a[3],b[0],c1,c2,c3);
1155         $ADDU   $t_2,$at
1156         $ADDU   $c_2,$t_2
1157         sltu    $at,$c_2,$t_2
1158         $ADDU   $c_3,$at
1159         mflo    $t_1
1160         mfhi    $t_2
1161         $ADDU   $c_1,$t_1
1162         sltu    $at,$c_1,$t_1
1163          $MULTU $a_4,$b_0               # mul_add_c(a[4],b[0],c2,c3,c1);
1164         $ADDU   $t_2,$at
1165         $ADDU   $c_2,$t_2
1166         sltu    $at,$c_2,$t_2
1167         $ADDU   $c_3,$at
1168         $ST     $c_1,3*$BNSZ($a0)       # r[3]=c1;
1169
1170         mflo    $t_1
1171         mfhi    $t_2
1172         $ADDU   $c_2,$t_1
1173         sltu    $at,$c_2,$t_1
1174         $MULTU  $a_3,$b_1               # mul_add_c(a[3],b[1],c2,c3,c1);
1175         $ADDU   $t_2,$at
1176         $ADDU   $c_3,$t_2
1177         sltu    $c_1,$c_3,$t_2
1178         mflo    $t_1
1179         mfhi    $t_2
1180         $ADDU   $c_2,$t_1
1181         sltu    $at,$c_2,$t_1
1182         $MULTU  $a_2,$b_2               # mul_add_c(a[2],b[2],c2,c3,c1);
1183         $ADDU   $t_2,$at
1184         $ADDU   $c_3,$t_2
1185         sltu    $at,$c_3,$t_2
1186         $ADDU   $c_1,$at
1187         mflo    $t_1
1188         mfhi    $t_2
1189         $ADDU   $c_2,$t_1
1190         sltu    $at,$c_2,$t_1
1191         $MULTU  $a_1,$b_3               # mul_add_c(a[1],b[3],c2,c3,c1);
1192         $ADDU   $t_2,$at
1193         $ADDU   $c_3,$t_2
1194         sltu    $at,$c_3,$t_2
1195         $ADDU   $c_1,$at
1196         mflo    $t_1
1197         mfhi    $t_2
1198         $ADDU   $c_2,$t_1
1199         sltu    $at,$c_2,$t_1
1200         $MULTU  $a_0,$b_4               # mul_add_c(a[0],b[4],c2,c3,c1);
1201         $ADDU   $t_2,$at
1202         $ADDU   $c_3,$t_2
1203         sltu    $at,$c_3,$t_2
1204         $ADDU   $c_1,$at
1205         mflo    $t_1
1206         mfhi    $t_2
1207         $ADDU   $c_2,$t_1
1208         sltu    $at,$c_2,$t_1
1209          $MULTU $a_0,$b_5               # mul_add_c(a[0],b[5],c3,c1,c2);
1210         $ADDU   $t_2,$at
1211         $ADDU   $c_3,$t_2
1212         sltu    $at,$c_3,$t_2
1213         $ADDU   $c_1,$at
1214         $ST     $c_2,4*$BNSZ($a0)       # r[4]=c2;
1215
1216         mflo    $t_1
1217         mfhi    $t_2
1218         $ADDU   $c_3,$t_1
1219         sltu    $at,$c_3,$t_1
1220         $MULTU  $a_1,$b_4               # mul_add_c(a[1],b[4],c3,c1,c2);
1221         $ADDU   $t_2,$at
1222         $ADDU   $c_1,$t_2
1223         sltu    $c_2,$c_1,$t_2
1224         mflo    $t_1
1225         mfhi    $t_2
1226         $ADDU   $c_3,$t_1
1227         sltu    $at,$c_3,$t_1
1228         $MULTU  $a_2,$b_3               # mul_add_c(a[2],b[3],c3,c1,c2);
1229         $ADDU   $t_2,$at
1230         $ADDU   $c_1,$t_2
1231         sltu    $at,$c_1,$t_2
1232         $ADDU   $c_2,$at
1233         mflo    $t_1
1234         mfhi    $t_2
1235         $ADDU   $c_3,$t_1
1236         sltu    $at,$c_3,$t_1
1237         $MULTU  $a_3,$b_2               # mul_add_c(a[3],b[2],c3,c1,c2);
1238         $ADDU   $t_2,$at
1239         $ADDU   $c_1,$t_2
1240         sltu    $at,$c_1,$t_2
1241         $ADDU   $c_2,$at
1242         mflo    $t_1
1243         mfhi    $t_2
1244         $ADDU   $c_3,$t_1
1245         sltu    $at,$c_3,$t_1
1246         $MULTU  $a_4,$b_1               # mul_add_c(a[4],b[1],c3,c1,c2);
1247         $ADDU   $t_2,$at
1248         $ADDU   $c_1,$t_2
1249         sltu    $at,$c_1,$t_2
1250         $ADDU   $c_2,$at
1251         mflo    $t_1
1252         mfhi    $t_2
1253         $ADDU   $c_3,$t_1
1254         sltu    $at,$c_3,$t_1
1255         $MULTU  $a_5,$b_0               # mul_add_c(a[5],b[0],c3,c1,c2);
1256         $ADDU   $t_2,$at
1257         $ADDU   $c_1,$t_2
1258         sltu    $at,$c_1,$t_2
1259         $ADDU   $c_2,$at
1260         mflo    $t_1
1261         mfhi    $t_2
1262         $ADDU   $c_3,$t_1
1263         sltu    $at,$c_3,$t_1
1264          $MULTU $a_6,$b_0               # mul_add_c(a[6],b[0],c1,c2,c3);
1265         $ADDU   $t_2,$at
1266         $ADDU   $c_1,$t_2
1267         sltu    $at,$c_1,$t_2
1268         $ADDU   $c_2,$at
1269         $ST     $c_3,5*$BNSZ($a0)       # r[5]=c3;
1270
1271         mflo    $t_1
1272         mfhi    $t_2
1273         $ADDU   $c_1,$t_1
1274         sltu    $at,$c_1,$t_1
1275         $MULTU  $a_5,$b_1               # mul_add_c(a[5],b[1],c1,c2,c3);
1276         $ADDU   $t_2,$at
1277         $ADDU   $c_2,$t_2
1278         sltu    $c_3,$c_2,$t_2
1279         mflo    $t_1
1280         mfhi    $t_2
1281         $ADDU   $c_1,$t_1
1282         sltu    $at,$c_1,$t_1
1283         $MULTU  $a_4,$b_2               # mul_add_c(a[4],b[2],c1,c2,c3);
1284         $ADDU   $t_2,$at
1285         $ADDU   $c_2,$t_2
1286         sltu    $at,$c_2,$t_2
1287         $ADDU   $c_3,$at
1288         mflo    $t_1
1289         mfhi    $t_2
1290         $ADDU   $c_1,$t_1
1291         sltu    $at,$c_1,$t_1
1292         $MULTU  $a_3,$b_3               # mul_add_c(a[3],b[3],c1,c2,c3);
1293         $ADDU   $t_2,$at
1294         $ADDU   $c_2,$t_2
1295         sltu    $at,$c_2,$t_2
1296         $ADDU   $c_3,$at
1297         mflo    $t_1
1298         mfhi    $t_2
1299         $ADDU   $c_1,$t_1
1300         sltu    $at,$c_1,$t_1
1301         $MULTU  $a_2,$b_4               # mul_add_c(a[2],b[4],c1,c2,c3);
1302         $ADDU   $t_2,$at
1303         $ADDU   $c_2,$t_2
1304         sltu    $at,$c_2,$t_2
1305         $ADDU   $c_3,$at
1306         mflo    $t_1
1307         mfhi    $t_2
1308         $ADDU   $c_1,$t_1
1309         sltu    $at,$c_1,$t_1
1310         $MULTU  $a_1,$b_5               # mul_add_c(a[1],b[5],c1,c2,c3);
1311         $ADDU   $t_2,$at
1312         $ADDU   $c_2,$t_2
1313         sltu    $at,$c_2,$t_2
1314         $ADDU   $c_3,$at
1315         mflo    $t_1
1316         mfhi    $t_2
1317         $ADDU   $c_1,$t_1
1318         sltu    $at,$c_1,$t_1
1319         $MULTU  $a_0,$b_6               # mul_add_c(a[0],b[6],c1,c2,c3);
1320         $ADDU   $t_2,$at
1321         $ADDU   $c_2,$t_2
1322         sltu    $at,$c_2,$t_2
1323         $ADDU   $c_3,$at
1324         mflo    $t_1
1325         mfhi    $t_2
1326         $ADDU   $c_1,$t_1
1327         sltu    $at,$c_1,$t_1
1328          $MULTU $a_0,$b_7               # mul_add_c(a[0],b[7],c2,c3,c1);
1329         $ADDU   $t_2,$at
1330         $ADDU   $c_2,$t_2
1331         sltu    $at,$c_2,$t_2
1332         $ADDU   $c_3,$at
1333         $ST     $c_1,6*$BNSZ($a0)       # r[6]=c1;
1334
1335         mflo    $t_1
1336         mfhi    $t_2
1337         $ADDU   $c_2,$t_1
1338         sltu    $at,$c_2,$t_1
1339         $MULTU  $a_1,$b_6               # mul_add_c(a[1],b[6],c2,c3,c1);
1340         $ADDU   $t_2,$at
1341         $ADDU   $c_3,$t_2
1342         sltu    $c_1,$c_3,$t_2
1343         mflo    $t_1
1344         mfhi    $t_2
1345         $ADDU   $c_2,$t_1
1346         sltu    $at,$c_2,$t_1
1347         $MULTU  $a_2,$b_5               # mul_add_c(a[2],b[5],c2,c3,c1);
1348         $ADDU   $t_2,$at
1349         $ADDU   $c_3,$t_2
1350         sltu    $at,$c_3,$t_2
1351         $ADDU   $c_1,$at
1352         mflo    $t_1
1353         mfhi    $t_2
1354         $ADDU   $c_2,$t_1
1355         sltu    $at,$c_2,$t_1
1356         $MULTU  $a_3,$b_4               # mul_add_c(a[3],b[4],c2,c3,c1);
1357         $ADDU   $t_2,$at
1358         $ADDU   $c_3,$t_2
1359         sltu    $at,$c_3,$t_2
1360         $ADDU   $c_1,$at
1361         mflo    $t_1
1362         mfhi    $t_2
1363         $ADDU   $c_2,$t_1
1364         sltu    $at,$c_2,$t_1
1365         $MULTU  $a_4,$b_3               # mul_add_c(a[4],b[3],c2,c3,c1);
1366         $ADDU   $t_2,$at
1367         $ADDU   $c_3,$t_2
1368         sltu    $at,$c_3,$t_2
1369         $ADDU   $c_1,$at
1370         mflo    $t_1
1371         mfhi    $t_2
1372         $ADDU   $c_2,$t_1
1373         sltu    $at,$c_2,$t_1
1374         $MULTU  $a_5,$b_2               # mul_add_c(a[5],b[2],c2,c3,c1);
1375         $ADDU   $t_2,$at
1376         $ADDU   $c_3,$t_2
1377         sltu    $at,$c_3,$t_2
1378         $ADDU   $c_1,$at
1379         mflo    $t_1
1380         mfhi    $t_2
1381         $ADDU   $c_2,$t_1
1382         sltu    $at,$c_2,$t_1
1383         $MULTU  $a_6,$b_1               # mul_add_c(a[6],b[1],c2,c3,c1);
1384         $ADDU   $t_2,$at
1385         $ADDU   $c_3,$t_2
1386         sltu    $at,$c_3,$t_2
1387         $ADDU   $c_1,$at
1388         mflo    $t_1
1389         mfhi    $t_2
1390         $ADDU   $c_2,$t_1
1391         sltu    $at,$c_2,$t_1
1392         $MULTU  $a_7,$b_0               # mul_add_c(a[7],b[0],c2,c3,c1);
1393         $ADDU   $t_2,$at
1394         $ADDU   $c_3,$t_2
1395         sltu    $at,$c_3,$t_2
1396         $ADDU   $c_1,$at
1397         mflo    $t_1
1398         mfhi    $t_2
1399         $ADDU   $c_2,$t_1
1400         sltu    $at,$c_2,$t_1
1401          $MULTU $a_7,$b_1               # mul_add_c(a[7],b[1],c3,c1,c2);
1402         $ADDU   $t_2,$at
1403         $ADDU   $c_3,$t_2
1404         sltu    $at,$c_3,$t_2
1405         $ADDU   $c_1,$at
1406         $ST     $c_2,7*$BNSZ($a0)       # r[7]=c2;
1407
1408         mflo    $t_1
1409         mfhi    $t_2
1410         $ADDU   $c_3,$t_1
1411         sltu    $at,$c_3,$t_1
1412         $MULTU  $a_6,$b_2               # mul_add_c(a[6],b[2],c3,c1,c2);
1413         $ADDU   $t_2,$at
1414         $ADDU   $c_1,$t_2
1415         sltu    $c_2,$c_1,$t_2
1416         mflo    $t_1
1417         mfhi    $t_2
1418         $ADDU   $c_3,$t_1
1419         sltu    $at,$c_3,$t_1
1420         $MULTU  $a_5,$b_3               # mul_add_c(a[5],b[3],c3,c1,c2);
1421         $ADDU   $t_2,$at
1422         $ADDU   $c_1,$t_2
1423         sltu    $at,$c_1,$t_2
1424         $ADDU   $c_2,$at
1425         mflo    $t_1
1426         mfhi    $t_2
1427         $ADDU   $c_3,$t_1
1428         sltu    $at,$c_3,$t_1
1429         $MULTU  $a_4,$b_4               # mul_add_c(a[4],b[4],c3,c1,c2);
1430         $ADDU   $t_2,$at
1431         $ADDU   $c_1,$t_2
1432         sltu    $at,$c_1,$t_2
1433         $ADDU   $c_2,$at
1434         mflo    $t_1
1435         mfhi    $t_2
1436         $ADDU   $c_3,$t_1
1437         sltu    $at,$c_3,$t_1
1438         $MULTU  $a_3,$b_5               # mul_add_c(a[3],b[5],c3,c1,c2);
1439         $ADDU   $t_2,$at
1440         $ADDU   $c_1,$t_2
1441         sltu    $at,$c_1,$t_2
1442         $ADDU   $c_2,$at
1443         mflo    $t_1
1444         mfhi    $t_2
1445         $ADDU   $c_3,$t_1
1446         sltu    $at,$c_3,$t_1
1447         $MULTU  $a_2,$b_6               # mul_add_c(a[2],b[6],c3,c1,c2);
1448         $ADDU   $t_2,$at
1449         $ADDU   $c_1,$t_2
1450         sltu    $at,$c_1,$t_2
1451         $ADDU   $c_2,$at
1452         mflo    $t_1
1453         mfhi    $t_2
1454         $ADDU   $c_3,$t_1
1455         sltu    $at,$c_3,$t_1
1456         $MULTU  $a_1,$b_7               # mul_add_c(a[1],b[7],c3,c1,c2);
1457         $ADDU   $t_2,$at
1458         $ADDU   $c_1,$t_2
1459         sltu    $at,$c_1,$t_2
1460         $ADDU   $c_2,$at
1461         mflo    $t_1
1462         mfhi    $t_2
1463         $ADDU   $c_3,$t_1
1464         sltu    $at,$c_3,$t_1
1465          $MULTU $a_2,$b_7               # mul_add_c(a[2],b[7],c1,c2,c3);
1466         $ADDU   $t_2,$at
1467         $ADDU   $c_1,$t_2
1468         sltu    $at,$c_1,$t_2
1469         $ADDU   $c_2,$at
1470         $ST     $c_3,8*$BNSZ($a0)       # r[8]=c3;
1471
1472         mflo    $t_1
1473         mfhi    $t_2
1474         $ADDU   $c_1,$t_1
1475         sltu    $at,$c_1,$t_1
1476         $MULTU  $a_3,$b_6               # mul_add_c(a[3],b[6],c1,c2,c3);
1477         $ADDU   $t_2,$at
1478         $ADDU   $c_2,$t_2
1479         sltu    $c_3,$c_2,$t_2
1480         mflo    $t_1
1481         mfhi    $t_2
1482         $ADDU   $c_1,$t_1
1483         sltu    $at,$c_1,$t_1
1484         $MULTU  $a_4,$b_5               # mul_add_c(a[4],b[5],c1,c2,c3);
1485         $ADDU   $t_2,$at
1486         $ADDU   $c_2,$t_2
1487         sltu    $at,$c_2,$t_2
1488         $ADDU   $c_3,$at
1489         mflo    $t_1
1490         mfhi    $t_2
1491         $ADDU   $c_1,$t_1
1492         sltu    $at,$c_1,$t_1
1493         $MULTU  $a_5,$b_4               # mul_add_c(a[5],b[4],c1,c2,c3);
1494         $ADDU   $t_2,$at
1495         $ADDU   $c_2,$t_2
1496         sltu    $at,$c_2,$t_2
1497         $ADDU   $c_3,$at
1498         mflo    $t_1
1499         mfhi    $t_2
1500         $ADDU   $c_1,$t_1
1501         sltu    $at,$c_1,$t_1
1502         $MULTU  $a_6,$b_3               # mul_add_c(a[6],b[3],c1,c2,c3);
1503         $ADDU   $t_2,$at
1504         $ADDU   $c_2,$t_2
1505         sltu    $at,$c_2,$t_2
1506         $ADDU   $c_3,$at
1507         mflo    $t_1
1508         mfhi    $t_2
1509         $ADDU   $c_1,$t_1
1510         sltu    $at,$c_1,$t_1
1511         $MULTU  $a_7,$b_2               # mul_add_c(a[7],b[2],c1,c2,c3);
1512         $ADDU   $t_2,$at
1513         $ADDU   $c_2,$t_2
1514         sltu    $at,$c_2,$t_2
1515         $ADDU   $c_3,$at
1516         mflo    $t_1
1517         mfhi    $t_2
1518         $ADDU   $c_1,$t_1
1519         sltu    $at,$c_1,$t_1
1520          $MULTU $a_7,$b_3               # mul_add_c(a[7],b[3],c2,c3,c1);
1521         $ADDU   $t_2,$at
1522         $ADDU   $c_2,$t_2
1523         sltu    $at,$c_2,$t_2
1524         $ADDU   $c_3,$at
1525         $ST     $c_1,9*$BNSZ($a0)       # r[9]=c1;
1526
1527         mflo    $t_1
1528         mfhi    $t_2
1529         $ADDU   $c_2,$t_1
1530         sltu    $at,$c_2,$t_1
1531         $MULTU  $a_6,$b_4               # mul_add_c(a[6],b[4],c2,c3,c1);
1532         $ADDU   $t_2,$at
1533         $ADDU   $c_3,$t_2
1534         sltu    $c_1,$c_3,$t_2
1535         mflo    $t_1
1536         mfhi    $t_2
1537         $ADDU   $c_2,$t_1
1538         sltu    $at,$c_2,$t_1
1539         $MULTU  $a_5,$b_5               # mul_add_c(a[5],b[5],c2,c3,c1);
1540         $ADDU   $t_2,$at
1541         $ADDU   $c_3,$t_2
1542         sltu    $at,$c_3,$t_2
1543         $ADDU   $c_1,$at
1544         mflo    $t_1
1545         mfhi    $t_2
1546         $ADDU   $c_2,$t_1
1547         sltu    $at,$c_2,$t_1
1548         $MULTU  $a_4,$b_6               # mul_add_c(a[4],b[6],c2,c3,c1);
1549         $ADDU   $t_2,$at
1550         $ADDU   $c_3,$t_2
1551         sltu    $at,$c_3,$t_2
1552         $ADDU   $c_1,$at
1553         mflo    $t_1
1554         mfhi    $t_2
1555         $ADDU   $c_2,$t_1
1556         sltu    $at,$c_2,$t_1
1557         $MULTU  $a_3,$b_7               # mul_add_c(a[3],b[7],c2,c3,c1);
1558         $ADDU   $t_2,$at
1559         $ADDU   $c_3,$t_2
1560         sltu    $at,$c_3,$t_2
1561         $ADDU   $c_1,$at
1562         mflo    $t_1
1563         mfhi    $t_2
1564         $ADDU   $c_2,$t_1
1565         sltu    $at,$c_2,$t_1
1566         $MULTU  $a_4,$b_7               # mul_add_c(a[4],b[7],c3,c1,c2);
1567         $ADDU   $t_2,$at
1568         $ADDU   $c_3,$t_2
1569         sltu    $at,$c_3,$t_2
1570         $ADDU   $c_1,$at
1571         $ST     $c_2,10*$BNSZ($a0)      # r[10]=c2;
1572
1573         mflo    $t_1
1574         mfhi    $t_2
1575         $ADDU   $c_3,$t_1
1576         sltu    $at,$c_3,$t_1
1577         $MULTU  $a_5,$b_6               # mul_add_c(a[5],b[6],c3,c1,c2);
1578         $ADDU   $t_2,$at
1579         $ADDU   $c_1,$t_2
1580         sltu    $c_2,$c_1,$t_2
1581         mflo    $t_1
1582         mfhi    $t_2
1583         $ADDU   $c_3,$t_1
1584         sltu    $at,$c_3,$t_1
1585         $MULTU  $a_6,$b_5               # mul_add_c(a[6],b[5],c3,c1,c2);
1586         $ADDU   $t_2,$at
1587         $ADDU   $c_1,$t_2
1588         sltu    $at,$c_1,$t_2
1589         $ADDU   $c_2,$at
1590         mflo    $t_1
1591         mfhi    $t_2
1592         $ADDU   $c_3,$t_1
1593         sltu    $at,$c_3,$t_1
1594         $MULTU  $a_7,$b_4               # mul_add_c(a[7],b[4],c3,c1,c2);
1595         $ADDU   $t_2,$at
1596         $ADDU   $c_1,$t_2
1597         sltu    $at,$c_1,$t_2
1598         $ADDU   $c_2,$at
1599         mflo    $t_1
1600         mfhi    $t_2
1601         $ADDU   $c_3,$t_1
1602         sltu    $at,$c_3,$t_1
1603          $MULTU $a_7,$b_5               # mul_add_c(a[7],b[5],c1,c2,c3);
1604         $ADDU   $t_2,$at
1605         $ADDU   $c_1,$t_2
1606         sltu    $at,$c_1,$t_2
1607         $ADDU   $c_2,$at
1608         $ST     $c_3,11*$BNSZ($a0)      # r[11]=c3;
1609
1610         mflo    $t_1
1611         mfhi    $t_2
1612         $ADDU   $c_1,$t_1
1613         sltu    $at,$c_1,$t_1
1614         $MULTU  $a_6,$b_6               # mul_add_c(a[6],b[6],c1,c2,c3);
1615         $ADDU   $t_2,$at
1616         $ADDU   $c_2,$t_2
1617         sltu    $c_3,$c_2,$t_2
1618         mflo    $t_1
1619         mfhi    $t_2
1620         $ADDU   $c_1,$t_1
1621         sltu    $at,$c_1,$t_1
1622         $MULTU  $a_5,$b_7               # mul_add_c(a[5],b[7],c1,c2,c3);
1623         $ADDU   $t_2,$at
1624         $ADDU   $c_2,$t_2
1625         sltu    $at,$c_2,$t_2
1626         $ADDU   $c_3,$at
1627         mflo    $t_1
1628         mfhi    $t_2
1629         $ADDU   $c_1,$t_1
1630         sltu    $at,$c_1,$t_1
1631          $MULTU $a_6,$b_7               # mul_add_c(a[6],b[7],c2,c3,c1);
1632         $ADDU   $t_2,$at
1633         $ADDU   $c_2,$t_2
1634         sltu    $at,$c_2,$t_2
1635         $ADDU   $c_3,$at
1636         $ST     $c_1,12*$BNSZ($a0)      # r[12]=c1;
1637
1638         mflo    $t_1
1639         mfhi    $t_2
1640         $ADDU   $c_2,$t_1
1641         sltu    $at,$c_2,$t_1
1642         $MULTU  $a_7,$b_6               # mul_add_c(a[7],b[6],c2,c3,c1);
1643         $ADDU   $t_2,$at
1644         $ADDU   $c_3,$t_2
1645         sltu    $c_1,$c_3,$t_2
1646         mflo    $t_1
1647         mfhi    $t_2
1648         $ADDU   $c_2,$t_1
1649         sltu    $at,$c_2,$t_1
1650         $MULTU  $a_7,$b_7               # mul_add_c(a[7],b[7],c3,c1,c2);
1651         $ADDU   $t_2,$at
1652         $ADDU   $c_3,$t_2
1653         sltu    $at,$c_3,$t_2
1654         $ADDU   $c_1,$at
1655         $ST     $c_2,13*$BNSZ($a0)      # r[13]=c2;
1656
1657         mflo    $t_1
1658         mfhi    $t_2
1659         $ADDU   $c_3,$t_1
1660         sltu    $at,$c_3,$t_1
1661         $ADDU   $t_2,$at
1662         $ADDU   $c_1,$t_2
1663         $ST     $c_3,14*$BNSZ($a0)      # r[14]=c3;
1664         $ST     $c_1,15*$BNSZ($a0)      # r[15]=c1;
1665
1666         .set    noreorder
1667 ___
1668 $code.=<<___ if ($flavour =~ /nubi/i);
1669         $REG_L  $s5,10*$SZREG($sp)
1670         $REG_L  $s4,9*$SZREG($sp)
1671         $REG_L  $s3,8*$SZREG($sp)
1672         $REG_L  $s2,7*$SZREG($sp)
1673         $REG_L  $s1,6*$SZREG($sp)
1674         $REG_L  $s0,5*$SZREG($sp)
1675         $REG_L  $t3,4*$SZREG($sp)
1676         $REG_L  $t2,3*$SZREG($sp)
1677         $REG_L  $t1,2*$SZREG($sp)
1678         $REG_L  $t0,1*$SZREG($sp)
1679         $REG_L  $gp,0*$SZREG($sp)
1680         jr      $ra
1681         $PTR_ADD $sp,12*$SZREG
1682 ___
1683 $code.=<<___ if ($flavour !~ /nubi/i);
1684         $REG_L  $s5,5*$SZREG($sp)
1685         $REG_L  $s4,4*$SZREG($sp)
1686         $REG_L  $s3,3*$SZREG($sp)
1687         $REG_L  $s2,2*$SZREG($sp)
1688         $REG_L  $s1,1*$SZREG($sp)
1689         $REG_L  $s0,0*$SZREG($sp)
1690         jr      $ra
1691         $PTR_ADD $sp,6*$SZREG
1692 ___
1693 $code.=<<___;
1694 .end    bn_mul_comba8
1695
1696 .align  5
1697 .globl  bn_mul_comba4
1698 .ent    bn_mul_comba4
1699 bn_mul_comba4:
1700 ___
1701 $code.=<<___ if ($flavour =~ /nubi/i);
1702         .frame  $sp,6*$SZREG,$ra
1703         .mask   0x8000f008,-$SZREG
1704         .set    noreorder
1705         $PTR_SUB $sp,6*$SZREG
1706         $REG_S  $ra,5*$SZREG($sp)
1707         $REG_S  $t3,4*$SZREG($sp)
1708         $REG_S  $t2,3*$SZREG($sp)
1709         $REG_S  $t1,2*$SZREG($sp)
1710         $REG_S  $t0,1*$SZREG($sp)
1711         $REG_S  $gp,0*$SZREG($sp)
1712 ___
1713 $code.=<<___;
1714         .set    reorder
1715         $LD     $a_0,0($a1)
1716         $LD     $b_0,0($a2)
1717         $LD     $a_1,$BNSZ($a1)
1718         $LD     $a_2,2*$BNSZ($a1)
1719         $MULTU  $a_0,$b_0               # mul_add_c(a[0],b[0],c1,c2,c3);
1720         $LD     $a_3,3*$BNSZ($a1)
1721         $LD     $b_1,$BNSZ($a2)
1722         $LD     $b_2,2*$BNSZ($a2)
1723         $LD     $b_3,3*$BNSZ($a2)
1724         mflo    $c_1
1725         mfhi    $c_2
1726         $ST     $c_1,0($a0)
1727
1728         $MULTU  $a_0,$b_1               # mul_add_c(a[0],b[1],c2,c3,c1);
1729         mflo    $t_1
1730         mfhi    $t_2
1731         $ADDU   $c_2,$t_1
1732         sltu    $at,$c_2,$t_1
1733         $MULTU  $a_1,$b_0               # mul_add_c(a[1],b[0],c2,c3,c1);
1734         $ADDU   $c_3,$t_2,$at
1735         mflo    $t_1
1736         mfhi    $t_2
1737         $ADDU   $c_2,$t_1
1738         sltu    $at,$c_2,$t_1
1739          $MULTU $a_2,$b_0               # mul_add_c(a[2],b[0],c3,c1,c2);
1740         $ADDU   $t_2,$at
1741         $ADDU   $c_3,$t_2
1742         sltu    $c_1,$c_3,$t_2
1743         $ST     $c_2,$BNSZ($a0)
1744
1745         mflo    $t_1
1746         mfhi    $t_2
1747         $ADDU   $c_3,$t_1
1748         sltu    $at,$c_3,$t_1
1749         $MULTU  $a_1,$b_1               # mul_add_c(a[1],b[1],c3,c1,c2);
1750         $ADDU   $t_2,$at
1751         $ADDU   $c_1,$t_2
1752         mflo    $t_1
1753         mfhi    $t_2
1754         $ADDU   $c_3,$t_1
1755         sltu    $at,$c_3,$t_1
1756         $MULTU  $a_0,$b_2               # mul_add_c(a[0],b[2],c3,c1,c2);
1757         $ADDU   $t_2,$at
1758         $ADDU   $c_1,$t_2
1759         sltu    $c_2,$c_1,$t_2
1760         mflo    $t_1
1761         mfhi    $t_2
1762         $ADDU   $c_3,$t_1
1763         sltu    $at,$c_3,$t_1
1764          $MULTU $a_0,$b_3               # mul_add_c(a[0],b[3],c1,c2,c3);
1765         $ADDU   $t_2,$at
1766         $ADDU   $c_1,$t_2
1767         sltu    $at,$c_1,$t_2
1768         $ADDU   $c_2,$at
1769         $ST     $c_3,2*$BNSZ($a0)
1770
1771         mflo    $t_1
1772         mfhi    $t_2
1773         $ADDU   $c_1,$t_1
1774         sltu    $at,$c_1,$t_1
1775         $MULTU  $a_1,$b_2               # mul_add_c(a[1],b[2],c1,c2,c3);
1776         $ADDU   $t_2,$at
1777         $ADDU   $c_2,$t_2
1778         sltu    $c_3,$c_2,$t_2
1779         mflo    $t_1
1780         mfhi    $t_2
1781         $ADDU   $c_1,$t_1
1782         sltu    $at,$c_1,$t_1
1783         $MULTU  $a_2,$b_1               # mul_add_c(a[2],b[1],c1,c2,c3);
1784         $ADDU   $t_2,$at
1785         $ADDU   $c_2,$t_2
1786         sltu    $at,$c_2,$t_2
1787         $ADDU   $c_3,$at
1788         mflo    $t_1
1789         mfhi    $t_2
1790         $ADDU   $c_1,$t_1
1791         sltu    $at,$c_1,$t_1
1792         $MULTU  $a_3,$b_0               # mul_add_c(a[3],b[0],c1,c2,c3);
1793         $ADDU   $t_2,$at
1794         $ADDU   $c_2,$t_2
1795         sltu    $at,$c_2,$t_2
1796         $ADDU   $c_3,$at
1797         mflo    $t_1
1798         mfhi    $t_2
1799         $ADDU   $c_1,$t_1
1800         sltu    $at,$c_1,$t_1
1801          $MULTU $a_3,$b_1               # mul_add_c(a[3],b[1],c2,c3,c1);
1802         $ADDU   $t_2,$at
1803         $ADDU   $c_2,$t_2
1804         sltu    $at,$c_2,$t_2
1805         $ADDU   $c_3,$at
1806         $ST     $c_1,3*$BNSZ($a0)
1807
1808         mflo    $t_1
1809         mfhi    $t_2
1810         $ADDU   $c_2,$t_1
1811         sltu    $at,$c_2,$t_1
1812         $MULTU  $a_2,$b_2               # mul_add_c(a[2],b[2],c2,c3,c1);
1813         $ADDU   $t_2,$at
1814         $ADDU   $c_3,$t_2
1815         sltu    $c_1,$c_3,$t_2
1816         mflo    $t_1
1817         mfhi    $t_2
1818         $ADDU   $c_2,$t_1
1819         sltu    $at,$c_2,$t_1
1820         $MULTU  $a_1,$b_3               # mul_add_c(a[1],b[3],c2,c3,c1);
1821         $ADDU   $t_2,$at
1822         $ADDU   $c_3,$t_2
1823         sltu    $at,$c_3,$t_2
1824         $ADDU   $c_1,$at
1825         mflo    $t_1
1826         mfhi    $t_2
1827         $ADDU   $c_2,$t_1
1828         sltu    $at,$c_2,$t_1
1829          $MULTU $a_2,$b_3               # mul_add_c(a[2],b[3],c3,c1,c2);
1830         $ADDU   $t_2,$at
1831         $ADDU   $c_3,$t_2
1832         sltu    $at,$c_3,$t_2
1833         $ADDU   $c_1,$at
1834         $ST     $c_2,4*$BNSZ($a0)
1835
1836         mflo    $t_1
1837         mfhi    $t_2
1838         $ADDU   $c_3,$t_1
1839         sltu    $at,$c_3,$t_1
1840         $MULTU  $a_3,$b_2               # mul_add_c(a[3],b[2],c3,c1,c2);
1841         $ADDU   $t_2,$at
1842         $ADDU   $c_1,$t_2
1843         sltu    $c_2,$c_1,$t_2
1844         mflo    $t_1
1845         mfhi    $t_2
1846         $ADDU   $c_3,$t_1
1847         sltu    $at,$c_3,$t_1
1848          $MULTU $a_3,$b_3               # mul_add_c(a[3],b[3],c1,c2,c3);
1849         $ADDU   $t_2,$at
1850         $ADDU   $c_1,$t_2
1851         sltu    $at,$c_1,$t_2
1852         $ADDU   $c_2,$at
1853         $ST     $c_3,5*$BNSZ($a0)
1854
1855         mflo    $t_1
1856         mfhi    $t_2
1857         $ADDU   $c_1,$t_1
1858         sltu    $at,$c_1,$t_1
1859         $ADDU   $t_2,$at
1860         $ADDU   $c_2,$t_2
1861         $ST     $c_1,6*$BNSZ($a0)
1862         $ST     $c_2,7*$BNSZ($a0)
1863
1864         .set    noreorder
1865 ___
1866 $code.=<<___ if ($flavour =~ /nubi/i);
1867         $REG_L  $t3,4*$SZREG($sp)
1868         $REG_L  $t2,3*$SZREG($sp)
1869         $REG_L  $t1,2*$SZREG($sp)
1870         $REG_L  $t0,1*$SZREG($sp)
1871         $REG_L  $gp,0*$SZREG($sp)
1872         $PTR_ADD $sp,6*$SZREG
1873 ___
1874 $code.=<<___;
1875         jr      $ra
1876         nop
1877 .end    bn_mul_comba4
1878 ___
1879
1880 ($a_4,$a_5,$a_6,$a_7)=($b_0,$b_1,$b_2,$b_3);
1881
1882 sub add_c2 () {
1883 my ($hi,$lo,$c0,$c1,$c2,
1884     $warm,      # !$warm denotes first call with specific sequence of
1885                 # $c_[XYZ] when there is no Z-carry to accumulate yet;
1886     $an,$bn     # these two are arguments for multiplication which
1887                 # result is used in *next* step [which is why it's
1888                 # commented as "forward multiplication" below];
1889     )=@_;
1890 $code.=<<___;
1891         mflo    $lo
1892         mfhi    $hi
1893         $ADDU   $c0,$lo
1894         sltu    $at,$c0,$lo
1895          $MULTU $an,$bn                 # forward multiplication
1896         $ADDU   $c0,$lo
1897         $ADDU   $at,$hi
1898         sltu    $lo,$c0,$lo
1899         $ADDU   $c1,$at
1900         $ADDU   $hi,$lo
1901 ___
1902 $code.=<<___    if (!$warm);
1903         sltu    $c2,$c1,$at
1904         $ADDU   $c1,$hi
1905         sltu    $hi,$c1,$hi
1906         $ADDU   $c2,$hi
1907 ___
1908 $code.=<<___    if ($warm);
1909         sltu    $at,$c1,$at
1910         $ADDU   $c1,$hi
1911         $ADDU   $c2,$at
1912         sltu    $hi,$c1,$hi
1913         $ADDU   $c2,$hi
1914 ___
1915 }
1916
1917 $code.=<<___;
1918
1919 .align  5
1920 .globl  bn_sqr_comba8
1921 .ent    bn_sqr_comba8
1922 bn_sqr_comba8:
1923 ___
1924 $code.=<<___ if ($flavour =~ /nubi/i);
1925         .frame  $sp,6*$SZREG,$ra
1926         .mask   0x8000f008,-$SZREG
1927         .set    noreorder
1928         $PTR_SUB $sp,6*$SZREG
1929         $REG_S  $ra,5*$SZREG($sp)
1930         $REG_S  $t3,4*$SZREG($sp)
1931         $REG_S  $t2,3*$SZREG($sp)
1932         $REG_S  $t1,2*$SZREG($sp)
1933         $REG_S  $t0,1*$SZREG($sp)
1934         $REG_S  $gp,0*$SZREG($sp)
1935 ___
1936 $code.=<<___;
1937         .set    reorder
1938         $LD     $a_0,0($a1)
1939         $LD     $a_1,$BNSZ($a1)
1940         $LD     $a_2,2*$BNSZ($a1)
1941         $LD     $a_3,3*$BNSZ($a1)
1942
1943         $MULTU  $a_0,$a_0               # mul_add_c(a[0],b[0],c1,c2,c3);
1944         $LD     $a_4,4*$BNSZ($a1)
1945         $LD     $a_5,5*$BNSZ($a1)
1946         $LD     $a_6,6*$BNSZ($a1)
1947         $LD     $a_7,7*$BNSZ($a1)
1948         mflo    $c_1
1949         mfhi    $c_2
1950         $ST     $c_1,0($a0)
1951
1952         $MULTU  $a_0,$a_1               # mul_add_c2(a[0],b[1],c2,c3,c1);
1953         mflo    $t_1
1954         mfhi    $t_2
1955         slt     $c_1,$t_2,$zero
1956         $SLL    $t_2,1
1957          $MULTU $a_2,$a_0               # mul_add_c2(a[2],b[0],c3,c1,c2);
1958         slt     $a2,$t_1,$zero
1959         $ADDU   $t_2,$a2
1960         $SLL    $t_1,1
1961         $ADDU   $c_2,$t_1
1962         sltu    $at,$c_2,$t_1
1963         $ADDU   $c_3,$t_2,$at
1964         $ST     $c_2,$BNSZ($a0)
1965 ___
1966         &add_c2($t_2,$t_1,$c_3,$c_1,$c_2,0,
1967                 $a_1,$a_1);             # mul_add_c(a[1],b[1],c3,c1,c2);
1968 $code.=<<___;
1969         mflo    $t_1
1970         mfhi    $t_2
1971         $ADDU   $c_3,$t_1
1972         sltu    $at,$c_3,$t_1
1973          $MULTU $a_0,$a_3               # mul_add_c2(a[0],b[3],c1,c2,c3);
1974         $ADDU   $t_2,$at
1975         $ADDU   $c_1,$t_2
1976         sltu    $at,$c_1,$t_2
1977         $ADDU   $c_2,$at
1978         $ST     $c_3,2*$BNSZ($a0)
1979 ___
1980         &add_c2($t_2,$t_1,$c_1,$c_2,$c_3,0,
1981                 $a_1,$a_2);             # mul_add_c2(a[1],b[2],c1,c2,c3);
1982         &add_c2($t_2,$t_1,$c_1,$c_2,$c_3,1,
1983                 $a_4,$a_0);             # mul_add_c2(a[4],b[0],c2,c3,c1);
1984 $code.=<<___;
1985         $ST     $c_1,3*$BNSZ($a0)
1986 ___
1987         &add_c2($t_2,$t_1,$c_2,$c_3,$c_1,0,
1988                 $a_3,$a_1);             # mul_add_c2(a[3],b[1],c2,c3,c1);
1989         &add_c2($t_2,$t_1,$c_2,$c_3,$c_1,1,
1990                 $a_2,$a_2);             # mul_add_c(a[2],b[2],c2,c3,c1);
1991 $code.=<<___;
1992         mflo    $t_1
1993         mfhi    $t_2
1994         $ADDU   $c_2,$t_1
1995         sltu    $at,$c_2,$t_1
1996          $MULTU $a_0,$a_5               # mul_add_c2(a[0],b[5],c3,c1,c2);
1997         $ADDU   $t_2,$at
1998         $ADDU   $c_3,$t_2
1999         sltu    $at,$c_3,$t_2
2000         $ADDU   $c_1,$at
2001         $ST     $c_2,4*$BNSZ($a0)
2002 ___
2003         &add_c2($t_2,$t_1,$c_3,$c_1,$c_2,0,
2004                 $a_1,$a_4);             # mul_add_c2(a[1],b[4],c3,c1,c2);
2005         &add_c2($t_2,$t_1,$c_3,$c_1,$c_2,1,
2006                 $a_2,$a_3);             # mul_add_c2(a[2],b[3],c3,c1,c2);
2007         &add_c2($t_2,$t_1,$c_3,$c_1,$c_2,1,
2008                 $a_6,$a_0);             # mul_add_c2(a[6],b[0],c1,c2,c3);
2009 $code.=<<___;
2010         $ST     $c_3,5*$BNSZ($a0)
2011 ___
2012         &add_c2($t_2,$t_1,$c_1,$c_2,$c_3,0,
2013                 $a_5,$a_1);             # mul_add_c2(a[5],b[1],c1,c2,c3);
2014         &add_c2($t_2,$t_1,$c_1,$c_2,$c_3,1,
2015                 $a_4,$a_2);             # mul_add_c2(a[4],b[2],c1,c2,c3);
2016         &add_c2($t_2,$t_1,$c_1,$c_2,$c_3,1,
2017                 $a_3,$a_3);             # mul_add_c(a[3],b[3],c1,c2,c3);
2018 $code.=<<___;
2019         mflo    $t_1
2020         mfhi    $t_2
2021         $ADDU   $c_1,$t_1
2022         sltu    $at,$c_1,$t_1
2023          $MULTU $a_0,$a_7               # mul_add_c2(a[0],b[7],c2,c3,c1);
2024         $ADDU   $t_2,$at
2025         $ADDU   $c_2,$t_2
2026         sltu    $at,$c_2,$t_2
2027         $ADDU   $c_3,$at
2028         $ST     $c_1,6*$BNSZ($a0)
2029 ___
2030         &add_c2($t_2,$t_1,$c_2,$c_3,$c_1,0,
2031                 $a_1,$a_6);             # mul_add_c2(a[1],b[6],c2,c3,c1);
2032         &add_c2($t_2,$t_1,$c_2,$c_3,$c_1,1,
2033                 $a_2,$a_5);             # mul_add_c2(a[2],b[5],c2,c3,c1);
2034         &add_c2($t_2,$t_1,$c_2,$c_3,$c_1,1,
2035                 $a_3,$a_4);             # mul_add_c2(a[3],b[4],c2,c3,c1);
2036         &add_c2($t_2,$t_1,$c_2,$c_3,$c_1,1,
2037                 $a_7,$a_1);             # mul_add_c2(a[7],b[1],c3,c1,c2);
2038 $code.=<<___;
2039         $ST     $c_2,7*$BNSZ($a0)
2040 ___
2041         &add_c2($t_2,$t_1,$c_3,$c_1,$c_2,0,
2042                 $a_6,$a_2);             # mul_add_c2(a[6],b[2],c3,c1,c2);
2043         &add_c2($t_2,$t_1,$c_3,$c_1,$c_2,1,
2044                 $a_5,$a_3);             # mul_add_c2(a[5],b[3],c3,c1,c2);
2045         &add_c2($t_2,$t_1,$c_3,$c_1,$c_2,1,
2046                 $a_4,$a_4);             # mul_add_c(a[4],b[4],c3,c1,c2);
2047 $code.=<<___;
2048         mflo    $t_1
2049         mfhi    $t_2
2050         $ADDU   $c_3,$t_1
2051         sltu    $at,$c_3,$t_1
2052          $MULTU $a_2,$a_7               # mul_add_c2(a[2],b[7],c1,c2,c3);
2053         $ADDU   $t_2,$at
2054         $ADDU   $c_1,$t_2
2055         sltu    $at,$c_1,$t_2
2056         $ADDU   $c_2,$at
2057         $ST     $c_3,8*$BNSZ($a0)
2058 ___
2059         &add_c2($t_2,$t_1,$c_1,$c_2,$c_3,0,
2060                 $a_3,$a_6);             # mul_add_c2(a[3],b[6],c1,c2,c3);
2061         &add_c2($t_2,$t_1,$c_1,$c_2,$c_3,1,
2062                 $a_4,$a_5);             # mul_add_c2(a[4],b[5],c1,c2,c3);
2063         &add_c2($t_2,$t_1,$c_1,$c_2,$c_3,1,
2064                 $a_7,$a_3);             # mul_add_c2(a[7],b[3],c2,c3,c1);
2065 $code.=<<___;
2066         $ST     $c_1,9*$BNSZ($a0)
2067 ___
2068         &add_c2($t_2,$t_1,$c_2,$c_3,$c_1,0,
2069                 $a_6,$a_4);             # mul_add_c2(a[6],b[4],c2,c3,c1);
2070         &add_c2($t_2,$t_1,$c_2,$c_3,$c_1,1,
2071                 $a_5,$a_5);             # mul_add_c(a[5],b[5],c2,c3,c1);
2072 $code.=<<___;
2073         mflo    $t_1
2074         mfhi    $t_2
2075         $ADDU   $c_2,$t_1
2076         sltu    $at,$c_2,$t_1
2077          $MULTU $a_4,$a_7               # mul_add_c2(a[4],b[7],c3,c1,c2);
2078         $ADDU   $t_2,$at
2079         $ADDU   $c_3,$t_2
2080         sltu    $at,$c_3,$t_2
2081         $ADDU   $c_1,$at
2082         $ST     $c_2,10*$BNSZ($a0)
2083 ___
2084         &add_c2($t_2,$t_1,$c_3,$c_1,$c_2,0,
2085                 $a_5,$a_6);             # mul_add_c2(a[5],b[6],c3,c1,c2);
2086         &add_c2($t_2,$t_1,$c_3,$c_1,$c_2,1,
2087                 $a_7,$a_5);             # mul_add_c2(a[7],b[5],c1,c2,c3);
2088 $code.=<<___;
2089         $ST     $c_3,11*$BNSZ($a0)
2090 ___
2091         &add_c2($t_2,$t_1,$c_1,$c_2,$c_3,0,
2092                 $a_6,$a_6);             # mul_add_c(a[6],b[6],c1,c2,c3);
2093 $code.=<<___;
2094         mflo    $t_1
2095         mfhi    $t_2
2096         $ADDU   $c_1,$t_1
2097         sltu    $at,$c_1,$t_1
2098          $MULTU $a_6,$a_7               # mul_add_c2(a[6],b[7],c2,c3,c1);
2099         $ADDU   $t_2,$at
2100         $ADDU   $c_2,$t_2
2101         sltu    $at,$c_2,$t_2
2102         $ADDU   $c_3,$at
2103         $ST     $c_1,12*$BNSZ($a0)
2104 ___
2105         &add_c2($t_2,$t_1,$c_2,$c_3,$c_1,0,
2106                 $a_7,$a_7);             # mul_add_c(a[7],b[7],c3,c1,c2);
2107 $code.=<<___;
2108         $ST     $c_2,13*$BNSZ($a0)
2109
2110         mflo    $t_1
2111         mfhi    $t_2
2112         $ADDU   $c_3,$t_1
2113         sltu    $at,$c_3,$t_1
2114         $ADDU   $t_2,$at
2115         $ADDU   $c_1,$t_2
2116         $ST     $c_3,14*$BNSZ($a0)
2117         $ST     $c_1,15*$BNSZ($a0)
2118
2119         .set    noreorder
2120 ___
2121 $code.=<<___ if ($flavour =~ /nubi/i);
2122         $REG_L  $t3,4*$SZREG($sp)
2123         $REG_L  $t2,3*$SZREG($sp)
2124         $REG_L  $t1,2*$SZREG($sp)
2125         $REG_L  $t0,1*$SZREG($sp)
2126         $REG_L  $gp,0*$SZREG($sp)
2127         $PTR_ADD $sp,6*$SZREG
2128 ___
2129 $code.=<<___;
2130         jr      $ra
2131         nop
2132 .end    bn_sqr_comba8
2133
2134 .align  5
2135 .globl  bn_sqr_comba4
2136 .ent    bn_sqr_comba4
2137 bn_sqr_comba4:
2138 ___
2139 $code.=<<___ if ($flavour =~ /nubi/i);
2140         .frame  $sp,6*$SZREG,$ra
2141         .mask   0x8000f008,-$SZREG
2142         .set    noreorder
2143         $PTR_SUB $sp,6*$SZREG
2144         $REG_S  $ra,5*$SZREG($sp)
2145         $REG_S  $t3,4*$SZREG($sp)
2146         $REG_S  $t2,3*$SZREG($sp)
2147         $REG_S  $t1,2*$SZREG($sp)
2148         $REG_S  $t0,1*$SZREG($sp)
2149         $REG_S  $gp,0*$SZREG($sp)
2150 ___
2151 $code.=<<___;
2152         .set    reorder
2153         $LD     $a_0,0($a1)
2154         $LD     $a_1,$BNSZ($a1)
2155         $MULTU  $a_0,$a_0               # mul_add_c(a[0],b[0],c1,c2,c3);
2156         $LD     $a_2,2*$BNSZ($a1)
2157         $LD     $a_3,3*$BNSZ($a1)
2158         mflo    $c_1
2159         mfhi    $c_2
2160         $ST     $c_1,0($a0)
2161
2162         $MULTU  $a_0,$a_1               # mul_add_c2(a[0],b[1],c2,c3,c1);
2163         mflo    $t_1
2164         mfhi    $t_2
2165         slt     $c_1,$t_2,$zero
2166         $SLL    $t_2,1
2167          $MULTU $a_2,$a_0               # mul_add_c2(a[2],b[0],c3,c1,c2);
2168         slt     $a2,$t_1,$zero
2169         $ADDU   $t_2,$a2
2170         $SLL    $t_1,1
2171         $ADDU   $c_2,$t_1
2172         sltu    $at,$c_2,$t_1
2173         $ADDU   $c_3,$t_2,$at
2174         $ST     $c_2,$BNSZ($a0)
2175 ___
2176         &add_c2($t_2,$t_1,$c_3,$c_1,$c_2,0,
2177                 $a_1,$a_1);             # mul_add_c(a[1],b[1],c3,c1,c2);
2178 $code.=<<___;
2179         mflo    $t_1
2180         mfhi    $t_2
2181         $ADDU   $c_3,$t_1
2182         sltu    $at,$c_3,$t_1
2183          $MULTU $a_0,$a_3               # mul_add_c2(a[0],b[3],c1,c2,c3);
2184         $ADDU   $t_2,$at
2185         $ADDU   $c_1,$t_2
2186         sltu    $at,$c_1,$t_2
2187         $ADDU   $c_2,$at
2188         $ST     $c_3,2*$BNSZ($a0)
2189 ___
2190         &add_c2($t_2,$t_1,$c_1,$c_2,$c_3,0,
2191                 $a_1,$a_2);             # mul_add_c2(a2[1],b[2],c1,c2,c3);
2192         &add_c2($t_2,$t_1,$c_1,$c_2,$c_3,1,
2193                 $a_3,$a_1);             # mul_add_c2(a[3],b[1],c2,c3,c1);
2194 $code.=<<___;
2195         $ST     $c_1,3*$BNSZ($a0)
2196 ___
2197         &add_c2($t_2,$t_1,$c_2,$c_3,$c_1,0,
2198                 $a_2,$a_2);             # mul_add_c(a[2],b[2],c2,c3,c1);
2199 $code.=<<___;
2200         mflo    $t_1
2201         mfhi    $t_2
2202         $ADDU   $c_2,$t_1
2203         sltu    $at,$c_2,$t_1
2204          $MULTU $a_2,$a_3               # mul_add_c2(a[2],b[3],c3,c1,c2);
2205         $ADDU   $t_2,$at
2206         $ADDU   $c_3,$t_2
2207         sltu    $at,$c_3,$t_2
2208         $ADDU   $c_1,$at
2209         $ST     $c_2,4*$BNSZ($a0)
2210 ___
2211         &add_c2($t_2,$t_1,$c_3,$c_1,$c_2,0,
2212                 $a_3,$a_3);             # mul_add_c(a[3],b[3],c1,c2,c3);
2213 $code.=<<___;
2214         $ST     $c_3,5*$BNSZ($a0)
2215
2216         mflo    $t_1
2217         mfhi    $t_2
2218         $ADDU   $c_1,$t_1
2219         sltu    $at,$c_1,$t_1
2220         $ADDU   $t_2,$at
2221         $ADDU   $c_2,$t_2
2222         $ST     $c_1,6*$BNSZ($a0)
2223         $ST     $c_2,7*$BNSZ($a0)
2224
2225         .set    noreorder
2226 ___
2227 $code.=<<___ if ($flavour =~ /nubi/i);
2228         $REG_L  $t3,4*$SZREG($sp)
2229         $REG_L  $t2,3*$SZREG($sp)
2230         $REG_L  $t1,2*$SZREG($sp)
2231         $REG_L  $t0,1*$SZREG($sp)
2232         $REG_L  $gp,0*$SZREG($sp)
2233         $PTR_ADD $sp,6*$SZREG
2234 ___
2235 $code.=<<___;
2236         jr      $ra
2237         nop
2238 .end    bn_sqr_comba4
2239 ___
2240 print $code;
2241 close STDOUT;