?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*-------------------------------------------------------------------------
  2.    printf_tiny.c - Tiny printf routine for use with sdcc/mcs51
  3.  
  4.    Copyright (C) 2004, Paul Stoffregen, paul@pjrc.com
  5.  
  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.
  10.  
  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.
  15.  
  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.
  20.  
  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. -------------------------------------------------------------------------*/
  28.  
  29. /*
  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().
  35.  *
  36.  * Five simple formats are supported
  37.  *
  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)
  43.  *
  44.  * For a more complete printf that supports longs, floating point and
  45.  * field width, try using printf_fast() or printf_large().
  46.  */
  47.  
  48.  
  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 */
  53.  
  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 */
  58.  
  59.  
  60.  
  61. /* extern void putchar(char ); */
  62.  
  63.  
  64. #define print_zero_flag PSW.5
  65.  
  66.  
  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_BUILD_LIB)
  71. /* Disable all warnings if building a library */
  72. #pragma disable_warning 190
  73. #elif defined(__SDCC_USE_XSTACK)
  74. #warning "printf_tiny not built, does not support --xstack"
  75. #elif defined(_SDCC_NO_ASM_LIB_FUNCS)
  76. #warning "printf_tiny not built, _SDCC_NO_ASM_LIB_FUNCS defined"
  77. #else
  78. /* Disable "ISO C forbids an empty source file" warning message */
  79. #pragma disable_warning 190
  80. #endif
  81. #else /* defines are compatible with printf_tiny */
  82.  
  83.  
  84.  
  85. void printf_tiny(__code const char *fmt, ...) __reentrant
  86. {
  87.         fmt;    /* suppress unreferenced variable warning */
  88.  
  89.         __asm
  90.  
  91. printf_begin:
  92.         mov     a, _bp          /* r0 will point to va_args (stack) */
  93.         add     a, #253
  94.         mov     r0, a           /* r0 points to MSB of fmt */
  95.         mov     dph, @r0
  96.         dec     r0
  97.         mov     dpl, @r0        /* dptr has address of fmt */
  98.         dec     r0
  99.  
  100.  
  101. printf_main_loop:
  102.         clr     a
  103.         movc    a, @a+dptr      /* get next byte of fmt string */
  104.         inc     dptr
  105.         add     a, #256 - 37
  106.         jz      printf_format   /* check for '%' */
  107.         add     a, #37
  108.         jz      printf_end_h
  109.         lcall   printf_putchar
  110.         sjmp    printf_main_loop
  111. printf_end_h:
  112.         ljmp    printf_end
  113.  
  114.  
  115. printf_format:
  116.         setb    print_zero_flag
  117.         clr     a
  118.         movc    a, @a+dptr      /* get next byte of data format */
  119.         inc     dptr
  120.         push    dph
  121.         push    dpl
  122.  
  123.  
  124. printf_format_s:
  125.         /*cjne  a, #'s', printf_format_c*/
  126.         cjne    a, #115, printf_format_c
  127. printf_string:
  128.         /* print a string... just grab each byte with __gptrget */
  129.         /* the user much pass a 24 bit generic pointer */
  130.         mov     b, @r0          /* b has type of address (generic *) */
  131.         dec     r0
  132.         mov     dph, @r0
  133.         dec     r0
  134.         mov     dpl, @r0        /* dptr has address of user's string */
  135.         dec     r0
  136. printf_str_loop:
  137.         lcall   __gptrget
  138.         jz      printf_format_done
  139.         inc     dptr
  140.         lcall   printf_putchar
  141.         sjmp    printf_str_loop
  142.  
  143.  
  144. printf_format_c:
  145.         /*cjne  a, #'c', printf_format_d*/
  146.         cjne    a, #99, printf_format_d
  147.         dec     r0
  148.         mov     a, @r0          /* Acc has the character to print */
  149.         dec     r0
  150.         lcall   printf_putchar
  151.         sjmp    printf_format_done
  152.  
  153.  
  154. printf_format_d:
  155.         /*cjne  a, #'d', printf_format_u*/
  156.         cjne    a, #100, printf_format_x
  157. #ifndef ALWAYS_PRINT_UNSIGNED
  158.         mov     a, @r0
  159.         jnb     acc.7, printf_uint
  160.         dec     r0
  161.         mov     a, @r0
  162.         cpl     a
  163.         add     a, #1
  164.         mov     @r0, a
  165.         inc     r0
  166.         mov     a, @r0
  167.         cpl     a
  168.         addc    a, #0
  169.         mov     @r0, a
  170.         /*mov   a, #'-'*/
  171.         mov     a, #45
  172.         lcall   printf_putchar
  173. #endif
  174.         sjmp    printf_uint
  175.  
  176.  
  177. printf_format_x:
  178.         /*cjne  a, #'x', printf_format_u*/
  179.         cjne    a, #120, printf_format_u
  180.         mov     dph, @r0
  181.         dec     r0
  182.         mov     dpl, @r0
  183.         dec     r0
  184.         clr     a
  185. printf_hex:
  186.         lcall   printf_phex_lsn
  187.         mov     a, dph
  188.         lcall   printf_phex_msn
  189.         mov     a, dph
  190.         lcall   printf_phex_lsn
  191.         mov     a, dpl
  192.         lcall   printf_phex_msn
  193.         mov     a, dpl
  194.         lcall   printf_phex_lsn
  195.         jnb     print_zero_flag, printf_format_done
  196.         /*mov   a, #'0'*/
  197.         mov     a, #48
  198.         lcall   printf_putchar
  199. printf_format_done:
  200.         pop     dpl
  201.         pop     dph
  202.         ljmp    printf_main_loop
  203.  
  204.  
  205. printf_format_u:
  206.         /*cjne  a, #'u', printf_format_done*/
  207.         cjne    a, #117, printf_format_done
  208. printf_uint:
  209.         mov     a, @r0
  210.         mov     r2, a
  211.         dec     r0
  212.         mov     a, @r0
  213.         mov     r1, a
  214.         dec     r0
  215. printf_int2bcd:
  216.         mov     r4, #16
  217.         mov     r5, #39
  218.         lcall   div_by_sub
  219.         mov     r7, a
  220.         mov     r4, #232
  221.         mov     r5, #3
  222.         lcall   div_by_sub
  223.         swap    a
  224.         mov     dph, a
  225.         mov     r4, #100
  226.         mov     r5, #0
  227.         lcall   div_by_sub
  228.         orl     dph, a
  229.         mov     a, r1
  230.         mov     b, #10
  231.         div     ab
  232.         swap    a
  233.         orl     a, b
  234.         mov     dpl, a
  235.         mov     a, r7
  236.         sjmp    printf_hex
  237.  
  238.  
  239.         /* Divide r2/r1 by r5/r4 using successive subtraction
  240.            returns quotient in r2/r1 and remainder in acc. */
  241. div_by_sub:
  242.         mov     r3, #0
  243. div_by_sub_loop:
  244.         inc     r3
  245.         clr     c
  246.         mov     a, r1
  247.         subb    a, r4
  248.         mov     r1, a
  249.         mov     a, r2
  250.         subb    a, r5
  251.         mov     r2, a
  252.         jnc     div_by_sub_loop
  253.         dec     r3
  254.         mov     a, r1
  255.         add     a, r4
  256.         mov     r1, a
  257.         mov     a, r2
  258.         addc    a, r5
  259.         mov     r2, a
  260.         mov     a, r3
  261.         ret
  262.  
  263.  
  264.         /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
  265. printf_phex_msn:
  266.         swap    a
  267. printf_phex_lsn:
  268.         anl     a, #15
  269.         jnz     printf_phex_ok
  270.         jb      print_zero_flag, printf_ret
  271. printf_phex_ok:
  272.         clr     print_zero_flag
  273.         add     a, #0x90
  274.         da      a
  275.         addc    a, #0x40
  276.         da      a
  277. printf_putchar:
  278. #ifdef DIRECT_SERIAL_OUTPUT
  279.         jnb     ti, printf_putchar
  280.         clr     ti
  281.         mov     sbuf, a
  282. #else
  283.         push    dph
  284.         push    dpl
  285.         push    b
  286.         mov     dpl, a
  287.         mov     a, r0
  288.         push    acc
  289.         lcall   _putchar
  290.         pop     acc
  291.         mov     r0, a
  292.         pop     b
  293.         pop     dpl
  294.         pop     dph
  295. #endif
  296. printf_ret:
  297.         ret
  298.  
  299.  
  300. printf_end:
  301.         __endasm;
  302. }
  303.  
  304.  
  305. #endif /* defines compatible with printf_tiny */
  306.