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