From: pjs Date: Fri, 27 Jul 2001 00:56:57 +0000 (+0000) Subject: Added printf_fast to library X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=9d72dfbd06e3070f10ca90d4c9d61287dbae470e;p=fw%2Fsdcc Added printf_fast to library git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@1107 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- diff --git a/device/include/stdio.h b/device/include/stdio.h index 5cbd260f..714b02ad 100644 --- a/device/include/stdio.h +++ b/device/include/stdio.h @@ -43,4 +43,8 @@ extern char *gets(char *); extern char getchar(void); extern void putchar(char); +#ifdef __mcs51 +extern void printf_fast(code char *fmt, ...) _REENTRANT; +#endif + #endif /* __SDC51_STDIO_H */ diff --git a/device/lib/Makefile.in b/device/lib/Makefile.in index c4e06c16..d85e1ee5 100644 --- a/device/lib/Makefile.in +++ b/device/lib/Makefile.in @@ -57,7 +57,7 @@ SOURCES = _atoi.c _atol.c _autobaud.c _bp.c _schar2fs.c \ _strstr.c _strtok.c _uchar2fs.c _uint2fs.c \ _ulong2fs.c malloc.c serial.c ser_ir.c printfl.c \ printf_large.c vprintf.c puts.c gets.c \ - assert.c _strcat.c time.c + assert.c _strcat.c time.c printf_fast.c OBJECTS = $(patsubst %.c,$(PORTDIR)/%.rel,$(SOURCES)) diff --git a/device/lib/libsdcc.lib b/device/lib/libsdcc.lib index 31c36e12..022546a3 100644 --- a/device/lib/libsdcc.lib +++ b/device/lib/libsdcc.lib @@ -40,6 +40,7 @@ puts gets printfl printf_large +printf_fast vprintf assert -time \ No newline at end of file +time diff --git a/device/lib/printf_fast.c b/device/lib/printf_fast.c new file mode 100644 index 00000000..a385aff8 --- /dev/null +++ b/device/lib/printf_fast.c @@ -0,0 +1,801 @@ +/* Fast printf routine for use with sdcc/mcs51 + * Copyright (c) 2001, Paul Stoffregen, paul@pjrc.com + * + * This program 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 + * of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +// include support for 32 bit base 10 integers (%ld and %lu) +#define LONG_INT + +// include support for minimum field widths (%8d, %20s) +#define FIELD_WIDTH + + +/* extern void putchar(char ); */ + + +static bit long_flag, short_flag, print_zero_flag, negative_flag; + +#ifdef FIELD_WIDTH +static bit field_width_flag; +static data unsigned char field_width; +#endif + + +void printf_fast(code char *fmt, ...) reentrant +{ + fmt; /* supress 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 + //cjne a, #'%', printf_normal + cjne a, #37, printf_normal + +printf_format: + clr _long_flag + clr _short_flag + clr _print_zero_flag + clr _negative_flag +#ifdef FIELD_WIDTH + clr _field_width_flag + mov _field_width, #0 +#endif + +printf_format_loop: + clr a + movc a, @a+dptr // get next byte of data format + inc dptr + + /* parse and consume the field width digits, even if */ + /* we don't build the code to make use of them */ + add a, #198 + jc printf_nondigit1 + add a, #10 + jnc printf_nondigit2 +#ifdef FIELD_WIDTH +printf_digit: + setb _field_width_flag + mov r1, a + mov a, _field_width + mov b, #10 + mul ab + add a, r1 + mov _field_width, a +#endif + sjmp printf_format_loop +printf_nondigit1: + add a, #10 +printf_nondigit2: + add a, #48 + + +printf_format_l: + //cjne a, #'l', printf_format_h + cjne a, #108, printf_format_h + setb _long_flag + sjmp printf_format_loop + +printf_format_h: + //cjne a, #'h', printf_format_s + cjne a, #104, printf_format_s + setb _short_flag + sjmp printf_format_loop + +printf_format_s: + //cjne a, #'s', printf_format_d + cjne a, #115, printf_format_d + ljmp printf_string + +printf_format_d: + //cjne a, #'d', printf_format_u + cjne a, #100, printf_format_u + lcall printf_get_int + ljmp printf_int + +printf_format_u: + //cjne a, #'u', printf_format_c + cjne a, #117, printf_format_c + lcall printf_get_int + ljmp printf_uint + +printf_format_c: + //cjne a, #'c', printf_format_x + cjne a, #99, printf_format_x + mov a, @r0 // Acc has the character to print + dec r0 + sjmp printf_char + +printf_format_x: + //cjne a, #'x', printf_normal + cjne a, #120, printf_normal + ljmp printf_hex + +printf_normal: + jz printf_eot +printf_char: + lcall printf_putchar + sjmp printf_main_loop + +printf_eot: + ljmp printf_end + + + + + /* print a string... just grab each byte with __gptrget */ + /* the user much pass a 24 bit _generic pointer */ + +printf_string: + push dph // save addr in fmt onto stack + push dpl + 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 + +#ifdef FIELD_WIDTH + jnb _field_width_flag, printf_str_loop + push dpl + push dph +printf_str_fw_loop: + lcall __gptrget + jz printf_str_space + inc dptr + dec _field_width + mov a, _field_width + jnz printf_str_fw_loop +printf_str_space: + lcall printf_space + pop dph + pop dpl +#endif FIELD_WIDTH + +printf_str_loop: + lcall __gptrget + jz printf_str_done + inc dptr + lcall printf_putchar + sjmp printf_str_loop +printf_str_done: + pop dpl // restore addr withing fmt + pop dph + ljmp printf_main_loop + + + + + + + + + /* printing in hex is easy because sdcc pushes the LSB first */ + +printf_hex: + lcall printf_hex8 + jb _short_flag, printf_hex_end + lcall printf_hex8 + jnb _long_flag, printf_hex_end + lcall printf_hex8 + lcall printf_hex8 +printf_hex_end: + lcall printf_zero + ljmp printf_main_loop +printf_hex8: + mov a, @r0 + lcall printf_phex_msn + mov a, @r0 + dec r0 + ljmp printf_phex_lsn + + +#ifndef LONG_INT +printf_ld_in_hex: + //mov a, #'0' + mov a, #48 + lcall printf_putchar + //mov a, #'x' + mov a, #120 + lcall printf_putchar + mov a, r0 + add a, #4 + mov r0, a + sjmp printf_hex +#endif + + + /* printing an integer is not so easy. For a signed int */ + /* check if it is negative and print the minus sign and */ + /* invert it to a positive integer */ + +printf_int: + mov a, r5 + jnb acc.7, printf_uint /* check if negative */ + setb _negative_flag + mov a, r1 /* invert integer */ + cpl a + addc a, #1 + mov r1, a + jb _short_flag, printf_uint + mov a, r2 + cpl a + addc a, #0 + mov r2, a + jnb _long_flag, printf_uint + mov a, r3 + cpl a + addc a, #0 + mov r3, a + mov a, r4 + cpl a + addc a, #0 + mov r4, a + + + /* printing integers is a lot of work... because it takes so */ + /* long, the first thing to do is make sure we're doing as */ + /* little work as possible, then convert the binary int to */ + /* packed BCD, and finally print each digit of the BCD number */ + +printf_uint: + + jb _short_flag, printf_uint_ck8 + jnb _long_flag, printf_uint_ck16 +printf_uint_ck32: + /* it's a 32 bit int... but if the upper 16 bits are zero */ + /* we can treat it like a 16 bit integer and convert much faster */ +#ifdef LONG_INT + mov a, r3 + jnz printf_uint_begin + mov a, r4 + jnz printf_uint_begin +#else + mov a, r3 + jnz printf_ld_in_hex ;print long integer as hex + mov a, r4 ;rather than just the low 16 bits + jnz printf_ld_in_hex +#endif + clr _long_flag +printf_uint_ck16: + /* it's a 16 bit int... but if the upper 8 bits are zero */ + /* we can treat it like a 8 bit integer and convert much faster */ + mov a, r2 + jnz printf_uint_begin + setb _short_flag +printf_uint_ck8: + /* it's an 8 bit int... if it's zero, it's a lot faster to just */ + /* print the digit zero and skip all the hard work! */ + mov a, r1 + jnz printf_uint_begin +#ifdef FIELD_WIDTH + jnb _field_width_flag, printf_uint_zero + dec _field_width + lcall printf_space +#endif +printf_uint_zero: + //mov a, #'0' + mov a, #48 + lcall printf_putchar + ljmp printf_main_loop + + +printf_uint_begin: + push dpl + push dph + lcall printf_int2bcd // bcd number in r3/r2/r7/r6/r5 + +#ifdef FIELD_WIDTH + jnb _field_width_flag, printf_uifw_end +#ifdef LONG_INT +printf_uifw_32: + mov r1, #10 + jnb _long_flag, printf_uifw_16 + mov a, r3 + anl a, #0xF0 + jnz printf_uifw_sub + dec r1 + mov a, r3 + anl a, #0x0F + jnz printf_uifw_sub + dec r1 + mov a, r2 + anl a, #0xF0 + jnz printf_uifw_sub + dec r1 + mov a, r2 + anl a, #0x0F + jnz printf_uifw_sub + dec r1 + mov a, r7 + anl a, #0xF0 + jnz printf_uifw_sub +#endif +printf_uifw_16: + mov r1, #5 + jb _short_flag, printf_uifw_8 + mov a, r7 + anl a, #0x0F + jnz printf_uifw_sub + dec r1 + mov a, r6 + anl a, #0xF0 + jnz printf_uifw_sub +printf_uifw_8: + mov r1, #3 + mov a, r6 + anl a, #0x0F + jnz printf_uifw_sub + dec r1 + mov a, r5 + anl a, #0xF0 + jnz printf_uifw_sub + dec r1 +printf_uifw_sub: + ;r1 has the number of digits for the number + mov a, _field_width + mov c, _negative_flag + subb a, r1 + jc printf_uifw_end + mov _field_width, a + +#ifdef LONG_INT + push ar3 + push ar2 +#endif + push ar7 + push ar6 + push ar5 + lcall printf_space + pop ar5 + pop ar6 + pop ar7 +#ifdef LONG_INT + pop ar2 + pop ar3 +#endif +printf_uifw_end: +#endif + + +printf_uint_doit: + jnb _negative_flag, printf_uint_pos + //mov a, #"-" + mov a, #45 + lcall printf_putchar +printf_uint_pos: + jb _short_flag, printf_uint8 +#ifdef LONG_INT + jnb _long_flag, printf_uint16 +printf_uint32: + push ar5 + push ar6 + push ar7 + mov dpl, r2 + mov a, r3 + mov dph, a + 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 + pop acc + mov dpl, a + lcall printf_phex_msn + mov a, dpl + pop dph + pop dpl + sjmp printf_uint16a +#endif + +printf_uint16: + mov dpl, r5 + mov dph, r6 + mov a, r7 +printf_uint16a: + lcall printf_phex_lsn + mov a, dph + lcall printf_phex_msn + mov a, dph + sjmp printf_uint8a + +printf_uint8: + mov dpl, r5 + mov a, r6 +printf_uint8a: + lcall printf_phex_lsn + mov a, dpl + lcall printf_phex_msn + mov a, dpl + lcall printf_phex_lsn + lcall printf_zero + pop dph + pop dpl + ljmp printf_main_loop + + + + + + + + + + + + /* read an integer into r1/r2/r3/r4, and msb into r5 */ +printf_get_int: + mov a, @r0 + mov r1, a + mov r5, a + dec r0 + jb _short_flag, printf_get_done + mov r2, ar1 + mov a, @r0 + mov r1, a + dec r0 + jnb _long_flag, printf_get_done + mov r4, ar2 + mov r3, ar1 + mov a, @r0 + mov r2, a + dec r0 + mov a, @r0 + mov r1, a + dec r0 +printf_get_done: + ret + + + + + + + + /* convert binary number in r4/r3/r2/r1 into bcd packed number + * in r3/r2/r7/r6/r5. The input number is destroyed in the + * process, to avoid needing extra memory for the result (and + * r1 gets used for temporary storage). dptr is overwritten, + * but r0 is not changed. + */ + +printf_int2bcd: + mov a, r1 + anl a, #0x0F + mov dptr, #_int2bcd_0 + movc a, @a+dptr + mov r5, a + + mov a, r1 + swap a + anl a, #0x0F + mov r1, a // recycle r1 for holding nibble + mov dptr, #_int2bcd_1 + movc a, @a+dptr + add a, r5 + da a + mov r5, a + mov a, r1 + orl a, #16 + movc a, @a+dptr + addc a, #0 + da a + mov r6, a + + jnb _short_flag, printf_i2bcd_16 // if 8 bit int, we're done + ret + +printf_i2bcd_16: + mov a, r2 + anl a, #0x0F + mov r1, a + mov dptr, #_int2bcd_2 + movc a, @a+dptr + add a, r5 + da a + mov r5, a + mov a, r1 + orl a, #16 + movc a, @a+dptr + addc a, r6 + da a + mov r6, a + + mov a, r2 + swap a + anl a, #0x0F + mov r1, a + mov dptr, #_int2bcd_3 + movc a, @a+dptr + add a, r5 + da a + mov r5, a + mov a, r1 + orl a, #16 + movc a, @a+dptr + addc a, r6 + da a + mov r6, a + mov a, r1 + orl a, #32 + movc a, @a+dptr + addc a, #0 + da a + mov r7, a + + jb _long_flag, printf_i2bcd_32 // if 16 bit int, we're done + ret + +printf_i2bcd_32: + +#ifdef LONG_INT + mov a, r3 + anl a, #0x0F + mov r1, a + mov dptr, #_int2bcd_4 + movc a, @a+dptr + add a, r5 + da a + mov r5, a + mov a, r1 + orl a, #16 + movc a, @a+dptr + addc a, r6 + da a + mov r6, a + mov a, r1 + orl a, #32 + movc a, @a+dptr + addc a, r7 + da a + mov r7, a + clr a + addc a, #0 + mov r2, a + + mov a, r3 + swap a + anl a, #0x0F + mov r1, a + mov dptr, #_int2bcd_5 + movc a, @a+dptr + add a, r5 + da a + mov r5, a + mov a, r1 + orl a, #16 + movc a, @a+dptr + addc a, r6 + da a + mov r6, a + mov a, r1 + orl a, #32 + movc a, @a+dptr + addc a, r7 + da a + mov r7, a + mov a, r1 + orl a, #48 + movc a, @a+dptr + addc a, r2 + da a + mov r2, a + + mov a, r4 + anl a, #0x0F + mov r1, a + mov dptr, #_int2bcd_6 + mov r3, #0 + lcall printf_bcd_add10 // saves 27 bytes, costs 5 cycles + + mov a, r4 + swap a + anl a, #0x0F + mov r1, a + mov dptr, #_int2bcd_7 +printf_bcd_add10: + movc a, @a+dptr + add a, r5 + da a + mov r5, a + mov a, r1 + orl a, #16 + movc a, @a+dptr + addc a, r6 + da a + mov r6, a + mov a, r1 + orl a, #32 + movc a, @a+dptr + addc a, r7 + da a + mov r7, a + mov a, r1 + orl a, #48 + movc a, @a+dptr + addc a, r2 + da a + mov r2, a + mov a, r1 + orl a, #64 + movc a, @a+dptr + addc a, r3 + da a + mov r3, a +#endif + ret + + + + +#ifdef FIELD_WIDTH +printf_space_loop: + //mov a, #' ' + mov a, #32 + lcall printf_putchar + dec _field_width +printf_space: + mov a, _field_width + jnz printf_space_loop + ret +#endif + + + + + + /* 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 + jnb _print_zero_flag, printf_ret +printf_phex_ok: + setb _print_zero_flag + add a, #0x90 + da a + addc a, #0x40 + da a +printf_putchar: + push dph + push dpl + push ar0 + mov dpl, a + lcall _putchar + pop ar0 + pop dpl + pop dph +printf_ret: + ret + + /* print a zero if all the calls to print the digits ended up */ + /* being leading zeros */ + +printf_zero: + jb _print_zero_flag, printf_ret + //mov a, #'0' + mov a, #48 + ljmp printf_putchar + +printf_end: + _endasm; +} + + +/* + * #! /usr/bin/perl + * for ($d=0; $d < 8; $d++) { + * $n = 16 ** $d; + * for ($p=0; $p < 5; $p++) { + * last unless (((16 ** $d) * 15) / (10 ** ($p * 2))) % 100; + * printf "code unsigned char int2bcd_%d_%d[15] = {", $d, $p; + * for ($i=0; $i < 16; $i++) { + * printf "0x%02d", + * (((16 ** $d) * $i) / (10 ** ($p * 2))) % 100; + * print ", " if $i < 15; + * } + * print "};\n"; + * } + * } + */ + + +code unsigned char int2bcd_0[] = { +0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15}; + +code unsigned char int2bcd_1[] = { +0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12, +0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02}; + +code unsigned char int2bcd_2[] = { +0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92, +0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40, +0x00, 0x02, 0x05, 0x07, 0x10, 0x12, 0x15, 0x17, +0x20, 0x23, 0x25, 0x28, 0x30, 0x33, 0x35, 0x38}; + +code unsigned char int2bcd_3[] = { +0x00, 0x96, 0x92, 0x88, 0x84, 0x80, 0x76, 0x72, +0x68, 0x64, 0x60, 0x56, 0x52, 0x48, 0x44, 0x40, +0x00, 0x40, 0x81, 0x22, 0x63, 0x04, 0x45, 0x86, +0x27, 0x68, 0x09, 0x50, 0x91, 0x32, 0x73, 0x14, +0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02, +0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06}; + +#ifdef LONG_INT +code unsigned char int2bcd_4[] = { +0x00, 0x36, 0x72, 0x08, 0x44, 0x80, 0x16, 0x52, +0x88, 0x24, 0x60, 0x96, 0x32, 0x68, 0x04, 0x40, +0x00, 0x55, 0x10, 0x66, 0x21, 0x76, 0x32, 0x87, +0x42, 0x98, 0x53, 0x08, 0x64, 0x19, 0x75, 0x30, +0x00, 0x06, 0x13, 0x19, 0x26, 0x32, 0x39, 0x45, +0x52, 0x58, 0x65, 0x72, 0x78, 0x85, 0x91, 0x98}; + +code unsigned char int2bcd_5[] = { +0x00, 0x76, 0x52, 0x28, 0x04, 0x80, 0x56, 0x32, +0x08, 0x84, 0x60, 0x36, 0x12, 0x88, 0x64, 0x40, +0x00, 0x85, 0x71, 0x57, 0x43, 0x28, 0x14, 0x00, +0x86, 0x71, 0x57, 0x43, 0x29, 0x14, 0x00, 0x86, +0x00, 0x04, 0x09, 0x14, 0x19, 0x24, 0x29, 0x34, +0x38, 0x43, 0x48, 0x53, 0x58, 0x63, 0x68, 0x72, +0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15}; + +code unsigned char int2bcd_6[] = { +0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12, +0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40, +0x00, 0x72, 0x44, 0x16, 0x88, 0x60, 0x32, 0x05, +0x77, 0x49, 0x21, 0x93, 0x65, 0x38, 0x10, 0x82, +0x00, 0x77, 0x55, 0x33, 0x10, 0x88, 0x66, 0x44, +0x21, 0x99, 0x77, 0x54, 0x32, 0x10, 0x88, 0x65, +0x00, 0x16, 0x33, 0x50, 0x67, 0x83, 0x00, 0x17, +0x34, 0x50, 0x67, 0x84, 0x01, 0x18, 0x34, 0x51, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02}; + +code unsigned char int2bcd_7[] = { +0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92, +0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40, +0x00, 0x54, 0x09, 0x63, 0x18, 0x72, 0x27, 0x81, +0x36, 0x91, 0x45, 0x00, 0x54, 0x09, 0x63, 0x18, +0x00, 0x43, 0x87, 0x30, 0x74, 0x17, 0x61, 0x04, +0x48, 0x91, 0x35, 0x79, 0x22, 0x66, 0x09, 0x53, +0x00, 0x68, 0x36, 0x05, 0x73, 0x42, 0x10, 0x79, +0x47, 0x15, 0x84, 0x52, 0x21, 0x89, 0x58, 0x26, +0x00, 0x02, 0x05, 0x08, 0x10, 0x13, 0x16, 0x18, +0x21, 0x24, 0x26, 0x29, 0x32, 0x34, 0x37, 0x40}; +#endif + +