1dnl  mc68020 mpn_lshift -- mpn left shift.
2
3dnl  Copyright 1996, 1999, 2000, 2001, 2002, 2003 Free Software Foundation,
4dnl  Inc.
5dnl
6dnl  This file is part of the GNU MP Library.
7dnl
8dnl  The GNU MP Library is free software; you can redistribute it and/or
9dnl  modify it under the terms of the GNU Lesser General Public License as
10dnl  published by the Free Software Foundation; either version 3 of the
11dnl  License, or (at your option) any later version.
12dnl
13dnl  The GNU MP Library is distributed in the hope that it will be useful,
14dnl  but WITHOUT ANY WARRANTY; without even the implied warranty of
15dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16dnl  Lesser General Public License for more details.
17dnl
18dnl  You should have received a copy of the GNU Lesser General Public License
19dnl  along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.
20
21include(`../config.m4')
22
23
24C           cycles/limb
25C        shift==1  shift>1
26C 68040:    5         12
27
28
29C mp_limb_t mpn_lshift (mp_ptr res_ptr, mp_srcptr s_ptr, mp_size_t s_size,
30C                       unsigned cnt);
31C
32C The "cnt" parameter is either 16 bits or 32 bits depending on
33C SIZEOF_UNSIGNED (see ABI notes in mpn/m68k/README).  The value is of
34C course only 1 to 31.  When loaded as 16 bits there's garbage in the upper
35C half, hence the use of cmpw.  The shift instructions take the their count
36C modulo 64, so the upper part doesn't matter to them either.
37C
38
39C INPUT PARAMETERS
40C res_ptr	(sp + 4)
41C s_ptr		(sp + 8)
42C s_size	(sp + 12)
43C cnt		(sp + 16)
44
45define(res_ptr, `a1')
46define(s_ptr,   `a0')
47define(s_size,  `d6')
48define(cnt,     `d4')
49
50ifdef(`SIZEOF_UNSIGNED',,
51`m4_error(`SIZEOF_UNSIGNED not defined, should be in config.m4
52')')
53
54PROLOGUE(mpn_lshift)
55C Save used registers on the stack.
56	moveml	d2-d6/a2, M(-,sp)
57
58C Copy the arguments to registers.
59	movel	M(sp,28), res_ptr
60	movel	M(sp,32), s_ptr
61	movel	M(sp,36), s_size
62ifelse(SIZEOF_UNSIGNED,2,
63`	movew	M(sp,40), cnt',
64`	movel	M(sp,40), cnt')
65
66	moveql	#1, d5
67	cmpw	d5, cnt
68	bne	L(Lnormal)
69	cmpl	s_ptr, res_ptr
70	bls	L(Lspecial)		C jump if s_ptr >= res_ptr
71
72ifelse(scale_available_p,1,`
73	lea	M(s_ptr,s_size,l,4), a2
74',`
75	movel	s_size, d0
76	asll	#2, d0
77	lea	M(s_ptr,d0,l), a2
78')
79	cmpl	res_ptr, a2
80	bls	L(Lspecial)		C jump if res_ptr >= s_ptr + s_size
81
82L(Lnormal):
83	moveql	#32, d5
84	subl	cnt, d5
85
86ifelse(scale_available_p,1,`
87	lea	M(s_ptr,s_size,l,4), s_ptr
88	lea	M(res_ptr,s_size,l,4), res_ptr
89',`
90	movel	s_size, d0
91	asll	#2, d0
92	addl	d0, s_ptr
93	addl	d0, res_ptr
94')
95	movel	M(-,s_ptr), d2
96	movel	d2, d0
97	lsrl	d5, d0		C compute carry limb
98
99	lsll	cnt, d2
100	movel	d2, d1
101	subql	#1, s_size
102	beq	L(Lend)
103	lsrl	#1, s_size
104	bcs	L(L1)
105	subql	#1, s_size
106
107L(Loop:)
108	movel	M(-,s_ptr), d2
109	movel	d2, d3
110	lsrl	d5, d3
111	orl	d3, d1
112	movel	d1, M(-,res_ptr)
113	lsll	cnt, d2
114L(L1:)
115	movel	M(-,s_ptr), d1
116	movel	d1, d3
117	lsrl	d5, d3
118	orl	d3, d2
119	movel	d2, M(-,res_ptr)
120	lsll	cnt, d1
121
122	dbf	s_size, L(Loop)
123	subl	#0x10000, s_size
124	bcc	L(Loop)
125
126L(Lend:)
127	movel	d1, M(-,res_ptr)	C store least significant limb
128
129C Restore used registers from stack frame.
130	moveml	M(sp,+), d2-d6/a2
131	rts
132
133C We loop from least significant end of the arrays, which is only
134C permissable if the source and destination don't overlap, since the
135C function is documented to work for overlapping source and destination.
136
137L(Lspecial):
138	clrl	d0			C initialize carry
139	eorw	#1, s_size
140	lsrl	#1, s_size
141	bcc	L(LL1)
142	subql	#1, s_size
143
144L(LLoop):
145	movel	M(s_ptr,+), d2
146	addxl	d2, d2
147	movel	d2, M(res_ptr,+)
148L(LL1):
149	movel	M(s_ptr,+), d2
150	addxl	d2, d2
151	movel	d2, M(res_ptr,+)
152
153	dbf	s_size, L(LLoop)
154	addxl	d0, d0		C save cy in lsb
155	subl	#0x10000, s_size
156	bcs	L(LLend)
157	lsrl	#1, d0		C restore cy
158	bra	L(LLoop)
159
160L(LLend):
161C Restore used registers from stack frame.
162	moveml	M(sp,+), d2-d6/a2
163	rts
164
165EPILOGUE(mpn_lshift)
166