3 # ====================================================================
4 # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
10 # On PA-7100LC this module performs ~90-50% better, less for longer
11 # keys, than code generated by gcc 3.2 for PA-RISC 1.1. Latter means
12 # that compiler utilized xmpyu instruction to perform 32x32=64-bit
13 # multiplication, which in turn means that "baseline" performance was
14 # optimal in respect to instruction set capabilities. Fair comparison
15 # with vendor compiler is problematic, because OpenSSL doesn't define
16 # BN_LLONG [presumably] for historical reasons, which drives compiler
17 # toward 4 times 16x16=32-bit multiplicatons [plus complementary
18 # shifts and additions] instead. This means that you should observe
19 # several times improvement over code generated by vendor compiler
20 # for PA-RISC 1.1, but the "baseline" is far from optimal. The actual
21 # improvement coefficient was never collected on PA-7100LC, or any
22 # other 1.1 CPU, because I don't have access to such machine with
23 # vendor compiler. But to give you a taste, PA-RISC 1.1 code path
24 # reportedly outperformed code generated by cc +DA1.1 +O3 by factor
27 # On PA-RISC 2.0 it has to compete with pa-risc2[W].s, which is
28 # reportedly ~2x faster than vendor compiler generated code [according
29 # to comment in pa-risc2[W].s]. Here comes a catch. Execution core of
30 # this implementation is actually 32-bit one, in the sense that it
31 # operates on 32-bit values. But pa-risc2[W].s operates on arrays of
32 # 64-bit BN_LONGs... How do they interoperate then? No problem. This
33 # module picks halves of 64-bit values in reverse order and pretends
34 # they were 32-bit BN_LONGs. But can 32-bit core compete with "pure"
35 # 64-bit code such as pa-risc2[W].s then? Well, the thing is that
36 # 32x32=64-bit multiplication is the best even PA-RISC 2.0 can do,
37 # i.e. there is no "wider" multiplication like on most other 64-bit
38 # platforms. This means that even being effectively 32-bit, this
39 # implementation performs "64-bit" computational task in same amount
40 # of arithmetic operations, most notably multiplications. It requires
41 # more memory references, most notably to tp[num], but this doesn't
42 # seem to exhaust memory port capacity. And indeed, dedicated PA-RISC
43 # 2.0 code path provides virtually same performance as pa-risc2[W].s:
44 # it's ~10% better for shortest key length and ~10% worse for longest
47 # In case it wasn't clear. The module has two distinct code paths:
48 # PA-RISC 1.1 and PA-RISC 2.0 ones. Latter features carry-free 64-bit
49 # additions and 64-bit integer loads, not to mention specific
50 # instruction scheduling. In 64-bit build naturally only 2.0 code path
51 # is assembled. In 32-bit application context both code paths are
52 # assembled, PA-RISC 2.0 CPU is detected at run-time and proper path
53 # is taken automatically. Also, in 32-bit build the module imposes
54 # couple of limitations: vector lengths has to be even and vector
55 # addresses has to be 64-bit aligned. Normally neither is a problem:
56 # most common key lengths are even and vectors are commonly malloc-ed,
57 # which ensures alignment.
59 # Special thanks to polarhome.com for providing HP-UX account on
60 # PA-RISC 1.1 machine, and to correspondent who chose to remain
61 # anonymous for testing the code on PA-RISC 2.0 machine.
63 $0 =~ m/(.*[\/\\])[^\
/\\]+$/; $dir=$1;
68 open STDOUT
,">$output";
70 if ($flavour =~ /64/) {
81 $LEVEL ="1.1"; #$LEVEL.="\n\t.ALLOW\t2.0";
92 $FRAME=8*$SIZE_T+$FRAME_MARKER; # 8 saved regs + frame marker
93 # [+ argument transfer]
94 $LOCALS=$FRAME-$FRAME_MARKER;
95 $FRAME+=32; # local variables
105 $n0="%r22"; # passed through stack in 32-bit
106 $num="%r21"; # passed through stack in 32-bit
119 $xfer=$n0; # accomodates [-16..15] offset in fld[dw]s
121 $fm0="%fr4"; $fti=$fm0;
124 $fai="%fr6"; $fab0="%fr7"; $fab1="%fr8";
125 $fni="%fr9"; $fnm0="%fr10"; $fnm1="%fr11";
131 .SUBSPA \
$CODE\
$,QUAD
=0,ALIGN
=8,ACCESS
=0x2C,CODE_ONLY
136 .EXPORT bn_mul_mont
,ENTRY
,ARGW0
=GR
,ARGW1
=GR
,ARGW2
=GR
,ARGW3
=GR
140 .CALLINFO FRAME
=`$FRAME-8*$SIZE_T`,NO_CALLS
,SAVE_RP
,SAVE_SP
,ENTRY_GR
=6
142 $PUSH %r2,-$SAVED_RP(%sp) ; standard prologue
143 $PUSHMA %r3,$FRAME(%sp)
144 $PUSH %r4,`-$FRAME+1*$SIZE_T`(%sp)
145 $PUSH %r5,`-$FRAME+2*$SIZE_T`(%sp)
146 $PUSH %r6,`-$FRAME+3*$SIZE_T`(%sp)
147 $PUSH %r7,`-$FRAME+4*$SIZE_T`(%sp)
148 $PUSH %r8,`-$FRAME+5*$SIZE_T`(%sp)
149 $PUSH %r9,`-$FRAME+6*$SIZE_T`(%sp)
150 $PUSH %r10,`-$FRAME+7*$SIZE_T`(%sp)
153 $code.=<<___
if ($SIZE_T==4);
154 ldw
`-$FRAME_MARKER-4`($fp),$n0
155 ldw
`-$FRAME_MARKER-8`($fp),$num
159 $code.=<<___
if ($BN_SZ==4);
160 comiclr
,<= 6,$num,%r0 ; are vectors long enough?
162 ldi
0,%r28 ; signal
"unhandled"
163 add
,ev
%r0,$num,$num ; is
$num even?
167 extru
,= $ti1,31,3,%r0 ; are ap
and np
64-bit aligned?
174 fldws
,ma
4($bp),${fbi
} ; bp
[0]
176 $code.=<<___
if ($BN_SZ==8);
177 comib
,> 3,$num,L\
$abort ; are vectors long enough?
178 ldi
0,%r28 ; signal
"unhandled"
179 addl
$num,$num,$num ; I operate on
32-bit
values
181 fldws
4($n0),${fn0
} ; only low part of n0
182 fldws
4($bp),${fbi
} ; bp
[0] in flipped word order
185 fldds
0($ap),${fai
} ; ap
[0,1]
186 fldds
0($np),${fni
} ; np
[0,1]
188 sh2addl
$num,%r0,$arrsz
190 ldo
36($arrsz),$hi1 ; space
for tp
[num
+1]
191 andcm
$hi1,$hi0,$hi1 ; align
193 $PUSH $fp,-$SIZE_T(%sp)
195 ldo
`$LOCALS+16`($fp),$xfer
196 ldo
`$LOCALS+32+4`($fp),$tp
198 xmpyu
${fai
}L
,${fbi
},${fab0
} ; ap
[0]*bp
[0]
199 xmpyu
${fai
}R
,${fbi
},${fab1
} ; ap
[1]*bp
[0]
200 xmpyu
${fn0
},${fab0
}R
,${fm0
}
202 addl
$arrsz,$ap,$ap ; point at the end
204 subi
0,$arrsz,$idx ; j
=0
205 ldo
8($idx),$idx ; j
++++
207 xmpyu
${fni
}L
,${fm0
}R
,${fnm0
} ; np
[0]*m
208 xmpyu
${fni
}R
,${fm0
}R
,${fnm1
} ; np
[1]*m
209 fstds
${fab0
},-16($xfer)
210 fstds
${fnm0
},-8($xfer)
211 fstds
${fab1
},0($xfer)
212 fstds
${fnm1
},8($xfer)
213 flddx
$idx($ap),${fai
} ; ap
[2,3]
214 flddx
$idx($np),${fni
} ; np
[2,3]
216 $code.=<<___
if ($BN_SZ==4);
218 mtctl
$hi0,%cr11 ; $hi0 still holds
31
219 extrd
,u
,*= $hi0,%sar,1,$hi0 ; executes on PA
-RISC
1.0
223 $code.=<<___
; # PA-RISC 2.0 code-path
224 xmpyu
${fai
}L
,${fbi
},${fab0
} ; ap
[j
]*bp
[0]
225 xmpyu
${fni
}L
,${fm0
}R
,${fnm0
} ; np
[j
]*m
227 fstds
${fab0
},-16($xfer)
229 extrd
,u
$ab0,31,32,$hi0
230 extrd
,u
$ab0,63,32,$ab0
232 fstds
${fnm0
},-8($xfer)
233 ldo
8($idx),$idx ; j
++++
234 addl
$ab0,$nm0,$nm0 ; low part is discarded
235 extrd
,u
$nm0,31,32,$hi1
238 xmpyu
${fai
}R
,${fbi
},${fab1
} ; ap
[j
+1]*bp
[0]
239 xmpyu
${fni
}R
,${fm0
}R
,${fnm1
} ; np
[j
+1]*m
241 fstds
${fab1
},0($xfer)
243 extrd
,u
$ab1,31,32,$hi0
245 fstds
${fnm1
},8($xfer)
246 extrd
,u
$ab1,63,32,$ab1
248 flddx
$idx($ap),${fai
} ; ap
[j
,j
+1]
249 flddx
$idx($np),${fni
} ; np
[j
,j
+1]
251 extrd
,u
$nm1,31,32,$hi1
253 xmpyu
${fai
}L
,${fbi
},${fab0
} ; ap
[j
]*bp
[0]
254 xmpyu
${fni
}L
,${fm0
}R
,${fnm0
} ; np
[j
]*m
256 fstds
${fab0
},-16($xfer)
258 extrd
,u
$ab0,31,32,$hi0
260 fstds
${fnm0
},-8($xfer)
261 extrd
,u
$ab0,63,32,$ab0
263 stw
$nm1,-4($tp) ; tp
[j
-1]
265 stw
,ma
$nm0,8($tp) ; tp
[j
-1]
266 addib
,<> 8,$idx,L\
$1st ; j
++++
267 extrd
,u
$nm0,31,32,$hi1
269 xmpyu
${fai
}R
,${fbi
},${fab1
} ; ap
[j
]*bp
[0]
270 xmpyu
${fni
}R
,${fm0
}R
,${fnm1
} ; np
[j
]*m
272 fstds
${fab1
},0($xfer)
274 extrd
,u
$ab1,31,32,$hi0
276 fstds
${fnm1
},8($xfer)
277 extrd
,u
$ab1,63,32,$ab1
282 extrd
,u
$nm1,31,32,$hi1
285 extrd
,u
$ab0,31,32,$hi0
286 stw
$nm1,-4($tp) ; tp
[j
-1]
287 extrd
,u
$ab0,63,32,$ab0
292 extrd
,u
$nm0,31,32,$hi1
293 stw
,ma
$nm0,8($tp) ; tp
[j
-1]
295 ldo
-1($num),$num ; i
--
296 subi
0,$arrsz,$idx ; j
=0
298 $code.=<<___
if ($BN_SZ==4);
299 fldws
,ma
4($bp),${fbi
} ; bp
[1]
301 $code.=<<___
if ($BN_SZ==8);
302 fldws
0($bp),${fbi
} ; bp
[1] in flipped word order
305 flddx
$idx($ap),${fai
} ; ap
[0,1]
306 flddx
$idx($np),${fni
} ; np
[0,1]
307 fldws
8($xfer),${fti
}R
; tp
[0]
309 extrd
,u
$ab1,31,32,$hi0
310 extrd
,u
$ab1,63,32,$ab1
311 ldo
8($idx),$idx ; j
++++
312 xmpyu
${fai
}L
,${fbi
},${fab0
} ; ap
[0]*bp
[1]
313 xmpyu
${fai
}R
,${fbi
},${fab1
} ; ap
[1]*bp
[1]
316 extrd
,u
$nm1,31,32,$hi1
317 fstws
,mb
${fab0
}L
,-8($xfer) ; save high part
318 stw
$nm1,-4($tp) ; tp
[j
-1]
320 fcpy
,sgl
%fr0,${fti
}L
; zero high part
321 fcpy
,sgl
%fr0,${fab0
}L
323 extrd
,u
$hi0,31,32,$hi1
324 fcnvxf
,dbl
,dbl
${fti
},${fti
} ; 32-bit unsigned
int -> double
325 fcnvxf
,dbl
,dbl
${fab0
},${fab0
}
329 fadd
,dbl
${fti
},${fab0
},${fab0
} ; add tp
[0]
330 fcnvfx
,dbl
,dbl
${fab0
},${fab0
} ; double
-> 33-bit unsigned
int
331 xmpyu
${fn0
},${fab0
}R
,${fm0
}
332 ldo
`$LOCALS+32+4`($fp),$tp
334 xmpyu
${fni
}L
,${fm0
}R
,${fnm0
} ; np
[0]*m
335 xmpyu
${fni
}R
,${fm0
}R
,${fnm1
} ; np
[1]*m
336 fstds
${fab0
},-16($xfer) ; 33-bit value
337 fstds
${fnm0
},-8($xfer)
338 flddx
$idx($ap),${fai
} ; ap
[2]
339 flddx
$idx($np),${fni
} ; np
[2]
340 ldo
8($idx),$idx ; j
++++
341 ldd
-16($xfer),$ab0 ; 33-bit value
343 ldw
0($xfer),$hi0 ; high part
345 xmpyu
${fai
}L
,${fbi
},${fab0
} ; ap
[j
]*bp
[i
]
346 xmpyu
${fni
}L
,${fm0
}R
,${fnm0
} ; np
[j
]*m
347 extrd
,u
$ab0,31,32,$ti0 ; carry bit
348 extrd
,u
$ab0,63,32,$ab0
349 fstds
${fab1
},0($xfer)
350 addl
$ti0,$hi0,$hi0 ; account carry bit
351 fstds
${fnm1
},8($xfer)
352 addl
$ab0,$nm0,$nm0 ; low part is discarded
353 ldw
0($tp),$ti1 ; tp
[1]
354 extrd
,u
$nm0,31,32,$hi1
355 fstds
${fab0
},-16($xfer)
356 fstds
${fnm0
},-8($xfer)
359 xmpyu
${fai
}R
,${fbi
},${fab1
} ; ap
[j
+1]*bp
[i
]
360 xmpyu
${fni
}R
,${fm0
}R
,${fnm1
} ; np
[j
+1]*m
362 fstds
${fab1
},0($xfer)
366 fstds
${fnm1
},8($xfer)
367 extrd
,u
$ab1,31,32,$hi0
368 extrd
,u
$ab1,63,32,$ab1
369 flddx
$idx($ap),${fai
} ; ap
[j
,j
+1]
370 flddx
$idx($np),${fni
} ; np
[j
,j
+1]
373 ldw
4($tp),$ti0 ; tp
[j
]
374 stw
$nm1,-4($tp) ; tp
[j
-1]
376 xmpyu
${fai
}L
,${fbi
},${fab0
} ; ap
[j
]*bp
[i
]
377 xmpyu
${fni
}L
,${fm0
}R
,${fnm0
} ; np
[j
]*m
379 fstds
${fab0
},-16($xfer)
383 fstds
${fnm0
},-8($xfer)
384 extrd
,u
$ab0,31,32,$hi0
385 extrd
,u
$nm1,31,32,$hi1
386 ldw
8($tp),$ti1 ; tp
[j
]
387 extrd
,u
$ab0,63,32,$ab0
390 stw
,ma
$nm0,8($tp) ; tp
[j
-1]
391 addib
,<> 8,$idx,L\
$inner ; j
++++
392 extrd
,u
$nm0,31,32,$hi1
394 xmpyu
${fai
}R
,${fbi
},${fab1
} ; ap
[j
]*bp
[i
]
395 xmpyu
${fni
}R
,${fm0
}R
,${fnm1
} ; np
[j
]*m
397 fstds
${fab1
},0($xfer)
401 fstds
${fnm1
},8($xfer)
402 extrd
,u
$ab1,31,32,$hi0
403 extrd
,u
$ab1,63,32,$ab1
404 ldw
4($tp),$ti0 ; tp
[j
]
409 extrd
,u
$nm1,31,32,$hi1
413 stw
$nm1,-4($tp) ; tp
[j
-1]
414 extrd
,u
$ab0,31,32,$hi0
415 ldw
8($tp),$ti1 ; tp
[j
]
416 extrd
,u
$ab0,63,32,$ab0
421 extrd
,u
$nm0,31,32,$hi1
422 stw
,ma
$nm0,8($tp) ; tp
[j
-1]
424 addib
,= -1,$num,L\
$outerdone ; i
--
425 subi
0,$arrsz,$idx ; j
=0
427 $code.=<<___
if ($BN_SZ==4);
428 fldws
,ma
4($bp),${fbi
} ; bp
[i
]
430 $code.=<<___
if ($BN_SZ==8);
431 ldi
12,$ti0 ; bp
[i
] in flipped word order
432 addl
,ev
%r0,$num,$num
438 flddx
$idx($ap),${fai
} ; ap
[0]
440 flddx
$idx($np),${fni
} ; np
[0]
441 fldws
8($xfer),${fti
}R
; tp
[0]
443 extrd
,u
$ab1,31,32,$hi0
444 extrd
,u
$ab1,63,32,$ab1
446 ldo
8($idx),$idx ; j
++++
447 xmpyu
${fai
}L
,${fbi
},${fab0
} ; ap
[0]*bp
[i
]
448 xmpyu
${fai
}R
,${fbi
},${fab1
} ; ap
[1]*bp
[i
]
449 ldw
4($tp),$ti0 ; tp
[j
]
452 fstws
,mb
${fab0
}L
,-8($xfer) ; save high part
454 extrd
,u
$nm1,31,32,$hi1
455 fcpy
,sgl
%fr0,${fti
}L
; zero high part
456 fcpy
,sgl
%fr0,${fab0
}L
457 stw
$nm1,-4($tp) ; tp
[j
-1]
459 fcnvxf
,dbl
,dbl
${fti
},${fti
} ; 32-bit unsigned
int -> double
460 fcnvxf
,dbl
,dbl
${fab0
},${fab0
}
462 fadd
,dbl
${fti
},${fab0
},${fab0
} ; add tp
[0]
464 extrd
,u
$hi0,31,32,$hi1
465 fcnvfx
,dbl
,dbl
${fab0
},${fab0
} ; double
-> 33-bit unsigned
int
468 xmpyu
${fn0
},${fab0
}R
,${fm0
}
471 ldo
`$LOCALS+32+4`($fp),$tp
476 extrd
,u
$ab1,31,32,$hi0
477 extrd
,u
$ab1,63,32,$ab1
479 ldw
4($tp),$ti0 ; tp
[j
]
483 extrd
,u
$nm1,31,32,$hi1
484 stw
$nm1,-4($tp) ; tp
[j
-1]
488 extrd
,u
$hi0,31,32,$hi1
492 ldo
`$LOCALS+32`($fp),$tp
493 sub %r0,%r0,%r0 ; clear borrow
495 $code.=<<___
if ($BN_SZ==4);
497 extru
,= $rp,31,3,%r0 ; is rp
64-bit aligned?
504 addib
,<> 4,$idx,L\
$sub
510 $code.=<<___
if ($BN_SZ==8);
514 shrpd
$ti0,$ti0,32,$ti0 ; flip word order
515 std
$ti0,-8($tp) ; save flipped value
516 sub,db
$ti0,$hi0,$hi1
518 addib
,<> 8,$idx,L\
$sub
521 extrd
,u
$ti0,31,32,$ti0 ; carry
in flipped word order
530 sub $rp,$arrsz,$rp ; rewind rp
532 ldo
`$LOCALS+32`($fp),$tp
536 addib
,<> 8,$idx,.-8 ; L\
$copy
540 if ($BN_SZ==4) { # PA-RISC 1.1 code-path
555 xmpyu
${fai
}L
,${fbi
},${fab0
} ; ap
[j
]*bp
[0]
556 xmpyu
${fni
}L
,${fm0
}R
,${fnm0
} ; np
[j
]*m
561 fstds
${fab0
},-16($xfer)
562 fstds
${fnm0
},-8($xfer)
564 ldo
8($idx),$idx ; j
++++
565 add
$ablo,$nmlo0,$nmlo0 ; discarded
572 xmpyu
${fai
}R
,${fbi
},${fab1
} ; ap
[j
+1]*bp
[0]
573 flddx
$idx($ap),${fai
} ; ap
[j
,j
+1]
574 xmpyu
${fni
}R
,${fm0
}R
,${fnm1
} ; np
[j
+1]*m
575 flddx
$idx($np),${fni
} ; np
[j
,j
+1]
580 add
$ablo,$nmlo1,$nmlo1
581 fstds
${fab1
},0($xfer)
582 addc
%r0,$nmhi1,$nmhi1
583 fstds
${fnm1
},8($xfer)
584 add
$hi1,$nmlo1,$nmlo1
589 xmpyu
${fai
}L
,${fbi
},${fab0
} ; ap
[j
]*bp
[0]
591 xmpyu
${fni
}L
,${fm0
}R
,${fnm0
} ; np
[j
]*m
594 stw
$nmlo1,-4($tp) ; tp
[j
-1]
596 fstds
${fab0
},-16($xfer)
597 add
$ablo,$nmlo0,$nmlo0
598 fstds
${fnm0
},-8($xfer)
599 addc
%r0,$nmhi0,$nmhi0
601 add
$hi1,$nmlo0,$nmlo0
603 stws
,ma
$nmlo0,8($tp) ; tp
[j
-1]
604 addib
,<> 8,$idx,L\
$1st_pa11 ; j
++++
609 xmpyu
${fai
}R
,${fbi
},${fab1
} ; ap
[j
]*bp
[0]
610 xmpyu
${fni
}R
,${fm0
}R
,${fnm1
} ; np
[j
]*m
612 fstds
${fab1
},0($xfer)
614 fstds
${fnm1
},8($xfer)
615 add
$ablo,$nmlo1,$nmlo1
617 addc
%r0,$nmhi1,$nmhi1
619 add
$hi1,$nmlo1,$nmlo1
625 stw
$nmlo1,-4($tp) ; tp
[j
-1]
628 add
$ablo,$nmlo0,$nmlo0
630 addc
%r0,$nmhi0,$nmhi0
631 ldws
,mb
8($xfer),$nmhi1
632 add
$hi1,$nmlo0,$nmlo0
635 stws
,ma
$nmlo0,8($tp) ; tp
[j
-1]
637 ldo
-1($num),$num ; i
--
638 subi
0,$arrsz,$idx ; j
=0
640 fldws
,ma
4($bp),${fbi
} ; bp
[1]
641 flddx
$idx($ap),${fai
} ; ap
[0,1]
642 flddx
$idx($np),${fni
} ; np
[0,1]
643 fldws
8($xfer),${fti
}R
; tp
[0]
646 ldo
8($idx),$idx ; j
++++
647 xmpyu
${fai
}L
,${fbi
},${fab0
} ; ap
[0]*bp
[1]
648 xmpyu
${fai
}R
,${fbi
},${fab1
} ; ap
[1]*bp
[1]
649 add
$hi1,$nmlo1,$nmlo1
650 addc
%r0,$nmhi1,$nmhi1
651 add
$ablo,$nmlo1,$nmlo1
653 fstws
,mb
${fab0
}L
,-8($xfer) ; save high part
654 stw
$nmlo1,-4($tp) ; tp
[j
-1]
656 fcpy
,sgl
%fr0,${fti
}L
; zero high part
657 fcpy
,sgl
%fr0,${fab0
}L
660 fcnvxf
,dbl
,dbl
${fti
},${fti
} ; 32-bit unsigned
int -> double
661 fcnvxf
,dbl
,dbl
${fab0
},${fab0
}
665 fadd
,dbl
${fti
},${fab0
},${fab0
} ; add tp
[0]
666 fcnvfx
,dbl
,dbl
${fab0
},${fab0
} ; double
-> 33-bit unsigned
int
667 xmpyu
${fn0
},${fab0
}R
,${fm0
}
668 ldo
`$LOCALS+32+4`($fp),$tp
670 xmpyu
${fni
}L
,${fm0
}R
,${fnm0
} ; np
[0]*m
671 xmpyu
${fni
}R
,${fm0
}R
,${fnm1
} ; np
[1]*m
672 fstds
${fab0
},-16($xfer) ; 33-bit value
673 fstds
${fnm0
},-8($xfer)
674 flddx
$idx($ap),${fai
} ; ap
[2,3]
675 flddx
$idx($np),${fni
} ; np
[2,3]
676 ldw
-16($xfer),$abhi ; carry bit actually
677 ldo
8($idx),$idx ; j
++++
681 ldw
0($xfer),$hi0 ; high part
683 xmpyu
${fai
}L
,${fbi
},${fab0
} ; ap
[j
]*bp
[i
]
684 xmpyu
${fni
}L
,${fm0
}R
,${fnm0
} ; np
[j
]*m
685 fstds
${fab1
},0($xfer)
686 addl
$abhi,$hi0,$hi0 ; account carry bit
687 fstds
${fnm1
},8($xfer)
688 add
$ablo,$nmlo0,$nmlo0 ; discarded
689 ldw
0($tp),$ti1 ; tp
[1]
691 fstds
${fab0
},-16($xfer)
692 fstds
${fnm0
},-8($xfer)
697 xmpyu
${fai
}R
,${fbi
},${fab1
} ; ap
[j
+1]*bp
[i
]
698 flddx
$idx($ap),${fai
} ; ap
[j
,j
+1]
699 xmpyu
${fni
}R
,${fm0
}R
,${fnm1
} ; np
[j
+1]*m
700 flddx
$idx($np),${fni
} ; np
[j
,j
+1]
702 ldw
4($tp),$ti0 ; tp
[j
]
708 fstds
${fab1
},0($xfer)
709 add
$ablo,$nmlo1,$nmlo1
710 fstds
${fnm1
},8($xfer)
711 addc
%r0,$nmhi1,$nmhi1
713 add
$hi1,$nmlo1,$nmlo1
717 xmpyu
${fai
}L
,${fbi
},${fab0
} ; ap
[j
]*bp
[i
]
718 ldw
8($tp),$ti1 ; tp
[j
]
719 xmpyu
${fni
}L
,${fm0
}R
,${fnm0
} ; np
[j
]*m
724 stw
$nmlo1,-4($tp) ; tp
[j
-1]
726 fstds
${fab0
},-16($xfer)
728 fstds
${fnm0
},-8($xfer)
729 add
$ablo,$nmlo0,$nmlo0
731 addc
%r0,$nmhi0,$nmhi0
733 add
$hi1,$nmlo0,$nmlo0
734 stws
,ma
$nmlo0,8($tp) ; tp
[j
-1]
735 addib
,<> 8,$idx,L\
$inner_pa11 ; j
++++
738 xmpyu
${fai
}R
,${fbi
},${fab1
} ; ap
[j
]*bp
[i
]
740 xmpyu
${fni
}R
,${fm0
}R
,${fnm1
} ; np
[j
]*m
743 ldw
4($tp),$ti0 ; tp
[j
]
745 fstds
${fab1
},0($xfer)
747 fstds
${fnm1
},8($xfer)
750 add
$ablo,$nmlo1,$nmlo1
752 addc
%r0,$nmhi1,$nmhi1
754 add
$hi1,$nmlo1,$nmlo1
759 stw
$nmlo1,-4($tp) ; tp
[j
-1]
762 ldw
8($tp),$ti1 ; tp
[j
]
765 add
$ablo,$nmlo0,$nmlo0
767 addc
%r0,$nmhi0,$nmhi0
768 ldws
,mb
8($xfer),$nmhi1
769 add
$hi1,$nmlo0,$nmlo0
772 stws
,ma
$nmlo0,8($tp) ; tp
[j
-1]
774 addib
,= -1,$num,L\
$outerdone_pa11; i
--
775 subi
0,$arrsz,$idx ; j
=0
777 fldws
,ma
4($bp),${fbi
} ; bp
[i
]
778 flddx
$idx($ap),${fai
} ; ap
[0]
781 flddx
$idx($np),${fni
} ; np
[0]
782 fldws
8($xfer),${fti
}R
; tp
[0]
786 ldo
8($idx),$idx ; j
++++
787 xmpyu
${fai
}L
,${fbi
},${fab0
} ; ap
[0]*bp
[i
]
788 xmpyu
${fai
}R
,${fbi
},${fab1
} ; ap
[1]*bp
[i
]
789 ldw
4($tp),$ti0 ; tp
[j
]
791 add
$hi1,$nmlo1,$nmlo1
792 addc
%r0,$nmhi1,$nmhi1
793 fstws
,mb
${fab0
}L
,-8($xfer) ; save high part
794 add
$ablo,$nmlo1,$nmlo1
796 fcpy
,sgl
%fr0,${fti
}L
; zero high part
797 fcpy
,sgl
%fr0,${fab0
}L
798 stw
$nmlo1,-4($tp) ; tp
[j
-1]
800 fcnvxf
,dbl
,dbl
${fti
},${fti
} ; 32-bit unsigned
int -> double
801 fcnvxf
,dbl
,dbl
${fab0
},${fab0
}
804 fadd
,dbl
${fti
},${fab0
},${fab0
} ; add tp
[0]
807 fcnvfx
,dbl
,dbl
${fab0
},${fab0
} ; double
-> 33-bit unsigned
int
810 xmpyu
${fn0
},${fab0
}R
,${fm0
}
813 ldo
`$LOCALS+32+4`($fp),$tp
821 ldw
4($tp),$ti0 ; tp
[j
]
823 add
$hi1,$nmlo1,$nmlo1
824 addc
%r0,$nmhi1,$nmhi1
825 add
$ablo,$nmlo1,$nmlo1
827 stw
$nmlo1,-4($tp) ; tp
[j
-1]
836 ldo
`$LOCALS+32+4`($fp),$tp
837 sub %r0,%r0,%r0 ; clear borrow
844 addib
,<> 4,$idx,L\
$sub_pa11
853 sub $rp,$arrsz,$rp ; rewind rp
855 ldo
`$LOCALS+32`($fp),$tp
859 addib
,<> 4,$idx,L\
$copy_pa11
868 ldi
1,%r28 ; signal
"handled"
869 ldo
$FRAME($fp),%sp ; destroy tp
[num
+1]
871 $POP `-$FRAME-$SAVED_RP`(%sp),%r2 ; standard epilogue
872 $POP `-$FRAME+1*$SIZE_T`(%sp),%r4
873 $POP `-$FRAME+2*$SIZE_T`(%sp),%r5
874 $POP `-$FRAME+3*$SIZE_T`(%sp),%r6
875 $POP `-$FRAME+4*$SIZE_T`(%sp),%r7
876 $POP `-$FRAME+5*$SIZE_T`(%sp),%r8
877 $POP `-$FRAME+6*$SIZE_T`(%sp),%r9
878 $POP `-$FRAME+7*$SIZE_T`(%sp),%r10
882 $POPMB -$FRAME(%sp),%r3
886 .STRINGZ
"Montgomery Multiplication for PA-RISC, CRYPTOGAMS by <appro\@openssl.org>"
889 # Explicitly encode PA-RISC 2.0 instructions used in this module, so
890 # that it can be compiled with .LEVEL 1.0. It should be noted that I
891 # wouldn't have to do this, if GNU assembler understood .ALLOW 2.0
895 my ($mod,$args) = @_;
896 my $orig = "ldd$mod\t$args";
898 if ($args =~ /%r([0-9]+)\(%r([0-9]+)\),%r([0-9]+)/) # format 4
899 { my $opcode=(0x03<<26)|($2<<21)|($1<<16)|(3<<6)|$3;
900 sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
902 elsif ($args =~ /(\-?[0-9]+)\(%r([0-9]+)\),%r([0-9]+)/) # format 5
903 { my $opcode=(0x03<<26)|($2<<21)|(1<<12)|(3<<6)|$3;
904 $opcode|=(($1&0xF)<<17)|(($1&0x10)<<12); # encode offset
905 $opcode|=(1<<5) if ($mod =~ /^,m/);
906 $opcode|=(1<<13) if ($mod =~ /^,mb/);
907 sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
913 my ($mod,$args) = @_;
914 my $orig = "std$mod\t$args";
916 if ($args =~ /%r([0-9]+),(\-?[0-9]+)\(%r([0-9]+)\)/) # format 6
917 { my $opcode=(0x03<<26)|($3<<21)|($1<<16)|(1<<12)|(0xB<<6);
918 $opcode|=(($2&0xF)<<1)|(($2&0x10)>>4); # encode offset
919 $opcode|=(1<<5) if ($mod =~ /^,m/);
920 $opcode|=(1<<13) if ($mod =~ /^,mb/);
921 sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
927 my ($mod,$args) = @_;
928 my $orig = "extrd$mod\t$args";
930 # I only have ",u" completer, it's implicitly encoded...
931 if ($args =~ /%r([0-9]+),([0-9]+),([0-9]+),%r([0-9]+)/) # format 15
932 { my $opcode=(0x36<<26)|($1<<21)|($4<<16);
934 $opcode |= (($2&0x20)<<6)|(($2&0x1f)<<5); # encode pos
935 $opcode |= (($len&0x20)<<7)|($len&0x1f); # encode len
936 sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
938 elsif ($args =~ /%r([0-9]+),%sar,([0-9]+),%r([0-9]+)/) # format 12
939 { my $opcode=(0x34<<26)|($1<<21)|($3<<16)|(2<<11)|(1<<9);
941 $opcode |= (($len&0x20)<<3)|($len&0x1f); # encode len
942 $opcode |= (1<<13) if ($mod =~ /,\**=/);
943 sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
949 my ($mod,$args) = @_;
950 my $orig = "shrpd$mod\t$args";
952 if ($args =~ /%r([0-9]+),%r([0-9]+),([0-9]+),%r([0-9]+)/) # format 14
953 { my $opcode=(0x34<<26)|($2<<21)|($1<<16)|(1<<10)|$4;
955 $opcode |= (($cpos&0x20)<<6)|(($cpos&0x1f)<<5); # encode sa
956 sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
962 my ($mod,$args) = @_;
963 my $orig = "sub$mod\t$args";
965 if ($mod eq ",db" && $args =~ /%r([0-9]+),%r([0-9]+),%r([0-9]+)/) {
966 my $opcode=(0x02<<26)|($2<<21)|($1<<16)|$3;
967 $opcode|=(1<<10); # e1
968 $opcode|=(1<<8); # e2
970 sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig
976 my ($mnemonic,$mod,$args)=@_;
977 my $opcode = eval("\$$mnemonic");
979 ref($opcode) eq 'CODE' ?
&$opcode($mod,$args) : "\t$mnemonic$mod\t$args";
982 foreach (split("\n",$code)) {
983 s/\`([^\`]*)\`/eval $1/ge;
984 # flip word order in 64-bit mode...
985 s/(xmpyu\s+)($fai|$fni)([LR])/$1.$2.($3 eq "L"?"R":"L")/e if ($BN_SZ==8);
986 # assemble 2.0 instructions in 32-bit mode...
987 s/^\s+([a-z]+)([\S]*)\s+([\S]*)/&assemble($1,$2,$3)/e if ($BN_SZ==4);
989 s/\bbv\b/bve/gm if ($SIZE_T==8);