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
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,
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
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
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"
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 */
88 mov a
, _bp
/* r0 will point to va_args (stack) */
90 mov r0
, a
/* r0 points to MSB of fmt */
93 mov dpl
, @r0
/* dptr has address of fmt */
99 movc a
, @a
+dptr
/* get next byte of fmt string */
102 jz printf_format
/* check for '%' */
106 sjmp printf_main_loop
114 movc a
, @a
+dptr
/* get next byte of data format */
121 /*cjne a, #'s', printf_format_c*/
122 cjne a
, #115, printf_format_c
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 *) */
130 mov dpl
, @r0
/* dptr has address of user's string */
134 jz printf_format_done
141 /*cjne a, #'c', printf_format_d*/
142 cjne a
, #99, printf_format_d
144 mov a
, @r0
/* Acc has the character to print */
147 sjmp printf_format_done
151 /*cjne a, #'d', printf_format_u*/
152 cjne a
, #100, printf_format_x
153 #ifndef ALWAYS_PRINT_UNSIGNED
155 jnb acc
.7, printf_uint
174 /*cjne a, #'x', printf_format_u*/
175 cjne a
, #120, printf_format_u
182 lcall printf_phex_lsn
184 lcall printf_phex_msn
186 lcall printf_phex_lsn
188 lcall printf_phex_msn
190 lcall printf_phex_lsn
191 jnb print_zero_flag
, printf_format_done
198 ljmp printf_main_loop
202 /*cjne a, #'u', printf_format_done*/
203 cjne a
, #117, printf_format_done
235 /* Divide r2/r1 by r5/r4 using successive subtraction
236 returns quotient in r2/r1 and remainder in acc. */
260 /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
266 jb print_zero_flag
, printf_ret
274 #ifdef DIRECT_SERIAL_OUTPUT
275 jnb ti
, printf_putchar
301 #endif /* defines compatible with printf_tiny */