94d8e9f403852ed0fc7f9d7de4182480dfdf7002
[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 #if !defined(SDCC_USE_XSTACK) && !defined(_SDCC_NO_ASM_LIB_FUNCS)
31 #  if defined(SDCC_mcs51)
32 #    if defined(SDCC_MODEL_SMALL)
33 #      if defined(SDCC_STACK_AUTO) && !defined(SDCC_PARMS_IN_BANK1)
34 #        define _DIVULONG_ASM_SMALL_AUTO
35 #      else
36 #        define _DIVULONG_ASM_SMALL
37 #      endif
38 #    endif
39 #  endif
40 #endif
41
42 #if defined _DIVULONG_ASM_SMALL
43
44 static void
45 _divlong_dummy (void) _naked
46 {
47         _asm
48
49                 .globl __divulong
50
51         __divulong:
52
53                 #define count   r2
54
55                 #define a0      dpl
56                 #define a1      dph
57                 #define a2      b
58                 #define a3      r3
59
60                 #define reste0  r4
61                 #define reste1  r5
62                 #define reste2  r6
63                 #define reste3  r7
64 #if !defined(SDCC_PARMS_IN_BANK1)
65
66 #if defined(SDCC_NOOVERLAY)
67                 .area DSEG    (DATA)
68 #else
69                 .area OSEG    (OVR,DATA)
70 #endif
71
72                 .globl __divulong_PARM_2
73                 .globl __divslong_PARM_2
74
75         __divulong_PARM_2:
76         __divslong_PARM_2:
77                 .ds     4
78
79                 .area CSEG    (CODE)
80
81                 #define b0      (__divulong_PARM_2)
82                 #define b1      (__divulong_PARM_2 + 1)
83                 #define b2      (__divulong_PARM_2 + 2)
84                 #define b3      (__divulong_PARM_2 + 3)
85 #else
86                 #define b0      (b1_0)
87                 #define b1      (b1_1)
88                 #define b2      (b1_2)
89                 #define b3      (b1_3)
90 #endif // !SDCC_PARMS_IN_BANK1
91                                         ; parameter a comes in a, b, dph, dpl
92                 mov     a3,a            ; save parameter a3
93
94                 mov     count,#32
95                 clr     a
96                 mov     reste0,a
97                 mov     reste1,a
98                 mov     reste2,a
99                 mov     reste3,a
100
101         ; optimization  loop in lp0 until the first bit is shifted into rest
102
103         lp0:    mov     a,a0            ; a <<= 1
104                 add     a,a0
105                 mov     a0,a
106                 mov     a,a1
107                 rlc     a
108                 mov     a1,a
109                 mov     a,a2
110                 rlc     a
111                 mov     a2,a
112                 mov     a,a3
113                 rlc     a
114                 mov     a3,a
115
116                 jc      in_lp
117                 djnz    count,lp0
118
119                 sjmp    exit
120
121         loop:   mov     a,a0            ; a <<= 1
122                 add     a,a0
123                 mov     a0,a
124                 mov     a,a1
125                 rlc     a
126                 mov     a1,a
127                 mov     a,a2
128                 rlc     a
129                 mov     a2,a
130                 mov     a,a3
131                 rlc     a
132                 mov     a3,a
133
134         in_lp:  mov     a,reste0        ; reste <<= 1
135                 rlc     a               ;   feed in carry
136                 mov     reste0,a
137                 mov     a,reste1
138                 rlc     a
139                 mov     reste1,a
140                 mov     a,reste2
141                 rlc     a
142                 mov     reste2,a
143                 mov     a,reste3
144                 rlc     a
145                 mov     reste3,a
146
147                 mov     a,reste0        ; reste - b
148                 subb    a,b0            ; carry is always clear here, because
149                                         ; reste <<= 1 never overflows
150                 mov     a,reste1
151                 subb    a,b1
152                 mov     a,reste2
153                 subb    a,b2
154                 mov     a,reste3
155                 subb    a,b3
156
157                 jc      minus           ; reste >= b?
158
159                                         ; -> yes;  reste -= b;
160                 mov     a,reste0
161                 subb    a,b0            ; carry is always clear here (jc)
162                 mov     reste0,a
163                 mov     a,reste1
164                 subb    a,b1
165                 mov     reste1,a
166                 mov     a,reste2
167                 subb    a,b2
168                 mov     reste2,a
169                 mov     a,reste3
170                 subb    a,b3
171                 mov     reste3,a
172
173                 orl     a0,#1
174
175         minus:  djnz    count,loop      ; -> no
176
177         exit:   mov     a,a3            ; prepare the return value
178                 ret
179
180         _endasm ;
181 }
182
183 #elif defined _DIVULONG_ASM_SMALL_AUTO
184
185 static void
186 _divlong_dummy (void) _naked
187 {
188         _asm
189
190                 .globl __divulong
191
192         __divulong:
193
194                 #define count   r2
195
196                 #define a0      dpl
197                 #define a1      dph
198                 #define a2      b
199                 #define a3      r3
200
201                 #define reste0  r4
202                 #define reste1  r5
203                 #define reste2  r6
204                 #define reste3  r7
205
206                 .globl __divlong        ; entry point for __divslong
207
208                 #define b0      r1
209
210                 ar0 = 0                 ; BUG register set is not considered
211                 ar1 = 1
212
213                                         ; parameter a comes in a, b, dph, dpl
214                 mov     a3,a            ; save parameter a3
215
216                 mov     a,sp
217                 add     a,#-2-3         ; 2 bytes return address, 3 bytes param b
218                 mov     r0,a            ; r0 points to b0
219
220         __divlong:                      ; entry point for __divslong
221
222                 mov     ar1,@r0         ; load b0
223                 inc     r0              ; r0 points to b1
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,a0            ; a <<= 1
235                 add     a,a0
236                 mov     a0,a
237                 mov     a,a1
238                 rlc     a
239                 mov     a1,a
240                 mov     a,a2
241                 rlc     a
242                 mov     a2,a
243                 mov     a,a3
244                 rlc     a
245                 mov     a3,a
246
247                 jc      in_lp
248                 djnz    count,lp0
249
250                 sjmp    exit
251
252         loop:   mov     a,a0            ; a <<= 1
253                 add     a,a0
254                 mov     a0,a
255                 mov     a,a1
256                 rlc     a
257                 mov     a1,a
258                 mov     a,a2
259                 rlc     a
260                 mov     a2,a
261                 mov     a,a3
262                 rlc     a
263                 mov     a3,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 - b
279                 subb    a,b0            ; carry is always clear here, because
280                                         ; reste <<= 1 never overflows
281                 mov     a,reste1
282                 subb    a,@r0           ; b1
283                 mov     a,reste2
284                 inc     r0
285                 subb    a,@r0           ; b2
286                 mov     a,reste3
287                 inc     r0
288                 subb    a,@r0           ; b3
289                 dec     r0
290                 dec     r0
291
292                 jc      minus           ; reste >= b?
293
294                                         ; -> yes;  reste -= b;
295                 mov     a,reste0
296                 subb    a,b0            ; carry is always clear here (jc)
297                 mov     reste0,a
298                 mov     a,reste1
299                 subb    a,@r0           ; b1
300                 mov     reste1,a
301                 mov     a,reste2
302                 inc     r0
303                 subb    a,@r0           ; b2
304                 mov     reste2,a
305                 mov     a,reste3
306                 inc     r0
307                 subb    a,@r0           ; b3
308                 mov     reste3,a
309                 dec     r0
310                 dec     r0
311
312                 orl     a0,#1
313
314         minus:  djnz    count,loop      ; -> no
315
316         exit:   mov     a,a3            ; 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 a, unsigned long b)
328 {
329   unsigned long reste = 0L;
330   unsigned char count = 32;
331   #if defined(SDCC_STACK_AUTO) || defined(SDCC_z80)
332     char c;
333   #else
334     bit c;
335   #endif
336
337   do
338   {
339     // reste: a <- 0;
340     c = MSB_SET(a);
341     a <<= 1;
342     reste <<= 1;
343     if (c)
344       reste |= 1L;
345
346     if (reste >= b)
347     {
348       reste -= b;
349       // a <- (result = 1)
350       a |= 1L;
351     }
352   }
353   while (--count);
354   return a;
355 }
356
357 #endif // _DIVULONG_ASM