* src/device/lib/_mulint.c : new, with assember functions
[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 #ifdef SDCC_STACK_AUTO
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_NOOVERLAY)             // BUG SDCC_NOOVERLAY is not set by -no-overlay
82                 .area DSEG    (DATA)
83 #else
84                 .area OSEG    (OVR,DATA)
85 #endif
86
87                 .globl __divuint_PARM_2
88                 .globl __divsint_PARM_2
89
90         __divuint_PARM_2:
91         __divsint_PARM_2:
92                 .ds     2
93
94                 .area CSEG    (CODE)
95
96                 #define bl      (__divuint_PARM_2)
97                 #define bh      (__divuint_PARM_2 + 1)
98
99 #endif // SDCC_STACK_AUTO
100
101                 mov     count,#16
102                 clr     a
103                 mov     reste_l,a
104                 mov     reste_h,a
105
106         loop:   mov     a,al            ; a <<= 1
107                 add     a,acc
108                 mov     al,a
109                 mov     a,ah
110                 rlc     a
111                 mov     ah,a
112
113                 mov     a,reste_l       ; reste <<= 1
114                 rlc     a               ;   feed in carry
115                 mov     reste_l,a
116                 mov     a,reste_h
117                 rlc     a
118                 mov     reste_h,a
119
120                 mov     a,reste_l       ; reste - b
121                 subb    a,bl            ; here carry is always clear, because
122                                         ; reste <<= 1 never overflows
123                 mov     b,a
124                 mov     a,reste_h
125                 subb    a,bh
126
127                 jc      smaller         ; reste >= b?
128
129                 mov     reste_h,a       ; -> yes;  reste = reste - b;
130                 mov     reste_l,b
131                 orl     al,#1
132         smaller:                        ; -> no
133                 djnz    count,loop
134                 ret
135
136         _endasm ;
137 }
138
139 #else  // defined _DIVUINT_ASM_SMALL || defined _DIVUINT_ASM_SMALL_AUTO
140
141 #define MSB_SET(x) ((x >> (8*sizeof(x)-1)) & 1)
142
143 unsigned int
144 _divuint (unsigned int a, unsigned int b)
145 {
146   unsigned int reste = 0;
147   unsigned char count = 16;
148   #if defined(SDCC_STACK_AUTO) || defined(SDCC_z80)
149     char c;
150   #else
151     bit c;
152   #endif
153
154   do
155   {
156     // reste: a <- 0;
157     c = MSB_SET(a);
158     a <<= 1;
159     reste <<= 1;
160     if (c)
161       reste |= 1;
162
163     if (reste >= b)
164     {
165       reste -= b;
166       // a <- (result = 1)
167       a |= 1;
168     }
169   }
170   while (--count);
171   return a;
172 }
173
174 #endif  // defined _DIVUINT_ASM_SMALL || defined _DIVUINT_ASM_SMALL_AUTO