diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /device/lib/printf_tiny.c | |
| download | sdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'device/lib/printf_tiny.c')
| -rw-r--r-- | device/lib/printf_tiny.c | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/device/lib/printf_tiny.c b/device/lib/printf_tiny.c new file mode 100644 index 0000000..0e97973 --- /dev/null +++ b/device/lib/printf_tiny.c @@ -0,0 +1,305 @@ +/*------------------------------------------------------------------------- + printf_tiny.c - Tiny printf routine for use with sdcc/mcs51 + + Copyright (C) 2004, Paul Stoffregen, paul@pjrc.com + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + +/* + * This tiny printf uses minimal code space, and it is fully reentrant + * and register bank neutral (usually safe to call from within an + * interrupt routine). Code size is under 270 bytes. Only one library + * function is called (_gptrget, 41 bytes), in addition to calls to + * putchar(). + * + * Five simple formats are supported + * + * %d signed 16 bit integer decimal (-32768 to 32767) + * %u unsigned 16 bit integer decimal (0 to 65535) + * %s string, takes a 24 bit generic pointer + * %c character. You must explicitly cast to char in SDCC + * %x 16 bit integer in hex (0 to FFFF) + * + * For a more complete printf that supports longs, floating point and + * field width, try using printf_fast() or printf_large(). + */ + + +/* This removes the negative number code, causing "%d" to be the same + as "%u". If you don't care about printing negative numbers, this + will save 21 bytes of code. */ +/* #define ALWAYS_PRINT_UNSIGNED */ + +/* Directly output characters to the serial port using simple polling, + rather than calling putchar(). This saves 14 bytes, plus the size + of putchar. */ +/* #define DIRECT_SERIAL_OUTPUT */ + + + +/* extern void putchar(char ); */ + + +#define print_zero_flag PSW.5 + + +#if !defined(__SDCC_mcs51) || defined(__SDCC_USE_XSTACK) || defined(_SDCC_NO_ASM_LIB_FUNCS) +/* Does printf_tiny really work on ds390 and ds400? + If it does, enable them in the line above */ +#if defined(_SDCC_BUILD_LIB) +/* Disable all warnings if building a library */ +#pragma disable_warning 190 +#elif defined(__SDCC_USE_XSTACK) +#warning "printf_tiny not built, does not support --xstack" +#elif defined(_SDCC_NO_ASM_LIB_FUNCS) +#warning "printf_tiny not built, _SDCC_NO_ASM_LIB_FUNCS defined" +#else +/* Disable "ISO C forbids an empty source file" warning message */ +#pragma disable_warning 190 +#endif +#else /* defines are compatible with printf_tiny */ + + + +void printf_tiny(__code const char *fmt, ...) __reentrant +{ + fmt; /* suppress unreferenced variable warning */ + + __asm + +printf_begin: + mov a, _bp /* r0 will point to va_args (stack) */ + add a, #253 + mov r0, a /* r0 points to MSB of fmt */ + mov dph, @r0 + dec r0 + mov dpl, @r0 /* dptr has address of fmt */ + dec r0 + + +printf_main_loop: + clr a + movc a, @a+dptr /* get next byte of fmt string */ + inc dptr + add a, #256 - 37 + jz printf_format /* check for '%' */ + add a, #37 + jz printf_end_h + lcall printf_putchar + sjmp printf_main_loop +printf_end_h: + ljmp printf_end + + +printf_format: + setb print_zero_flag + clr a + movc a, @a+dptr /* get next byte of data format */ + inc dptr + push dph + push dpl + + +printf_format_s: + /*cjne a, #'s', printf_format_c*/ + cjne a, #115, printf_format_c +printf_string: + /* print a string... just grab each byte with __gptrget */ + /* the user much pass a 24 bit generic pointer */ + mov b, @r0 /* b has type of address (generic *) */ + dec r0 + mov dph, @r0 + dec r0 + mov dpl, @r0 /* dptr has address of user's string */ + dec r0 +printf_str_loop: + lcall __gptrget + jz printf_format_done + inc dptr + lcall printf_putchar + sjmp printf_str_loop + + +printf_format_c: + /*cjne a, #'c', printf_format_d*/ + cjne a, #99, printf_format_d + dec r0 + mov a, @r0 /* Acc has the character to print */ + dec r0 + lcall printf_putchar + sjmp printf_format_done + + +printf_format_d: + /*cjne a, #'d', printf_format_u*/ + cjne a, #100, printf_format_x +#ifndef ALWAYS_PRINT_UNSIGNED + mov a, @r0 + jnb acc.7, printf_uint + dec r0 + mov a, @r0 + cpl a + add a, #1 + mov @r0, a + inc r0 + mov a, @r0 + cpl a + addc a, #0 + mov @r0, a + /*mov a, #'-'*/ + mov a, #45 + lcall printf_putchar +#endif + sjmp printf_uint + + +printf_format_x: + /*cjne a, #'x', printf_format_u*/ + cjne a, #120, printf_format_u + mov dph, @r0 + dec r0 + mov dpl, @r0 + dec r0 + clr a +printf_hex: + lcall printf_phex_lsn + mov a, dph + lcall printf_phex_msn + mov a, dph + lcall printf_phex_lsn + mov a, dpl + lcall printf_phex_msn + mov a, dpl + lcall printf_phex_lsn + jnb print_zero_flag, printf_format_done + /*mov a, #'0'*/ + mov a, #48 + lcall printf_putchar +printf_format_done: + pop dpl + pop dph + ljmp printf_main_loop + + +printf_format_u: + /*cjne a, #'u', printf_format_done*/ + cjne a, #117, printf_format_done +printf_uint: + mov a, @r0 + mov r2, a + dec r0 + mov a, @r0 + mov r1, a + dec r0 +printf_int2bcd: + mov r4, #16 + mov r5, #39 + lcall div_by_sub + mov r7, a + mov r4, #232 + mov r5, #3 + lcall div_by_sub + swap a + mov dph, a + mov r4, #100 + mov r5, #0 + lcall div_by_sub + orl dph, a + mov a, r1 + mov b, #10 + div ab + swap a + orl a, b + mov dpl, a + mov a, r7 + sjmp printf_hex + + + /* Divide r2/r1 by r5/r4 using successive subtraction + returns quotient in r2/r1 and remainder in acc. */ +div_by_sub: + mov r3, #0 +div_by_sub_loop: + inc r3 + clr c + mov a, r1 + subb a, r4 + mov r1, a + mov a, r2 + subb a, r5 + mov r2, a + jnc div_by_sub_loop + dec r3 + mov a, r1 + add a, r4 + mov r1, a + mov a, r2 + addc a, r5 + mov r2, a + mov a, r3 + ret + + + /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */ +printf_phex_msn: + swap a +printf_phex_lsn: + anl a, #15 + jnz printf_phex_ok + jb print_zero_flag, printf_ret +printf_phex_ok: + clr print_zero_flag + add a, #0x90 + da a + addc a, #0x40 + da a +printf_putchar: +#ifdef DIRECT_SERIAL_OUTPUT + jnb ti, printf_putchar + clr ti + mov sbuf, a +#else + push dph + push dpl + push b + mov dpl, a + mov a, r0 + push acc + lcall _putchar + pop acc + mov r0, a + pop b + pop dpl + pop dph +#endif +printf_ret: + ret + + +printf_end: + __endasm; +} + + +#endif /* defines compatible with printf_tiny */ |
