387585c02b16b67075decfc889f76c969ac268f4
[fw/sdcc] / device / lib / _mulint.c
1 /*-------------------------------------------------------------------------
2   _mulint.c :- routine for (unsigned) int (16 bit) multiplication
3
4              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (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 /* Signed and unsigned multiplication are the same - as long as the output
26    has the same precision as the input.
27
28    Assembler-functions are provided for:
29      ds390
30      mcs51 small
31      mcs51 small stack-auto
32      mcs51 large
33 */
34
35 #if !defined(SDCC_USE_XSTACK) && !defined(_SDCC_NO_ASM_LIB_FUNCS)
36 #  if defined(SDCC_ds390)
37 #    if !defined(SDCC_STACK_AUTO)
38 #      define _MULINT_ASM_LARGE
39 #    endif
40 #  elif defined(SDCC_mcs51)
41 #    if defined(SDCC_MODEL_SMALL)
42 #      if defined(SDCC_STACK_AUTO) && !defined(SDCC_PARMS_IN_BANK1)
43 #        define _MULINT_ASM_SMALL_AUTO
44 #      else
45 #        define _MULINT_ASM_SMALL
46 #      endif
47 #    else // must be SDCC_MODEL_LARGE
48 #      if !defined(SDCC_STACK_AUTO)
49 #        define _MULINT_ASM_LARGE
50 #     endif
51 #   endif
52 #  endif
53 #endif
54
55 #if defined(_MULINT_ASM_LARGE)
56
57 #pragma save
58 #pragma less_pedantic
59 int
60 _mulint (int a, int b)
61 {
62   a*b; // hush the compiler
63
64   /* mulint=
65       (int)(lsb_a*lsb_b) +
66       (char)(msb_a*lsb_b)<<8 +
67       (char)(lsb_a*msb_b)<<8
68   */
69
70   _asm
71     mov r2,dph ; msb_a
72     mov r3,dpl ; lsb_a
73
74     mov b,r3 ; lsb_a
75 #if defined(SDCC_PARMS_IN_BANK1)
76     mov a,b1_0
77 #else
78     mov dptr,#__mulint_PARM_2
79     movx a,@dptr ; lsb_b
80 #endif
81     mul ab ; lsb_a*lsb_b
82     mov r0,a
83     mov r1,b
84
85     mov b,r2 ; msb_a
86 #if defined(SDCC_PARMS_IN_BANK1)
87     mov a,b1_0
88 #else
89     movx a,@dptr ; lsb_b
90 #endif
91     mul ab ; msb_a*lsb_b
92     add a,r1
93     mov r1,a
94
95     mov b,r3 ; lsb_a
96 #if defined(SDCC_PARMS_IN_BANK1)
97     mov a,b1_1
98 #else
99     inc dptr
100     movx a,@dptr ; msb_b
101 #endif
102     mul ab ; lsb_a*msb_b
103     add a,r1
104
105     mov dph,a
106     mov dpl,r0
107     ret
108   _endasm;
109 }
110 #pragma restore
111
112 #elif defined(_MULINT_ASM_SMALL) || defined(_MULINT_ASM_SMALL_AUTO)
113
114 #pragma save
115 #pragma less_pedantic
116 int
117 _mulint_dummy (void) _naked
118 {
119         _asm
120
121         __mulint:
122
123                 .globl __mulint
124
125 #if !defined(SDCC_STACK_AUTO) || defined(SDCC_PARMS_IN_BANK1)
126
127 #if defined(SDCC_NOOVERLAY)
128                 .area DSEG    (DATA)
129 #else
130                 .area OSEG    (OVR,DATA)
131 #endif
132 #if defined(SDCC_PARMS_IN_BANK1)
133         #define bl      (b1_0)
134         #define bh      (b1_1)
135 #else
136         #define bl      (__mulint_PARM_2)
137         #define bh      (__mulint_PARM_2 + 1)
138         __mulint_PARM_2:
139
140                 .globl __mulint_PARM_2
141
142                 .ds     2
143 #endif
144
145                 .area CSEG    (CODE)
146
147                 ; globbered registers none
148
149                 mov     a,dpl                   ;  1  al
150                 mov     b,bl                    ;  2  bl
151                 mul     ab                      ;  4  al * bl
152                 xch     a,dpl                   ;  1  store low-byte of return value, fetch al
153                 push    b                       ;  2
154
155                 mov     b,bh                    ;  2  bh
156                 mul     ab                      ;  4  al * bh
157                 pop     b                       ;  2
158                 add     a,b                     ;  1
159                 xch     a,dph                   ;  1  ah -> acc
160
161                 mov     b,bl                    ;  2  bl
162                 mul     ab                      ;  4  ah * bl
163                 add     a,dph                   ;  1
164                 mov     dph,a                   ;  1
165                 ret                             ;  2
166                                                 ; 30
167
168 #else // SDCC_STACK_AUTO
169
170                 ; globbered registers r0
171
172                 mov     a,#-2                   ;  1  return address 2 bytes
173                 add     a,sp                    ;  1
174                 mov     r0,a                    ;  1  r0 points to bh
175
176                 mov     a,@r0                   ;  1  bh
177                 mov     b,dpl                   ;  2  al
178                 mul     ab                      ;  4  al * bh
179                 push    acc                     ;  2
180
181                 mov     b,dpl                   ;  2  al
182                 dec     r0                      ;  1
183                 mov     a,@r0                   ;  1  bl
184                 mul     ab                      ;  4  al * bl
185
186                 mov     dpl,a                   ;  1  low-byte of return-value
187
188                 pop     acc                     ;  2
189                 add     a,b                     ;  1
190                 xch     a,dph                   ;  1  ah -> acc
191
192                 mov     b,@r0                   ;  2  bl
193                 mul     ab                      ;  4  ah * bl
194                 add     a,dph                   ;  1
195                 mov     dph,a                   ;  1
196
197                 ret
198
199 #endif // SDCC_STACK_AUTO
200
201         _endasm ;
202 }
203 #pragma restore
204
205 #else
206
207 union uu {
208         struct { unsigned char lo,hi ;} s;
209         unsigned int t;
210 } ;
211
212 int
213 _mulint (int a, int b)
214 {
215 #if !defined(SDCC_STACK_AUTO) && (defined(SDCC_MODEL_LARGE) || defined(SDCC_ds390))     // still needed for large
216         union uu xdata *x;
217         union uu xdata *y;
218         union uu t;
219         x = (union uu xdata *)&a;
220         y = (union uu xdata *)&b;
221 #else
222         register union uu *x;
223         register union uu *y;
224         union uu t;
225         x = (union uu *)&a;
226         y = (union uu *)&b;
227 #endif
228
229         t.t = x->s.lo * y->s.lo;
230         t.s.hi += (x->s.lo * y->s.hi) + (x->s.hi * y->s.lo);
231
232        return t.t;
233 }
234
235 #endif
236
237 #undef _MULINT_ASM