9cb36f0e69df2aef9bc6a2f095dbd4eed3185a0f
[fw/sdcc] / device / lib / _divuint.c
1 /*-------------------------------------------------------------------------
2   _divuint.c :- routine for unsigned int (16 bit) division
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 _DIVUINT_ASM_SMALL_AUTO
35 #      else
36 #        define _DIVUINT_ASM_SMALL
37 #      endif
38 #    endif
39 #  endif
40 #endif
41
42 #if defined _DIVUINT_ASM_SMALL || defined _DIVUINT_ASM_SMALL_AUTO
43
44 static void
45 _divuint_dummy (void) _naked
46 {
47         _asm
48
49                 .globl __divuint
50
51         __divuint:
52
53                 #define count   r2
54                 #define reste_l r3
55                 #define reste_h r4
56                 #define al      dpl
57                 #define ah      dph
58
59 #if defined(SDCC_STACK_AUTO) && !defined(SDCC_PARMS_IN_BANK1)
60
61                 ar0 = 0                 ; BUG register set is not considered
62                 ar1 = 1
63
64                 .globl __divint
65
66                 mov     a,sp
67                 add     a,#-2           ; 2 bytes return address
68                 mov     r0,a            ; r0 points to bh
69                 mov     ar1,@r0         ; load bh
70                 dec     r0
71                 mov     ar0,@r0         ; load bl
72
73                 #define bl      r0
74                 #define bh      r1
75
76         __divint:                       ; entry point for __divsint
77
78
79 #else // SDCC_STACK_AUTO
80
81 #if !defined(SDCC_PARMS_IN_BANK1)
82 #if defined(SDCC_NOOVERLAY)
83                 .area DSEG    (DATA)
84 #else
85                 .area OSEG    (OVR,DATA)
86 #endif
87
88                 .globl __divuint_PARM_2
89                 .globl __divsint_PARM_2
90
91         __divuint_PARM_2:
92         __divsint_PARM_2:
93                 .ds     2
94
95                 .area CSEG    (CODE)
96 #endif // !SDCC_PARMS_IN_BANK1
97 #if defined(SDCC_PARMS_IN_BANK1)
98                 #define bl      (b1_0)
99                 #define bh      (b1_1)
100 #else
101                 #define bl      (__divuint_PARM_2)
102                 #define bh      (__divuint_PARM_2 + 1)
103 #endif // SDCC_PARMS_IN_BANK1
104 #endif // SDCC_STACK_AUTO
105
106                 mov     count,#16
107                 clr     a
108                 mov     reste_l,a
109                 mov     reste_h,a
110
111         loop:   mov     a,al            ; a <<= 1
112                 add     a,acc
113                 mov     al,a
114                 mov     a,ah
115                 rlc     a
116                 mov     ah,a
117
118                 mov     a,reste_l       ; reste <<= 1
119                 rlc     a               ;   feed in carry
120                 mov     reste_l,a
121                 mov     a,reste_h
122                 rlc     a
123                 mov     reste_h,a
124
125                 mov     a,reste_l       ; reste - b
126                 subb    a,bl            ; here carry is always clear, because
127                                         ; reste <<= 1 never overflows
128                 mov     b,a
129                 mov     a,reste_h
130                 subb    a,bh
131
132                 jc      smaller         ; reste >= b?
133
134                 mov     reste_h,a       ; -> yes;  reste = reste - b;
135                 mov     reste_l,b
136                 orl     al,#1
137         smaller:                        ; -> no
138                 djnz    count,loop
139                 ret
140
141         _endasm ;
142 }
143
144 #else  // defined _DIVUINT_ASM_SMALL || defined _DIVUINT_ASM_SMALL_AUTO
145
146 #define MSB_SET(x) ((x >> (8*sizeof(x)-1)) & 1)
147
148 unsigned int
149 _divuint (unsigned int a, unsigned int b)
150 {
151   unsigned int reste = 0;
152   unsigned char count = 16;
153   #if defined(SDCC_STACK_AUTO) || defined(SDCC_z80)
154     char c;
155   #else
156     bit c;
157   #endif
158
159   do
160   {
161     // reste: a <- 0;
162     c = MSB_SET(a);
163     a <<= 1;
164     reste <<= 1;
165     if (c)
166       reste |= 1;
167
168     if (reste >= b)
169     {
170       reste -= b;
171       // a <- (result = 1)
172       a |= 1;
173     }
174   }
175   while (--count);
176   return a;
177 }
178
179 #endif  // defined _DIVUINT_ASM_SMALL || defined _DIVUINT_ASM_SMALL_AUTO