1/* mc68020 lshift -- Shift left a low-level natural-number integer.
2 *
3 *      Copyright (C) 1996, 1998, 2001, 2002 Free Software Foundation, Inc.
4 *
5 * This file is part of Libgcrypt.
6 *
7 * Libgcrypt is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * Libgcrypt 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 Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License 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 */
27
28
29#include "sysdep.h"
30#include "asm-syntax.h"
31
32
33/*******************
34 * mpi_limb_t
35 * _gcry_mpih_lshift( mpi_ptr_t wp,	(sp + 4)
36 *		   mpi_ptr_t up,	(sp + 8)
37 *		   mpi_size_t usize,	(sp + 12)
38 *		   unsigned cnt)	(sp + 16)
39 */
40
41#define res_ptr a1
42#define s_ptr a0
43#define s_size d6
44#define cnt d4
45
46	TEXT
47	ALIGN
48	GLOBL	C_SYMBOL_NAME(_gcry_mpih_lshift)
49
50C_SYMBOL_NAME(_gcry_mpih_lshift:)
51PROLOG(_gcry_mpih_lshift)
52
53	/* Save used registers on the stack.  */
54	moveml	R(d2)-R(d6)/R(a2),MEM_PREDEC(sp)
55
56	/* Copy the arguments to registers.  */
57	movel	MEM_DISP(sp,28),R(res_ptr)
58	movel	MEM_DISP(sp,32),R(s_ptr)
59	movel	MEM_DISP(sp,36),R(s_size)
60	movel	MEM_DISP(sp,40),R(cnt)
61
62	moveql	#1,R(d5)
63	cmpl	R(d5),R(cnt)
64	bne	L(Lnormal)
65	cmpl	R(s_ptr),R(res_ptr)
66	bls	L(Lspecial)		/* jump if s_ptr >= res_ptr */
67#if (defined (__mc68020__) || defined (__NeXT__) || defined(mc68020))
68	lea	MEM_INDX1(s_ptr,s_size,l,4),R(a2)
69#else /* not mc68020 */
70	movel	R(s_size),R(d0)
71	asll	#2,R(d0)
72	lea	MEM_INDX(s_ptr,d0,l),R(a2)
73#endif
74	cmpl	R(res_ptr),R(a2)
75	bls	L(Lspecial)		/* jump if res_ptr >= s_ptr + s_size */
76
77L(Lnormal:)
78	moveql	#32,R(d5)
79	subl	R(cnt),R(d5)
80
81#if (defined (__mc68020__) || defined (__NeXT__) || defined(mc68020))
82	lea	MEM_INDX1(s_ptr,s_size,l,4),R(s_ptr)
83	lea	MEM_INDX1(res_ptr,s_size,l,4),R(res_ptr)
84#else /* not mc68000 */
85	movel	R(s_size),R(d0)
86	asll	#2,R(d0)
87	addl	R(s_size),R(s_ptr)
88	addl	R(s_size),R(res_ptr)
89#endif
90	movel	MEM_PREDEC(s_ptr),R(d2)
91	movel	R(d2),R(d0)
92	lsrl	R(d5),R(d0)		/* compute carry limb */
93
94	lsll	R(cnt),R(d2)
95	movel	R(d2),R(d1)
96	subql	#1,R(s_size)
97	beq	L(Lend)
98	lsrl	#1,R(s_size)
99	bcs	L(L1)
100	subql	#1,R(s_size)
101
102L(Loop:)
103	movel	MEM_PREDEC(s_ptr),R(d2)
104	movel	R(d2),R(d3)
105	lsrl	R(d5),R(d3)
106	orl	R(d3),R(d1)
107	movel	R(d1),MEM_PREDEC(res_ptr)
108	lsll	R(cnt),R(d2)
109L(L1:)
110	movel	MEM_PREDEC(s_ptr),R(d1)
111	movel	R(d1),R(d3)
112	lsrl	R(d5),R(d3)
113	orl	R(d3),R(d2)
114	movel	R(d2),MEM_PREDEC(res_ptr)
115	lsll	R(cnt),R(d1)
116
117	dbf	R(s_size),L(Loop)
118	subl	#0x10000,R(s_size)
119	bcc	L(Loop)
120
121L(Lend:)
122	movel	R(d1),MEM_PREDEC(res_ptr) /* store least significant limb */
123
124/* Restore used registers from stack frame.  */
125	moveml	MEM_POSTINC(sp),R(d2)-R(d6)/R(a2)
126	rts
127
128/* We loop from least significant end of the arrays, which is only
129   permissable if the source and destination don't overlap, since the
130   function is documented to work for overlapping source and destination.  */
131
132L(Lspecial:)
133	clrl	R(d0)			/* initialize carry */
134	eorw	#1,R(s_size)
135	lsrl	#1,R(s_size)
136	bcc	L(LL1)
137	subql	#1,R(s_size)
138
139L(LLoop:)
140	movel	MEM_POSTINC(s_ptr),R(d2)
141	addxl	R(d2),R(d2)
142	movel	R(d2),MEM_POSTINC(res_ptr)
143L(LL1:)
144	movel	MEM_POSTINC(s_ptr),R(d2)
145	addxl	R(d2),R(d2)
146	movel	R(d2),MEM_POSTINC(res_ptr)
147
148	dbf	R(s_size),L(LLoop)
149	addxl	R(d0),R(d0)		/* save cy in lsb */
150	subl	#0x10000,R(s_size)
151	bcs	L(LLend)
152	lsrl	#1,R(d0)		/* restore cy */
153	bra	L(LLoop)
154
155L(LLend:)
156/* Restore used registers from stack frame.  */
157	moveml	MEM_POSTINC(sp),R(d2)-R(d6)/R(a2)
158	rts
159EPILOG(_gcry_mpih_lshift)
160
161
162
163
164
165