* configure.in: added missing mcs51 in status output
[fw/sdcc] / 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
82                 #define b0      (__modulong_PARM_2)
83                 #define b1      (__modulong_PARM_2 + 1)
84                 #define b2      (__modulong_PARM_2 + 2)
85                 #define b3      (__modulong_PARM_2 + 3)
86 #endif
87                                         ; parameter a comes in a, b, dph, dpl
88                 mov     a3,a            ; save parameter a3
89
90                 mov     a,b0            ; b == 0? avoid endless loop
91                 orl     a,b1
92                 orl     a,b2
93                 orl     a,b3
94                 jz      div_by_0
95
96                 mov     count,#0
97                 clr     c               ; when loop1 jumps immediately to loop2
98
99         loop1:  inc     count
100
101                 mov     a,b3            ; if (!MSB_SET(b))
102                 jb      acc.7,loop2
103
104                 mov     a,b0            ; b <<= 1
105                 add     a,acc
106                 mov     b0,a
107                 mov     a,b1
108                 rlc     a
109                 mov     b1,a
110                 mov     a,b2
111                 rlc     a
112                 mov     b2,a
113                 mov     a,b3
114                 rlc     a
115                 mov     b3,a
116
117                 mov     a,a0            ; a - b
118                 subb    a,b0            ; here carry is always clear
119                 mov     a,a1
120                 subb    a,b1
121                 mov     a,a2
122                 subb    a,b2
123                 mov     a,a3
124                 subb    a,b3
125
126                 jnc     loop1
127
128
129                 clr     c
130                 mov     a,b3            ; b >>= 1;
131                 rrc     a
132                 mov     b3,a
133                 mov     a,b2
134                 rrc     a
135                 mov     b2,a
136                 mov     a,b1
137                 rrc     a
138                 mov     b1,a
139                 mov     a,b0
140                 rrc     a
141                 mov     b0,a
142
143         loop2:  ; clr   c                 never set
144                 mov     a,a0            ; a - b
145                 subb    a,b0
146                 mov     r4,a
147                 mov     a,a1
148                 subb    a,b1
149                 mov     r5,a
150                 mov     a,a2
151                 subb    a,b2
152                 mov     r6,a
153                 mov     a,a3
154                 subb    a,b3
155
156                 jc      smaller         ; a >= b?
157
158                 mov     a3,a            ; -> yes;  a = a - b;
159                 mov     a2,r6
160                 mov     a1,r5
161                 mov     a0,r4
162         smaller:                        ; -> no
163                 clr     c
164                 mov     a,b3            ; b >>= 1;
165                 rrc     a
166                 mov     b3,a
167                 mov     a,b2
168                 rrc     a
169                 mov     b2,a
170                 mov     a,b1
171                 rrc     a
172                 mov     b1,a
173                 mov     a,b0
174                 rrc     a
175                 mov     b0,a
176
177                 djnz    count,loop2
178
179                 mov     a,a3            ; prepare the return value
180         div_by_0:
181                 ret
182
183         _endasm ;
184 }
185
186 #elif defined _MODULONG_ASM_SMALL_AUTO
187
188 static void
189 _modlong_dummy (void) _naked
190 {
191         _asm
192
193                 .globl __modulong
194
195         __modulong:
196
197                 #define count   r0
198
199                 #define a0      dpl
200                 #define a1      dph
201                 #define a2      b
202                 #define a3      r1
203
204                 #define b0      r2
205                 #define b1      r3
206                 #define b2      r4
207                 #define b3      r5
208
209                 ar2 = 2                 ; BUG register set is not considered
210                 ar3 = 3
211                 ar4 = 4
212                 ar5 = 5
213
214                 .globl __modlong        ; entry point for __modslong
215
216                                         ; parameter a comes in a, b, dph, dpl
217                 mov     a3,a            ; save parameter a3
218
219                 mov     a,sp
220                 add     a,#-2-3         ; 2 bytes return address, 3 bytes param b
221                 mov     r0,a            ; r1 points to b0
222
223
224                 mov     ar2,@r0         ; load b0
225                 inc     r0              ; r0 points to b1
226                 mov     ar3,@r0         ; b1
227                 inc     r0
228                 mov     ar4,@r0         ; b2
229                 inc     r0
230                 mov     ar5,@r0         ; b3
231
232         __modlong:                      ; entry point for __modslong
233                                         ; a in r1, b, dph, dpl
234                                         ; b in r5, r4, r3, r2 
235
236                 mov     count,#0
237
238                 mov     a,b0            ; b == 0? avoid endless loop
239                 orl     a,b1
240                 orl     a,b2
241                 orl     a,b3
242                 jz      div_by_0
243
244                 mov     count,#0
245                 clr     c               ; when loop1 jumps immediately to loop2
246
247         loop1:  inc     count
248
249                 mov     a,b3            ; if (!MSB_SET(b))
250                 jb      acc.7,loop2
251
252                 mov     a,b0            ; b <<= 1
253                 add     a,acc
254                 mov     b0,a
255                 mov     a,b1
256                 rlc     a
257                 mov     b1,a
258                 mov     a,b2
259                 rlc     a
260                 mov     b2,a
261                 mov     a,b3
262                 rlc     a
263                 mov     b3,a
264
265                 mov     a,a0            ; a - b
266                 subb    a,b0            ; here carry is always clear
267                 mov     a,a1
268                 subb    a,b1
269                 mov     a,a2
270                 subb    a,b2
271                 mov     a,a3
272                 subb    a,b3
273
274                 jnc     loop1
275
276
277                 clr     c
278                 mov     a,b3            ; b >>= 1;
279                 rrc     a
280                 mov     b3,a
281                 mov     a,b2
282                 rrc     a
283                 mov     b2,a
284                 mov     a,b1
285                 rrc     a
286                 mov     b1,a
287                 mov     a,b0
288                 rrc     a
289                 mov     b0,a
290
291         loop2:  ; clr   c                 never set
292                 mov     a,a0            ; a - b
293                 subb    a,b0
294                 mov     a,a1
295                 subb    a,b1
296                 mov     r6,a            ; d1
297                 mov     a,a2
298                 subb    a,b2
299                 mov     r7,a            ; d2
300                 mov     a,a3
301                 subb    a,b3
302
303                 jc      smaller         ; a >= b?
304
305                 mov     a3,a            ; -> yes;  a = a - b;
306                 mov     a2,r7
307                 mov     a1,r6
308                 mov     a,a0
309                 subb    a,b0
310                 mov     a0,a
311         smaller:                        ; -> no
312                 clr     c
313                 mov     a,b3            ; b >>= 1;
314                 rrc     a
315                 mov     b3,a
316                 mov     a,b2
317                 rrc     a
318                 mov     b2,a
319                 mov     a,b1
320                 rrc     a
321                 mov     b1,a
322                 mov     a,b0
323                 rrc     a
324                 mov     b0,a
325
326                 djnz    count,loop2
327
328                 mov     a,a3            ; prepare the return value
329         div_by_0:
330                 ret
331
332         _endasm ;
333 }
334
335 #else // _MODULONG_ASM
336
337 #define MSB_SET(x) ((x >> (8*sizeof(x)-1)) & 1)
338
339 unsigned long
340 _modulong (unsigned long a, unsigned long b)
341 {
342   unsigned char count = 0;
343
344   while (!MSB_SET(b))
345   {
346      b <<= 1;
347      if (b > a)
348      {
349         b >>=1;
350         break;
351      }
352      count++;
353   }
354   do
355   {
356     if (a >= b)
357       a -= b;
358     b >>= 1;
359   }
360   while (count--);
361
362   return a;
363 }
364
365 #endif // _MODULONG_ASM