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