Improved PowerPC support. Proper ./config support for ppc targets,
authorAndy Polyakov <appro@openssl.org>
Tue, 27 Apr 2004 22:05:50 +0000 (22:05 +0000)
committerAndy Polyakov <appro@openssl.org>
Tue, 27 Apr 2004 22:05:50 +0000 (22:05 +0000)
especially for AIX. But most important BIGNUM assembler implementation
submitted by IBM.

Submitted by: Peter Waltenberg <pwalten@au1.ibm.com>
Reviewed by: appro

Configure
TABLE
config
crypto/bn/Makefile.ssl
crypto/bn/asm/ppc.pl [new file with mode: 0644]

index 84b03a6..72b76bb 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -390,7 +390,8 @@ my %table=(
 "linux-aout",  "gcc:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -m486 -Wall::(unknown):::BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_out_asm}",
 "linux-mipsel",   "gcc:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC2_CHAR RC4_INDEX DES_INT DES_UNROLL DES_RISC2::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
 "linux-mips",   "gcc:-DB_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC2_CHAR RC4_INDEX DES_INT DES_UNROLL DES_RISC2::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
-"linux-ppc",    "gcc:-DB_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_RISC1 DES_UNROLL::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
+"linux-ppc",    "gcc:-DB_ENDIAN -DTERMIO -O3 -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_RISC1 DES_UNROLL:asm/linux_ppc32.o:::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
+"linux-ppc64",  "gcc:-m64 -DB_ENDIAN -DTERMIO -O3 -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHAR RC4_CHUNK DES_RISC1 DES_UNROLL:asm/linux_ppc64.o:::::::::dlfcn:linux-shared:-fPIC:-m64:.so..\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
 "linux-m68k",   "gcc:-DB_ENDIAN -DTERMIO -O2 -fomit-frame-pointer -Wall::-D_REENTRANT:::BN_LLONG::",
 "linux-s390",  "gcc:-DB_ENDIAN -DTERMIO -DNO_ASM -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
 "linux-s390x", "gcc:-DB_ENDIAN -DTERMIO -DNO_ASM -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
@@ -446,11 +447,12 @@ my %table=(
 
 
 # IBM's AIX.
-"aix-cc",   "cc:-O -DB_ENDIAN -qmaxmem=16384::(unknown):AIX::BN_LLONG RC4_CHAR:::",
-"aix-gcc",  "gcc:-O3 -DB_ENDIAN::(unknown):AIX::BN_LLONG RC4_CHAR:::",
-"aix43-cc",   "cc:-O -DAIX -DB_ENDIAN -qmaxmem=16384::(unknown):::BN_LLONG RC4_CHAR::::::::::dlfcn:aix-shared:::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)::",
-"aix43-gcc",  "gcc:-O1 -DAIX -DB_ENDIAN::(unknown):::BN_LLONG RC4_CHAR::::::::::dlfcn:",
-"aix64-cc",   "cc:-O -DAIX -DB_ENDIAN -qmaxmem=16384 -q64::(unknown):::SIXTY_FOUR_BIT_LONG RC4_CHAR::::::::::dlfcn:aix-shared::-q64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)::-X 64",
+"aix-gcc",  "gcc:-O -DB_ENDIAN::(unknown):AIX::BN_LLONG RC4_CHAR:asm/aix_ppc32.o:::::::::dlfcn:",
+"aix43-cc", "cc:-O -DB_ENDIAN -qmaxmem=16384::(unknown):::BN_LLONG RC4_CHAR:asm/aix_ppc32.o:::::::::dlfcn:aix-shared:::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)::",
+# Below targets assume AIX 5. Idea is to effectively disregard $OBJECT_MODE
+# at build time. $OBJECT_MODE is respected at ./config stage!
+"aix-cc",   "cc:-q32 -O -DB_ENDIAN -qmaxmem=16384::(unknown):AIX::BN_LLONG RC4_CHAR:asm/aix_ppc32.o:::::::::dlfcn:aix-shared::-q32:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)::-X 32",
+"aix64-cc", "cc:-q64 -O -DB_ENDIAN -qmaxmem=16384::(unknown):AIX::SIXTY_FOUR_BIT_LONG RC4_CHAR:asm/aix_ppc64.o:::::::::dlfcn:aix-shared::-q64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)::-X 64",
 
 #
 # Cray T90 and similar (SDSC)
@@ -553,7 +555,7 @@ my %table=(
 
 ##### MacOS X (a.k.a. Rhapsody or Darwin) setup
 "rhapsody-ppc-cc","cc:-O3 -DB_ENDIAN::(unknown):MACOSX_RHAPSODY::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:::",
-"darwin-ppc-cc","cc:-O3 -fomit-frame-pointer -fno-common -DB_ENDIAN::-D_REENTRANT:MACOSX::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:::::::::::darwin-shared:-fPIC::.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib",
+"darwin-ppc-cc","cc:-O3 -fno-common -DB_ENDIAN::-D_REENTRANT:MACOSX::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:asm/osx_ppc32.o::::::::::darwin-shared:-fPIC::.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib",
 "darwin-i386-cc","cc:-O3 -fomit-frame-pointer -fno-common -DB_ENDIAN::-D_REENTRANT:MACOSX::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:::::::::::darwin-shared:-fPIC::.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib",
 
 ##### A/UX
diff --git a/TABLE b/TABLE
index 1500669..e9895cb 100644 (file)
--- a/TABLE
+++ b/TABLE
@@ -1027,13 +1027,13 @@ $arflags      =
 
 *** aix-cc
 $cc           = cc
-$cflags       = -O -DB_ENDIAN -qmaxmem=16384
+$cflags       = -q32 -O -DB_ENDIAN -qmaxmem=16384
 $unistd       = 
 $thread_cflag = (unknown)
 $sys_id       = AIX
 $lflags       = 
 $bn_ops       = BN_LLONG RC4_CHAR
-$bn_obj       = 
+$bn_obj       = asm/aix_ppc32.o
 $des_obj      = 
 $bf_obj       = 
 $md5_obj      = 
@@ -1042,23 +1042,23 @@ $cast_obj     =
 $rc4_obj      = 
 $rmd160_obj   = 
 $rc5_obj      = 
-$dso_scheme   = 
-$shared_target= 
+$dso_scheme   = dlfcn
+$shared_target= aix-shared
 $shared_cflag = 
-$shared_ldflag = 
-$shared_extension = 
+$shared_ldflag = -q32
+$shared_extension = .so.$(SHLIB_MAJOR).$(SHLIB_MINOR)
 $ranlib       = 
-$arflags      = 
+$arflags      = -X 32
 
 *** aix-gcc
 $cc           = gcc
-$cflags       = -O3 -DB_ENDIAN
+$cflags       = -O -DB_ENDIAN
 $unistd       = 
 $thread_cflag = (unknown)
 $sys_id       = AIX
 $lflags       = 
 $bn_ops       = BN_LLONG RC4_CHAR
-$bn_obj       = 
+$bn_obj       = asm/aix_ppc32.o
 $des_obj      = 
 $bf_obj       = 
 $md5_obj      = 
@@ -1067,7 +1067,7 @@ $cast_obj     =
 $rc4_obj      = 
 $rmd160_obj   = 
 $rc5_obj      = 
-$dso_scheme   = 
+$dso_scheme   = dlfcn
 $shared_target= 
 $shared_cflag = 
 $shared_ldflag = 
@@ -1077,13 +1077,13 @@ $arflags      =
 
 *** aix43-cc
 $cc           = cc
-$cflags       = -O -DAIX -DB_ENDIAN -qmaxmem=16384
+$cflags       = -O -DB_ENDIAN -qmaxmem=16384
 $unistd       = 
 $thread_cflag = (unknown)
 $sys_id       = 
 $lflags       = 
 $bn_ops       = BN_LLONG RC4_CHAR
-$bn_obj       = 
+$bn_obj       = asm/aix_ppc32.o
 $des_obj      = 
 $bf_obj       = 
 $md5_obj      = 
@@ -1100,40 +1100,15 @@ $shared_extension = .so.$(SHLIB_MAJOR).$(SHLIB_MINOR)
 $ranlib       = 
 $arflags      = 
 
-*** aix43-gcc
-$cc           = gcc
-$cflags       = -O1 -DAIX -DB_ENDIAN
-$unistd       = 
-$thread_cflag = (unknown)
-$sys_id       = 
-$lflags       = 
-$bn_ops       = BN_LLONG RC4_CHAR
-$bn_obj       = 
-$des_obj      = 
-$bf_obj       = 
-$md5_obj      = 
-$sha1_obj     = 
-$cast_obj     = 
-$rc4_obj      = 
-$rmd160_obj   = 
-$rc5_obj      = 
-$dso_scheme   = dlfcn
-$shared_target= 
-$shared_cflag = 
-$shared_ldflag = 
-$shared_extension = 
-$ranlib       = 
-$arflags      = 
-
 *** aix64-cc
 $cc           = cc
-$cflags       = -O -DAIX -DB_ENDIAN -qmaxmem=16384 -q64
+$cflags       = -q64 -O -DB_ENDIAN -qmaxmem=16384
 $unistd       = 
 $thread_cflag = (unknown)
-$sys_id       = 
+$sys_id       = AIX
 $lflags       = 
 $bn_ops       = SIXTY_FOUR_BIT_LONG RC4_CHAR
-$bn_obj       = 
+$bn_obj       = asm/aix_ppc64.o
 $des_obj      = 
 $bf_obj       = 
 $md5_obj      = 
@@ -1452,13 +1427,13 @@ $arflags      =
 
 *** darwin-ppc-cc
 $cc           = cc
-$cflags       = -O3 -fomit-frame-pointer -fno-common -DB_ENDIAN
+$cflags       = -O3 -fno-common -DB_ENDIAN
 $unistd       = 
 $thread_cflag = -D_REENTRANT
 $sys_id       = MACOSX
 $lflags       = 
 $bn_ops       = BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR
-$bn_obj       = 
+$bn_obj       = asm/osx_ppc32.o
 $des_obj      = 
 $bf_obj       = 
 $md5_obj      = 
@@ -1702,7 +1677,7 @@ $arflags      =
 
 *** debug-levitte-linux-elf
 $cc           = gcc
-$cflags       = -DLEVITTE_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DBN_DEBUG -DBN_DEBUG_RAND -DCRYPTO_MDEBUG -DENGINE_CONF_DEBUG -DL_ENDIAN -DTERMIO -D_POSIX_SOURCE -DPEDANTIC -ggdb -g3 -mcpu=i486 -pedantic -ansi -Wall -Wshadow -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wno-long-long -Wundef -Wconversion -pipe
+$cflags       = -DLEVITTE_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_DEBUG -DBN_DEBUG_RAND -DCRYPTO_MDEBUG -DENGINE_CONF_DEBUG -DL_ENDIAN -DTERMIO -D_POSIX_SOURCE -DPEDANTIC -ggdb -g3 -mcpu=i486 -pedantic -ansi -Wall -Wshadow -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wno-long-long -Wundef -Wconversion -pipe
 $unistd       = 
 $thread_cflag = -D_REENTRANT
 $sys_id       = 
@@ -1727,7 +1702,7 @@ $arflags      =
 
 *** debug-levitte-linux-elf-extreme
 $cc           = gcc
-$cflags       = -DLEVITTE_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DBN_DEBUG -DBN_DEBUG_RAND -DCRYPTO_MDEBUG -DENGINE_CONF_DEBUG -DL_ENDIAN -DTERMIO -D_POSIX_SOURCE -DPEDANTIC -ggdb -g3 -mcpu=i486 -pedantic -ansi -Wall -W -Wundef -Wshadow -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wno-long-long -Wundef -Wconversion -pipe
+$cflags       = -DLEVITTE_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_DEBUG -DBN_DEBUG_RAND -DCRYPTO_MDEBUG -DENGINE_CONF_DEBUG -DL_ENDIAN -DTERMIO -D_POSIX_SOURCE -DPEDANTIC -ggdb -g3 -mcpu=i486 -pedantic -ansi -Wall -W -Wundef -Wshadow -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wno-long-long -Wundef -Wconversion -pipe
 $unistd       = 
 $thread_cflag = -D_REENTRANT
 $sys_id       = 
@@ -1752,7 +1727,7 @@ $arflags      =
 
 *** debug-levitte-linux-noasm
 $cc           = gcc
-$cflags       = -DLEVITTE_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DBN_DEBUG -DBN_DEBUG_RAND -DCRYPTO_MDEBUG -DENGINE_CONF_DEBUG -DOPENSSL_NO_ASM -DL_ENDIAN -DTERMIO -D_POSIX_SOURCE -DPEDANTIC -ggdb -g3 -mcpu=i486 -pedantic -ansi -Wall -Wshadow -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wno-long-long -Wundef -Wconversion -pipe
+$cflags       = -DLEVITTE_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_DEBUG -DBN_DEBUG_RAND -DCRYPTO_MDEBUG -DENGINE_CONF_DEBUG -DOPENSSL_NO_ASM -DL_ENDIAN -DTERMIO -D_POSIX_SOURCE -DPEDANTIC -ggdb -g3 -mcpu=i486 -pedantic -ansi -Wall -Wshadow -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wno-long-long -Wundef -Wconversion -pipe
 $unistd       = 
 $thread_cflag = -D_REENTRANT
 $sys_id       = 
@@ -1777,7 +1752,7 @@ $arflags      =
 
 *** debug-levitte-linux-noasm-extreme
 $cc           = gcc
-$cflags       = -DLEVITTE_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DBN_DEBUG -DBN_DEBUG_RAND -DCRYPTO_MDEBUG -DENGINE_CONF_DEBUG -DOPENSSL_NO_ASM -DL_ENDIAN -DTERMIO -D_POSIX_SOURCE -DPEDANTIC -ggdb -g3 -mcpu=i486 -pedantic -ansi -Wall -W -Wundef -Wshadow -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wno-long-long -Wundef -Wconversion -pipe
+$cflags       = -DLEVITTE_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_DEBUG -DBN_DEBUG_RAND -DCRYPTO_MDEBUG -DENGINE_CONF_DEBUG -DOPENSSL_NO_ASM -DL_ENDIAN -DTERMIO -D_POSIX_SOURCE -DPEDANTIC -ggdb -g3 -mcpu=i486 -pedantic -ansi -Wall -W -Wundef -Wshadow -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wno-long-long -Wundef -Wconversion -pipe
 $unistd       = 
 $thread_cflag = -D_REENTRANT
 $sys_id       = 
@@ -3127,7 +3102,7 @@ $arflags      =
 
 *** linux-ia32-icc
 $cc           = icc
-$cflags       = -DL_ENDIAN -DTERMIO -O2
+$cflags       = -DL_ENDIAN -DTERMIO -O2 -no_cpprt
 $unistd       = 
 $thread_cflag = -D_REENTRANT
 $sys_id       = 
@@ -3352,13 +3327,13 @@ $arflags      =
 
 *** linux-ppc
 $cc           = gcc
-$cflags       = -DB_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall
+$cflags       = -DB_ENDIAN -DTERMIO -O3 -Wall
 $unistd       = 
 $thread_cflag = -D_REENTRANT
 $sys_id       = 
 $lflags       = -ldl
 $bn_ops       = BN_LLONG RC4_CHAR RC4_CHUNK DES_RISC1 DES_UNROLL
-$bn_obj       = 
+$bn_obj       = asm/linux_ppc32.o
 $des_obj      = 
 $bf_obj       = 
 $md5_obj      = 
@@ -3375,6 +3350,31 @@ $shared_extension = .so.$(SHLIB_MAJOR).$(SHLIB_MINOR)
 $ranlib       = 
 $arflags      = 
 
+*** linux-ppc64
+$cc           = gcc
+$cflags       = -m64 -DB_ENDIAN -DTERMIO -O3 -Wall
+$unistd       = 
+$thread_cflag = -D_REENTRANT
+$sys_id       = 
+$lflags       = -ldl
+$bn_ops       = SIXTY_FOUR_BIT_LONG RC4_CHAR RC4_CHUNK DES_RISC1 DES_UNROLL
+$bn_obj       = asm/linux_ppc64.o
+$des_obj      = 
+$bf_obj       = 
+$md5_obj      = 
+$sha1_obj     = 
+$cast_obj     = 
+$rc4_obj      = 
+$rmd160_obj   = 
+$rc5_obj      = 
+$dso_scheme   = dlfcn
+$shared_target= linux-shared
+$shared_cflag = -fPIC
+$shared_ldflag = -m64
+$shared_extension = .so..$(SHLIB_MAJOR).$(SHLIB_MINOR)
+$ranlib       = 
+$arflags      = 
+
 *** linux-ppro
 $cc           = gcc
 $cflags       = -DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -mcpu=pentiumpro -Wall
diff --git a/config b/config
index a0dc457..46102ce 100755 (executable)
--- a/config
+++ b/config
@@ -110,12 +110,8 @@ case "${SYSTEM}:${RELEASE}:${VERSION}:${MACHINE}" in
        echo "m68k-apple-aux3"; exit 0
        ;;
 
-    AIX:[3456789]:4:*)
-       echo "${MACHINE}-ibm-aix43"; exit 0
-       ;;
-
-    AIX:*:[56789]:*)
-       echo "${MACHINE}-ibm-aix43"; exit 0
+    AIX:*:[5-9]:*)
+       echo "${MACHINE}-ibm-aix5"; exit 0
        ;;
 
     AIX:*)
@@ -537,10 +533,7 @@ EOF
        ${CC} -o dummy dummy.c && OUT=`./dummy ${MACHINE}`
        rm dummy dummy.c
        ;;
-  ppc64-*-linux2)
-       #Use the standard target for PPC architecture until we create a
-       #special one for the 64bit architecture.
-       OUT="linux-ppc" ;;
+  ppc64-*-linux2) OUT="linux-ppc64" ;;
   ppc-*-linux2) OUT="linux-ppc" ;;
   m68k-*-linux*) OUT="linux-m68k" ;;
   ia64-*-linux?) OUT="linux-ia64" ;;
@@ -719,6 +712,35 @@ EOF
        fi
        options="$options -D_REENTRANT" ;;
   *-hpux)      OUT="hpux-parisc-$CC" ;;
+  *-aix5)
+       KERNEL_BITS=`(getconf KERNEL_BITMODE) 2>/dev/null`
+       KERNEL_BITS=${KERNEL_BITS:-32}
+       if [ $KERNEL_BITS -eq 64 ]; then
+           # we default to 64-bit because PKI performance is >3x better...
+           OBJECT_MODE=${OBJECT_MODE:-$KERNEL_BITS}
+       else
+           OBJECT_MODE=32
+       fi
+       OUT="aix-cc"
+       if [ "$CC" = "cc" -a $OBJECT_MODE -eq 64 ]; then
+           OUT="aix64-cc"
+           echo "WARNING! If you wish to build 32-bit kit, then you have to"
+           echo "         invoke './Configure aix-cc' *manually*."
+           if [ "$TEST" = "false" ]; then
+               echo "         You have ~5 seconds to press Ctrl-C to abort."
+               (stty -icanon min 0 time 50; read waste) < /dev/tty
+           fi
+       elif [ "$CC" = "gcc ]; then
+           OUT="aix-gcc"
+       fi
+       ;;
+  *-aix)
+       if [ "$CC" = "gcc" ]; then
+           OUT="aix-gcc"
+       else
+           OUT="aix43-cc"
+       fi
+       ;;
   # these are all covered by the catchall below
   # *-aix) OUT="aix-$CC" ;;
   # *-dgux) OUT="dgux" ;;
index 70fec63..490d6d7 100644 (file)
@@ -129,6 +129,13 @@ asm/pa-risc2W.o: asm/pa-risc2W.s
 asm/pa-risc2.o: asm/pa-risc2.s
        /usr/ccs/bin/as -o asm/pa-risc2.o asm/pa-risc2.s
 
+# ppc - AIX, Linux, MacOS X...
+asm/linux_ppc32.s: asm/ppc.pl; $(PERL) $< $@
+asm/linux_ppc64.s: asm/ppc.pl; $(PERL) $< $@
+asm/aix_ppc32.s: asm/ppc.pl;   $(PERL) $< $@
+asm/aix_ppc64.s: asm/ppc.pl;   $(PERL) $< $@
+asm/osx_ppc32.s: asm/ppc.pl;   $(PERL) $< $@
+
 files:
        $(PERL) $(TOP)/util/files.pl Makefile.ssl >> $(TOP)/MINFO
 
diff --git a/crypto/bn/asm/ppc.pl b/crypto/bn/asm/ppc.pl
new file mode 100644 (file)
index 0000000..307c7cc
--- /dev/null
@@ -0,0 +1,2081 @@
+#!/usr/bin/env perl
+#
+# Implemented as a Perl wrapper as we want to support several different
+# architectures with single file. We pick up the target based on the
+# file name we are asked to generate.
+#
+# It should be noted though that this perl code is nothing like
+# <openssl>/crypto/perlasm/x86*. In this case perl is used pretty much
+# as pre-processor to cover for platform differences in name decoration,
+# linker tables, 32-/64-bit instruction sets...
+#
+# As you might know there're several PowerPC ABI in use. Most notably
+# Linux and AIX use different 32-bit ABIs. Good news are that these ABIs
+# are similar enough to implement leaf(!) functions, which would be ABI
+# neutral. And that's what you find here: ABI neutral leaf functions.
+# In case you wonder what that is...
+#
+#       AIX performance
+#
+#      MEASUREMENTS WITH cc ON a 200 MhZ PowerPC 604e.
+#
+#      The following is the performance of 32-bit compiler
+#      generated code:
+#
+#      OpenSSL 0.9.6c 21 dec 2001
+#      built on: Tue Jun 11 11:06:51 EDT 2002
+#      options:bn(64,32) ...
+#compiler: cc -DTHREADS  -DAIX -DB_ENDIAN -DBN_LLONG -O3
+#                  sign    verify    sign/s verify/s
+#rsa  512 bits   0.0098s   0.0009s    102.0   1170.6
+#rsa 1024 bits   0.0507s   0.0026s     19.7    387.5
+#rsa 2048 bits   0.3036s   0.0085s      3.3    117.1
+#rsa 4096 bits   2.0040s   0.0299s      0.5     33.4
+#dsa  512 bits   0.0087s   0.0106s    114.3     94.5
+#dsa 1024 bits   0.0256s   0.0313s     39.0     32.0   
+#
+#      Same bechmark with this assembler code:
+#
+#rsa  512 bits   0.0056s   0.0005s    178.6   2049.2
+#rsa 1024 bits   0.0283s   0.0015s     35.3    674.1
+#rsa 2048 bits   0.1744s   0.0050s      5.7    201.2
+#rsa 4096 bits   1.1644s   0.0179s      0.9     55.7
+#dsa  512 bits   0.0052s   0.0062s    191.6    162.0
+#dsa 1024 bits   0.0149s   0.0180s     67.0     55.5
+#
+#      Number of operations increases by at almost 75%
+#
+#      Here are performance numbers for 64-bit compiler
+#      generated code:
+#
+#      OpenSSL 0.9.6g [engine] 9 Aug 2002
+#      built on: Fri Apr 18 16:59:20 EDT 2003
+#      options:bn(64,64) ...
+#      compiler: cc -DTHREADS -D_REENTRANT -q64 -DB_ENDIAN -O3
+#                  sign    verify    sign/s verify/s
+#rsa  512 bits   0.0028s   0.0003s    357.1   3844.4
+#rsa 1024 bits   0.0148s   0.0008s     67.5   1239.7
+#rsa 2048 bits   0.0963s   0.0028s     10.4    353.0
+#rsa 4096 bits   0.6538s   0.0102s      1.5     98.1
+#dsa  512 bits   0.0026s   0.0032s    382.5    313.7
+#dsa 1024 bits   0.0081s   0.0099s    122.8    100.6
+#
+#      Same benchmark with this assembler code:
+#
+#rsa  512 bits   0.0020s   0.0002s    510.4   6273.7
+#rsa 1024 bits   0.0088s   0.0005s    114.1   2128.3
+#rsa 2048 bits   0.0540s   0.0016s     18.5    622.5
+#rsa 4096 bits   0.3700s   0.0058s      2.7    171.0
+#dsa  512 bits   0.0016s   0.0020s    610.7    507.1
+#dsa 1024 bits   0.0047s   0.0058s    212.5    173.2
+#      
+#      Again, performance increases by at about 75%
+#
+#       Mac OS X, Apple G5 1.8GHz (Note this is 32 bit code)
+#       OpenSSL 0.9.7c 30 Sep 2003
+#
+#       Original code.
+#
+#rsa  512 bits   0.0011s   0.0001s    906.1  11012.5
+#rsa 1024 bits   0.0060s   0.0003s    166.6   3363.1
+#rsa 2048 bits   0.0370s   0.0010s     27.1    982.4
+#rsa 4096 bits   0.2426s   0.0036s      4.1    280.4
+#dsa  512 bits   0.0010s   0.0012s   1038.1    841.5
+#dsa 1024 bits   0.0030s   0.0037s    329.6    269.7
+#dsa 2048 bits   0.0101s   0.0127s     98.9     78.6
+#
+#       Same benchmark with this assembler code:
+#
+#rsa  512 bits   0.0007s   0.0001s   1416.2  16645.9
+#rsa 1024 bits   0.0036s   0.0002s    274.4   5380.6
+#rsa 2048 bits   0.0222s   0.0006s     45.1   1589.5
+#rsa 4096 bits   0.1469s   0.0022s      6.8    449.6
+#dsa  512 bits   0.0006s   0.0007s   1664.2   1376.2
+#dsa 1024 bits   0.0018s   0.0023s    545.0    442.2
+#dsa 2048 bits   0.0061s   0.0075s    163.5    132.8
+#
+#        Performance increase of ~60%
+#
+#      If you have comments or suggestions to improve code send
+#      me a note at schari@us.ibm.com
+#
+
+$opf = shift;
+
+if ($opf =~ /32\.s/) {
+       $BITS=  32;
+       $BNSZ=  $BITS/8;
+       $ISA=   "\"ppc\"";
+
+       $LD=    "lwz";          # load
+       $LDU=   "lwzu";         # load and update
+       $ST=    "stw";          # store
+       $STU=   "stwu";         # store and update
+       $UMULL= "mullw";        # unsigned multiply low
+       $UMULH= "mulhwu";       # unsigned multiply high
+       $UDIV=  "divwu";        # unsigned divide
+       $UCMPI= "cmplwi";       # unsigned compare with immediate
+       $UCMP=  "cmplw";        # unsigned compare
+       $COUNTZ="cntlzw";       # count leading zeros
+       $SHL=   "slw";          # shift left
+       $SHR=   "srw";          # unsigned shift right
+       $SHRI=  "srwi";         # unsigned shift right by immediate     
+       $SHLI=  "slwi";         # shift left by immediate
+       $CLRU=  "clrlwi";       # clear upper bits
+       $INSR=  "insrwi";       # insert right
+       $ROTL=  "rotlwi";       # rotate left by immediate
+} elsif ($opf =~ /64\.s/) {
+       $BITS=  64;
+       $BNSZ=  $BITS/8;
+       $ISA=   "\"ppc64\"";
+
+       # same as above, but 64-bit mnemonics...
+       $LD=    "ld";           # load
+       $LDU=   "ldu";          # load and update
+       $ST=    "std";          # store
+       $STU=   "stdu";         # store and update
+       $UMULL= "mulld";        # unsigned multiply low
+       $UMULH= "mulhdu";       # unsigned multiply high
+       $UDIV=  "divdu";        # unsigned divide
+       $UCMPI= "cmpldi";       # unsigned compare with immediate
+       $UCMP=  "cmpld";        # unsigned compare
+       $COUNTZ="cntlzd";       # count leading zeros
+       $SHL=   "sld";          # shift left
+       $SHR=   "srd";          # unsigned shift right
+       $SHRI=  "srdi";         # unsigned shift right by immediate     
+       $SHLI=  "sldi";         # shift left by immediate
+       $CLRU=  "clrldi";       # clear upper bits
+       $INSR=  "insrdi";       # insert right 
+       $ROTL=  "rotldi";       # rotate left by immediate
+} else { die "nonsense $opf"; }
+
+( defined shift || open STDOUT,">$opf" ) || die "can't open $opf: $!";
+
+# function entry points from the AIX code
+#
+# There are other, more elegant, ways to handle this. We (IBM) chose
+# this approach as it plays well with scripts we run to 'namespace'
+# OpenSSL .i.e. we add a prefix to all the public symbols so we can
+# co-exist in the same process with other implementations of OpenSSL.
+# 'cleverer' ways of doing these substitutions tend to hide data we
+# need to be obvious.
+#
+my @items = ("bn_sqr_comba4",
+            "bn_sqr_comba8",
+            "bn_mul_comba4",
+            "bn_mul_comba8",
+            "bn_sub_words",
+            "bn_add_words",
+            "bn_div_words",
+            "bn_sqr_words",
+            "bn_mul_words",
+            "bn_mul_add_words");
+
+if    ($opf =~ /linux/)        {  do_linux();  }
+elsif ($opf =~ /aix/)  {  do_aix();    }
+elsif ($opf =~ /osx/)  {  do_osx();    }
+else                   {  do_bsd();    }
+
+sub do_linux {
+    $d=&data();
+
+    if ($BITS==64) {
+      foreach $t (@items) {
+        $d =~ s/\.$t:/\
+\t.section\t".opd","aw"\
+\t.align\t3\
+\t.globl\t$t\
+$t:\
+\t.quad\t.$t,.TOC.\@tocbase,0\
+\t.size\t$t,24\
+\t.previous\n\
+\t.type\t.$t,\@function\
+\t.globl\t.$t\
+.$t:/g;
+      }
+    }
+    else {
+      foreach $t (@items) {
+        $d=~s/\.$t/$t/g;
+      }
+    }
+    # hide internal labels to avoid pollution of name table...
+    $d=~s/Lppcasm_/.Lppcasm_/gm;
+    print $d;
+}
+
+sub do_aix {
+    # AIX assembler is smart enough to please the linker without
+    # making us do something special...
+    print &data();
+}
+
+# MacOSX 32 bit
+sub do_osx {
+    $d=&data();
+    # Change the bn symbol prefix from '.' to '_'
+    foreach $t (@items) {
+      $d=~s/\.$t/_$t/g;
+    }
+    # Change .machine to something OS X asm will accept
+    $d=~s/\.machine.*/.text/g;
+    $d=~s/\#/;/g; # change comment from '#' to ';'
+    print $d;
+}
+
+# BSD (Untested)
+sub do_bsd {
+    $d=&data();
+    foreach $t (@items) {
+      $d=~s/\.$t/_$t/g;
+    }
+    print $d;
+}
+
+sub data {
+       local($data)=<<EOF;
+#--------------------------------------------------------------------
+#
+#
+#
+#
+#      File:           ppc32.s
+#
+#      Created by:     Suresh Chari
+#                      IBM Thomas J. Watson Research Library
+#                      Hawthorne, NY
+#
+#
+#      Description:    Optimized assembly routines for OpenSSL crypto
+#                      on the 32 bitPowerPC platform.
+#
+#
+#      Version History
+#
+#      2. Fixed bn_add,bn_sub and bn_div_words, added comments,
+#         cleaned up code. Also made a single version which can
+#         be used for both the AIX and Linux compilers. See NOTE
+#         below.
+#                              12/05/03                Suresh Chari
+#                      (with lots of help from)        Andy Polyakov
+##     
+#      1. Initial version      10/20/02                Suresh Chari
+#
+#
+#      The following file works for the xlc,cc
+#      and gcc compilers.
+#
+#      NOTE:   To get the file to link correctly with the gcc compiler
+#              you have to change the names of the routines and remove
+#              the first .(dot) character. This should automatically
+#              be done in the build process.
+#
+#      Hand optimized assembly code for the following routines
+#      
+#      bn_sqr_comba4
+#      bn_sqr_comba8
+#      bn_mul_comba4
+#      bn_mul_comba8
+#      bn_sub_words
+#      bn_add_words
+#      bn_div_words
+#      bn_sqr_words
+#      bn_mul_words
+#      bn_mul_add_words
+#
+#      NOTE:   It is possible to optimize this code more for
+#      specific PowerPC or Power architectures. On the Northstar
+#      architecture the optimizations in this file do
+#       NOT provide much improvement.
+#
+#      If you have comments or suggestions to improve code send
+#      me a note at schari\@us.ibm.com
+#
+#--------------------------------------------------------------------------
+#
+#      Defines to be used in the assembly code.
+#      
+.set r0,0      # we use it as storage for value of 0
+.set SP,1      # preserved
+.set RTOC,2    # preserved 
+.set r3,3      # 1st argument/return value
+.set r4,4      # 2nd argument/volatile register
+.set r5,5      # 3rd argument/volatile register
+.set r6,6      # ...
+.set r7,7
+.set r8,8
+.set r9,9
+.set r10,10
+.set r11,11
+.set r12,12
+.set r13,13    # not used, nor any other "below" it...
+
+.set BO_IF_NOT,4
+.set BO_IF,12
+.set BO_dCTR_NZERO,16
+.set BO_dCTR_ZERO,18
+.set BO_ALWAYS,20
+.set CR0_LT,0;
+.set CR0_GT,1;
+.set CR0_EQ,2
+.set CR1_FX,4;
+.set CR1_FEX,5;
+.set CR1_VX,6
+.set LR,8
+
+#      Declare function names to be global
+#      NOTE:   For gcc these names MUST be changed to remove
+#              the first . i.e. for example change ".bn_sqr_comba4"
+#              to "bn_sqr_comba4". This should be automatically done
+#              in the build.
+       
+       .globl  .bn_sqr_comba4
+       .globl  .bn_sqr_comba8
+       .globl  .bn_mul_comba4
+       .globl  .bn_mul_comba8
+       .globl  .bn_sub_words
+       .globl  .bn_add_words
+       .globl  .bn_div_words
+       .globl  .bn_sqr_words
+       .globl  .bn_mul_words
+       .globl  .bn_mul_add_words
+       
+# .text section
+       
+       .machine        $ISA
+
+#
+#      NOTE:   The following label name should be changed to
+#              "bn_sqr_comba4" i.e. remove the first dot
+#              for the gcc compiler. This should be automatically
+#              done in the build
+#
+
+.align 4
+.bn_sqr_comba4:
+#
+# Optimized version of bn_sqr_comba4.
+#
+# void bn_sqr_comba4(BN_ULONG *r, BN_ULONG *a)
+# r3 contains r
+# r4 contains a
+#
+# Freely use registers r5,r6,r7,r8,r9,r10,r11 as follows:      
+# 
+# r5,r6 are the two BN_ULONGs being multiplied.
+# r7,r8 are the results of the 32x32 giving 64 bit multiply.
+# r9,r10, r11 are the equivalents of c1,c2, c3.
+# Here's the assembly
+#
+#
+       xor             r0,r0,r0                # set r0 = 0. Used in the addze
+                                               # instructions below
+       
+                                               #sqr_add_c(a,0,c1,c2,c3)
+       $LD             r5,`0*$BNSZ`(r4)                
+       $UMULL          r9,r5,r5                
+       $UMULH          r10,r5,r5               #in first iteration. No need
+                                               #to add since c1=c2=c3=0.
+                                               # Note c3(r11) is NOT set to 0
+                                               # but will be.
+
+       $ST             r9,`0*$BNSZ`(r3)        # r[0]=c1;
+                                               # sqr_add_c2(a,1,0,c2,c3,c1);
+       $LD             r6,`1*$BNSZ`(r4)                
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+                                       
+       addc            r7,r7,r7                # compute (r7,r8)=2*(r7,r8)
+       adde            r8,r8,r8
+       addze           r9,r0                   # catch carry if any.
+                                               # r9= r0(=0) and carry 
+       
+       addc            r10,r7,r10              # now add to temp result.
+       addze           r11,r8                  # r8 added to r11 which is 0 
+       addze           r9,r9
+       
+       $ST             r10,`1*$BNSZ`(r3)       #r[1]=c2; 
+                                               #sqr_add_c(a,1,c3,c1,c2)
+       $UMULL          r7,r6,r6
+       $UMULH          r8,r6,r6
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r0
+                                               #sqr_add_c2(a,2,0,c3,c1,c2)
+       $LD             r6,`2*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r7,r7,r7
+       adde            r8,r8,r8
+       addze           r10,r10
+       
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+       $ST             r11,`2*$BNSZ`(r3)       #r[2]=c3 
+                                               #sqr_add_c2(a,3,0,c1,c2,c3);
+       $LD             r6,`3*$BNSZ`(r4)                
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r7,r7,r7
+       adde            r8,r8,r8
+       addze           r11,r0
+       
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+                                               #sqr_add_c2(a,2,1,c1,c2,c3);
+       $LD             r5,`1*$BNSZ`(r4)
+       $LD             r6,`2*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r7,r7,r7
+       adde            r8,r8,r8
+       addze           r11,r11
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+       $ST             r9,`3*$BNSZ`(r3)        #r[3]=c1
+                                               #sqr_add_c(a,2,c2,c3,c1);
+       $UMULL          r7,r6,r6
+       $UMULH          r8,r6,r6
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r0
+                                               #sqr_add_c2(a,3,1,c2,c3,c1);
+       $LD             r6,`3*$BNSZ`(r4)                
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r7,r7,r7
+       adde            r8,r8,r8
+       addze           r9,r9
+       
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+       $ST             r10,`4*$BNSZ`(r3)       #r[4]=c2
+                                               #sqr_add_c2(a,3,2,c3,c1,c2);
+       $LD             r5,`2*$BNSZ`(r4)                
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r7,r7,r7
+       adde            r8,r8,r8
+       addze           r10,r0
+       
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+       $ST             r11,`5*$BNSZ`(r3)       #r[5] = c3
+                                               #sqr_add_c(a,3,c1,c2,c3);
+       $UMULL          r7,r6,r6                
+       $UMULH          r8,r6,r6
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+
+       $ST             r9,`6*$BNSZ`(r3)        #r[6]=c1
+       $ST             r10,`7*$BNSZ`(r3)       #r[7]=c2
+       bclr    BO_ALWAYS,CR0_LT
+       .long   0x00000000
+
+#
+#      NOTE:   The following label name should be changed to
+#              "bn_sqr_comba8" i.e. remove the first dot
+#              for the gcc compiler. This should be automatically
+#              done in the build
+#
+       
+.align 4
+.bn_sqr_comba8:
+#
+# This is an optimized version of the bn_sqr_comba8 routine.
+# Tightly uses the adde instruction
+#
+#
+# void bn_sqr_comba8(BN_ULONG *r, BN_ULONG *a)
+# r3 contains r
+# r4 contains a
+#
+# Freely use registers r5,r6,r7,r8,r9,r10,r11 as follows:      
+# 
+# r5,r6 are the two BN_ULONGs being multiplied.
+# r7,r8 are the results of the 32x32 giving 64 bit multiply.
+# r9,r10, r11 are the equivalents of c1,c2, c3.
+#
+# Possible optimization of loading all 8 longs of a into registers
+# doesnt provide any speedup
+# 
+
+       xor             r0,r0,r0                #set r0 = 0.Used in addze
+                                               #instructions below.
+
+                                               #sqr_add_c(a,0,c1,c2,c3);
+       $LD             r5,`0*$BNSZ`(r4)
+       $UMULL          r9,r5,r5                #1st iteration: no carries.
+       $UMULH          r10,r5,r5
+       $ST             r9,`0*$BNSZ`(r3)        # r[0]=c1;
+                                               #sqr_add_c2(a,1,0,c2,c3,c1);
+       $LD             r6,`1*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6        
+       
+       addc            r10,r7,r10              #add the two register number
+       adde            r11,r8,r0               # (r8,r7) to the three register
+       addze           r9,r0                   # number (r9,r11,r10).NOTE:r0=0
+       
+       addc            r10,r7,r10              #add the two register number
+       adde            r11,r8,r11              # (r8,r7) to the three register
+       addze           r9,r9                   # number (r9,r11,r10).
+       
+       $ST             r10,`1*$BNSZ`(r3)       # r[1]=c2
+                               
+                                               #sqr_add_c(a,1,c3,c1,c2);
+       $UMULL          r7,r6,r6
+       $UMULH          r8,r6,r6
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r0
+                                               #sqr_add_c2(a,2,0,c3,c1,c2);
+       $LD             r6,`2*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+       
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+       
+       $ST             r11,`2*$BNSZ`(r3)       #r[2]=c3
+                                               #sqr_add_c2(a,3,0,c1,c2,c3);
+       $LD             r6,`3*$BNSZ`(r4)        #r6 = a[3]. r5 is already a[0].
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r0
+       
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+                                               #sqr_add_c2(a,2,1,c1,c2,c3);
+       $LD             r5,`1*$BNSZ`(r4)
+       $LD             r6,`2*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+       
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+       
+       $ST             r9,`3*$BNSZ`(r3)        #r[3]=c1;
+                                               #sqr_add_c(a,2,c2,c3,c1);
+       $UMULL          r7,r6,r6
+       $UMULH          r8,r6,r6
+       
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r0
+                                               #sqr_add_c2(a,3,1,c2,c3,c1);
+       $LD             r6,`3*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+       
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+                                               #sqr_add_c2(a,4,0,c2,c3,c1);
+       $LD             r5,`0*$BNSZ`(r4)
+       $LD             r6,`4*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+       
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+       $ST             r10,`4*$BNSZ`(r3)       #r[4]=c2;
+                                               #sqr_add_c2(a,5,0,c3,c1,c2);
+       $LD             r6,`5*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r0
+       
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+                                               #sqr_add_c2(a,4,1,c3,c1,c2);
+       $LD             r5,`1*$BNSZ`(r4)
+       $LD             r6,`4*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+       
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+                                               #sqr_add_c2(a,3,2,c3,c1,c2);
+       $LD             r5,`2*$BNSZ`(r4)
+       $LD             r6,`3*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+       
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+       $ST             r11,`5*$BNSZ`(r3)       #r[5]=c3;
+                                               #sqr_add_c(a,3,c1,c2,c3);
+       $UMULL          r7,r6,r6
+       $UMULH          r8,r6,r6
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r0
+                                               #sqr_add_c2(a,4,2,c1,c2,c3);
+       $LD             r6,`4*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+       
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+                                               #sqr_add_c2(a,5,1,c1,c2,c3);
+       $LD             r5,`1*$BNSZ`(r4)
+       $LD             r6,`5*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+       
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+                                               #sqr_add_c2(a,6,0,c1,c2,c3);
+       $LD             r5,`0*$BNSZ`(r4)
+       $LD             r6,`6*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+       $ST             r9,`6*$BNSZ`(r3)        #r[6]=c1;
+                                               #sqr_add_c2(a,7,0,c2,c3,c1);
+       $LD             r6,`7*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r0
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+                                               #sqr_add_c2(a,6,1,c2,c3,c1);
+       $LD             r5,`1*$BNSZ`(r4)
+       $LD             r6,`6*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+                                               #sqr_add_c2(a,5,2,c2,c3,c1);
+       $LD             r5,`2*$BNSZ`(r4)
+       $LD             r6,`5*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+                                               #sqr_add_c2(a,4,3,c2,c3,c1);
+       $LD             r5,`3*$BNSZ`(r4)
+       $LD             r6,`4*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+       $ST             r10,`7*$BNSZ`(r3)       #r[7]=c2;
+                                               #sqr_add_c(a,4,c3,c1,c2);
+       $UMULL          r7,r6,r6
+       $UMULH          r8,r6,r6
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r0
+                                               #sqr_add_c2(a,5,3,c3,c1,c2);
+       $LD             r6,`5*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+                                               #sqr_add_c2(a,6,2,c3,c1,c2);
+       $LD             r5,`2*$BNSZ`(r4)
+       $LD             r6,`6*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+       
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+                                               #sqr_add_c2(a,7,1,c3,c1,c2);
+       $LD             r5,`1*$BNSZ`(r4)
+       $LD             r6,`7*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+       $ST             r11,`8*$BNSZ`(r3)       #r[8]=c3;
+                                               #sqr_add_c2(a,7,2,c1,c2,c3);
+       $LD             r5,`2*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r0
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+                                               #sqr_add_c2(a,6,3,c1,c2,c3);
+       $LD             r5,`3*$BNSZ`(r4)
+       $LD             r6,`6*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+                                               #sqr_add_c2(a,5,4,c1,c2,c3);
+       $LD             r5,`4*$BNSZ`(r4)
+       $LD             r6,`5*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+       $ST             r9,`9*$BNSZ`(r3)        #r[9]=c1;
+                                               #sqr_add_c(a,5,c2,c3,c1);
+       $UMULL          r7,r6,r6
+       $UMULH          r8,r6,r6
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r0
+                                               #sqr_add_c2(a,6,4,c2,c3,c1);
+       $LD             r6,`6*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+                                               #sqr_add_c2(a,7,3,c2,c3,c1);
+       $LD             r5,`3*$BNSZ`(r4)
+       $LD             r6,`7*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+       $ST             r10,`10*$BNSZ`(r3)      #r[10]=c2;
+                                               #sqr_add_c2(a,7,4,c3,c1,c2);
+       $LD             r5,`4*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r0
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+                                               #sqr_add_c2(a,6,5,c3,c1,c2);
+       $LD             r5,`5*$BNSZ`(r4)
+       $LD             r6,`6*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       addze           r10,r10
+       $ST             r11,`11*$BNSZ`(r3)      #r[11]=c3;
+                                               #sqr_add_c(a,6,c1,c2,c3);
+       $UMULL          r7,r6,r6
+       $UMULH          r8,r6,r6
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r0
+                                               #sqr_add_c2(a,7,5,c1,c2,c3)
+       $LD             r6,`7*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+       addc            r9,r7,r9
+       adde            r10,r8,r10
+       addze           r11,r11
+       $ST             r9,`12*$BNSZ`(r3)       #r[12]=c1;
+       
+                                               #sqr_add_c2(a,7,6,c2,c3,c1)
+       $LD             r5,`6*$BNSZ`(r4)
+       $UMULL          r7,r5,r6
+       $UMULH          r8,r5,r6
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r0
+       addc            r10,r7,r10
+       adde            r11,r8,r11
+       addze           r9,r9
+       $ST             r10,`13*$BNSZ`(r3)      #r[13]=c2;
+                                               #sqr_add_c(a,7,c3,c1,c2);
+       $UMULL          r7,r6,r6
+       $UMULH          r8,r6,r6
+       addc            r11,r7,r11
+       adde            r9,r8,r9
+       $ST             r11,`14*$BNSZ`(r3)      #r[14]=c3;
+       $ST             r9, `15*$BNSZ`(r3)      #r[15]=c1;
+
+
+       bclr    BO_ALWAYS,CR0_LT
+
+       .long   0x00000000
+
+#
+#      NOTE:   The following label name should be changed to
+#              "bn_mul_comba4" i.e. remove the first dot
+#              for the gcc compiler. This should be automatically
+#              done in the build
+#
+
+.align 4
+.bn_mul_comba4:
+#
+# This is an optimized version of the bn_mul_comba4 routine.
+#
+# void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
+# r3 contains r
+# r4 contains a
+# r5 contains b
+# r6, r7 are the 2 BN_ULONGs being multiplied.
+# r8, r9 are the results of the 32x32 giving 64 multiply.
+# r10, r11, r12 are the equivalents of c1, c2, and c3.
+#
+       xor     r0,r0,r0                #r0=0. Used in addze below.
+                                       #mul_add_c(a[0],b[0],c1,c2,c3);
+       $LD     r6,`0*$BNSZ`(r4)                
+       $LD     r7,`0*$BNSZ`(r5)                
+       $UMULL  r10,r6,r7               
+       $UMULH  r11,r6,r7               
+       $ST     r10,`0*$BNSZ`(r3)       #r[0]=c1
+                                       #mul_add_c(a[0],b[1],c2,c3,c1);
+       $LD     r7,`1*$BNSZ`(r5)                
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r8,r11
+       adde    r12,r9,r0
+       addze   r10,r0
+                                       #mul_add_c(a[1],b[0],c2,c3,c1);
+       $LD     r6, `1*$BNSZ`(r4)               
+       $LD     r7, `0*$BNSZ`(r5)               
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r8,r11
+       adde    r12,r9,r12
+       addze   r10,r10
+       $ST     r11,`1*$BNSZ`(r3)       #r[1]=c2
+                                       #mul_add_c(a[2],b[0],c3,c1,c2);
+       $LD     r6,`2*$BNSZ`(r4)                
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r8,r12
+       adde    r10,r9,r10
+       addze   r11,r0
+                                       #mul_add_c(a[1],b[1],c3,c1,c2);
+       $LD     r6,`1*$BNSZ`(r4)                
+       $LD     r7,`1*$BNSZ`(r5)                
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r8,r12
+       adde    r10,r9,r10
+       addze   r11,r11
+                                       #mul_add_c(a[0],b[2],c3,c1,c2);
+       $LD     r6,`0*$BNSZ`(r4)                
+       $LD     r7,`2*$BNSZ`(r5)                
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r8,r12
+       adde    r10,r9,r10
+       addze   r11,r11
+       $ST     r12,`2*$BNSZ`(r3)       #r[2]=c3
+                                       #mul_add_c(a[0],b[3],c1,c2,c3);
+       $LD     r7,`3*$BNSZ`(r5)                
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r8,r10
+       adde    r11,r9,r11
+       addze   r12,r0
+                                       #mul_add_c(a[1],b[2],c1,c2,c3);
+       $LD     r6,`1*$BNSZ`(r4)
+       $LD     r7,`2*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r8,r10
+       adde    r11,r9,r11
+       addze   r12,r12
+                                       #mul_add_c(a[2],b[1],c1,c2,c3);
+       $LD     r6,`2*$BNSZ`(r4)
+       $LD     r7,`1*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r8,r10
+       adde    r11,r9,r11
+       addze   r12,r12
+                                       #mul_add_c(a[3],b[0],c1,c2,c3);
+       $LD     r6,`3*$BNSZ`(r4)
+       $LD     r7,`0*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r8,r10
+       adde    r11,r9,r11
+       addze   r12,r12
+       $ST     r10,`3*$BNSZ`(r3)       #r[3]=c1
+                                       #mul_add_c(a[3],b[1],c2,c3,c1);
+       $LD     r7,`1*$BNSZ`(r5)                
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r8,r11
+       adde    r12,r9,r12
+       addze   r10,r0
+                                       #mul_add_c(a[2],b[2],c2,c3,c1);
+       $LD     r6,`2*$BNSZ`(r4)
+       $LD     r7,`2*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r8,r11
+       adde    r12,r9,r12
+       addze   r10,r10
+                                       #mul_add_c(a[1],b[3],c2,c3,c1);
+       $LD     r6,`1*$BNSZ`(r4)
+       $LD     r7,`3*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r8,r11
+       adde    r12,r9,r12
+       addze   r10,r10
+       $ST     r11,`4*$BNSZ`(r3)       #r[4]=c2
+                                       #mul_add_c(a[2],b[3],c3,c1,c2);
+       $LD     r6,`2*$BNSZ`(r4)                
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r8,r12
+       adde    r10,r9,r10
+       addze   r11,r0
+                                       #mul_add_c(a[3],b[2],c3,c1,c2);
+       $LD     r6,`3*$BNSZ`(r4)
+       $LD     r7,`2*$BNSZ`(r4)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r8,r12
+       adde    r10,r9,r10
+       addze   r11,r11
+       $ST     r12,`5*$BNSZ`(r3)       #r[5]=c3
+                                       #mul_add_c(a[3],b[3],c1,c2,c3);
+       $LD     r7,`3*$BNSZ`(r5)                
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r8,r10
+       adde    r11,r9,r11
+
+       $ST     r10,`6*$BNSZ`(r3)       #r[6]=c1
+       $ST     r11,`7*$BNSZ`(r3)       #r[7]=c2
+       bclr    BO_ALWAYS,CR0_LT
+       .long   0x00000000
+
+#
+#      NOTE:   The following label name should be changed to
+#              "bn_mul_comba8" i.e. remove the first dot
+#              for the gcc compiler. This should be automatically
+#              done in the build
+#
+       
+.align 4
+.bn_mul_comba8:
+#
+# Optimized version of the bn_mul_comba8 routine.
+#
+# void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
+# r3 contains r
+# r4 contains a
+# r5 contains b
+# r6, r7 are the 2 BN_ULONGs being multiplied.
+# r8, r9 are the results of the 32x32 giving 64 multiply.
+# r10, r11, r12 are the equivalents of c1, c2, and c3.
+#
+       xor     r0,r0,r0                #r0=0. Used in addze below.
+       
+                                       #mul_add_c(a[0],b[0],c1,c2,c3);
+       $LD     r6,`0*$BNSZ`(r4)        #a[0]
+       $LD     r7,`0*$BNSZ`(r5)        #b[0]
+       $UMULL  r10,r6,r7
+       $UMULH  r11,r6,r7
+       $ST     r10,`0*$BNSZ`(r3)       #r[0]=c1;
+                                       #mul_add_c(a[0],b[1],c2,c3,c1);
+       $LD     r7,`1*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       addze   r12,r9                  # since we didnt set r12 to zero before.
+       addze   r10,r0
+                                       #mul_add_c(a[1],b[0],c2,c3,c1);
+       $LD     r6,`1*$BNSZ`(r4)
+       $LD     r7,`0*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+       $ST     r11,`1*$BNSZ`(r3)       #r[1]=c2;
+                                       #mul_add_c(a[2],b[0],c3,c1,c2);
+       $LD     r6,`2*$BNSZ`(r4)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r0
+                                       #mul_add_c(a[1],b[1],c3,c1,c2);
+       $LD     r6,`1*$BNSZ`(r4)
+       $LD     r7,`1*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+                                       #mul_add_c(a[0],b[2],c3,c1,c2);
+       $LD     r6,`0*$BNSZ`(r4)
+       $LD     r7,`2*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+       $ST     r12,`2*$BNSZ`(r3)       #r[2]=c3;
+                                       #mul_add_c(a[0],b[3],c1,c2,c3);
+       $LD     r7,`3*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r0
+                                       #mul_add_c(a[1],b[2],c1,c2,c3);
+       $LD     r6,`1*$BNSZ`(r4)
+       $LD     r7,`2*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+               
+                                       #mul_add_c(a[2],b[1],c1,c2,c3);
+       $LD     r6,`2*$BNSZ`(r4)
+       $LD     r7,`1*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+                                       #mul_add_c(a[3],b[0],c1,c2,c3);
+       $LD     r6,`3*$BNSZ`(r4)
+       $LD     r7,`0*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+       $ST     r10,`3*$BNSZ`(r3)       #r[3]=c1;
+                                       #mul_add_c(a[4],b[0],c2,c3,c1);
+       $LD     r6,`4*$BNSZ`(r4)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r0
+                                       #mul_add_c(a[3],b[1],c2,c3,c1);
+       $LD     r6,`3*$BNSZ`(r4)
+       $LD     r7,`1*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+                                       #mul_add_c(a[2],b[2],c2,c3,c1);
+       $LD     r6,`2*$BNSZ`(r4)
+       $LD     r7,`2*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+                                       #mul_add_c(a[1],b[3],c2,c3,c1);
+       $LD     r6,`1*$BNSZ`(r4)
+       $LD     r7,`3*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+                                       #mul_add_c(a[0],b[4],c2,c3,c1);
+       $LD     r6,`0*$BNSZ`(r4)
+       $LD     r7,`4*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+       $ST     r11,`4*$BNSZ`(r3)       #r[4]=c2;
+                                       #mul_add_c(a[0],b[5],c3,c1,c2);
+       $LD     r7,`5*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r0
+                                       #mul_add_c(a[1],b[4],c3,c1,c2);
+       $LD     r6,`1*$BNSZ`(r4)                
+       $LD     r7,`4*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+                                       #mul_add_c(a[2],b[3],c3,c1,c2);
+       $LD     r6,`2*$BNSZ`(r4)                
+       $LD     r7,`3*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+                                       #mul_add_c(a[3],b[2],c3,c1,c2);
+       $LD     r6,`3*$BNSZ`(r4)                
+       $LD     r7,`2*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+                                       #mul_add_c(a[4],b[1],c3,c1,c2);
+       $LD     r6,`4*$BNSZ`(r4)                
+       $LD     r7,`1*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+                                       #mul_add_c(a[5],b[0],c3,c1,c2);
+       $LD     r6,`5*$BNSZ`(r4)                
+       $LD     r7,`0*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+       $ST     r12,`5*$BNSZ`(r3)       #r[5]=c3;
+                                       #mul_add_c(a[6],b[0],c1,c2,c3);
+       $LD     r6,`6*$BNSZ`(r4)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r0
+                                       #mul_add_c(a[5],b[1],c1,c2,c3);
+       $LD     r6,`5*$BNSZ`(r4)
+       $LD     r7,`1*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+                                       #mul_add_c(a[4],b[2],c1,c2,c3);
+       $LD     r6,`4*$BNSZ`(r4)
+       $LD     r7,`2*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+                                       #mul_add_c(a[3],b[3],c1,c2,c3);
+       $LD     r6,`3*$BNSZ`(r4)
+       $LD     r7,`3*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+                                       #mul_add_c(a[2],b[4],c1,c2,c3);
+       $LD     r6,`2*$BNSZ`(r4)
+       $LD     r7,`4*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+                                       #mul_add_c(a[1],b[5],c1,c2,c3);
+       $LD     r6,`1*$BNSZ`(r4)
+       $LD     r7,`5*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+                                       #mul_add_c(a[0],b[6],c1,c2,c3);
+       $LD     r6,`0*$BNSZ`(r4)
+       $LD     r7,`6*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+       $ST     r10,`6*$BNSZ`(r3)       #r[6]=c1;
+                                       #mul_add_c(a[0],b[7],c2,c3,c1);
+       $LD     r7,`7*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r0
+                                       #mul_add_c(a[1],b[6],c2,c3,c1);
+       $LD     r6,`1*$BNSZ`(r4)
+       $LD     r7,`6*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+                                       #mul_add_c(a[2],b[5],c2,c3,c1);
+       $LD     r6,`2*$BNSZ`(r4)
+       $LD     r7,`5*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+                                       #mul_add_c(a[3],b[4],c2,c3,c1);
+       $LD     r6,`3*$BNSZ`(r4)
+       $LD     r7,`4*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+                                       #mul_add_c(a[4],b[3],c2,c3,c1);
+       $LD     r6,`4*$BNSZ`(r4)
+       $LD     r7,`3*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+                                       #mul_add_c(a[5],b[2],c2,c3,c1);
+       $LD     r6,`5*$BNSZ`(r4)
+       $LD     r7,`2*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+                                       #mul_add_c(a[6],b[1],c2,c3,c1);
+       $LD     r6,`6*$BNSZ`(r4)
+       $LD     r7,`1*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+                                       #mul_add_c(a[7],b[0],c2,c3,c1);
+       $LD     r6,`7*$BNSZ`(r4)
+       $LD     r7,`0*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+       $ST     r11,`7*$BNSZ`(r3)       #r[7]=c2;
+                                       #mul_add_c(a[7],b[1],c3,c1,c2);
+       $LD     r7,`1*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r0
+                                       #mul_add_c(a[6],b[2],c3,c1,c2);
+       $LD     r6,`6*$BNSZ`(r4)
+       $LD     r7,`2*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+                                       #mul_add_c(a[5],b[3],c3,c1,c2);
+       $LD     r6,`5*$BNSZ`(r4)
+       $LD     r7,`3*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+                                       #mul_add_c(a[4],b[4],c3,c1,c2);
+       $LD     r6,`4*$BNSZ`(r4)
+       $LD     r7,`4*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+                                       #mul_add_c(a[3],b[5],c3,c1,c2);
+       $LD     r6,`3*$BNSZ`(r4)
+       $LD     r7,`5*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+                                       #mul_add_c(a[2],b[6],c3,c1,c2);
+       $LD     r6,`2*$BNSZ`(r4)
+       $LD     r7,`6*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+                                       #mul_add_c(a[1],b[7],c3,c1,c2);
+       $LD     r6,`1*$BNSZ`(r4)
+       $LD     r7,`7*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+       $ST     r12,`8*$BNSZ`(r3)       #r[8]=c3;
+                                       #mul_add_c(a[2],b[7],c1,c2,c3);
+       $LD     r6,`2*$BNSZ`(r4)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r0
+                                       #mul_add_c(a[3],b[6],c1,c2,c3);
+       $LD     r6,`3*$BNSZ`(r4)
+       $LD     r7,`6*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+                                       #mul_add_c(a[4],b[5],c1,c2,c3);
+       $LD     r6,`4*$BNSZ`(r4)
+       $LD     r7,`5*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+                                       #mul_add_c(a[5],b[4],c1,c2,c3);
+       $LD     r6,`5*$BNSZ`(r4)
+       $LD     r7,`4*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+                                       #mul_add_c(a[6],b[3],c1,c2,c3);
+       $LD     r6,`6*$BNSZ`(r4)
+       $LD     r7,`3*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+                                       #mul_add_c(a[7],b[2],c1,c2,c3);
+       $LD     r6,`7*$BNSZ`(r4)
+       $LD     r7,`2*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+       $ST     r10,`9*$BNSZ`(r3)       #r[9]=c1;
+                                       #mul_add_c(a[7],b[3],c2,c3,c1);
+       $LD     r7,`3*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r0
+                                       #mul_add_c(a[6],b[4],c2,c3,c1);
+       $LD     r6,`6*$BNSZ`(r4)
+       $LD     r7,`4*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+                                       #mul_add_c(a[5],b[5],c2,c3,c1);
+       $LD     r6,`5*$BNSZ`(r4)
+       $LD     r7,`5*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+                                       #mul_add_c(a[4],b[6],c2,c3,c1);
+       $LD     r6,`4*$BNSZ`(r4)
+       $LD     r7,`6*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+                                       #mul_add_c(a[3],b[7],c2,c3,c1);
+       $LD     r6,`3*$BNSZ`(r4)
+       $LD     r7,`7*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+       $ST     r11,`10*$BNSZ`(r3)      #r[10]=c2;
+                                       #mul_add_c(a[4],b[7],c3,c1,c2);
+       $LD     r6,`4*$BNSZ`(r4)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r0
+                                       #mul_add_c(a[5],b[6],c3,c1,c2);
+       $LD     r6,`5*$BNSZ`(r4)
+       $LD     r7,`6*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+                                       #mul_add_c(a[6],b[5],c3,c1,c2);
+       $LD     r6,`6*$BNSZ`(r4)
+       $LD     r7,`5*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+                                       #mul_add_c(a[7],b[4],c3,c1,c2);
+       $LD     r6,`7*$BNSZ`(r4)
+       $LD     r7,`4*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       addze   r11,r11
+       $ST     r12,`11*$BNSZ`(r3)      #r[11]=c3;
+                                       #mul_add_c(a[7],b[5],c1,c2,c3);
+       $LD     r7,`5*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r0
+                                       #mul_add_c(a[6],b[6],c1,c2,c3);
+       $LD     r6,`6*$BNSZ`(r4)
+       $LD     r7,`6*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+                                       #mul_add_c(a[5],b[7],c1,c2,c3);
+       $LD     r6,`5*$BNSZ`(r4)
+       $LD     r7,`7*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r10,r10,r8
+       adde    r11,r11,r9
+       addze   r12,r12
+       $ST     r10,`12*$BNSZ`(r3)      #r[12]=c1;
+                                       #mul_add_c(a[6],b[7],c2,c3,c1);
+       $LD     r6,`6*$BNSZ`(r4)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r0
+                                       #mul_add_c(a[7],b[6],c2,c3,c1);
+       $LD     r6,`7*$BNSZ`(r4)
+       $LD     r7,`6*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r11,r11,r8
+       adde    r12,r12,r9
+       addze   r10,r10
+       $ST     r11,`13*$BNSZ`(r3)      #r[13]=c2;
+                                       #mul_add_c(a[7],b[7],c3,c1,c2);
+       $LD     r7,`7*$BNSZ`(r5)
+       $UMULL  r8,r6,r7
+       $UMULH  r9,r6,r7
+       addc    r12,r12,r8
+       adde    r10,r10,r9
+       $ST     r12,`14*$BNSZ`(r3)      #r[14]=c3;
+       $ST     r10,`15*$BNSZ`(r3)      #r[15]=c1;
+       bclr    BO_ALWAYS,CR0_LT
+       .long   0x00000000
+
+#
+#      NOTE:   The following label name should be changed to
+#              "bn_sub_words" i.e. remove the first dot
+#              for the gcc compiler. This should be automatically
+#              done in the build
+#
+#
+.align 4
+.bn_sub_words:
+#
+#      Handcoded version of bn_sub_words
+#
+#BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
+#
+#      r3 = r
+#      r4 = a
+#      r5 = b
+#      r6 = n
+#
+#       Note:  No loop unrolling done since this is not a performance
+#               critical loop.
+
+       xor     r0,r0,r0        #set r0 = 0
+#
+#      check for r6 = 0 AND set carry bit.
+#
+       subfc.  r7,r0,r6        # If r6 is 0 then result is 0.
+                               # if r6 > 0 then result !=0
+                               # In either case carry bit is set.
+       bc      BO_IF,CR0_EQ,Lppcasm_sub_adios
+       addi    r4,r4,-$BNSZ
+       addi    r3,r3,-$BNSZ
+       addi    r5,r5,-$BNSZ
+       mtctr   r6
+Lppcasm_sub_mainloop:  
+       $LDU    r7,$BNSZ(r4)
+       $LDU    r8,$BNSZ(r5)
+       subfe   r6,r8,r7        # r6 = r7+carry bit + onescomplement(r8)
+                               # if carry = 1 this is r7-r8. Else it
+                               # is r7-r8 -1 as we need.
+       $STU    r6,$BNSZ(r3)
+       bc      BO_dCTR_NZERO,CR0_EQ,Lppcasm_sub_mainloop
+Lppcasm_sub_adios:     
+       subfze  r3,r0           # if carry bit is set then r3 = 0 else -1
+       andi.   r3,r3,1         # keep only last bit.
+       bclr    BO_ALWAYS,CR0_LT
+       .long   0x00000000
+
+
+#
+#      NOTE:   The following label name should be changed to
+#              "bn_add_words" i.e. remove the first dot
+#              for the gcc compiler. This should be automatically
+#              done in the build
+#
+
+.align 4
+.bn_add_words:
+#
+#      Handcoded version of bn_add_words
+#
+#BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
+#
+#      r3 = r
+#      r4 = a
+#      r5 = b
+#      r6 = n
+#
+#       Note:  No loop unrolling done since this is not a performance
+#               critical loop.
+
+       xor     r0,r0,r0
+#
+#      check for r6 = 0. Is this needed?
+#
+       addic.  r6,r6,0         #test r6 and clear carry bit.
+       bc      BO_IF,CR0_EQ,Lppcasm_add_adios
+       addi    r4,r4,-$BNSZ
+       addi    r3,r3,-$BNSZ
+       addi    r5,r5,-$BNSZ
+       mtctr   r6
+Lppcasm_add_mainloop:  
+       $LDU    r7,$BNSZ(r4)
+       $LDU    r8,$BNSZ(r5)
+       adde    r8,r7,r8
+       $STU    r8,$BNSZ(r3)
+       bc      BO_dCTR_NZERO,CR0_EQ,Lppcasm_add_mainloop
+Lppcasm_add_adios:     
+       addze   r3,r0                   #return carry bit.
+       bclr    BO_ALWAYS,CR0_LT
+       .long   0x00000000
+
+#
+#      NOTE:   The following label name should be changed to
+#              "bn_div_words" i.e. remove the first dot
+#              for the gcc compiler. This should be automatically
+#              done in the build
+#
+
+.align 4
+.bn_div_words:
+#
+#      This is a cleaned up version of code generated by
+#      the AIX compiler. The only optimization is to use
+#      the PPC instruction to count leading zeros instead
+#      of call to num_bits_word. Since this was compiled
+#      only at level -O2 we can possibly squeeze it more?
+#      
+#      r3 = h
+#      r4 = l
+#      r5 = d
+       
+       $UCMPI  0,r5,0                  # compare r5 and 0
+       bc      BO_IF_NOT,CR0_EQ,Lppcasm_div1   # proceed if d!=0
+       li      r3,-1                   # d=0 return -1
+       bclr    BO_ALWAYS,CR0_LT        
+Lppcasm_div1:
+       xor     r0,r0,r0                #r0=0
+       $COUNTZ r7,r5                   #r7 = num leading 0s in d.
+       subfic  r8,r7,$BITS             #r8 = BN_num_bits_word(d)
+       cmpi    0,0,r8,$BITS            #
+       bc      BO_IF,CR0_EQ,Lppcasm_div2       #proceed if (r8==$BITS) 
+       li      r9,1                    # r9=1
+       $SHL    r10,r9,r8               # r9<<=r8
+       $UCMP   0,r3,r10                #       
+       bc      BO_IF,CR0_GT,Lppcasm_div2       #or if (h > (1<<r8))
+       $UDIV   r3,r3,r0                #if not assert(0) divide by 0!
+                                       #that's how we signal overflow
+       bclr    BO_ALWAYS,CR0_LT        #return. NEVER REACHED.
+Lppcasm_div2:
+       $UCMP   0,r3,r5                 #h>=d?
+       bc      BO_IF,CR0_LT,Lppcasm_div3       #goto Lppcasm_div3 if not
+       subf    r3,r5,r3                #h-=d ; 
+Lppcasm_div3:                          #r7 = BN_BITS2-i. so r7=i
+       cmpi    0,0,r7,0                # is (i == 0)?
+       bc      BO_IF,CR0_EQ,Lppcasm_div4
+       $SHL    r3,r3,r7                # h = (h<< i)
+       $SHR    r8,r4,r8                # r8 = (l >> BN_BITS2 -i)
+       $SHL    r5,r5,r7                # d<<=i
+       or      r3,r3,r8                # h = (h<<i)|(l>>(BN_BITS2-i))
+       $SHL    r4,r4,r7                # l <<=i
+Lppcasm_div4:
+       $SHRI   r9,r5,`$BITS/2`         # r9 = dh
+                                       # dl will be computed when needed
+                                       # as it saves registers.
+       li      r6,2                    #r6=2
+       mtctr   r6                      #counter will be in count.
+Lppcasm_divouterloop: 
+       $SHRI   r8,r3,`$BITS/2`         #r8 = (h>>BN_BITS4)
+       $SHRI   r11,r4,`$BITS/2`        #r11= (l&BN_MASK2h)>>BN_BITS4
+                                       # compute here for innerloop.
+       $UCMP   0,r8,r9                 # is (h>>BN_BITS4)==dh
+       bc      BO_IF_NOT,CR0_EQ,Lppcasm_div5   # goto Lppcasm_div5 if not
+
+       li      r8,-1
+       $CLRU   r8,r8,`$BITS/2`         #q = BN_MASK2l 
+       b       Lppcasm_div6
+Lppcasm_div5:
+       $UDIV   r8,r3,r9                #q = h/dh
+Lppcasm_div6:
+       $UMULL  r12,r9,r8               #th = q*dh
+       $CLRU   r10,r5,`$BITS/2`        #r10=dl
+       $UMULL  r6,r8,r10               #tl = q*dl
+       
+Lppcasm_divinnerloop:
+       subf    r10,r12,r3              #t = h -th
+       $SHRI   r7,r10,`$BITS/2`        #r7= (t &BN_MASK2H), sort of...
+       addic.  r7,r7,0                 #test if r7 == 0. used below.
+                                       # now want to compute
+                                       # r7 = (t<<BN_BITS4)|((l&BN_MASK2h)>>BN_BITS4)
+                                       # the following 2 instructions do that
+       $SHLI   r7,r10,`$BITS/2`        # r7 = (t<<BN_BITS4)
+       or      r7,r7,r11               # r7|=((l&BN_MASK2h)>>BN_BITS4)
+       $UCMP   1,r6,r7                 # compare (tl <= r7)
+       bc      BO_IF_NOT,CR0_EQ,Lppcasm_divinnerexit
+       bc      BO_IF_NOT,CR1_FEX,Lppcasm_divinnerexit
+       addi    r8,r8,-1                #q--
+       subf    r12,r9,r12              #th -=dh
+       $CLRU   r10,r5,`$BITS/2`        #r10=dl. t is no longer needed in loop.
+       subf    r6,r10,r6               #tl -=dl
+       b       Lppcasm_divinnerloop
+Lppcasm_divinnerexit:
+       $SHRI   r10,r6,`$BITS/2`        #t=(tl>>BN_BITS4)
+       $SHLI   r11,r6,`$BITS/2`        #tl=(tl<<BN_BITS4)&BN_MASK2h;
+       $UCMP   1,r4,r11                # compare l and tl
+       add     r12,r12,r10             # th+=t
+       bc      BO_IF_NOT,CR1_FX,Lppcasm_div7  # if (l>=tl) goto Lppcasm_div7
+       addi    r12,r12,1               # th++
+Lppcasm_div7:
+       subf    r11,r11,r4              #r11=l-tl
+       $UCMP   1,r3,r12                #compare h and th
+       bc      BO_IF_NOT,CR1_FX,Lppcasm_div8   #if (h>=th) goto Lppcasm_div8
+       addi    r8,r8,-1                # q--
+       add     r3,r5,r3                # h+=d
+Lppcasm_div8:
+       subf    r12,r12,r3              #r12 = h-th
+       $SHLI   r4,r11,`$BITS/2`        #l=(l&BN_MASK2l)<<BN_BITS4
+                                       # want to compute
+                                       # h = ((h<<BN_BITS4)|(l>>BN_BITS4))&BN_MASK2
+                                       # the following 2 instructions will do this.
+       $INSR   r11,r12,`$BITS/2`,`$BITS/2`     # r11 is the value we want rotated $BITS/2.
+       $ROTL   r3,r11,`$BITS/2`        # rotate by $BITS/2 and store in r3
+       bc      BO_dCTR_ZERO,CR0_EQ,Lppcasm_div9#if (count==0) break ;
+       $SHLI   r0,r8,`$BITS/2`         #ret =q<<BN_BITS4
+       b       Lppcasm_divouterloop
+Lppcasm_div9:
+       or      r3,r8,r0
+       bclr    BO_ALWAYS,CR0_LT
+       .long   0x00000000
+
+#
+#      NOTE:   The following label name should be changed to
+#              "bn_sqr_words" i.e. remove the first dot
+#              for the gcc compiler. This should be automatically
+#              done in the build
+#
+.align 4
+.bn_sqr_words:
+#
+#      Optimized version of bn_sqr_words
+#
+#      void bn_sqr_words(BN_ULONG *r, BN_ULONG *a, int n)
+#
+#      r3 = r
+#      r4 = a
+#      r5 = n
+#
+#      r6 = a[i].
+#      r7,r8 = product.
+#
+#      No unrolling done here. Not performance critical.
+
+       addic.  r5,r5,0                 #test r5.
+       bc      BO_IF,CR0_EQ,Lppcasm_sqr_adios
+       addi    r4,r4,-$BNSZ
+       addi    r3,r3,-$BNSZ
+       mtctr   r5
+Lppcasm_sqr_mainloop:  
+                                       #sqr(r[0],r[1],a[0]);
+       $LDU    r6,$BNSZ(r4)
+       $UMULL  r7,r6,r6
+       $UMULH  r8,r6,r6
+       $STU    r7,$BNSZ(r3)
+       $STU    r8,$BNSZ(r3)
+       bc      BO_dCTR_NZERO,CR0_EQ,Lppcasm_sqr_mainloop
+Lppcasm_sqr_adios:     
+       bclr    BO_ALWAYS,CR0_LT
+       .long   0x00000000
+
+
+#
+#      NOTE:   The following label name should be changed to
+#              "bn_mul_words" i.e. remove the first dot
+#              for the gcc compiler. This should be automatically
+#              done in the build
+#
+
+.align 4       
+.bn_mul_words:
+#
+# BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
+#
+# r3 = rp
+# r4 = ap
+# r5 = num
+# r6 = w
+       xor     r0,r0,r0
+       xor     r12,r12,r12             # used for carry
+       rlwinm. r7,r5,30,2,31           # num >> 2
+       bc      BO_IF,CR0_EQ,Lppcasm_mw_REM
+       mtctr   r7
+Lppcasm_mw_LOOP:       
+                                       #mul(rp[0],ap[0],w,c1);
+       $LD     r8,`0*$BNSZ`(r4)
+       $UMULL  r9,r6,r8
+       $UMULH  r10,r6,r8
+       addc    r9,r9,r12
+       #addze  r10,r10                 #carry is NOT ignored.
+                                       #will be taken care of
+                                       #in second spin below
+                                       #using adde.
+       $ST     r9,`0*$BNSZ`(r3)
+                                       #mul(rp[1],ap[1],w,c1);
+       $LD     r8,`1*$BNSZ`(r4)        
+       $UMULL  r11,r6,r8
+       $UMULH  r12,r6,r8
+       adde    r11,r11,r10
+       #addze  r12,r12
+       $ST     r11,`1*$BNSZ`(r3)
+                                       #mul(rp[2],ap[2],w,c1);
+       $LD     r8,`2*$BNSZ`(r4)
+       $UMULL  r9,r6,r8
+       $UMULH  r10,r6,r8
+       adde    r9,r9,r12
+       #addze  r10,r10
+       $ST     r9,`2*$BNSZ`(r3)
+                                       #mul_add(rp[3],ap[3],w,c1);
+       $LD     r8,`3*$BNSZ`(r4)
+       $UMULL  r11,r6,r8
+       $UMULH  r12,r6,r8
+       adde    r11,r11,r10
+       addze   r12,r12                 #this spin we collect carry into
+                                       #r12
+       $ST     r11,`3*$BNSZ`(r3)
+       
+       addi    r3,r3,`4*$BNSZ`
+       addi    r4,r4,`4*$BNSZ`
+       bc      BO_dCTR_NZERO,CR0_EQ,Lppcasm_mw_LOOP
+
+Lppcasm_mw_REM:
+       andi.   r5,r5,0x3
+       bc      BO_IF,CR0_EQ,Lppcasm_mw_OVER
+                                       #mul(rp[0],ap[0],w,c1);
+       $LD     r8,`0*$BNSZ`(r4)
+       $UMULL  r9,r6,r8
+       $UMULH  r10,r6,r8
+       addc    r9,r9,r12
+       addze   r10,r10
+       $ST     r9,`0*$BNSZ`(r3)
+       addi    r12,r10,0
+       
+       addi    r5,r5,-1
+       cmpli   0,0,r5,0
+       bc      BO_IF,CR0_EQ,Lppcasm_mw_OVER
+
+       
+                                       #mul(rp[1],ap[1],w,c1);
+       $LD     r8,`1*$BNSZ`(r4)        
+       $UMULL  r9,r6,r8
+       $UMULH  r10,r6,r8
+       addc    r9,r9,r12
+       addze   r10,r10
+       $ST     r9,`1*$BNSZ`(r3)
+       addi    r12,r10,0
+       
+       addi    r5,r5,-1
+       cmpli   0,0,r5,0
+       bc      BO_IF,CR0_EQ,Lppcasm_mw_OVER
+       
+                                       #mul_add(rp[2],ap[2],w,c1);
+       $LD     r8,`2*$BNSZ`(r4)
+       $UMULL  r9,r6,r8
+       $UMULH  r10,r6,r8
+       addc    r9,r9,r12
+       addze   r10,r10
+       $ST     r9,`2*$BNSZ`(r3)
+       addi    r12,r10,0
+               
+Lppcasm_mw_OVER:       
+       addi    r3,r12,0
+       bclr    BO_ALWAYS,CR0_LT
+       .long   0x00000000
+
+#
+#      NOTE:   The following label name should be changed to
+#              "bn_mul_add_words" i.e. remove the first dot
+#              for the gcc compiler. This should be automatically
+#              done in the build
+#
+
+.align 4
+.bn_mul_add_words:
+#
+# BN_ULONG bn_mul_add_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
+#
+# r3 = rp
+# r4 = ap
+# r5 = num
+# r6 = w
+#
+# empirical evidence suggests that unrolled version performs best!!
+#
+       xor     r0,r0,r0                #r0 = 0
+       xor     r12,r12,r12             #r12 = 0 . used for carry               
+       rlwinm. r7,r5,30,2,31           # num >> 2
+       bc      BO_IF,CR0_EQ,Lppcasm_maw_leftover       # if (num < 4) go LPPCASM_maw_leftover
+       mtctr   r7
+Lppcasm_maw_mainloop:  
+                                       #mul_add(rp[0],ap[0],w,c1);
+       $LD     r8,`0*$BNSZ`(r4)
+       $LD     r11,`0*$BNSZ`(r3)
+       $UMULL  r9,r6,r8
+       $UMULH  r10,r6,r8
+       addc    r9,r9,r12               #r12 is carry.
+       addze   r10,r10
+       addc    r9,r9,r11
+       #addze  r10,r10
+                                       #the above instruction addze
+                                       #is NOT needed. Carry will NOT
+                                       #be ignored. It's not affected
+                                       #by multiply and will be collected
+                                       #in the next spin
+       $ST     r9,`0*$BNSZ`(r3)
+       
+                                       #mul_add(rp[1],ap[1],w,c1);
+       $LD     r8,`1*$BNSZ`(r4)        
+       $LD     r9,`1*$BNSZ`(r3)
+       $UMULL  r11,r6,r8
+       $UMULH  r12,r6,r8
+       adde    r11,r11,r10             #r10 is carry.
+       addze   r12,r12
+       addc    r11,r11,r9
+       #addze  r12,r12
+       $ST     r11,`1*$BNSZ`(r3)
+       
+                                       #mul_add(rp[2],ap[2],w,c1);
+       $LD     r8,`2*$BNSZ`(r4)
+       $UMULL  r9,r6,r8
+       $LD     r11,`2*$BNSZ`(r3)
+       $UMULH  r10,r6,r8
+       adde    r9,r9,r12
+       addze   r10,r10
+       addc    r9,r9,r11
+       #addze  r10,r10
+       $ST     r9,`2*$BNSZ`(r3)
+       
+                                       #mul_add(rp[3],ap[3],w,c1);
+       $LD     r8,`3*$BNSZ`(r4)
+       $UMULL  r11,r6,r8
+       $LD     r9,`3*$BNSZ`(r3)
+       $UMULH  r12,r6,r8
+       adde    r11,r11,r10
+       addze   r12,r12
+       addc    r11,r11,r9
+       addze   r12,r12
+       $ST     r11,`3*$BNSZ`(r3)
+       addi    r3,r3,`4*$BNSZ`
+       addi    r4,r4,`4*$BNSZ`
+       bc      BO_dCTR_NZERO,CR0_EQ,Lppcasm_maw_mainloop
+       
+Lppcasm_maw_leftover:
+       andi.   r5,r5,0x3
+       bc      BO_IF,CR0_EQ,Lppcasm_maw_adios
+       addi    r3,r3,-$BNSZ
+       addi    r4,r4,-$BNSZ
+                                       #mul_add(rp[0],ap[0],w,c1);
+       mtctr   r5
+       $LDU    r8,$BNSZ(r4)
+       $UMULL  r9,r6,r8
+       $UMULH  r10,r6,r8
+       $LDU    r11,$BNSZ(r3)
+       addc    r9,r9,r11
+       addze   r10,r10
+       addc    r9,r9,r12
+       addze   r12,r10
+       $ST     r9,0(r3)
+       
+       bc      BO_dCTR_ZERO,CR0_EQ,Lppcasm_maw_adios
+                                       #mul_add(rp[1],ap[1],w,c1);
+       $LDU    r8,$BNSZ(r4)    
+       $UMULL  r9,r6,r8
+       $UMULH  r10,r6,r8
+       $LDU    r11,$BNSZ(r3)
+       addc    r9,r9,r11
+       addze   r10,r10
+       addc    r9,r9,r12
+       addze   r12,r10
+       $ST     r9,0(r3)
+       
+       bc      BO_dCTR_ZERO,CR0_EQ,Lppcasm_maw_adios
+                                       #mul_add(rp[2],ap[2],w,c1);
+       $LDU    r8,$BNSZ(r4)
+       $UMULL  r9,r6,r8
+       $UMULH  r10,r6,r8
+       $LDU    r11,$BNSZ(r3)
+       addc    r9,r9,r11
+       addze   r10,r10
+       addc    r9,r9,r12
+       addze   r12,r10
+       $ST     r9,0(r3)
+               
+Lppcasm_maw_adios:     
+       addi    r3,r12,0
+       bclr    BO_ALWAYS,CR0_LT
+       .long   0x00000000
+       .align  4
+EOF
+       $data =~ s/\`([^\`]*)\`/eval $1/gem;
+
+       # if some assembler chokes on some simplified mnemonic,
+       # this is the spot to fix it up, e.g.:
+       # GNU as doesn't seem to accept cmplw, 32-bit unsigned compare
+       $data =~ s/^(\s*)cmplw(\s+)([^,]+),(.*)/$1cmpl$2$3,0,$4/gm;
+       # assembler X doesn't accept li, load immediate value
+       #$data =~ s/^(\s*)li(\s+)([^,]+),(.*)/$1addi$2$3,0,$4/gm;
+       return($data);
+}