📄 printf.c
字号:
/* 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. */#define LONG_INT#define FIELD_WIDTH// extern void putchar(char );// #define COUT 0x0030// #define PHEX 0x0034// #define PHEX16 0x0036// #define NEWLINE 0x003A#define COUT 0x2030#define PHEX 0x2034#define PHEX16 0x2036#define NEWLINE 0x203Astatic bit long_flag, short_flag, print_zero_flag, negative_flag;#ifdef FIELD_WIDTHstatic bit field_width_flag;static bit leading_zero_flag;static data unsigned char field_width;#endifbit at 0x1F debug;void printfd(code char *fmt, ...) reentrant{ fmt; /* suppress unreferenced variable warning */ if (debug == 0) return; _asm ljmp printf_begin _endasm;}void printf(code char *fmt, ...) reentrant{ fmt; /* supress unreferenced variable warning */ _asmprintf_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 r0printf_main_loop: clr a movc a, @a+dptr // get next byte of fmt string inc dptr //cjne a, #'%', printf_normal cjne a, #37, printf_normalprintf_format: clr _long_flag clr _short_flag clr _print_zero_flag clr _negative_flag#ifdef FIELD_WIDTH clr _field_width_flag clr _leading_zero_flag mov _field_width, #0#endifprintf_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_WIDTHprintf_digit: jnz printf_digit_2 cjne a, _field_width, printf_digit_2 setb _leading_zero_flagprintf_digit_2: 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_loopprintf_nondigit1: add a, #10printf_nondigit2: add a, #48printf_format_l: //cjne a, #'l', printf_format_h cjne a, #108, printf_format_h setb _long_flag sjmp printf_format_loopprintf_format_h: //cjne a, #'h', printf_format_s cjne a, #104, printf_format_s setb _short_flag sjmp printf_format_loopprintf_format_s: //cjne a, #'s', printf_format_d cjne a, #115, printf_format_d ljmp printf_stringprintf_format_d: //cjne a, #'d', printf_format_u cjne a, #100, printf_format_u lcall printf_get_int ljmp printf_intprintf_format_u: //cjne a, #'u', printf_format_c cjne a, #117, printf_format_c lcall printf_get_int ljmp printf_uintprintf_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_charprintf_format_x: //cjne a, #'x', printf_normal cjne a, #120, printf_normal ljmp printf_hexprintf_normal: jz printf_eotprintf_char: lcall printf_putchar sjmp printf_main_loopprintf_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 clr _leading_zero_flag // never leading zeros for strings push dpl push dphprintf_str_fw_loop: lcall __gptrget jz printf_str_space inc dptr dec _field_width mov a, _field_width jnz printf_str_fw_loopprintf_str_space: lcall printf_space pop dph pop dpl#endif // FIELD_WIDTHprintf_str_loop: lcall __gptrget jz printf_str_done inc dptr lcall printf_putchar sjmp printf_str_loopprintf_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_hex8printf_hex_end: lcall printf_zero ljmp printf_main_loopprintf_hex8: mov a, @r0 lcall printf_phex_msn mov a, @r0 dec r0 ljmp printf_phex_lsn#ifndef LONG_INTprintf_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_ck16printf_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_flagprintf_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_flagprintf_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#endifprintf_uint_zero: //mov a, #'0' mov a, #48 lcall printf_putchar ljmp printf_main_loopprintf_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_INTprintf_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#endifprintf_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_subprintf_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 r1printf_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#endifprintf_uifw_end:#endifprintf_uint_doit: jnb _negative_flag, printf_uint_pos //mov a, #"-" mov a, #45 lcall printf_putcharprintf_uint_pos: jb _short_flag, printf_uint8#ifdef LONG_INT jnb _long_flag, printf_uint16printf_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#endifprintf_uint16: mov dpl, r5 mov dph, r6 mov a, r7printf_uint16a: lcall printf_phex_lsn mov a, dph lcall printf_phex_msn mov a, dph sjmp printf_uint8aprintf_uint8: mov dpl, r5 mov a, r6printf_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -