Imported Upstream version 2.9.0
[debian/cc1111] / device / lib / hc08 / _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   char c;
332
333   do
334   {
335     // reste: a <- 0;
336     c = MSB_SET(a);
337     a <<= 1;
338     reste <<= 1;
339     if (c)
340       reste |= 1L;
341
342     if (reste >= b)
343     {
344       reste -= b;
345       // a <- (result = 1)
346       a |= 1L;
347     }
348   }
349   while (--count);
350   return a;
351 }
352
353 #endif // _DIVULONG_ASM