Imported Upstream version 2.9.0
[debian/cc1111] / device / lib / _modulong.c
1 /*-------------------------------------------------------------------------
2    _modulong.c - routine for modulus of 32 bit unsigned long
3
4              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
5
6              Bug fixes by Martijn van Balen, aed@iae.nl
7
8    This library is free software; you can redistribute it and/or modify it
9    under the terms of the GNU Library General Public License as published by the
10    Free Software Foundation; either version 2, or (at your option) any
11    later version.
12
13    This library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU Library General Public License for more details.
17
18    You should have received a copy of the GNU Library General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22    In other words, you are welcome to use, share and improve this program.
23    You are forbidden to forbid anyone else to use, share and improve
24    what you give them.   Help stamp out software-hoarding!
25 -------------------------------------------------------------------------*/
26
27 /*   Assembler-functions are provided for:
28      mcs51 small
29      mcs51 small stack-auto
30 */
31
32 #if !defined(SDCC_USE_XSTACK) && !defined(_SDCC_NO_ASM_LIB_FUNCS)
33 #  if defined(SDCC_mcs51)
34 #    if defined(SDCC_MODEL_SMALL)
35 #      if defined(SDCC_STACK_AUTO) && !defined (SDCC_PARMS_IN_BANK1)
36 #        define _MODULONG_ASM_SMALL_AUTO
37 #      else
38 #        define _MODULONG_ASM_SMALL
39 #      endif
40 #    endif
41 #  endif
42 #endif
43
44 #if defined _MODULONG_ASM_SMALL
45
46 static void
47 _modlong_dummy (void) __naked
48 {
49         __asm
50
51         .globl __modulong
52
53         #define a0      dpl
54         #define a1      dph
55         #define a2      b
56         #define a3      r1
57         #define count   r0
58
59 __modulong:
60 #if defined(SDCC_PARMS_IN_BANK1)
61         #define b0      (b1_0)
62         #define b1      (b1_1)
63         #define b2      (b1_2)
64         #define b3      (b1_3)
65 #else
66 #if defined(SDCC_NOOVERLAY)
67         .area DSEG    (DATA)
68 #else
69         .area OSEG    (OVR,DATA)
70 #endif
71
72         .globl __modulong_PARM_2
73         .globl __modslong_PARM_2
74
75 __modulong_PARM_2:
76 __modslong_PARM_2:
77         .ds     4
78
79         .area CSEG    (CODE)
80
81         #define b0      (__modulong_PARM_2)
82         #define b1      (__modulong_PARM_2 + 1)
83         #define b2      (__modulong_PARM_2 + 2)
84         #define b3      (__modulong_PARM_2 + 3)
85 #endif
86                                 ; parameter a comes in a, b, dph, dpl
87         mov     a3,a            ; save parameter a3
88
89         mov     a,b0            ; b == 0? avoid endless loop
90         orl     a,b1
91         orl     a,b2
92         orl     a,b3
93         jz      div_by_0
94
95         mov     count,#0
96         clr     c               ; when loop1 jumps immediately to loop2
97
98 loop1:  inc     count
99
100         mov     a,b3            ; if (!MSB_SET(b))
101         jb      acc.7,loop2
102
103         mov     a,b0            ; b <<= 1
104         add     a,acc
105         mov     b0,a
106         mov     a,b1
107         rlc     a
108         mov     b1,a
109         mov     a,b2
110         rlc     a
111         mov     b2,a
112         mov     a,b3
113         rlc     a
114         mov     b3,a
115
116         mov     a,a0            ; a - b
117         subb    a,b0            ; here carry is always clear
118         mov     a,a1
119         subb    a,b1
120         mov     a,a2
121         subb    a,b2
122         mov     a,a3
123         subb    a,b3
124
125         jnc     loop1
126
127
128         clr     c
129         mov     a,b3            ; b >>= 1;
130         rrc     a
131         mov     b3,a
132         mov     a,b2
133         rrc     a
134         mov     b2,a
135         mov     a,b1
136         rrc     a
137         mov     b1,a
138         mov     a,b0
139         rrc     a
140         mov     b0,a
141
142 loop2:  ; clr   c                 never set
143         mov     a,a0            ; a - b
144         subb    a,b0
145         mov     r4,a
146         mov     a,a1
147         subb    a,b1
148         mov     r5,a
149         mov     a,a2
150         subb    a,b2
151         mov     r6,a
152         mov     a,a3
153         subb    a,b3
154
155         jc      smaller         ; a >= b?
156
157         mov     a3,a            ; -> yes;  a = a - b;
158         mov     a2,r6
159         mov     a1,r5
160         mov     a0,r4
161 smaller:                        ; -> no
162         clr     c
163         mov     a,b3            ; b >>= 1;
164         rrc     a
165         mov     b3,a
166         mov     a,b2
167         rrc     a
168         mov     b2,a
169         mov     a,b1
170         rrc     a
171         mov     b1,a
172         mov     a,b0
173         rrc     a
174         mov     b0,a
175
176         djnz    count,loop2
177
178         mov     a,a3            ; prepare the return value
179 div_by_0:
180         ret
181
182         __endasm;
183 }
184
185 #elif defined _MODULONG_ASM_SMALL_AUTO
186
187 static void
188 _modlong_dummy (void) __naked
189 {
190         __asm
191
192         .globl __modulong
193
194 __modulong:
195
196         #define count   r0
197
198         #define a0      dpl
199         #define a1      dph
200         #define a2      b
201         #define a3      r1
202
203         #define b0      r2
204         #define b1      r3
205         #define b2      r4
206         #define b3      r5
207
208         ar2 = 2                 ; BUG register set is not considered
209         ar3 = 3
210         ar4 = 4
211         ar5 = 5
212
213         .globl __modlong        ; entry point for __modslong
214
215                                 ; parameter a comes in a, b, dph, dpl
216         mov     a3,a            ; save parameter a3
217
218         mov     a,sp
219         add     a,#-2-3         ; 2 bytes return address, 3 bytes param b
220         mov     r0,a            ; r1 points to b0
221
222         mov     ar2,@r0         ; load b0
223         inc     r0              ; r0 points to b1
224         mov     ar3,@r0         ; b1
225         inc     r0
226         mov     ar4,@r0         ; b2
227         inc     r0
228         mov     ar5,@r0         ; b3
229
230 __modlong:                      ; entry point for __modslong
231                                 ; a in r1, b, dph, dpl
232                                 ; b in r5, r4, r3, r2 
233
234         mov     count,#0
235
236         mov     a,b0            ; b == 0? avoid endless loop
237         orl     a,b1
238         orl     a,b2
239         orl     a,b3
240         jz      div_by_0
241
242         mov     count,#0
243         clr     c               ; when loop1 jumps immediately to loop2
244
245 loop1:  inc     count
246
247         mov     a,b3            ; if (!MSB_SET(b))
248         jb      acc.7,loop2
249
250         mov     a,b0            ; b <<= 1
251         add     a,acc
252         mov     b0,a
253         mov     a,b1
254         rlc     a
255         mov     b1,a
256         mov     a,b2
257         rlc     a
258         mov     b2,a
259         mov     a,b3
260         rlc     a
261         mov     b3,a
262
263         mov     a,a0            ; a - b
264         subb    a,b0            ; here carry is always clear
265         mov     a,a1
266         subb    a,b1
267         mov     a,a2
268         subb    a,b2
269         mov     a,a3
270         subb    a,b3
271
272         jnc     loop1
273
274         clr     c
275         mov     a,b3            ; b >>= 1;
276         rrc     a
277         mov     b3,a
278         mov     a,b2
279         rrc     a
280         mov     b2,a
281         mov     a,b1
282         rrc     a
283         mov     b1,a
284         mov     a,b0
285         rrc     a
286         mov     b0,a
287
288 loop2:  ; clr   c                 never set
289         mov     a,a0            ; a - b
290         subb    a,b0
291         mov     a,a1
292         subb    a,b1
293         mov     r6,a            ; d1
294         mov     a,a2
295         subb    a,b2
296         mov     r7,a            ; d2
297         mov     a,a3
298         subb    a,b3
299
300         jc      smaller         ; a >= b?
301
302         mov     a3,a            ; -> yes;  a = a - b;
303         mov     a2,r7
304         mov     a1,r6
305         mov     a,a0
306         subb    a,b0
307         mov     a0,a
308 smaller:                        ; -> no
309         clr     c
310         mov     a,b3            ; b >>= 1;
311         rrc     a
312         mov     b3,a
313         mov     a,b2
314         rrc     a
315         mov     b2,a
316         mov     a,b1
317         rrc     a
318         mov     b1,a
319         mov     a,b0
320         rrc     a
321         mov     b0,a
322
323         djnz    count,loop2
324
325         mov     a,a3            ; prepare the return value
326 div_by_0:
327         ret
328
329         __endasm;
330 }
331
332 #else // _MODULONG_ASM
333
334 #define MSB_SET(x) ((x >> (8*sizeof(x)-1)) & 1)
335
336 unsigned long
337 _modulong (unsigned long a, unsigned long b)
338 {
339   unsigned char count = 0;
340
341   while (!MSB_SET(b))
342   {
343      b <<= 1;
344      if (b > a)
345      {
346         b >>=1;
347         break;
348      }
349      count++;
350   }
351   do
352   {
353     if (a >= b)
354       a -= b;
355     b >>= 1;
356   }
357   while (count--);
358
359   return a;
360 }
361
362 #endif // _MODULONG_ASM