Prepare for SDCC 4.5.0 release.
[sdcc.git] / sdcc / device / lib / printf_tiny.c
blob555f7cb4cf4f4a56e284f5e98b84687606008b96
1 /*-------------------------------------------------------------------------
2 printf_tiny.c - Tiny printf routine for use with sdcc/mcs51
4 Copyright (C) 2004, Paul Stoffregen, paul@pjrc.com
6 This library is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
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 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this library; see the file COPYING. If not, write to the
18 Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301, USA.
21 As a special exception, if you link this library with other files,
22 some of which are compiled with SDCC, to produce an executable,
23 this library does not by itself cause the resulting executable to
24 be covered by the GNU General Public License. This exception does
25 not however invalidate any other reasons why the executable file
26 might be covered by the GNU General Public License.
27 -------------------------------------------------------------------------*/
30 * This tiny printf uses minimal code space, and it is fully reentrant
31 * and register bank neutral (usually safe to call from within an
32 * interrupt routine). Code size is under 270 bytes. Only one library
33 * function is called (_gptrget, 41 bytes), in addition to calls to
34 * putchar().
36 * Five simple formats are supported
38 * %d signed 16 bit integer decimal (-32768 to 32767)
39 * %u unsigned 16 bit integer decimal (0 to 65535)
40 * %s string, takes a 24 bit generic pointer
41 * %c character. You must explicitly cast to char in SDCC
42 * %x 16 bit integer in hex (0 to FFFF)
44 * For a more complete printf that supports longs, floating point and
45 * field width, try using printf_fast() or printf_large().
49 /* This removes the negative number code, causing "%d" to be the same
50 as "%u". If you don't care about printing negative numbers, this
51 will save 21 bytes of code. */
52 /* #define ALWAYS_PRINT_UNSIGNED */
54 /* Directly output characters to the serial port using simple polling,
55 rather than calling putchar(). This saves 14 bytes, plus the size
56 of putchar. */
57 /* #define DIRECT_SERIAL_OUTPUT */
61 /* extern void putchar(char ); */
64 #define print_zero_flag PSW.5
67 #if !defined(__SDCC_mcs51) || defined(__SDCC_USE_XSTACK) || defined(_SDCC_NO_ASM_LIB_FUNCS)
68 /* Does printf_tiny really work on ds390 and ds400?
69 If it does, enable them in the line above */
70 #if defined(__SDCC_USE_XSTACK)
71 #warning "printf_tiny not built, does not support --xstack"
72 #elif defined(_SDCC_NO_ASM_LIB_FUNCS)
73 #warning "printf_tiny not built, _SDCC_NO_ASM_LIB_FUNCS defined"
74 #endif
75 /* Disable "ISO C forbids an empty source file" warning message */
76 #pragma disable_warning 190
77 #else /* defines are compatible with printf_tiny */
81 void printf_tiny(__code const char *fmt, ...) __reentrant
83 fmt; /* suppress unreferenced variable warning */
85 __asm
87 printf_begin:
88 mov a, _bp /* r0 will point to va_args (stack) */
89 add a, #253
90 mov r0, a /* r0 points to MSB of fmt */
91 mov dph, @r0
92 dec r0
93 mov dpl, @r0 /* dptr has address of fmt */
94 dec r0
97 printf_main_loop:
98 clr a
99 movc a, @a+dptr /* get next byte of fmt string */
100 inc dptr
101 add a, #256 - 37
102 jz printf_format /* check for '%' */
103 add a, #37
104 jz printf_end_h
105 lcall printf_putchar
106 sjmp printf_main_loop
107 printf_end_h:
108 ljmp printf_end
111 printf_format:
112 setb print_zero_flag
113 clr a
114 movc a, @a+dptr /* get next byte of data format */
115 inc dptr
116 push dph
117 push dpl
120 printf_format_s:
121 /*cjne a, #'s', printf_format_c*/
122 cjne a, #115, printf_format_c
123 printf_string:
124 /* print a string... just grab each byte with __gptrget */
125 /* the user much pass a 24 bit generic pointer */
126 mov b, @r0 /* b has type of address (generic *) */
127 dec r0
128 mov dph, @r0
129 dec r0
130 mov dpl, @r0 /* dptr has address of user's string */
131 dec r0
132 printf_str_loop:
133 lcall __gptrget
134 jz printf_format_done
135 inc dptr
136 lcall printf_putchar
137 sjmp printf_str_loop
140 printf_format_c:
141 /*cjne a, #'c', printf_format_d*/
142 cjne a, #99, printf_format_d
143 dec r0
144 mov a, @r0 /* Acc has the character to print */
145 dec r0
146 lcall printf_putchar
147 sjmp printf_format_done
150 printf_format_d:
151 /*cjne a, #'d', printf_format_u*/
152 cjne a, #100, printf_format_x
153 #ifndef ALWAYS_PRINT_UNSIGNED
154 mov a, @r0
155 jnb acc.7, printf_uint
156 dec r0
157 mov a, @r0
158 cpl a
159 add a, #1
160 mov @r0, a
161 inc r0
162 mov a, @r0
163 cpl a
164 addc a, #0
165 mov @r0, a
166 /*mov a, #'-'*/
167 mov a, #45
168 lcall printf_putchar
169 #endif
170 sjmp printf_uint
173 printf_format_x:
174 /*cjne a, #'x', printf_format_u*/
175 cjne a, #120, printf_format_u
176 mov dph, @r0
177 dec r0
178 mov dpl, @r0
179 dec r0
180 clr a
181 printf_hex:
182 lcall printf_phex_lsn
183 mov a, dph
184 lcall printf_phex_msn
185 mov a, dph
186 lcall printf_phex_lsn
187 mov a, dpl
188 lcall printf_phex_msn
189 mov a, dpl
190 lcall printf_phex_lsn
191 jnb print_zero_flag, printf_format_done
192 /*mov a, #'0'*/
193 mov a, #48
194 lcall printf_putchar
195 printf_format_done:
196 pop dpl
197 pop dph
198 ljmp printf_main_loop
201 printf_format_u:
202 /*cjne a, #'u', printf_format_done*/
203 cjne a, #117, printf_format_done
204 printf_uint:
205 mov a, @r0
206 mov r2, a
207 dec r0
208 mov a, @r0
209 mov r1, a
210 dec r0
211 printf_int2bcd:
212 mov r4, #16
213 mov r5, #39
214 lcall div_by_sub
215 mov r7, a
216 mov r4, #232
217 mov r5, #3
218 lcall div_by_sub
219 swap a
220 mov dph, a
221 mov r4, #100
222 mov r5, #0
223 lcall div_by_sub
224 orl dph, a
225 mov a, r1
226 mov b, #10
227 div ab
228 swap a
229 orl a, b
230 mov dpl, a
231 mov a, r7
232 sjmp printf_hex
235 /* Divide r2/r1 by r5/r4 using successive subtraction
236 returns quotient in r2/r1 and remainder in acc. */
237 div_by_sub:
238 mov r3, #0
239 div_by_sub_loop:
240 inc r3
241 clr c
242 mov a, r1
243 subb a, r4
244 mov r1, a
245 mov a, r2
246 subb a, r5
247 mov r2, a
248 jnc div_by_sub_loop
249 dec r3
250 mov a, r1
251 add a, r4
252 mov r1, a
253 mov a, r2
254 addc a, r5
255 mov r2, a
256 mov a, r3
260 /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
261 printf_phex_msn:
262 swap a
263 printf_phex_lsn:
264 anl a, #15
265 jnz printf_phex_ok
266 jb print_zero_flag, printf_ret
267 printf_phex_ok:
268 clr print_zero_flag
269 add a, #0x90
270 da a
271 addc a, #0x40
272 da a
273 printf_putchar:
274 #ifdef DIRECT_SERIAL_OUTPUT
275 jnb ti, printf_putchar
276 clr ti
277 mov sbuf, a
278 #else
279 push dph
280 push dpl
281 push b
282 mov dpl, a
283 mov a, r0
284 push acc
285 lcall _putchar
286 pop acc
287 mov r0, a
288 pop b
289 pop dpl
290 pop dph
291 #endif
292 printf_ret:
296 printf_end:
297 __endasm;
301 #endif /* defines compatible with printf_tiny */