53a2b87cc509d171d05b3e487bcdf5c920c12a29
[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 x0      dpl
58                 #define x1      dph
59                 #define x2      b
60                 #define x3      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 y0      (__divulong_PARM_2)
84                 #define y1      (__divulong_PARM_2 + 1)
85                 #define y2      (__divulong_PARM_2 + 2)
86                 #define y3      (__divulong_PARM_2 + 3)
87 #else
88                 #define y0      (b1_0)
89                 #define y1      (b1_1)
90                 #define y2      (b1_2)
91                 #define y3      (b1_3)
92 #endif // !SDCC_PARMS_IN_BANK1
93                                         ; parameter x comes in a, b, dph, dpl
94                 mov     x3,a            ; save parameter x3
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,x0            ; x <<= 1
106                 add     a,x0
107                 mov     x0,a
108                 mov     a,x1
109                 rlc     a
110                 mov     x1,a
111                 mov     a,x2
112                 rlc     a
113                 mov     x2,a
114                 mov     a,x3
115                 rlc     a
116                 mov     x3,a
117
118                 jc      in_lp
119                 djnz    count,lp0
120
121                 sjmp    exit
122
123         loop:   mov     a,x0            ; x <<= 1
124                 add     a,x0
125                 mov     x0,a
126                 mov     a,x1
127                 rlc     a
128                 mov     x1,a
129                 mov     a,x2
130                 rlc     a
131                 mov     x2,a
132                 mov     a,x3
133                 rlc     a
134                 mov     x3,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 - y
150                 subb    a,y0            ; carry is always clear here, because
151                                         ; reste <<= 1 never overflows
152                 mov     a,reste1
153                 subb    a,y1
154                 mov     a,reste2
155                 subb    a,y2
156                 mov     a,reste3
157                 subb    a,y3
158
159                 jc      minus           ; reste >= y?
160
161                                         ; -> yes;  reste -= y;
162                 mov     a,reste0
163                 subb    a,y0            ; carry is always clear here (jc)
164                 mov     reste0,a
165                 mov     a,reste1
166                 subb    a,y1
167                 mov     reste1,a
168                 mov     a,reste2
169                 subb    a,y2
170                 mov     reste2,a
171                 mov     a,reste3
172                 subb    a,y3
173                 mov     reste3,a
174
175                 orl     x0,#1
176
177         minus:  djnz    count,loop      ; -> no
178
179         exit:   mov     a,x3            ; 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 x0      dpl
199                 #define x1      dph
200                 #define x2      b
201                 #define x3      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 y0      r1
211
212                                         ; parameter x comes in a, b, dph, dpl
213                 mov     x3,a            ; save parameter x3
214
215                 mov     a,sp
216                 add     a,#-2-3         ; 2 bytes return address, 3 bytes param y
217                 mov     r0,a            ; r0 points to y0
218
219         __divlong:                      ; entry point for __divslong
220
221                 mov     a,@r0           ; load y0
222                 mov     r1,a
223                 inc     r0              ; r0 points to y1
224
225                 mov     count,#32
226                 clr     a
227                 mov     reste0,a
228                 mov     reste1,a
229                 mov     reste2,a
230                 mov     reste3,a
231
232         ; optimization  loop in lp0 until the first bit is shifted into rest
233
234         lp0:    mov     a,x0            ; x <<= 1
235                 add     a,x0
236                 mov     x0,a
237                 mov     a,x1
238                 rlc     a
239                 mov     x1,a
240                 mov     a,x2
241                 rlc     a
242                 mov     x2,a
243                 mov     a,x3
244                 rlc     a
245                 mov     x3,a
246
247                 jc      in_lp
248                 djnz    count,lp0
249
250                 sjmp    exit
251
252         loop:   mov     a,x0            ; x <<= 1
253                 add     a,x0
254                 mov     x0,a
255                 mov     a,x1
256                 rlc     a
257                 mov     x1,a
258                 mov     a,x2
259                 rlc     a
260                 mov     x2,a
261                 mov     a,x3
262                 rlc     a
263                 mov     x3,a
264
265         in_lp:  mov     a,reste0        ; reste <<= 1
266                 rlc     a               ;   feed in carry
267                 mov     reste0,a
268                 mov     a,reste1
269                 rlc     a
270                 mov     reste1,a
271                 mov     a,reste2
272                 rlc     a
273                 mov     reste2,a
274                 mov     a,reste3
275                 rlc     a
276                 mov     reste3,a
277
278                 mov     a,reste0        ; reste - y
279                 subb    a,y0            ; carry is always clear here, because
280                                         ; reste <<= 1 never overflows
281                 mov     a,reste1
282                 subb    a,@r0           ; y1
283                 mov     a,reste2
284                 inc     r0
285                 subb    a,@r0           ; y2
286                 mov     a,reste3
287                 inc     r0
288                 subb    a,@r0           ; y3
289                 dec     r0
290                 dec     r0
291
292                 jc      minus           ; reste >= y?
293
294                                         ; -> yes;  reste -= y;
295                 mov     a,reste0
296                 subb    a,y0            ; carry is always clear here (jc)
297                 mov     reste0,a
298                 mov     a,reste1
299                 subb    a,@r0           ; y1
300                 mov     reste1,a
301                 mov     a,reste2
302                 inc     r0
303                 subb    a,@r0           ; y2
304                 mov     reste2,a
305                 mov     a,reste3
306                 inc     r0
307                 subb    a,@r0           ; y3
308                 mov     reste3,a
309                 dec     r0
310                 dec     r0
311
312                 orl     x0,#1
313
314         minus:  djnz    count,loop      ; -> no
315
316         exit:   mov     a,x3            ; prepare the return value
317                 ret
318
319         _endasm ;
320 }
321
322 #else // _DIVULONG_ASM
323
324 #define MSB_SET(x) ((x >> (8*sizeof(x)-1)) & 1)
325
326 unsigned long
327 _divulong (unsigned long x, unsigned long y)
328 {
329   unsigned long reste = 0L;
330   unsigned char count = 32;
331   BOOL c;
332
333   do
334   {
335     // reste: x <- 0;
336     c = MSB_SET(x);
337     x <<= 1;
338     reste <<= 1;
339     if (c)
340       reste |= 1L;
341
342     if (reste >= y)
343     {
344       reste -= y;
345       // x <- (result = 1)
346       x |= 1L;
347     }
348   }
349   while (--count);
350   return x;
351 }
352
353 #endif // _DIVULONG_ASM