2 # Copyright 2009-2018 The OpenSSL Project Authors. All Rights Reserved.
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
10 # ====================================================================
11 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
12 # project. The module is, however, dual licensed under OpenSSL and
13 # CRYPTOGAMS licenses depending on where you obtain it. For further
14 # details see http://www.openssl.org/~appro/cryptogams/.
15 # ====================================================================
17 # On PA-7100LC this module performs ~90-50% better, less for longer
18 # keys, than code generated by gcc 3.2 for PA-RISC 1.1. Latter means
19 # that compiler utilized xmpyu instruction to perform 32x32=64-bit
20 # multiplication, which in turn means that "baseline" performance was
21 # optimal in respect to instruction set capabilities. Fair comparison
22 # with vendor compiler is problematic, because OpenSSL doesn't define
23 # BN_LLONG [presumably] for historical reasons, which drives compiler
24 # toward 4 times 16x16=32-bit multiplications [plus complementary
25 # shifts and additions] instead. This means that you should observe
26 # several times improvement over code generated by vendor compiler
27 # for PA-RISC 1.1, but the "baseline" is far from optimal. The actual
28 # improvement coefficient was never collected on PA-7100LC, or any
29 # other 1.1 CPU, because I don't have access to such machine with
30 # vendor compiler. But to give you a taste, PA-RISC 1.1 code path
31 # reportedly outperformed code generated by cc +DA1.1 +O3 by factor
34 # On PA-RISC 2.0 it has to compete with pa-risc2[W].s, which is
35 # reportedly ~2x faster than vendor compiler generated code [according
36 # to comment in pa-risc2[W].s]. Here comes a catch. Execution core of
37 # this implementation is actually 32-bit one, in the sense that it
38 # operates on 32-bit values. But pa-risc2[W].s operates on arrays of
39 # 64-bit BN_LONGs... How do they interoperate then? No problem. This
40 # module picks halves of 64-bit values in reverse order and pretends
41 # they were 32-bit BN_LONGs. But can 32-bit core compete with "pure"
42 # 64-bit code such as pa-risc2[W].s then? Well, the thing is that
43 # 32x32=64-bit multiplication is the best even PA-RISC 2.0 can do,
44 # i.e. there is no "wider" multiplication like on most other 64-bit
45 # platforms. This means that even being effectively 32-bit, this
46 # implementation performs "64-bit" computational task in same amount
47 # of arithmetic operations, most notably multiplications. It requires
48 # more memory references, most notably to tp[num], but this doesn't
49 # seem to exhaust memory port capacity. And indeed, dedicated PA-RISC
50 # 2.0 code path provides virtually same performance as pa-risc2[W].s:
51 # it's ~10% better for shortest key length and ~10% worse for longest
54 # In case it wasn't clear. The module has two distinct code paths:
55 # PA-RISC 1.1 and PA-RISC 2.0 ones. Latter features carry-free 64-bit
56 # additions and 64-bit integer loads, not to mention specific
57 # instruction scheduling. In 64-bit build naturally only 2.0 code path
58 # is assembled. In 32-bit application context both code paths are
59 # assembled, PA-RISC 2.0 CPU is detected at run-time and proper path
60 # is taken automatically. Also, in 32-bit build the module imposes
61 # couple of limitations: vector lengths has to be even and vector
62 # addresses has to be 64-bit aligned. Normally neither is a problem:
63 # most common key lengths are even and vectors are commonly malloc-ed,
64 # which ensures alignment.
66 # Special thanks to polarhome.com for providing HP-UX account on
67 # PA-RISC 1.1 machine, and to correspondent who chose to remain
68 # anonymous for testing the code on PA-RISC 2.0 machine.
70 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
75 open STDOUT,">$output";
77 if ($flavour =~ /64/) {
88 $LEVEL ="1.1"; #$LEVEL.="\n\t.ALLOW\t2.0";
97 if (open CONF,"<${dir}../../opensslconf.h") {
99 if (m/#\s*define\s+SIXTY_FOUR_BIT/) {
109 $FRAME=8*$SIZE_T+$FRAME_MARKER; # 8 saved regs + frame marker
110 # [+ argument transfer]
111 $LOCALS=$FRAME-$FRAME_MARKER;
112 $FRAME+=32; # local variables
122 $n0="%r22"; # passed through stack in 32-bit
123 $num="%r21"; # passed through stack in 32-bit
136 $xfer=$n0; # accommodates [-16..15] offset in fld[dw]s
138 $fm0="%fr4"; $fti=$fm0;
141 $fai="%fr6"; $fab0="%fr7"; $fab1="%fr8";
142 $fni="%fr9"; $fnm0="%fr10"; $fnm1="%fr11";
147 .SUBSPA \$CODE\$,QUAD=0,ALIGN=8,ACCESS=0x2C,CODE_ONLY
149 .EXPORT bn_mul_mont,ENTRY,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR
153 .CALLINFO FRAME=`$FRAME-8*$SIZE_T`,NO_CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=6
155 $PUSH %r2,-$SAVED_RP(%sp) ; standard prologue
156 $PUSHMA %r3,$FRAME(%sp)
157 $PUSH %r4,`-$FRAME+1*$SIZE_T`(%sp)
158 $PUSH %r5,`-$FRAME+2*$SIZE_T`(%sp)
159 $PUSH %r6,`-$FRAME+3*$SIZE_T`(%sp)
160 $PUSH %r7,`-$FRAME+4*$SIZE_T`(%sp)
161 $PUSH %r8,`-$FRAME+5*$SIZE_T`(%sp)
162 $PUSH %r9,`-$FRAME+6*$SIZE_T`(%sp)
163 $PUSH %r10,`-$FRAME+7*$SIZE_T`(%sp)
166 $code.=<<___ if ($SIZE_T==4);
167 ldw `-$FRAME_MARKER-4`($fp),$n0
168 ldw `-$FRAME_MARKER-8`($fp),$num
172 $code.=<<___ if ($BN_SZ==4);
173 comiclr,<= 6,$num,%r0 ; are vectors long enough?
175 ldi 0,%r28 ; signal "unhandled"
176 add,ev %r0,$num,$num ; is $num even?
180 extru,= $ti1,31,3,%r0 ; are ap and np 64-bit aligned?
187 fldws,ma 4($bp),${fbi} ; bp[0]
189 $code.=<<___ if ($BN_SZ==8);
190 comib,> 3,$num,L\$abort ; are vectors long enough?
191 ldi 0,%r28 ; signal "unhandled"
192 addl $num,$num,$num ; I operate on 32-bit values
194 fldws 4($n0),${fn0} ; only low part of n0
195 fldws 4($bp),${fbi} ; bp[0] in flipped word order
198 fldds 0($ap),${fai} ; ap[0,1]
199 fldds 0($np),${fni} ; np[0,1]
201 sh2addl $num,%r0,$arrsz
203 ldo 36($arrsz),$hi1 ; space for tp[num+1]
204 andcm $hi1,$hi0,$hi1 ; align
206 $PUSH $fp,-$SIZE_T(%sp)
208 ldo `$LOCALS+16`($fp),$xfer
209 ldo `$LOCALS+32+4`($fp),$tp
211 xmpyu ${fai}L,${fbi},${fab0} ; ap[0]*bp[0]
212 xmpyu ${fai}R,${fbi},${fab1} ; ap[1]*bp[0]
213 xmpyu ${fn0},${fab0}R,${fm0}
215 addl $arrsz,$ap,$ap ; point at the end
217 subi 0,$arrsz,$idx ; j=0
218 ldo 8($idx),$idx ; j++++
220 xmpyu ${fni}L,${fm0}R,${fnm0} ; np[0]*m
221 xmpyu ${fni}R,${fm0}R,${fnm1} ; np[1]*m
222 fstds ${fab0},-16($xfer)
223 fstds ${fnm0},-8($xfer)
224 fstds ${fab1},0($xfer)
225 fstds ${fnm1},8($xfer)
226 flddx $idx($ap),${fai} ; ap[2,3]
227 flddx $idx($np),${fni} ; np[2,3]
229 $code.=<<___ if ($BN_SZ==4);
230 mtctl $hi0,%cr11 ; $hi0 still holds 31
231 extrd,u,*= $hi0,%sar,1,$hi0 ; executes on PA-RISC 1.0
235 $code.=<<___; # PA-RISC 2.0 code-path
236 xmpyu ${fai}L,${fbi},${fab0} ; ap[j]*bp[0]
237 xmpyu ${fni}L,${fm0}R,${fnm0} ; np[j]*m
239 fstds ${fab0},-16($xfer)
241 extrd,u $ab0,31,32,$hi0
242 extrd,u $ab0,63,32,$ab0
244 fstds ${fnm0},-8($xfer)
245 ldo 8($idx),$idx ; j++++
246 addl $ab0,$nm0,$nm0 ; low part is discarded
247 extrd,u $nm0,31,32,$hi1
250 xmpyu ${fai}R,${fbi},${fab1} ; ap[j+1]*bp[0]
251 xmpyu ${fni}R,${fm0}R,${fnm1} ; np[j+1]*m
253 fstds ${fab1},0($xfer)
255 extrd,u $ab1,31,32,$hi0
257 fstds ${fnm1},8($xfer)
258 extrd,u $ab1,63,32,$ab1
260 flddx $idx($ap),${fai} ; ap[j,j+1]
261 flddx $idx($np),${fni} ; np[j,j+1]
263 extrd,u $nm1,31,32,$hi1
265 xmpyu ${fai}L,${fbi},${fab0} ; ap[j]*bp[0]
266 xmpyu ${fni}L,${fm0}R,${fnm0} ; np[j]*m
268 fstds ${fab0},-16($xfer)
270 extrd,u $ab0,31,32,$hi0
272 fstds ${fnm0},-8($xfer)
273 extrd,u $ab0,63,32,$ab0
275 stw $nm1,-4($tp) ; tp[j-1]
277 stw,ma $nm0,8($tp) ; tp[j-1]
278 addib,<> 8,$idx,L\$1st ; j++++
279 extrd,u $nm0,31,32,$hi1
281 xmpyu ${fai}R,${fbi},${fab1} ; ap[j]*bp[0]
282 xmpyu ${fni}R,${fm0}R,${fnm1} ; np[j]*m
284 fstds ${fab1},0($xfer)
286 extrd,u $ab1,31,32,$hi0
288 fstds ${fnm1},8($xfer)
289 extrd,u $ab1,63,32,$ab1
294 extrd,u $nm1,31,32,$hi1
297 extrd,u $ab0,31,32,$hi0
298 stw $nm1,-4($tp) ; tp[j-1]
299 extrd,u $ab0,63,32,$ab0
304 extrd,u $nm0,31,32,$hi1
305 stw,ma $nm0,8($tp) ; tp[j-1]
307 ldo -1($num),$num ; i--
308 subi 0,$arrsz,$idx ; j=0
310 $code.=<<___ if ($BN_SZ==4);
311 fldws,ma 4($bp),${fbi} ; bp[1]
313 $code.=<<___ if ($BN_SZ==8);
314 fldws 0($bp),${fbi} ; bp[1] in flipped word order
317 flddx $idx($ap),${fai} ; ap[0,1]
318 flddx $idx($np),${fni} ; np[0,1]
319 fldws 8($xfer),${fti}R ; tp[0]
321 extrd,u $ab1,31,32,$hi0
322 extrd,u $ab1,63,32,$ab1
323 ldo 8($idx),$idx ; j++++
324 xmpyu ${fai}L,${fbi},${fab0} ; ap[0]*bp[1]
325 xmpyu ${fai}R,${fbi},${fab1} ; ap[1]*bp[1]
328 extrd,u $nm1,31,32,$hi1
329 fstws,mb ${fab0}L,-8($xfer) ; save high part
330 stw $nm1,-4($tp) ; tp[j-1]
332 fcpy,sgl %fr0,${fti}L ; zero high part
333 fcpy,sgl %fr0,${fab0}L
335 extrd,u $hi0,31,32,$hi1
336 fcnvxf,dbl,dbl ${fti},${fti} ; 32-bit unsigned int -> double
337 fcnvxf,dbl,dbl ${fab0},${fab0}
341 fadd,dbl ${fti},${fab0},${fab0} ; add tp[0]
342 fcnvfx,dbl,dbl ${fab0},${fab0} ; double -> 33-bit unsigned int
343 xmpyu ${fn0},${fab0}R,${fm0}
344 ldo `$LOCALS+32+4`($fp),$tp
346 xmpyu ${fni}L,${fm0}R,${fnm0} ; np[0]*m
347 xmpyu ${fni}R,${fm0}R,${fnm1} ; np[1]*m
348 fstds ${fab0},-16($xfer) ; 33-bit value
349 fstds ${fnm0},-8($xfer)
350 flddx $idx($ap),${fai} ; ap[2]
351 flddx $idx($np),${fni} ; np[2]
352 ldo 8($idx),$idx ; j++++
353 ldd -16($xfer),$ab0 ; 33-bit value
355 ldw 0($xfer),$hi0 ; high part
357 xmpyu ${fai}L,${fbi},${fab0} ; ap[j]*bp[i]
358 xmpyu ${fni}L,${fm0}R,${fnm0} ; np[j]*m
359 extrd,u $ab0,31,32,$ti0 ; carry bit
360 extrd,u $ab0,63,32,$ab0
361 fstds ${fab1},0($xfer)
362 addl $ti0,$hi0,$hi0 ; account carry bit
363 fstds ${fnm1},8($xfer)
364 addl $ab0,$nm0,$nm0 ; low part is discarded
365 ldw 0($tp),$ti1 ; tp[1]
366 extrd,u $nm0,31,32,$hi1
367 fstds ${fab0},-16($xfer)
368 fstds ${fnm0},-8($xfer)
371 xmpyu ${fai}R,${fbi},${fab1} ; ap[j+1]*bp[i]
372 xmpyu ${fni}R,${fm0}R,${fnm1} ; np[j+1]*m
374 fstds ${fab1},0($xfer)
378 fstds ${fnm1},8($xfer)
379 extrd,u $ab1,31,32,$hi0
380 extrd,u $ab1,63,32,$ab1
381 flddx $idx($ap),${fai} ; ap[j,j+1]
382 flddx $idx($np),${fni} ; np[j,j+1]
385 ldw 4($tp),$ti0 ; tp[j]
386 stw $nm1,-4($tp) ; tp[j-1]
388 xmpyu ${fai}L,${fbi},${fab0} ; ap[j]*bp[i]
389 xmpyu ${fni}L,${fm0}R,${fnm0} ; np[j]*m
391 fstds ${fab0},-16($xfer)
395 fstds ${fnm0},-8($xfer)
396 extrd,u $ab0,31,32,$hi0
397 extrd,u $nm1,31,32,$hi1
398 ldw 8($tp),$ti1 ; tp[j]
399 extrd,u $ab0,63,32,$ab0
402 stw,ma $nm0,8($tp) ; tp[j-1]
403 addib,<> 8,$idx,L\$inner ; j++++
404 extrd,u $nm0,31,32,$hi1
406 xmpyu ${fai}R,${fbi},${fab1} ; ap[j]*bp[i]
407 xmpyu ${fni}R,${fm0}R,${fnm1} ; np[j]*m
409 fstds ${fab1},0($xfer)
413 fstds ${fnm1},8($xfer)
414 extrd,u $ab1,31,32,$hi0
415 extrd,u $ab1,63,32,$ab1
416 ldw 4($tp),$ti0 ; tp[j]
421 extrd,u $nm1,31,32,$hi1
425 stw $nm1,-4($tp) ; tp[j-1]
426 extrd,u $ab0,31,32,$hi0
427 ldw 8($tp),$ti1 ; tp[j]
428 extrd,u $ab0,63,32,$ab0
433 extrd,u $nm0,31,32,$hi1
434 stw,ma $nm0,8($tp) ; tp[j-1]
436 addib,= -1,$num,L\$outerdone ; i--
437 subi 0,$arrsz,$idx ; j=0
439 $code.=<<___ if ($BN_SZ==4);
440 fldws,ma 4($bp),${fbi} ; bp[i]
442 $code.=<<___ if ($BN_SZ==8);
443 ldi 12,$ti0 ; bp[i] in flipped word order
444 addl,ev %r0,$num,$num
450 flddx $idx($ap),${fai} ; ap[0]
452 flddx $idx($np),${fni} ; np[0]
453 fldws 8($xfer),${fti}R ; tp[0]
455 extrd,u $ab1,31,32,$hi0
456 extrd,u $ab1,63,32,$ab1
458 ldo 8($idx),$idx ; j++++
459 xmpyu ${fai}L,${fbi},${fab0} ; ap[0]*bp[i]
460 xmpyu ${fai}R,${fbi},${fab1} ; ap[1]*bp[i]
461 ldw 4($tp),$ti0 ; tp[j]
464 fstws,mb ${fab0}L,-8($xfer) ; save high part
466 extrd,u $nm1,31,32,$hi1
467 fcpy,sgl %fr0,${fti}L ; zero high part
468 fcpy,sgl %fr0,${fab0}L
469 stw $nm1,-4($tp) ; tp[j-1]
471 fcnvxf,dbl,dbl ${fti},${fti} ; 32-bit unsigned int -> double
472 fcnvxf,dbl,dbl ${fab0},${fab0}
474 fadd,dbl ${fti},${fab0},${fab0} ; add tp[0]
476 extrd,u $hi0,31,32,$hi1
477 fcnvfx,dbl,dbl ${fab0},${fab0} ; double -> 33-bit unsigned int
480 xmpyu ${fn0},${fab0}R,${fm0}
483 ldo `$LOCALS+32+4`($fp),$tp
488 extrd,u $ab1,31,32,$hi0
489 extrd,u $ab1,63,32,$ab1
491 ldw 4($tp),$ti0 ; tp[j]
495 extrd,u $nm1,31,32,$hi1
496 stw $nm1,-4($tp) ; tp[j-1]
500 extrd,u $hi0,31,32,$hi1
504 ldo `$LOCALS+32`($fp),$tp
505 sub %r0,%r0,%r0 ; clear borrow
507 $code.=<<___ if ($BN_SZ==4);
509 extru,= $rp,31,3,%r0 ; is rp 64-bit aligned?
516 addib,<> 4,$idx,L\$sub
521 $code.=<<___ if ($BN_SZ==8);
525 shrpd $ti0,$ti0,32,$ti0 ; flip word order
526 std $ti0,-8($tp) ; save flipped value
527 sub,db $ti0,$hi0,$hi1
529 addib,<> 8,$idx,L\$sub
532 extrd,u $ti0,31,32,$ti0 ; carry in flipped word order
536 ldo `$LOCALS+32`($fp),$tp
537 sub $rp,$arrsz,$rp ; rewind rp
545 addib,<> 8,$idx,L\$copy
549 if ($BN_SZ==4) { # PA-RISC 1.1 code-path
563 xmpyu ${fai}L,${fbi},${fab0} ; ap[j]*bp[0]
564 xmpyu ${fni}L,${fm0}R,${fnm0} ; np[j]*m
569 fstds ${fab0},-16($xfer)
570 fstds ${fnm0},-8($xfer)
572 ldo 8($idx),$idx ; j++++
573 add $ablo,$nmlo0,$nmlo0 ; discarded
580 xmpyu ${fai}R,${fbi},${fab1} ; ap[j+1]*bp[0]
581 flddx $idx($ap),${fai} ; ap[j,j+1]
582 xmpyu ${fni}R,${fm0}R,${fnm1} ; np[j+1]*m
583 flddx $idx($np),${fni} ; np[j,j+1]
588 add $ablo,$nmlo1,$nmlo1
589 fstds ${fab1},0($xfer)
590 addc %r0,$nmhi1,$nmhi1
591 fstds ${fnm1},8($xfer)
592 add $hi1,$nmlo1,$nmlo1
597 xmpyu ${fai}L,${fbi},${fab0} ; ap[j]*bp[0]
599 xmpyu ${fni}L,${fm0}R,${fnm0} ; np[j]*m
602 stw $nmlo1,-4($tp) ; tp[j-1]
604 fstds ${fab0},-16($xfer)
605 add $ablo,$nmlo0,$nmlo0
606 fstds ${fnm0},-8($xfer)
607 addc %r0,$nmhi0,$nmhi0
609 add $hi1,$nmlo0,$nmlo0
611 stws,ma $nmlo0,8($tp) ; tp[j-1]
612 addib,<> 8,$idx,L\$1st_pa11 ; j++++
617 xmpyu ${fai}R,${fbi},${fab1} ; ap[j]*bp[0]
618 xmpyu ${fni}R,${fm0}R,${fnm1} ; np[j]*m
620 fstds ${fab1},0($xfer)
622 fstds ${fnm1},8($xfer)
623 add $ablo,$nmlo1,$nmlo1
625 addc %r0,$nmhi1,$nmhi1
627 add $hi1,$nmlo1,$nmlo1
633 stw $nmlo1,-4($tp) ; tp[j-1]
636 add $ablo,$nmlo0,$nmlo0
638 addc %r0,$nmhi0,$nmhi0
639 ldws,mb 8($xfer),$nmhi1
640 add $hi1,$nmlo0,$nmlo0
643 stws,ma $nmlo0,8($tp) ; tp[j-1]
645 ldo -1($num),$num ; i--
646 subi 0,$arrsz,$idx ; j=0
648 fldws,ma 4($bp),${fbi} ; bp[1]
649 flddx $idx($ap),${fai} ; ap[0,1]
650 flddx $idx($np),${fni} ; np[0,1]
651 fldws 8($xfer),${fti}R ; tp[0]
654 ldo 8($idx),$idx ; j++++
655 xmpyu ${fai}L,${fbi},${fab0} ; ap[0]*bp[1]
656 xmpyu ${fai}R,${fbi},${fab1} ; ap[1]*bp[1]
657 add $hi1,$nmlo1,$nmlo1
658 addc %r0,$nmhi1,$nmhi1
659 add $ablo,$nmlo1,$nmlo1
661 fstws,mb ${fab0}L,-8($xfer) ; save high part
662 stw $nmlo1,-4($tp) ; tp[j-1]
664 fcpy,sgl %fr0,${fti}L ; zero high part
665 fcpy,sgl %fr0,${fab0}L
668 fcnvxf,dbl,dbl ${fti},${fti} ; 32-bit unsigned int -> double
669 fcnvxf,dbl,dbl ${fab0},${fab0}
673 fadd,dbl ${fti},${fab0},${fab0} ; add tp[0]
674 fcnvfx,dbl,dbl ${fab0},${fab0} ; double -> 33-bit unsigned int
675 xmpyu ${fn0},${fab0}R,${fm0}
676 ldo `$LOCALS+32+4`($fp),$tp
678 xmpyu ${fni}L,${fm0}R,${fnm0} ; np[0]*m
679 xmpyu ${fni}R,${fm0}R,${fnm1} ; np[1]*m
680 fstds ${fab0},-16($xfer) ; 33-bit value
681 fstds ${fnm0},-8($xfer)
682 flddx $idx($ap),${fai} ; ap[2,3]
683 flddx $idx($np),${fni} ; np[2,3]
684 ldw -16($xfer),$abhi ; carry bit actually
685 ldo 8($idx),$idx ; j++++
689 ldw 0($xfer),$hi0 ; high part
691 xmpyu ${fai}L,${fbi},${fab0} ; ap[j]*bp[i]
692 xmpyu ${fni}L,${fm0}R,${fnm0} ; np[j]*m
693 fstds ${fab1},0($xfer)
694 addl $abhi,$hi0,$hi0 ; account carry bit
695 fstds ${fnm1},8($xfer)
696 add $ablo,$nmlo0,$nmlo0 ; discarded
697 ldw 0($tp),$ti1 ; tp[1]
699 fstds ${fab0},-16($xfer)
700 fstds ${fnm0},-8($xfer)
705 xmpyu ${fai}R,${fbi},${fab1} ; ap[j+1]*bp[i]
706 flddx $idx($ap),${fai} ; ap[j,j+1]
707 xmpyu ${fni}R,${fm0}R,${fnm1} ; np[j+1]*m
708 flddx $idx($np),${fni} ; np[j,j+1]
710 ldw 4($tp),$ti0 ; tp[j]
716 fstds ${fab1},0($xfer)
717 add $ablo,$nmlo1,$nmlo1
718 fstds ${fnm1},8($xfer)
719 addc %r0,$nmhi1,$nmhi1
721 add $hi1,$nmlo1,$nmlo1
725 xmpyu ${fai}L,${fbi},${fab0} ; ap[j]*bp[i]
726 ldw 8($tp),$ti1 ; tp[j]
727 xmpyu ${fni}L,${fm0}R,${fnm0} ; np[j]*m
732 stw $nmlo1,-4($tp) ; tp[j-1]
734 fstds ${fab0},-16($xfer)
736 fstds ${fnm0},-8($xfer)
737 add $ablo,$nmlo0,$nmlo0
739 addc %r0,$nmhi0,$nmhi0
741 add $hi1,$nmlo0,$nmlo0
742 stws,ma $nmlo0,8($tp) ; tp[j-1]
743 addib,<> 8,$idx,L\$inner_pa11 ; j++++
746 xmpyu ${fai}R,${fbi},${fab1} ; ap[j]*bp[i]
748 xmpyu ${fni}R,${fm0}R,${fnm1} ; np[j]*m
751 ldw 4($tp),$ti0 ; tp[j]
753 fstds ${fab1},0($xfer)
755 fstds ${fnm1},8($xfer)
758 add $ablo,$nmlo1,$nmlo1
760 addc %r0,$nmhi1,$nmhi1
762 add $hi1,$nmlo1,$nmlo1
767 stw $nmlo1,-4($tp) ; tp[j-1]
770 ldw 8($tp),$ti1 ; tp[j]
773 add $ablo,$nmlo0,$nmlo0
775 addc %r0,$nmhi0,$nmhi0
776 ldws,mb 8($xfer),$nmhi1
777 add $hi1,$nmlo0,$nmlo0
780 stws,ma $nmlo0,8($tp) ; tp[j-1]
782 addib,= -1,$num,L\$outerdone_pa11; i--
783 subi 0,$arrsz,$idx ; j=0
785 fldws,ma 4($bp),${fbi} ; bp[i]
786 flddx $idx($ap),${fai} ; ap[0]
789 flddx $idx($np),${fni} ; np[0]
790 fldws 8($xfer),${fti}R ; tp[0]
794 ldo 8($idx),$idx ; j++++
795 xmpyu ${fai}L,${fbi},${fab0} ; ap[0]*bp[i]
796 xmpyu ${fai}R,${fbi},${fab1} ; ap[1]*bp[i]
797 ldw 4($tp),$ti0 ; tp[j]
799 add $hi1,$nmlo1,$nmlo1
800 addc %r0,$nmhi1,$nmhi1
801 fstws,mb ${fab0}L,-8($xfer) ; save high part
802 add $ablo,$nmlo1,$nmlo1
804 fcpy,sgl %fr0,${fti}L ; zero high part
805 fcpy,sgl %fr0,${fab0}L
806 stw $nmlo1,-4($tp) ; tp[j-1]
808 fcnvxf,dbl,dbl ${fti},${fti} ; 32-bit unsigned int -> double
809 fcnvxf,dbl,dbl ${fab0},${fab0}
812 fadd,dbl ${fti},${fab0},${fab0} ; add tp[0]
815 fcnvfx,dbl,dbl ${fab0},${fab0} ; double -> 33-bit unsigned int
818 xmpyu ${fn0},${fab0}R,${fm0}
821 ldo `$LOCALS+32+4`($fp),$tp
829 ldw 4($tp),$ti0 ; tp[j]
831 add $hi1,$nmlo1,$nmlo1
832 addc %r0,$nmhi1,$nmhi1
833 add $ablo,$nmlo1,$nmlo1
835 stw $nmlo1,-4($tp) ; tp[j-1]
844 ldo `$LOCALS+32+4`($fp),$tp
845 sub %r0,%r0,%r0 ; clear borrow
852 addib,<> 4,$idx,L\$sub_pa11
857 ldo `$LOCALS+32`($fp),$tp
858 sub $rp,$arrsz,$rp ; rewind rp
866 addib,<> 4,$idx,L\$copy_pa11
875 ldi 1,%r28 ; signal "handled"
876 ldo $FRAME($fp),%sp ; destroy tp[num+1]
878 $POP `-$FRAME-$SAVED_RP`(%sp),%r2 ; standard epilogue
879 $POP `-$FRAME+1*$SIZE_T`(%sp),%r4
880 $POP `-$FRAME+2*$SIZE_T`(%sp),%r5
881 $POP `-$FRAME+3*$SIZE_T`(%sp),%r6
882 $POP `-$FRAME+4*$SIZE_T`(%sp),%r7
883 $POP `-$FRAME+5*$SIZE_T`(%sp),%r8
884 $POP `-$FRAME+6*$SIZE_T`(%sp),%r9
885 $POP `-$FRAME+7*$SIZE_T`(%sp),%r10
889 $POPMB -$FRAME(%sp),%r3
891 .STRINGZ "Montgomery Multiplication for PA-RISC, CRYPTOGAMS by <appro\@openssl.org>"
894 # Explicitly encode PA-RISC 2.0 instructions used in this module, so
895 # that it can be compiled with .LEVEL 1.0. It should be noted that I
896 # wouldn't have to do this, if GNU assembler understood .ALLOW 2.0
900 my ($mod,$args) = @_;
901 my $orig = "ldd$mod\t$args";
903 if ($args =~ /%r([0-9]+)\(%r([0-9]+)\),%r([0-9]+)/) # format 4
904 { my $opcode=(0x03<<26)|($2<<21)|($1<<16)|(3<<6)|$3;
905 sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
907 elsif ($args =~ /(\-?[0-9]+)\(%r([0-9]+)\),%r([0-9]+)/) # format 5
908 { my $opcode=(0x03<<26)|($2<<21)|(1<<12)|(3<<6)|$3;
909 $opcode|=(($1&0xF)<<17)|(($1&0x10)<<12); # encode offset
910 $opcode|=(1<<5) if ($mod =~ /^,m/);
911 $opcode|=(1<<13) if ($mod =~ /^,mb/);
912 sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
918 my ($mod,$args) = @_;
919 my $orig = "std$mod\t$args";
921 if ($args =~ /%r([0-9]+),(\-?[0-9]+)\(%r([0-9]+)\)/) # format 6
922 { my $opcode=(0x03<<26)|($3<<21)|($1<<16)|(1<<12)|(0xB<<6);
923 $opcode|=(($2&0xF)<<1)|(($2&0x10)>>4); # encode offset
924 $opcode|=(1<<5) if ($mod =~ /^,m/);
925 $opcode|=(1<<13) if ($mod =~ /^,mb/);
926 sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
932 my ($mod,$args) = @_;
933 my $orig = "extrd$mod\t$args";
935 # I only have ",u" completer, it's implicitly encoded...
936 if ($args =~ /%r([0-9]+),([0-9]+),([0-9]+),%r([0-9]+)/) # format 15
937 { my $opcode=(0x36<<26)|($1<<21)|($4<<16);
939 $opcode |= (($2&0x20)<<6)|(($2&0x1f)<<5); # encode pos
940 $opcode |= (($len&0x20)<<7)|($len&0x1f); # encode len
941 sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
943 elsif ($args =~ /%r([0-9]+),%sar,([0-9]+),%r([0-9]+)/) # format 12
944 { my $opcode=(0x34<<26)|($1<<21)|($3<<16)|(2<<11)|(1<<9);
946 $opcode |= (($len&0x20)<<3)|($len&0x1f); # encode len
947 $opcode |= (1<<13) if ($mod =~ /,\**=/);
948 sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
954 my ($mod,$args) = @_;
955 my $orig = "shrpd$mod\t$args";
957 if ($args =~ /%r([0-9]+),%r([0-9]+),([0-9]+),%r([0-9]+)/) # format 14
958 { my $opcode=(0x34<<26)|($2<<21)|($1<<16)|(1<<10)|$4;
960 $opcode |= (($cpos&0x20)<<6)|(($cpos&0x1f)<<5); # encode sa
961 sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
967 my ($mod,$args) = @_;
968 my $orig = "sub$mod\t$args";
970 if ($mod eq ",db" && $args =~ /%r([0-9]+),%r([0-9]+),%r([0-9]+)/) {
971 my $opcode=(0x02<<26)|($2<<21)|($1<<16)|$3;
972 $opcode|=(1<<10); # e1
973 $opcode|=(1<<8); # e2
975 sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig
981 my ($mnemonic,$mod,$args)=@_;
982 my $opcode = eval("\$$mnemonic");
984 ref($opcode) eq 'CODE' ? &$opcode($mod,$args) : "\t$mnemonic$mod\t$args";
987 foreach (split("\n",$code)) {
988 s/\`([^\`]*)\`/eval $1/ge;
989 # flip word order in 64-bit mode...
990 s/(xmpyu\s+)($fai|$fni)([LR])/$1.$2.($3 eq "L"?"R":"L")/e if ($BN_SZ==8);
991 # assemble 2.0 instructions in 32-bit mode...
992 s/^\s+([a-z]+)([\S]*)\s+([\S]*)/&assemble($1,$2,$3)/e if ($BN_SZ==4);
994 s/\bbv\b/bve/gm if ($SIZE_T==8);