Update head to match stable 1.0
[gnupg.git] / mpi / m68k / mpih-lshift.S
1 /* mc68020 lshift -- Shift left a low-level natural-number integer.
2  *
3  *      Copyright (C) 1996, 1998, 2001 Free Software Foundation, Inc.
4  *       
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  *
21  * Note: This code is heavily based on the GNU MP Library.
22  *       Actually it's the same code with only minor changes in the
23  *       way the data is stored; this is to support the abstraction
24  *       of an optional secure memory allocation which may be used
25  *       to avoid revealing of sensitive data due to paging etc.
26  *       The GNU MP Library itself is published under the LGPL;
27  *       however I decided to publish this code under the plain GPL.
28  */
29
30
31 #include "sysdep.h"
32 #include "asm-syntax.h"
33
34
35 /*******************
36  * mpi_limb_t
37  * mpihelp_lshift( mpi_ptr_t wp,        (sp + 4)
38  *                 mpi_ptr_t up,        (sp + 8)
39  *                 mpi_size_t usize,    (sp + 12)
40  *                 unsigned cnt)        (sp + 16)
41  */
42
43 #define res_ptr a1
44 #define s_ptr a0
45 #define s_size d6
46 #define cnt d4
47
48         TEXT
49         ALIGN
50         GLOBL   C_SYMBOL_NAME(mpihelp_lshift)
51
52 C_SYMBOL_NAME(mpihelp_lshift:)
53 PROLOG(mpihelp_lshift)
54
55         /* Save used registers on the stack.  */
56         moveml  R(d2)-R(d6)/R(a2),MEM_PREDEC(sp)
57
58         /* Copy the arguments to registers.  */
59         movel   MEM_DISP(sp,28),R(res_ptr)
60         movel   MEM_DISP(sp,32),R(s_ptr)
61         movel   MEM_DISP(sp,36),R(s_size)
62         movel   MEM_DISP(sp,40),R(cnt)
63
64         moveql  #1,R(d5)
65         cmpl    R(d5),R(cnt)
66         bne     L(Lnormal)
67         cmpl    R(s_ptr),R(res_ptr)
68         bls     L(Lspecial)             /* jump if s_ptr >= res_ptr */
69 #if (defined (__mc68020__) || defined (__NeXT__) || defined(mc68020))
70         lea     MEM_INDX1(s_ptr,s_size,l,4),R(a2)
71 #else /* not mc68020 */
72         movel   R(s_size),R(d0)
73         asll    #2,R(d0)
74         lea     MEM_INDX(s_ptr,d0,l),R(a2)
75 #endif
76         cmpl    R(res_ptr),R(a2)
77         bls     L(Lspecial)             /* jump if res_ptr >= s_ptr + s_size */
78
79 L(Lnormal:)
80         moveql  #32,R(d5)
81         subl    R(cnt),R(d5)
82
83 #if (defined (__mc68020__) || defined (__NeXT__) || defined(mc68020))
84         lea     MEM_INDX1(s_ptr,s_size,l,4),R(s_ptr)
85         lea     MEM_INDX1(res_ptr,s_size,l,4),R(res_ptr)
86 #else /* not mc68000 */
87         movel   R(s_size),R(d0)
88         asll    #2,R(d0)
89         addl    R(s_size),R(s_ptr)
90         addl    R(s_size),R(res_ptr)
91 #endif
92         movel   MEM_PREDEC(s_ptr),R(d2)
93         movel   R(d2),R(d0)
94         lsrl    R(d5),R(d0)             /* compute carry limb */
95
96         lsll    R(cnt),R(d2)
97         movel   R(d2),R(d1)
98         subql   #1,R(s_size)
99         beq     L(Lend)
100         lsrl    #1,R(s_size)
101         bcs     L(L1)
102         subql   #1,R(s_size)
103
104 L(Loop:)
105         movel   MEM_PREDEC(s_ptr),R(d2)
106         movel   R(d2),R(d3)
107         lsrl    R(d5),R(d3)
108         orl     R(d3),R(d1)
109         movel   R(d1),MEM_PREDEC(res_ptr)
110         lsll    R(cnt),R(d2)
111 L(L1:)
112         movel   MEM_PREDEC(s_ptr),R(d1)
113         movel   R(d1),R(d3)
114         lsrl    R(d5),R(d3)
115         orl     R(d3),R(d2)
116         movel   R(d2),MEM_PREDEC(res_ptr)
117         lsll    R(cnt),R(d1)
118
119         dbf     R(s_size),L(Loop)
120         subl    #0x10000,R(s_size)
121         bcc     L(Loop)
122
123 L(Lend:)
124         movel   R(d1),MEM_PREDEC(res_ptr) /* store least significant limb */
125
126 /* Restore used registers from stack frame.  */
127         moveml  MEM_POSTINC(sp),R(d2)-R(d6)/R(a2)
128         rts
129
130 /* We loop from least significant end of the arrays, which is only
131    permissable if the source and destination don't overlap, since the
132    function is documented to work for overlapping source and destination.  */
133
134 L(Lspecial:)
135         clrl    R(d0)                   /* initialize carry */
136         eorw    #1,R(s_size)
137         lsrl    #1,R(s_size)
138         bcc     L(LL1)
139         subql   #1,R(s_size)
140
141 L(LLoop:)
142         movel   MEM_POSTINC(s_ptr),R(d2)
143         addxl   R(d2),R(d2)
144         movel   R(d2),MEM_POSTINC(res_ptr)
145 L(LL1:)
146         movel   MEM_POSTINC(s_ptr),R(d2)
147         addxl   R(d2),R(d2)
148         movel   R(d2),MEM_POSTINC(res_ptr)
149
150         dbf     R(s_size),L(LLoop)
151         addxl   R(d0),R(d0)             /* save cy in lsb */
152         subl    #0x10000,R(s_size)
153         bcs     L(LLend)
154         lsrl    #1,R(d0)                /* restore cy */
155         bra     L(LLoop)
156
157 L(LLend:)
158 /* Restore used registers from stack frame.  */
159         moveml  MEM_POSTINC(sp),R(d2)-R(d6)/R(a2)
160         rts
161 EPILOG(mpihelp_lshift)
162
163
164
165
166