1dnl  mc68020 mpn_rshift -- mpn right 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:    9         12
27
28
29C mp_limb_t mpn_rshift (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_rshift)
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	res_ptr, s_ptr
70	bls	L(Lspecial)		C jump if res_ptr >= s_ptr
71
72ifelse(scale_available_p,1,`
73	lea	M(res_ptr,s_size,l,4), a2
74',`
75	movel	s_size, d0
76	asll	#2, d0
77	lea	M(res_ptr,d0,l), a2
78')
79	cmpl	s_ptr, a2
80	bls	L(Lspecial)		C jump if s_ptr >= res_ptr + s_size
81
82L(Lnormal:)
83	moveql	#32, d5
84	subl	cnt, d5
85	movel	M(s_ptr,+), d2
86	movel	d2, d0
87	lsll	d5, d0		C compute carry limb
88
89	lsrl	cnt, d2
90	movel	d2, d1
91	subql	#1, s_size
92	beq	L(Lend)
93	lsrl	#1, s_size
94	bcs	L(L1)
95	subql	#1, s_size
96
97L(Loop:)
98	movel	M(s_ptr,+), d2
99	movel	d2, d3
100	lsll	d5, d3
101	orl	d3, d1
102	movel	d1, M(res_ptr,+)
103	lsrl	cnt, d2
104L(L1:)
105	movel	M(s_ptr,+), d1
106	movel	d1, d3
107	lsll	d5, d3
108	orl	d3, d2
109	movel	d2, M(res_ptr,+)
110	lsrl	cnt, d1
111
112	dbf	s_size, L(Loop)
113	subl	#0x10000, s_size
114	bcc	L(Loop)
115
116L(Lend:)
117	movel	d1, M(res_ptr)	C store most significant limb
118
119C Restore used registers from stack frame.
120	moveml	M(sp,+), d2-d6/a2
121	rts
122
123C We loop from most significant end of the arrays, which is only permissable
124C if the source and destination don't overlap, since the function is
125C documented to work for overlapping source and destination.
126
127L(Lspecial:)
128ifelse(scale_available_p,1,`
129	lea	M(s_ptr,s_size,l,4), s_ptr
130	lea	M(res_ptr,s_size,l,4), res_ptr
131',`
132	movel	s_size, d0
133	asll	#2, d0
134	addl	d0, s_ptr
135	addl	d0, res_ptr
136')
137
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	roxrl	#1, d2
147	movel	d2, M(-,res_ptr)
148L(LL1:)
149	movel	M(-,s_ptr), d2
150	roxrl	#1, d2
151	movel	d2, M(-,res_ptr)
152
153	dbf	s_size, L(LLoop)
154	roxrl	#1, d0		C save cy in msb
155	subl	#0x10000, s_size
156	bcs	L(LLend)
157	addl	d0, 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_rshift)
166