Imported Upstream version 2.9.0
[debian/cc1111] / 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