* sdcc/device/lib/Makefile.in: added library sources for mcs51, small,
[fw/sdcc] / device / lib / _divulong.c
1 /*-------------------------------------------------------------------------
2    _divulong.c - routine for division of 32 bit unsigned long
3
4              Ecrit par -  Jean-Louis Vern . jlvern@writeme.com (1999)
5
6    This library is free software; you can redistribute it and/or modify it
7    under the terms of the GNU Library General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20    In other words, you are welcome to use, share and improve this program.
21    You are forbidden to forbid anyone else to use, share and improve
22    what you give them.   Help stamp out software-hoarding!
23 -------------------------------------------------------------------------*/
24
25 /*   Assembler-functions are provided for:
26      mcs51 small
27      mcs51 small stack-auto
28 */
29
30 #include <stdbool.h>
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 _DIVULONG_ASM_SMALL_AUTO
37 #      else
38 #        define _DIVULONG_ASM_SMALL
39 #      endif
40 #    endif
41 #  endif
42 #endif
43
44 #if defined _DIVULONG_ASM_SMALL
45
46 static void
47 _divlong_dummy (void) _naked
48 {
49         _asm
50
51                 .globl __divulong
52
53         __divulong:
54
55                 #define count   r2
56
57                 #define a0      dpl
58                 #define a1      dph
59                 #define a2      b
60                 #define a3      r3
61
62                 #define reste0  r4
63                 #define reste1  r5
64                 #define reste2  r6
65                 #define reste3  r7
66 #if !defined(SDCC_PARMS_IN_BANK1)
67
68 #if defined(SDCC_NOOVERLAY)
69                 .area DSEG    (DATA)
70 #else
71                 .area OSEG    (OVR,DATA)
72 #endif
73
74                 .globl __divulong_PARM_2
75                 .globl __divslong_PARM_2
76
77         __divulong_PARM_2:
78         __divslong_PARM_2:
79                 .ds     4
80
81                 .area CSEG    (CODE)
82
83                 #define b0      (__divulong_PARM_2)
84                 #define b1      (__divulong_PARM_2 + 1)
85                 #define b2      (__divulong_PARM_2 + 2)
86                 #define b3      (__divulong_PARM_2 + 3)
87 #else
88                 #define b0      (b1_0)
89                 #define b1      (b1_1)
90                 #define b2      (b1_2)
91                 #define b3      (b1_3)
92 #endif // !SDCC_PARMS_IN_BANK1
93                                         ; parameter a comes in a, b, dph, dpl
94                 mov     a3,a            ; save parameter a3
95
96                 mov     count,#32
97                 clr     a
98                 mov     reste0,a
99                 mov     reste1,a
100                 mov     reste2,a
101                 mov     reste3,a
102
103         ; optimization  loop in lp0 until the first bit is shifted into rest
104
105         lp0:    mov     a,a0            ; a <<= 1
106                 add     a,a0
107                 mov     a0,a
108                 mov     a,a1
109                 rlc     a
110                 mov     a1,a
111                 mov     a,a2
112                 rlc     a
113                 mov     a2,a
114                 mov     a,a3
115                 rlc     a
116                 mov     a3,a
117
118                 jc      in_lp
119                 djnz    count,lp0
120
121                 sjmp    exit
122
123         loop:   mov     a,a0            ; a <<= 1
124                 add     a,a0
125                 mov     a0,a
126                 mov     a,a1
127                 rlc     a
128                 mov     a1,a
129                 mov     a,a2
130                 rlc     a
131                 mov     a2,a
132                 mov     a,a3
133                 rlc     a
134                 mov     a3,a
135
136         in_lp:  mov     a,reste0        ; reste <<= 1
137                 rlc     a               ;   feed in carry
138                 mov     reste0,a
139                 mov     a,reste1
140                 rlc     a
141                 mov     reste1,a
142                 mov     a,reste2
143                 rlc     a
144                 mov     reste2,a
145                 mov     a,reste3
146                 rlc     a
147                 mov     reste3,a
148
149                 mov     a,reste0        ; reste - b
150                 subb    a,b0            ; carry is always clear here, because
151                                         ; reste <<= 1 never overflows
152                 mov     a,reste1
153                 subb    a,b1
154                 mov     a,reste2
155                 subb    a,b2
156                 mov     a,reste3
157                 subb    a,b3
158
159                 jc      minus           ; reste >= b?
160
161                                         ; -> yes;  reste -= b;
162                 mov     a,reste0
163                 subb    a,b0            ; carry is always clear here (jc)
164                 mov     reste0,a
165                 mov     a,reste1
166                 subb    a,b1
167                 mov     reste1,a
168                 mov     a,reste2
169                 subb    a,b2
170                 mov     reste2,a
171                 mov     a,reste3
172                 subb    a,b3
173                 mov     reste3,a
174
175                 orl     a0,#1
176
177         minus:  djnz    count,loop      ; -> no
178
179         exit:   mov     a,a3            ; prepare the return value
180                 ret
181
182         _endasm ;
183 }
184
185 #elif defined _DIVULONG_ASM_SMALL_AUTO
186
187 static void
188 _divlong_dummy (void) _naked
189 {
190         _asm
191
192                 .globl __divulong
193
194         __divulong:
195
196                 #define count   r2
197
198                 #define a0      dpl
199                 #define a1      dph
200                 #define a2      b
201                 #define a3      r3
202
203                 #define reste0  r4
204                 #define reste1  r5
205                 #define reste2  r6
206                 #define reste3  r7
207
208                 .globl __divlong        ; entry point for __divslong
209
210                 #define b0      r1
211
212                 ar0 = 0                 ; BUG register set is not considered
213                 ar1 = 1
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            ; r0 points to b0
221
222         __divlong:                      ; entry point for __divslong
223
224                 mov     ar1,@r0         ; load b0
225                 inc     r0              ; r0 points to b1
226
227                 mov     count,#32
228                 clr     a
229                 mov     reste0,a
230                 mov     reste1,a
231                 mov     reste2,a
232                 mov     reste3,a
233
234         ; optimization  loop in lp0 until the first bit is shifted into rest
235
236         lp0:    mov     a,a0            ; a <<= 1
237                 add     a,a0
238                 mov     a0,a
239                 mov     a,a1
240                 rlc     a
241                 mov     a1,a
242                 mov     a,a2
243                 rlc     a
244                 mov     a2,a
245                 mov     a,a3
246                 rlc     a
247                 mov     a3,a
248
249                 jc      in_lp
250                 djnz    count,lp0
251
252                 sjmp    exit
253
254         loop:   mov     a,a0            ; a <<= 1
255                 add     a,a0
256                 mov     a0,a
257                 mov     a,a1
258                 rlc     a
259                 mov     a1,a
260                 mov     a,a2
261                 rlc     a
262                 mov     a2,a
263                 mov     a,a3
264                 rlc     a
265                 mov     a3,a
266
267         in_lp:  mov     a,reste0        ; reste <<= 1
268                 rlc     a               ;   feed in carry
269                 mov     reste0,a
270                 mov     a,reste1
271                 rlc     a
272                 mov     reste1,a
273                 mov     a,reste2
274                 rlc     a
275                 mov     reste2,a
276                 mov     a,reste3
277                 rlc     a
278                 mov     reste3,a
279
280                 mov     a,reste0        ; reste - b
281                 subb    a,b0            ; carry is always clear here, because
282                                         ; reste <<= 1 never overflows
283                 mov     a,reste1
284                 subb    a,@r0           ; b1
285                 mov     a,reste2
286                 inc     r0
287                 subb    a,@r0           ; b2
288                 mov     a,reste3
289                 inc     r0
290                 subb    a,@r0           ; b3
291                 dec     r0
292                 dec     r0
293
294                 jc      minus           ; reste >= b?
295
296                                         ; -> yes;  reste -= b;
297                 mov     a,reste0
298                 subb    a,b0            ; carry is always clear here (jc)
299                 mov     reste0,a
300                 mov     a,reste1
301                 subb    a,@r0           ; b1
302                 mov     reste1,a
303                 mov     a,reste2
304                 inc     r0
305                 subb    a,@r0           ; b2
306                 mov     reste2,a
307                 mov     a,reste3
308                 inc     r0
309                 subb    a,@r0           ; b3
310                 mov     reste3,a
311                 dec     r0
312                 dec     r0
313
314                 orl     a0,#1
315
316         minus:  djnz    count,loop      ; -> no
317
318         exit:   mov     a,a3            ; prepare the return value
319                 ret
320
321         _endasm ;
322 }
323
324 #else // _DIVULONG_ASM
325
326 #define MSB_SET(x) ((x >> (8*sizeof(x)-1)) & 1)
327
328 unsigned long
329 _divulong (unsigned long a, unsigned long b)
330 {
331   unsigned long reste = 0L;
332   unsigned char count = 32;
333   BOOL c;
334
335   do
336   {
337     // reste: a <- 0;
338     c = MSB_SET(a);
339     a <<= 1;
340     reste <<= 1;
341     if (c)
342       reste |= 1L;
343
344     if (reste >= b)
345     {
346       reste -= b;
347       // a <- (result = 1)
348       a |= 1L;
349     }
350   }
351   while (--count);
352   return a;
353 }
354
355 #endif // _DIVULONG_ASM