?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download

  1. /*-------------------------------------------------------------------------
  2.    printf_fast.c - Fast 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. /**                                                              **/
  31. /**    Major features.  These determine what capabilities your   **/
  32. /**    compiled printf_fast will have.                           **/
  33. /**                                                              **/
  34. /******************************************************************/
  35.  
  36. // Include support for 32 bit base 10 integers (%ld and %lu).  Without
  37. // this, you won't be able to print 32 bit integers as base 10.  They
  38. // will appear in hexadecimal.
  39. #define LONG
  40.  
  41. // Include support for floating point numbers (%f).  Don't forget to
  42. // enable LONG above, if you want to print floats greater than
  43. // 65535.997.  You can have 6 good digits after the decimal point,
  44. // or an 8th if a small error is ok.  +/- 2^32 to 1/10^8 isn't the
  45. // full dynamic range of 32 bit floats, but it covers the most
  46. // commonly used range.  Adds about 500-600 bytes of code.
  47. //#define FLOAT
  48.  
  49. // Include support for minimum field widths (%8d, %20s, %12.5f)
  50. #define FIELD_WIDTH
  51.  
  52. // Include fast integer conversion.  Without this, a compact but slower
  53. // algorithm is used to convert integers (%d, %u, int part of %f).
  54. // Even the slow algorithm is much faster than a typical C implementation
  55. // based on repetitive division by 10.  If you enable this, you get an
  56. // extremely fast version (only 8 table lookups and 8 adds to convert a
  57. // 32 bit integer), but it costs extra code space for larger lookup
  58. // tables and optimized non-looping code.
  59. #define FAST_INTEGER
  60.  
  61.  
  62. /******************************************************************/
  63. /**                                                              **/
  64. /**    Minor tweaks.  These provide small code savings, with     **/
  65. /**    a partial loss of functionality.                          **/
  66. /**                                                              **/
  67. /******************************************************************/
  68.  
  69.  
  70. // If you enabled FLOAT, enabling this replaces the normal %f float
  71. // output with a very compact version that always prints 4 fractional
  72. // digits and does not have round off.  Zero will print as "0.0000",
  73. // and 1.999997 will print as "1.9999" (not rounded up to 2).  The
  74. // 4th digit is not accurate (+/- 2).  This simpler version also
  75. // avoids using 5 bytes of internal data memory.  Code size is about
  76. // 240 bytes less.
  77. //#define FLOAT_FIXED4
  78.  
  79. // If you used FLOAT (not FLOAT_FIXED4), this will remove the smart
  80. // default number of digits code.  When you use "%f" without a field
  81. // width, normally the smart default width code chooses a good number
  82. // of digits based on size of the number.  If you enabled FIELD_WIDTH
  83. // and use a number, like "%.5f", this smart default code is never
  84. // used anyway.  Saves about 40 bytes of code.
  85. //#define FLOAT_DEFAULT_FRAC_DIGITS 6
  86.  
  87. // If you used FLOAT (not FLOAT_FIXED4) and you do not specify a
  88. // field width, normally trailing zeros are trimmed.  Using this
  89. // removes that feature (saves only a few bytes).
  90. //#define DO_NOT_TRIM_TRAILING_ZEROS
  91.  
  92. // Omit saving and restoring registers when calling putchar().  If you
  93. // are desparate for a little more code space, this will give you a
  94. // small savings.  You MUST define putchar() with #pragma callee_saves,
  95. // or implement it in assembly and avoid changing the registers.
  96. //#define PUTCHAR_CALLEE_SAVES
  97.  
  98.  
  99. /* extern void putchar(char ); */
  100.  
  101. // Warning: using static/global variables makes these functions NON-reentrant!
  102. // reentrant keyword is only used for parameter passing method
  103.  
  104. static __bit long_flag, short_flag, print_zero_flag, negative_flag;
  105.  
  106. #ifdef FIELD_WIDTH
  107. static __bit field_width_flag;
  108. static __bit leading_zero_flag;
  109. static __data unsigned char field_width;
  110. #endif
  111.  
  112. #ifdef FLOAT
  113. #define __SDCC_FLOAT_LIB
  114. #include <float.h>
  115. static __bit continue_float;
  116. #ifndef FLOAT_FIXED4
  117. static __data unsigned char frac_field_width;
  118. static __data unsigned char float_frac_bcd[4];
  119. // TODO: can float_frac_bcd be overlaid with temps used by trig functions
  120. #endif
  121. #endif
  122.  
  123. #ifndef FAST_INTEGER
  124. #ifdef LONG
  125. static __data unsigned int i2bcd_tmp;  // slow 32 int conversion needs temp space
  126. #endif
  127. #endif
  128.  
  129.  
  130. #ifndef PRINTF_FAST
  131. #define PRINTF_FAST printf_fast
  132. #endif
  133.  
  134.  
  135. #if !defined(__SDCC_mcs51) || defined(__SDCC_USE_XSTACK) || defined(_SDCC_NO_ASM_LIB_FUNCS)
  136. // Does printf_fast really work on ds390 and ds400?
  137. // If it does, enable them in the line above
  138. #if defined(__SDCC_USE_XSTACK)
  139. #warning "printf_fast not built, does not support --xstack"
  140. #elif defined(_SDCC_NO_ASM_LIB_FUNCS)
  141. #warning "printf_fast not built, _SDCC_NO_ASM_LIB_FUNCS defined"
  142. #endif
  143. #else // defines are compatible with printf_fast
  144.  
  145.  
  146. void PRINTF_FAST(__code const char *fmt, ...) __reentrant
  147. {
  148.         fmt;    /* suppress unreferenced variable warning */
  149.  
  150.         __asm
  151.  
  152. printf_begin:
  153.         mov     a, _bp          // r0 will point to va_args (stack)
  154.         add     a, #253
  155.         mov     r0, a           // r0 points to MSB of fmt
  156.         mov     dph, @r0
  157.         dec     r0
  158.         mov     dpl, @r0        // dptr has address of fmt
  159.         dec     r0
  160.  
  161. printf_main_loop:
  162.         clr     a
  163.         movc    a, @a+dptr      // get next byte of fmt string
  164.         inc     dptr
  165.         //cjne  a, #'%', printf_normal
  166.         cjne    a, #37, printf_normal
  167.  
  168. printf_format:
  169.         clr     _long_flag
  170.         clr     _short_flag
  171.         clr     _print_zero_flag
  172.         clr     _negative_flag
  173. #ifdef FIELD_WIDTH
  174.         clr     _field_width_flag
  175.         clr     _leading_zero_flag
  176.         mov     r1, #_field_width
  177.         mov     @r1, #0
  178. #endif
  179. #ifdef FLOAT
  180.         clr     _continue_float
  181. #endif
  182.  
  183. printf_format_loop:
  184.         clr     a
  185.         movc    a, @a+dptr      // get next byte of data format
  186.         inc     dptr
  187.  
  188.         /* parse and consume the field width digits, even if */
  189.         /* we don't build the code to make use of them */
  190.         add     a, #198
  191.         jc      printf_nondigit1
  192.         add     a, #10
  193.         jnc     printf_nondigit2
  194. #ifdef FIELD_WIDTH
  195. printf_digit:
  196.         jnz     printf_digit_2
  197.         cjne    a, _field_width, printf_digit_2
  198.         setb    _leading_zero_flag
  199. printf_digit_2:
  200.         setb    _field_width_flag
  201.         mov     r2, a
  202.         mov     a, @r1
  203.         mov     b, #10
  204.         mul     ab
  205.         add     a, r2
  206.         mov     @r1, a
  207. #endif
  208.         sjmp    printf_format_loop
  209. printf_nondigit1:
  210.         add     a, #10
  211. printf_nondigit2:
  212.         add     a, #48
  213.  
  214. printf_format_l:
  215.         //cjne  a, #'l', printf_format_h
  216.         cjne    a, #108, printf_format_h
  217.         setb    _long_flag
  218.         sjmp    printf_format_loop
  219.  
  220. printf_format_h:
  221.         //cjne  a, #'h', printf_format_s
  222.         cjne    a, #104, printf_format_s
  223.         setb    _short_flag
  224.         sjmp    printf_format_loop
  225.  
  226. printf_format_s:
  227.         //cjne  a, #'s', printf_format_d
  228.         cjne    a, #115, printf_format_d
  229.         ljmp    printf_string
  230.  
  231. printf_format_d:
  232.         //cjne  a, #'d', printf_format_u
  233.         cjne    a, #100, printf_format_u
  234.         lcall   printf_get_int
  235.         ljmp    printf_int
  236.  
  237. printf_format_u:
  238.         //cjne  a, #'u', printf_format_c
  239.         cjne    a, #117, printf_format_c
  240.         lcall   printf_get_int
  241.         ljmp    printf_uint
  242.  
  243. printf_format_c:
  244.         //cjne  a, #'c', printf_format_x
  245.         cjne    a, #99, printf_format_x
  246.         dec     r0
  247.         mov     a, @r0          // Acc has the character to print
  248.         dec     r0
  249.         sjmp    printf_char
  250.  
  251. printf_format_x:
  252.         //cjne  a, #'x', printf_format_f
  253.         cjne    a, #120, printf_format_f
  254.         ljmp    printf_hex
  255.  
  256. printf_format_f:
  257. #ifdef FLOAT
  258.         //cjne  a, #'f', printf_format_dot
  259.         cjne    a, #102, printf_format_dot
  260.         ljmp    print_float
  261. #endif
  262.  
  263. printf_format_dot:
  264.         //cjne  a, #'.', printf_normal
  265.         cjne    a, #46, printf_normal
  266. #ifdef FLOAT
  267. #ifdef FLOAT_FIXED4
  268.         mov     r1, #ar3        // parse frac field, but discard if FIXED4
  269. #else
  270.         mov     r1, #_frac_field_width
  271.         mov     @r1, #0
  272. #endif
  273. #endif
  274.         sjmp    printf_format_loop
  275.  
  276. printf_normal:
  277.         jz      printf_eot
  278. printf_char:
  279.         lcall   printf_putchar
  280.         ljmp    printf_main_loop
  281.  
  282. printf_eot:
  283.         ljmp    printf_end
  284.  
  285.  
  286.         /* print a string... just grab each byte with __gptrget */
  287.         /* the user much pass a 24 bit generic pointer */
  288.  
  289. printf_string:
  290.         push    dph             // save addr in fmt onto stack
  291.         push    dpl
  292.         mov     b, @r0          // b has type of address (generic *)
  293.         dec     r0
  294.         mov     dph, @r0
  295.         dec     r0
  296.         mov     dpl, @r0        // dptr has address of user's string
  297.         dec     r0
  298.  
  299. #ifdef FIELD_WIDTH
  300.         jnb     _field_width_flag, printf_str_loop
  301.         clr     _leading_zero_flag      // never leading zeros for strings
  302.         push    dpl
  303.         push    dph
  304. printf_str_fw_loop:
  305.         lcall   __gptrget
  306.         jz      printf_str_space
  307.         inc     dptr
  308.         dec     _field_width
  309.         mov     a, _field_width
  310.         jnz     printf_str_fw_loop
  311. printf_str_space:
  312.         lcall   printf_space
  313.         pop     dph
  314.         pop     dpl
  315. #endif // FIELD_WIDTH
  316.  
  317. printf_str_loop:
  318.         lcall   __gptrget
  319.         jz      printf_str_done
  320.         inc     dptr
  321.         lcall   printf_putchar
  322.         sjmp    printf_str_loop
  323. printf_str_done:
  324.         pop     dpl             // restore addr withing fmt
  325.         pop     dph
  326.         ljmp    printf_main_loop
  327.  
  328.  
  329.         /* printing in hex is easy because sdcc pushes the LSB first */
  330.  
  331. printf_hex:
  332.         lcall   printf_hex8
  333.         jb      _short_flag, printf_hex_end
  334.         lcall   printf_hex8
  335.         jnb     _long_flag, printf_hex_end
  336.         lcall   printf_hex8
  337.         lcall   printf_hex8
  338. printf_hex_end:
  339.         lcall   printf_zero
  340.         ljmp    printf_main_loop
  341. printf_hex8:
  342.         mov     a, @r0
  343.         lcall   printf_phex_msn
  344.         mov     a, @r0
  345.         dec     r0
  346.         ljmp    printf_phex_lsn
  347.  
  348.  
  349. #ifndef LONG
  350. printf_ld_in_hex:
  351.         //mov   a, #'0'
  352.         mov     a, #48
  353.         lcall   printf_putchar
  354.         //mov   a, #'x'
  355.         mov     a, #120
  356.         lcall   printf_putchar
  357.         mov     a, r0
  358.         add     a, #4
  359.         mov     r0, a
  360.         sjmp    printf_hex
  361. #endif
  362.  
  363.  
  364.         /* printing an integer is not so easy.  For a signed int */
  365.         /* check if it is negative and print the minus sign and */
  366.         /* invert it to a positive integer */
  367.  
  368. printf_int:
  369.         mov     a, r5
  370.         jnb     acc.7, printf_uint      /* check if negative */
  371.         setb    _negative_flag
  372.         mov     a, r1                   /* invert integer */
  373.         cpl     a
  374.         add     a, #1
  375.         mov     r1, a
  376.         jb      _short_flag, printf_uint
  377.         mov     a, r2
  378.         cpl     a
  379.         addc    a, #0
  380.         mov     r2, a
  381.         jnb     _long_flag, printf_uint
  382.         mov     a, r3
  383.         cpl     a
  384.         addc    a, #0
  385.         mov     r3, a
  386.         mov     a, r4
  387.         cpl     a
  388.         addc    a, #0
  389.         mov     r4, a
  390.  
  391.  
  392.         /* printing integers is a lot of work... because it takes so */
  393.         /* long, the first thing to do is make sure we're doing as */
  394.         /* little work as possible, then convert the binary int to */
  395.         /* packed BCD, and finally print each digit of the BCD number */
  396.  
  397. printf_uint:
  398.  
  399.         jb      _short_flag, printf_uint_ck8
  400.         jnb     _long_flag, printf_uint_ck16
  401. printf_uint_ck32:
  402.         /* it's a 32 bit int... but if the upper 16 bits are zero */
  403.         /* we can treat it like a 16 bit integer and convert much faster */
  404. #ifdef LONG
  405.         mov     a, r3
  406.         jnz     printf_uint_begin
  407.         mov     a, r4
  408.         jnz     printf_uint_begin
  409. #else
  410.         mov     a, r3
  411.         jnz     printf_ld_in_hex        // print long integer as hex
  412.         mov     a, r4                   // rather than just the low 16 bits
  413.         jnz     printf_ld_in_hex
  414. #endif
  415.         clr     _long_flag
  416. printf_uint_ck16:
  417.         /* it's a 16 bit int... but if the upper 8 bits are zero */
  418.         /* we can treat it like a 8 bit integer and convert much faster */
  419.         mov     a, r2
  420.         jnz     printf_uint_begin
  421.         setb    _short_flag
  422. printf_uint_ck8:
  423.         /* it's an 8 bit int... if it's zero, it's a lot faster to just */
  424.         /* print the digit zero and skip all the hard work! */
  425.         mov     a, r1
  426.         jnz     printf_uint_begin
  427. #ifdef FLOAT
  428.         /* never use the "just print zero" shortcut if we're printing */
  429.         /* the integer part of a float  (fixes bug 1255403)  */
  430.         jb      _continue_float, printf_uint_begin
  431. #endif
  432. #ifdef FIELD_WIDTH
  433.         jnb     _field_width_flag, printf_uint_zero
  434.         mov     a, _field_width
  435.         jz      printf_uint_zero
  436.         dec     _field_width
  437.         lcall   printf_space
  438. #endif
  439. printf_uint_zero:
  440.         //mov   a, #'0'
  441.         mov     a, #48
  442.         lcall   printf_putchar
  443.         ljmp    printf_main_loop
  444.  
  445. printf_uint_begin:
  446.         push    dpl
  447.         push    dph
  448.         lcall   printf_int2bcd          // bcd number in r3/r2/r7/r6/r5
  449. printf_uint_2:
  450.  
  451. #ifdef FIELD_WIDTH
  452.         jnb     _field_width_flag, printf_uifw_end
  453. #ifdef LONG
  454. printf_uifw_32:
  455.         mov     r1, #10
  456.         jnb     _long_flag, printf_uifw_16
  457.         mov     a, r3
  458.         anl     a, #0xF0
  459.         jnz     printf_uifw_sub
  460.         dec     r1
  461.         mov     a, r3
  462.         anl     a, #0x0F
  463.         jnz     printf_uifw_sub
  464.         dec     r1
  465.         mov     a, r2
  466.         anl     a, #0xF0
  467.         jnz     printf_uifw_sub
  468.         dec     r1
  469.         mov     a, r2
  470.         anl     a, #0x0F
  471.         jnz     printf_uifw_sub
  472.         dec     r1
  473.         mov     a, r7
  474.         anl     a, #0xF0
  475.         jnz     printf_uifw_sub
  476. #endif // LONG
  477. printf_uifw_16:
  478.         mov     r1, #5
  479.         jb      _short_flag, printf_uifw_8
  480.         mov     a, r7
  481.         anl     a, #0x0F
  482.         jnz     printf_uifw_sub
  483.         dec     r1
  484.         mov     a, r6
  485.         anl     a, #0xF0
  486.         jnz     printf_uifw_sub
  487. printf_uifw_8:
  488.         mov     r1, #3
  489.         mov     a, r6
  490.         anl     a, #0x0F
  491.         jnz     printf_uifw_sub
  492.         dec     r1
  493.         mov     a, r5
  494.         anl     a, #0xF0
  495.         jnz     printf_uifw_sub
  496.         dec     r1
  497. printf_uifw_sub:
  498.         //r1 has the number of digits for the number
  499.         mov     a, _field_width
  500.         mov     c, _negative_flag
  501.         subb    a, r1
  502.         jc      printf_uifw_end
  503.         mov     _field_width, a
  504.  
  505. #ifndef PUTCHAR_CALLEE_SAVES
  506. #ifdef LONG
  507.         push    ar3
  508.         push    ar2
  509. #endif
  510.         push    ar7
  511.         push    ar6
  512.         push    ar5
  513. #endif
  514.         lcall   printf_space
  515. #ifndef PUTCHAR_CALLEE_SAVES
  516.         pop     ar5
  517.         pop     ar6
  518.         pop     ar7
  519. #ifdef LONG
  520.         pop     ar2
  521.         pop     ar3
  522. #endif
  523. #endif
  524.  
  525.  
  526. printf_uifw_end:
  527. #endif // FIELD_WIDTH
  528.  
  529.  
  530. printf_uint_doit:
  531.         jnb     _negative_flag, printf_uint_pos
  532. #ifdef PUTCHAR_CALLEE_SAVES
  533.         //mov   a, #'-'
  534.         mov     a, #45
  535.         lcall   printf_putchar
  536. #else
  537. #ifdef LONG
  538.         push    ar3
  539.         push    ar2
  540. #endif
  541.         push    ar7
  542.         push    ar6
  543.         push    ar5
  544.         //mov   a, #'-'
  545.         mov     a, #45
  546.         lcall   printf_putchar
  547.         pop     ar5
  548.         pop     ar6
  549.         pop     ar7
  550. #ifdef LONG
  551.         pop     ar2
  552.         pop     ar3
  553. #endif
  554. #endif // PUTCHAR_CALLEE_SAVES
  555.  
  556. printf_uint_pos:
  557.         jb      _short_flag, printf_uint8
  558. #ifdef LONG
  559.         jnb     _long_flag, printf_uint16
  560. printf_uint32:
  561.         push    ar5
  562.         push    ar6
  563.         push    ar7
  564.         mov     dpl, r2
  565.         mov     a, r3
  566.         mov     dph, a
  567.         lcall   printf_phex_msn
  568.         mov     a, dph
  569.         lcall   printf_phex_lsn
  570.         mov     a, dpl
  571.         lcall   printf_phex_msn
  572.         mov     a, dpl
  573.         lcall   printf_phex_lsn
  574.         pop     acc
  575.         mov     dpl, a
  576.         lcall   printf_phex_msn
  577.         mov     a, dpl
  578.         pop     dph
  579.         pop     dpl
  580.         sjmp    printf_uint16a
  581. #endif // LONG
  582.  
  583. printf_uint16:
  584.         mov     dpl, r5
  585.         mov     dph, r6
  586.         mov     a, r7
  587. printf_uint16a:
  588.         lcall   printf_phex_lsn
  589.         mov     a, dph
  590.         lcall   printf_phex_msn
  591.         mov     a, dph
  592.         sjmp    printf_uint8a
  593.  
  594. printf_uint8:
  595.         mov     dpl, r5
  596.         mov     a, r6
  597. printf_uint8a:
  598.         lcall   printf_phex_lsn
  599.         mov     a, dpl
  600.         lcall   printf_phex_msn
  601.         mov     a, dpl
  602.         lcall   printf_phex_lsn
  603.         lcall   printf_zero
  604.         pop     dph
  605.         pop     dpl
  606. #ifdef FLOAT
  607.         jnb     _continue_float, 0002$
  608.         ret
  609. 0002$:
  610. #endif
  611.         ljmp    printf_main_loop
  612.  
  613.  
  614. #ifdef FLOAT
  615. #ifdef FLOAT_FIXED4
  616.         // Print a float the easy way.  First, extract the integer part and
  617.         // use the integer printing code.  Then extract the fractional part,
  618.         // convert each bit to 4 digit BCD, and print the BCD sum.  Absolutely
  619.         // no field width control, always 4 digits printed past the decimal
  620.         // point.  No round off.  1.9999987 prints as 1.9999, not 2.0000.
  621. print_float:
  622. #ifdef FIELD_WIDTH
  623.         jnb     _field_width_flag, print_float_begin
  624.         mov     a, _field_width
  625.         add     a, #251
  626.         mov     _field_width, a
  627.         jc      print_float_begin
  628.         mov     _field_width, #0
  629. #endif
  630. print_float_begin:
  631.         push    ar0             // keep r0 safe, will need it again
  632.         lcall   printf_get_float
  633.         clr     c
  634.         mov     a, #158                 // check for large float we can't print
  635.         subb    a, r7
  636.         jnc     print_float_size_ok
  637. printf_float_too_big:
  638.         // TODO: should print some sort of overflow error??
  639.         pop     ar0
  640.         ljmp    printf_format_loop
  641. print_float_size_ok:
  642.         push    dpl
  643.         lcall   fs_rshift_a
  644.         pop     dpl
  645.         setb    _continue_float
  646. #ifndef LONG
  647.         mov     a, r3
  648.         orl     a, r4
  649.         jnz     printf_float_too_big
  650. #endif
  651.         lcall   printf_uint             // print the integer portion
  652.         //mov   a, #'.'
  653.         mov     a, #0x2E
  654.         lcall   printf_putchar
  655.         // now that the integer part is printed, we need to refetch the
  656.         // float from the va_args and extract the fractional part
  657.         pop     ar0
  658.         lcall   printf_get_float
  659.         push    ar0
  660.         push    dpl
  661.         push    dph
  662.         mov     a, r7
  663.         cjne    a, #126, print_float_frac_lshift
  664.         sjmp    print_float_frac // input between 0.5 to 0.9999
  665. print_float_frac_lshift:
  666.         jc      print_float_frac_rshift
  667.         //Acc (exponent) is greater than 126 (input >= 1.0)
  668.         add     a, #130
  669.         mov     r5, a
  670. print_float_lshift_loop:
  671.         clr     c
  672.         mov     a, r2
  673.         rlc     a
  674.         mov     r2, a
  675.         mov     a, r3
  676.         rlc     a
  677.         mov     r3, a
  678.         mov     a, r4
  679.         rlc     a
  680.         mov     r4, a
  681.         djnz    r5, print_float_lshift_loop
  682.         sjmp    print_float_frac
  683. print_float_frac_rshift:
  684.         //Acc (exponent) is less than 126 (input < 0.5)
  685.         cpl     a
  686.         add     a, #127
  687.         lcall   fs_rshift_a
  688. print_float_frac:
  689.         // now we've got the fractional part, so now is the time to
  690.         // convert to BCD... just convert each bit to BCD using a
  691.         // lookup table and BCD sum them together
  692.         mov     r7, #14
  693.         clr     a
  694.         mov     r6, a
  695.         mov     r5, a
  696.         mov     dptr, #_frac2bcd        // FLOAT_FIXED4 version (14 entries)
  697. print_float_frac_loop:
  698.         mov     a, r3
  699.         rlc     a
  700.         mov     r3, a
  701.         mov     a, r4
  702.         rlc     a
  703.         mov     r4, a
  704.         jnc     print_float_frac_skip
  705.         clr     a
  706.         movc    a, @a+dptr
  707.         add     a, r5
  708.         da      a
  709.         mov     r5, a
  710.         mov     a, #1
  711.         movc    a, @a+dptr
  712.         addc    a, r6
  713.         da      a
  714.         mov     r6, a
  715. print_float_frac_skip:
  716.         inc     dptr
  717.         inc     dptr
  718.         djnz    r7, print_float_frac_loop
  719.         // the BCD sum is in dptr, so all we've got to do is output
  720.         // all 4 digits.  No trailing zero suppression, no nice round
  721.         // off (impossible to change the integer part since we already
  722.         // printed it).
  723.         mov     dph, r6
  724.         mov     dpl, r5
  725.         setb    _print_zero_flag
  726.         mov     a, dph
  727.         lcall   printf_phex_msn
  728.         mov     a, dph
  729.         lcall   printf_phex_lsn
  730.         mov     a, dpl
  731.         lcall   printf_phex_msn
  732.         mov     a, dpl
  733.         lcall   printf_phex_lsn
  734.         pop     dph
  735.         pop     dpl
  736.         pop     ar0
  737.         ljmp    printf_main_loop
  738.  
  739. #else // not FLOAT_FIXED4
  740.  
  741.  
  742. print_float:
  743.         // Print a float the not-as-easy way, with a configurable number of
  744.         // fractional digits (up to 8) and proper round-off (up to 7 digits).
  745.         // First, extract the fractional part, convert to BCD, and then add
  746.         // the scaled round-off.  Store the rounded fractional digits and
  747.         // their carry.  Then extract the integer portion, increment it if
  748.         // the rounding caused a carry.  Use the integer printing to output
  749.         // the integer, and then output the stored fractional digits.  This
  750.         // approach requires 5 bytes of internal RAM to store the 8 fractional
  751.         // digits and the number of them we'll actually print.  This code is
  752.         // a couple hundred bytes larger and a bit slower than the FIXED4
  753.         // version, but it gives very nice results.
  754. print_float_1:
  755. #ifdef FIELD_WIDTH
  756.         jnb     _field_width_flag, print_float_default_width
  757.         // The caller specified exact field width, so use it.  Need to
  758.         // convert the whole float digits into the integer portion only.
  759.         mov     a, _field_width
  760.         setb    c
  761.         subb    a, _frac_field_width
  762.         mov     _field_width, a
  763.         jnc     print_float_begin
  764.         mov     _field_width, #0
  765.         sjmp    print_float_begin
  766. #endif
  767. print_float_default_width:
  768.         // The caller didn't specify field width (or FIELD_WIDTH is
  769.         // not defined so it's ignored).  We've still got to know
  770.         // how many fractional digits are going to print, so we can
  771.         // round off properly.
  772. #ifdef FLOAT_DEFAULT_FRAC_DIGITS
  773.         mov     _frac_field_width, #FLOAT_DEFAULT_FRAC_DIGITS
  774. #else
  775.         // default fractional field width (between 0 to 7)
  776.         // attempt to scale the default number of fractional digits
  777.         // based on the magnitude of the float
  778.         mov     a, @r0
  779.         anl     a, #0x7F        // ignore sign bit
  780.         mov     r2, a           // r2 is first byte of float
  781.         dec     r0
  782.         mov     ar3, @r0        // r3 is second byte of float
  783.         inc     r0
  784.         mov     r6, dpl
  785.         mov     r7, dph
  786.         mov     dptr, #_float_range_table
  787.         mov     r5, #7
  788. print_float_default_loop:
  789.         clr     a
  790.         movc    a, @a+dptr
  791.         add     a, r3
  792.         inc     dptr
  793.         clr     a
  794.         movc    a, @a+dptr
  795.         addc    a, r2
  796.         jnc     print_float_default_done
  797.         inc     dptr
  798.         djnz    r5, print_float_default_loop
  799. print_float_default_done:
  800.         mov     _frac_field_width, r5
  801.         mov     dpl, r6
  802.         mov     dph, r7
  803. #endif // not FLOAT_DEFAULT_FRAC_DIGITS
  804.  
  805. print_float_begin:
  806.         push    ar0                     // keep r0 safe, will need it again
  807.         lcall   printf_get_float
  808.         push    dpl
  809.         push    dph
  810.         mov     a, r7
  811.         cjne    a, #126, print_float_frac_lshift
  812.         sjmp    print_float_frac        // input between 0.5 to 0.9999
  813.  
  814. print_float_frac_lshift:
  815.         jc      print_float_frac_rshift
  816.         //Acc (exponent) is greater than 126 (input >= 1.0)
  817.         add     a, #130
  818.         mov     r5, a
  819. print_float_lshift_loop:
  820.         clr     c
  821.         mov     a, r2
  822.         rlc     a
  823.         mov     r2, a
  824.         mov     a, r3
  825.         rlc     a
  826.         mov     r3, a
  827.         mov     a, r4
  828.         rlc     a
  829.         mov     r4, a
  830.         djnz    r5, print_float_lshift_loop
  831.         sjmp    print_float_frac
  832. print_float_frac_rshift:
  833.         //Acc (exponent) is less than 126 (input < 0.5)
  834.         cpl     a
  835.         add     a, #127
  836.         lcall   fs_rshift_a
  837. print_float_frac:
  838.         // Convert the fraction in r4/r3/r2/r1 into 8 BCD digits in r0/r7/r6/r5
  839.         mov     b, #27
  840.         clr     a
  841.         mov     r0, a
  842.         mov     r7, a
  843.         mov     r6, a
  844.         mov     r5, a
  845.         mov     dptr, #_frac2bcd        // FLOAT version (27 entries)
  846. print_float_frac_loop:
  847.         mov     a, r1
  848.         rlc     a
  849.         mov     r1, a
  850.         mov     a, r2
  851.         rlc     a
  852.         mov     r2, a
  853.         mov     a, r3
  854.         rlc     a
  855.         mov     r3, a
  856.         mov     a, r4
  857.         rlc     a
  858.         mov     r4, a
  859.         jnc     print_float_frac_skip
  860.         clr     a
  861.         movc    a, @a+dptr
  862.         add     a, r5
  863.         da      a
  864.         mov     r5, a
  865.         mov     a, #1
  866.         movc    a, @a+dptr
  867.         addc    a, r6
  868.         da      a
  869.         mov     r6, a
  870.         mov     a, #2
  871.         movc    a, @a+dptr
  872.         addc    a, r7
  873.         da      a
  874.         mov     r7, a
  875.         mov     a, #3
  876.         movc    a, @a+dptr
  877.         addc    a, r0
  878.         da      a
  879.         mov     r0, a
  880. print_float_frac_skip:
  881.         inc     dptr
  882.         inc     dptr
  883.         inc     dptr
  884.         inc     dptr
  885.         djnz    b, print_float_frac_loop
  886. print_float_frac_roundoff:
  887.         // Now it's time to round-off the BCD digits to the desired precision.
  888.         clr     a
  889.         mov     r4, #0x50               // r4/r3/r2/r1 = 0.5 (bcd rounding)
  890.         mov     r3, a
  891.         mov     r2, a
  892.         mov     r1, a
  893.         mov     a, _frac_field_width
  894.         rl      a
  895.         rl      a
  896.         anl     a, #0xFC
  897.         mov     dph, r0                 // fs_rshift_a will overwrite r0 & dpl
  898.         lcall   fs_rshift_a             // divide r4/r3/r2/r1 by 10^frac_field_width
  899.         mov     a, r5
  900.         add     a, r1                   // add rounding to fractional part
  901.         da      a
  902.         mov     _float_frac_bcd+3, a    // and store it for later use
  903.         mov     a, r6
  904.         addc    a, r2
  905.         da      a
  906.         mov     _float_frac_bcd+2, a
  907.         mov     a, r7
  908.         addc    a, r3
  909.         da      a
  910.         mov     _float_frac_bcd+1, a
  911.         mov     a, dph
  912.         addc    a, r4
  913.         da      a
  914.         mov     _float_frac_bcd+0, a
  915.         mov     sign_b, c               // keep fractional carry in sign_b
  916.         pop     dph
  917.         pop     dpl
  918. print_float_int:
  919.         // Time to work on the integer portion... fetch the float again, check
  920.         // size (exponent), scale to integer, add the fraction's carry, and
  921.         // let the integer printing code do all the work.
  922.         pop     ar0
  923.         lcall   printf_get_float
  924.         push    ar0
  925.         clr     c
  926.         mov     a, #158                 // check for large float we can't print
  927.         subb    a, r7
  928.         jnc     print_float_size_ok
  929. printf_float_too_big:
  930.         // TODO: should print some sort of overflow error??
  931.         pop     ar0
  932.         ljmp    printf_format_loop
  933. print_float_size_ok:
  934.         push    dpl
  935.         lcall   fs_rshift_a
  936.         pop     dpl
  937.         jnb     sign_b, print_float_do_int
  938.         // if we get here, the fractional round off caused the
  939.         // integer part to increment.  Add 1 for a proper result
  940.         mov     a, r1
  941.         add     a, #1
  942.         mov     r1, a
  943.         clr     a
  944.         addc    a, r2
  945.         mov     r2, a
  946. #ifdef LONG
  947.         clr     a
  948.         addc    a, r3
  949.         mov     r3, a
  950.         clr     a
  951.         addc    a, r4
  952.         mov     r4, a
  953. #endif
  954.         jc      printf_float_too_big
  955. print_float_do_int:
  956. #ifndef LONG
  957.         mov     a, r3
  958.         orl     a, r4
  959.         jnz     printf_float_too_big
  960. #endif
  961.         setb    _continue_float
  962.         lcall   printf_uint             // print the integer portion
  963.  
  964.  
  965. print_float_frac_width:
  966.         // Now all we have to do is output the fractional digits that
  967.         // were previous computed and stored in memory.
  968. #ifdef FIELD_WIDTH
  969.         jb      _field_width_flag, print_float_do_frac
  970. #endif
  971. #ifndef DO_NOT_TRIM_TRAILING_ZEROS
  972.         // if the user did not explicitly set a
  973.         // field width, trim off trailing zeros
  974. print_float_frac_trim:
  975.         mov     a, _frac_field_width
  976.         jz      print_float_do_frac
  977.         lcall   get_float_frac_digit
  978.         jnz     print_float_do_frac
  979.         djnz    _frac_field_width, print_float_frac_trim
  980. #endif
  981.  
  982. print_float_do_frac:
  983.         mov     a, _frac_field_width
  984.         jz      print_float_done
  985.         //mov   a, #'.'
  986.         mov     a, #0x2E
  987.         lcall   printf_putchar
  988.         mov     r0, #0
  989.         setb    _print_zero_flag
  990. print_float_do_frac_loop:
  991.         inc     r0
  992.         mov     a, r0
  993.         lcall   get_float_frac_digit
  994.         lcall   printf_phex_lsn
  995.         mov     a, r0
  996.         cjne    a, _frac_field_width, print_float_do_frac_loop
  997.  
  998. print_float_done:
  999.         pop     ar0
  1000.         ljmp    printf_main_loop
  1001.  
  1002.  
  1003.         // acc=1 for tenths, acc=2 for hundredths, etc
  1004. get_float_frac_digit:
  1005.         dec     a
  1006.         clr     c
  1007.         rrc     a
  1008.         mov     psw.5, c
  1009.         add     a, #_float_frac_bcd
  1010.         mov     r1, a
  1011.         mov     a, @r1
  1012.         jb      psw.5, get_float_frac_digit_done
  1013.         swap    a
  1014. get_float_frac_digit_done:
  1015.         anl     a, #15
  1016.         ret
  1017.  
  1018. #endif // end of normal FLOAT code (not FLOAT_FIXED4)
  1019.  
  1020.  
  1021. // These helper functions are used, regardless of which type of
  1022. // FLOAT code is used.
  1023.  
  1024. #if 0
  1025. pm2_print_float:
  1026.          mov    a, r7
  1027.          lcall  pm2_entry_phex
  1028.          mov    a, #0x20
  1029.          lcall  pm2_entry_cout
  1030.          lcall  _print_r4321
  1031.          mov    a, #0x20
  1032.          lcall  pm2_entry_cout
  1033.          ret
  1034. #endif
  1035.  
  1036.         // Fetch a float from the va_args and put it into
  1037.         // r7(exp) r4/r3/r2(mant) and also clear r1 and preset
  1038.         // the flags
  1039. printf_get_float:
  1040.         mov     a, @r0
  1041.         dec     r0
  1042.         mov     r1, a
  1043.         mov     a, @r0
  1044.         dec     r0
  1045.         mov     r4, a
  1046.         rlc     a
  1047.         mov     a, r1
  1048.         rlc     a
  1049.         mov     _negative_flag, c
  1050.         mov     r7, a
  1051.         jz      printf_get_float_2
  1052.         orl     ar4, #0x80
  1053. printf_get_float_2:
  1054.         mov     a, @r0
  1055.         dec     r0
  1056.         mov     r3, a
  1057.         mov     a, @r0
  1058.         dec     r0
  1059.         mov     r2, a
  1060.         mov     r1, #0
  1061.         clr     _short_flag
  1062.         setb    _long_flag
  1063.         ret
  1064. #endif // FLOAT
  1065.  
  1066.  
  1067.         /* read an integer into r1/r2/r3/r4, and msb into r5 */
  1068. printf_get_int:
  1069.         mov     a, @r0
  1070.         mov     r1, a
  1071.         mov     r5, a
  1072.         dec     r0
  1073.         jb      _short_flag, printf_get_done
  1074.         mov     r2, ar1
  1075.         mov     a, @r0
  1076.         mov     r1, a
  1077.         dec     r0
  1078.         jnb     _long_flag, printf_get_done
  1079.         mov     r4, ar2
  1080.         mov     r3, ar1
  1081.         mov     a, @r0
  1082.         mov     r2, a
  1083.         dec     r0
  1084.         mov     a, @r0
  1085.         mov     r1, a
  1086.         dec     r0
  1087. printf_get_done:
  1088.         ret
  1089.  
  1090.  
  1091. #ifdef FAST_INTEGER
  1092.  
  1093.         /* convert binary number in r4/r3/r2/r1 into bcd packed number
  1094.          * in r3/r2/r7/r6/r5.  The input number is destroyed in the
  1095.          * process, to avoid needing extra memory for the result (and
  1096.          * r1 gets used for temporary storage).  dptr is overwritten,
  1097.          * but r0 is not changed.
  1098.          */
  1099.  
  1100. printf_int2bcd:
  1101.         mov     a, r1
  1102.         mov     b, #100
  1103.         div     ab
  1104.         mov     r6, a
  1105.         mov     a, #10
  1106.         xch     a, b
  1107.         div     ab
  1108.         swap    a
  1109.         orl     a, b
  1110.         mov     r5, a
  1111.  
  1112.         jnb     _short_flag, printf_i2bcd_16    // if 8 bit int, we're done
  1113.         ret
  1114.  
  1115. printf_i2bcd_16:
  1116.         mov     a, r2
  1117.         anl     a, #0x0F
  1118.         mov     r1, a
  1119.         mov     dptr, #_int2bcd_2
  1120.         movc    a, @a+dptr
  1121.         add     a, r5
  1122.         da      a
  1123.         mov     r5, a
  1124.         mov     a, r1
  1125.         orl     a, #16
  1126.         movc    a, @a+dptr
  1127.         addc    a, r6
  1128.         da      a
  1129.         mov     r6, a
  1130.  
  1131.         mov     a, r2
  1132.         swap    a
  1133.         anl     a, #0x0F
  1134.         mov     r1, a
  1135.         mov     dptr, #_int2bcd_3
  1136.         movc    a, @a+dptr
  1137.         add     a, r5
  1138.         da      a
  1139.         mov     r5, a
  1140.         mov     a, r1
  1141.         orl     a, #16
  1142.         movc    a, @a+dptr
  1143.         addc    a, r6
  1144.         da      a
  1145.         mov     r6, a
  1146.         mov     a, r1
  1147.         orl     a, #32
  1148.         movc    a, @a+dptr
  1149.         addc    a, #0
  1150.         da      a
  1151.         mov     r7, a
  1152.  
  1153.         jb      _long_flag, printf_i2bcd_32     // if 16 bit int, we're done
  1154.         ret
  1155.  
  1156. printf_i2bcd_32:
  1157.  
  1158. #ifdef LONG
  1159.         mov     a, r3
  1160.         anl     a, #0x0F
  1161.         mov     r1, a
  1162.         mov     dptr, #_int2bcd_4
  1163.         movc    a, @a+dptr
  1164.         add     a, r5
  1165.         da      a
  1166.         mov     r5, a
  1167.         mov     a, r1
  1168.         orl     a, #16
  1169.         movc    a, @a+dptr
  1170.         addc    a, r6
  1171.         da      a
  1172.         mov     r6, a
  1173.         mov     a, r1
  1174.         orl     a, #32
  1175.         movc    a, @a+dptr
  1176.         addc    a, r7
  1177.         da      a
  1178.         mov     r7, a
  1179.         clr     a
  1180.         addc    a, #0
  1181.         mov     r2, a
  1182.  
  1183.         mov     a, r3
  1184.         swap    a
  1185.         anl     a, #0x0F
  1186.         mov     r1, a
  1187.         mov     dptr, #_int2bcd_5
  1188.         movc    a, @a+dptr
  1189.         add     a, r5
  1190.         da      a
  1191.         mov     r5, a
  1192.         mov     a, r1
  1193.         orl     a, #16
  1194.         movc    a, @a+dptr
  1195.         addc    a, r6
  1196.         da      a
  1197.         mov     r6, a
  1198.         mov     a, r1
  1199.         orl     a, #32
  1200.         movc    a, @a+dptr
  1201.         addc    a, r7
  1202.         da      a
  1203.         mov     r7, a
  1204.         mov     a, r1
  1205.         orl     a, #48
  1206.         movc    a, @a+dptr
  1207.         addc    a, r2
  1208.         da      a
  1209.         mov     r2, a
  1210.  
  1211.         mov     a, r4
  1212.         anl     a, #0x0F
  1213.         mov     r1, a
  1214.         mov     dptr, #_int2bcd_6
  1215.         mov     r3, #0
  1216.         lcall   printf_bcd_add10        // saves 27 bytes, costs 5 cycles
  1217.  
  1218.         mov     a, r4
  1219.         swap    a
  1220.         anl     a, #0x0F
  1221.         mov     r1, a
  1222.         mov     dptr, #_int2bcd_7
  1223. printf_bcd_add10:
  1224.         movc    a, @a+dptr
  1225.         add     a, r5
  1226.         da      a
  1227.         mov     r5, a
  1228.         mov     a, r1
  1229.         orl     a, #16
  1230.         movc    a, @a+dptr
  1231.         addc    a, r6
  1232.         da      a
  1233.         mov     r6, a
  1234.         mov     a, r1
  1235.         orl     a, #32
  1236.         movc    a, @a+dptr
  1237.         addc    a, r7
  1238.         da      a
  1239.         mov     r7, a
  1240.         mov     a, r1
  1241.         orl     a, #48
  1242.         movc    a, @a+dptr
  1243.         addc    a, r2
  1244.         da      a
  1245.         mov     r2, a
  1246.         mov     a, r1
  1247.         orl     a, #64
  1248.         movc    a, @a+dptr
  1249.         addc    a, r3
  1250.         da      a
  1251.         mov     r3, a
  1252. #endif // LONG
  1253.         ret
  1254.  
  1255.  
  1256. #else // not FAST_INTEGER
  1257.  
  1258.         /* convert binary number in r4/r3/r2/r1 into bcd packed number
  1259.          * in r3/r2/r7/r6/r5.  The input number is destroyed in the
  1260.          * process, to avoid needing extra memory for the result (and
  1261.          * r1 gets used for temporary storage).  dptr is overwritten,
  1262.          * but r0 is not changed.
  1263.          */
  1264.  
  1265. #ifdef LONG
  1266.  
  1267. printf_int2bcd:
  1268.         mov     a, #8
  1269.         jb      _short_flag, printf_int2bcd_begin
  1270.         mov     a, #16
  1271.         jnb     _long_flag, printf_int2bcd_begin
  1272.         mov     a, #32
  1273. printf_int2bcd_begin:
  1274.         mov     b, a
  1275.         clr     a
  1276.         mov     r5, a
  1277.         mov     r6, a
  1278.         mov     r7, a
  1279.         mov     (_i2bcd_tmp + 0), a
  1280.         mov     (_i2bcd_tmp + 1), a
  1281.         mov     dptr, #_int2bcd
  1282. printf_i2bcd_loop:
  1283.         mov     a, r4
  1284.         rrc     a
  1285.         mov     r4, a
  1286.         mov     a, r3
  1287.         rrc     a
  1288.         mov     r3, a
  1289.         mov     a, r2
  1290.         rrc     a
  1291.         mov     r2, a
  1292.         mov     a, r1
  1293.         rrc     a
  1294.         mov     r1, a
  1295.         jnc     print_i2bcd_skip
  1296.         clr     a
  1297.         movc    a, @a+dptr
  1298.         add     a, r5
  1299.         da      a
  1300.         mov     r5, a
  1301.         mov     a, #1
  1302.         movc    a, @a+dptr
  1303.         addc    a, r6
  1304.         da      a
  1305.         mov     r6, a
  1306.         mov     a, #2
  1307.         movc    a, @a+dptr
  1308.         addc    a, r7
  1309.         da      a
  1310.         mov     r7, a
  1311.         mov     a, #3
  1312.         movc    a, @a+dptr
  1313.         addc    a, (_i2bcd_tmp + 0)
  1314.         da      a
  1315.         mov     (_i2bcd_tmp + 0), a
  1316.         mov     a, #4
  1317.         movc    a, @a+dptr
  1318.         addc    a, (_i2bcd_tmp + 1)
  1319.         da      a
  1320.         mov     (_i2bcd_tmp + 1), a
  1321. print_i2bcd_skip:
  1322.         inc     dptr
  1323.         inc     dptr
  1324.         inc     dptr
  1325.         inc     dptr
  1326.         inc     dptr
  1327.         djnz    b, printf_i2bcd_loop
  1328.         mov     r2, (_i2bcd_tmp + 0)
  1329.         mov     r3, (_i2bcd_tmp + 1)
  1330.         ret
  1331.  
  1332. #else //  not LONG
  1333.  
  1334. printf_int2bcd:
  1335.         mov     a, #8
  1336.         jb      _short_flag, printf_int2bcd_begin
  1337.         mov     a, #16
  1338. printf_int2bcd_begin:
  1339.         mov     b, a
  1340.         clr     a
  1341.         mov     r5, a
  1342.         mov     r6, a
  1343.         mov     r7, a
  1344.         mov     dptr, #_int2bcd
  1345. printf_i2bcd_loop:
  1346.         mov     a, r2
  1347.         rrc     a
  1348.         mov     r2, a
  1349.         mov     a, r1
  1350.         rrc     a
  1351.         mov     r1, a
  1352.         jnc     printf_i2bcd_add_skip
  1353.         clr     a
  1354.         movc    a, @a+dptr
  1355.         add     a, r5
  1356.         da      a
  1357.         mov     r5, a
  1358.         mov     a, #1
  1359.         movc    a, @a+dptr
  1360.         addc    a, r6
  1361.         da      a
  1362.         mov     r6, a
  1363.         mov     a, #2
  1364.         movc    a, @a+dptr
  1365.         addc    a, r7
  1366.         da      a
  1367.         mov     r7, a
  1368. printf_i2bcd_add_skip:
  1369.         inc     dptr
  1370.         inc     dptr
  1371.         inc     dptr
  1372.         djnz    b, printf_i2bcd_loop
  1373.         ret
  1374.  
  1375. #endif // not LONG
  1376.  
  1377.  
  1378. #endif // not FAST_INTEGER
  1379.  
  1380.  
  1381. #ifdef FIELD_WIDTH
  1382. printf_space_loop:
  1383.         //mov   a, #' '
  1384.         mov     a, #32
  1385.         jnb     _leading_zero_flag, printf_space_output
  1386.         //mov   a, #'0'
  1387.         mov     a, #48
  1388. printf_space_output:
  1389.         lcall   printf_putchar
  1390.         dec     _field_width
  1391. printf_space:
  1392.         mov     a, _field_width
  1393.         jnz     printf_space_loop
  1394.         ret
  1395. #endif
  1396.  
  1397.         /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
  1398.  
  1399. printf_phex_msn:
  1400.         swap    a
  1401. printf_phex_lsn:
  1402.         anl     a, #15
  1403.         jnz     printf_phex_ok
  1404.         jnb     _print_zero_flag, printf_ret
  1405. printf_phex_ok:
  1406.         setb    _print_zero_flag
  1407.         add     a, #0x90
  1408.         da      a
  1409.         addc    a, #0x40
  1410.         da      a
  1411. printf_putchar:
  1412. #ifdef PUTCHAR_CALLEE_SAVES
  1413.         push    dph
  1414.         push    dpl
  1415.         mov     dpl, a
  1416.         lcall   _putchar
  1417.         pop     dpl
  1418.         pop     dph
  1419. #else
  1420.         push    dph
  1421.         push    dpl
  1422.         push    ar0
  1423.         mov     dpl, a
  1424.         lcall   _putchar
  1425.         pop     ar0
  1426.         pop     dpl
  1427.         pop     dph
  1428. #endif
  1429. printf_ret:
  1430.         ret
  1431.  
  1432.         /* print a zero if all the calls to print the digits ended up */
  1433.         /* being leading zeros */
  1434.  
  1435. printf_zero:
  1436.         jb      _print_zero_flag, printf_ret
  1437.         //mov   a, #'0'
  1438.         mov     a, #48
  1439.         ljmp    printf_putchar
  1440.  
  1441. printf_end:
  1442.         __endasm;
  1443. }
  1444.  
  1445.  
  1446. #ifdef FAST_INTEGER
  1447. /*
  1448.  * #! /usr/bin/perl
  1449.  * for ($d=0; $d < 8; $d++) {
  1450.  *      $n = 16 ** $d;
  1451.  *      for ($p=0; $p < 5; $p++) {
  1452.  *              last unless (((16 ** $d) * 15) / (10 ** ($p * 2))) % 100;
  1453.  *              printf "code unsigned char int2bcd_%d_%d[15] = {", $d, $p;
  1454.  *              for ($i=0; $i < 16; $i++) {
  1455.  *                      printf "0x%02d",
  1456.  *                         (((16 ** $d) * $i) / (10 ** ($p * 2))) % 100;
  1457.  *                      print ", " if $i < 15;
  1458.  *              }
  1459.  *              print "};\n";
  1460.  *      }
  1461.  * }
  1462.  */
  1463.  
  1464. #if 0
  1465. static __code unsigned char int2bcd_0[] = {
  1466. 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
  1467. 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
  1468.  
  1469. static __code unsigned char int2bcd_1[] = {
  1470. 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
  1471. 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
  1472. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  1473. 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02};
  1474. #endif
  1475.  
  1476. static __code unsigned char int2bcd_2[] = {
  1477. 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
  1478. 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
  1479. 0x00, 0x02, 0x05, 0x07, 0x10, 0x12, 0x15, 0x17,
  1480. 0x20, 0x23, 0x25, 0x28, 0x30, 0x33, 0x35, 0x38};
  1481.  
  1482. static __code unsigned char int2bcd_3[] = {
  1483. 0x00, 0x96, 0x92, 0x88, 0x84, 0x80, 0x76, 0x72,
  1484. 0x68, 0x64, 0x60, 0x56, 0x52, 0x48, 0x44, 0x40,
  1485. 0x00, 0x40, 0x81, 0x22, 0x63, 0x04, 0x45, 0x86,
  1486. 0x27, 0x68, 0x09, 0x50, 0x91, 0x32, 0x73, 0x14,
  1487. 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02,
  1488. 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06};
  1489.  
  1490. #ifdef LONG
  1491. static __code unsigned char int2bcd_4[] = {
  1492. 0x00, 0x36, 0x72, 0x08, 0x44, 0x80, 0x16, 0x52,
  1493. 0x88, 0x24, 0x60, 0x96, 0x32, 0x68, 0x04, 0x40,
  1494. 0x00, 0x55, 0x10, 0x66, 0x21, 0x76, 0x32, 0x87,
  1495. 0x42, 0x98, 0x53, 0x08, 0x64, 0x19, 0x75, 0x30,
  1496. 0x00, 0x06, 0x13, 0x19, 0x26, 0x32, 0x39, 0x45,
  1497. 0x52, 0x58, 0x65, 0x72, 0x78, 0x85, 0x91, 0x98};
  1498.  
  1499. static __code unsigned char int2bcd_5[] = {
  1500. 0x00, 0x76, 0x52, 0x28, 0x04, 0x80, 0x56, 0x32,
  1501. 0x08, 0x84, 0x60, 0x36, 0x12, 0x88, 0x64, 0x40,
  1502. 0x00, 0x85, 0x71, 0x57, 0x43, 0x28, 0x14, 0x00,
  1503. 0x86, 0x71, 0x57, 0x43, 0x29, 0x14, 0x00, 0x86,
  1504. 0x00, 0x04, 0x09, 0x14, 0x19, 0x24, 0x29, 0x34,
  1505. 0x38, 0x43, 0x48, 0x53, 0x58, 0x63, 0x68, 0x72,
  1506. 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
  1507. 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
  1508.  
  1509. static __code unsigned char int2bcd_6[] = {
  1510. 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
  1511. 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
  1512. 0x00, 0x72, 0x44, 0x16, 0x88, 0x60, 0x32, 0x05,
  1513. 0x77, 0x49, 0x21, 0x93, 0x65, 0x38, 0x10, 0x82,
  1514. 0x00, 0x77, 0x55, 0x33, 0x10, 0x88, 0x66, 0x44,
  1515. 0x21, 0x99, 0x77, 0x54, 0x32, 0x10, 0x88, 0x65,
  1516. 0x00, 0x16, 0x33, 0x50, 0x67, 0x83, 0x00, 0x17,
  1517. 0x34, 0x50, 0x67, 0x84, 0x01, 0x18, 0x34, 0x51,
  1518. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
  1519. 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02};
  1520.  
  1521. static __code unsigned char int2bcd_7[] = {
  1522. 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
  1523. 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
  1524. 0x00, 0x54, 0x09, 0x63, 0x18, 0x72, 0x27, 0x81,
  1525. 0x36, 0x91, 0x45, 0x00, 0x54, 0x09, 0x63, 0x18,
  1526. 0x00, 0x43, 0x87, 0x30, 0x74, 0x17, 0x61, 0x04,
  1527. 0x48, 0x91, 0x35, 0x79, 0x22, 0x66, 0x09, 0x53,
  1528. 0x00, 0x68, 0x36, 0x05, 0x73, 0x42, 0x10, 0x79,
  1529. 0x47, 0x15, 0x84, 0x52, 0x21, 0x89, 0x58, 0x26,
  1530. 0x00, 0x02, 0x05, 0x08, 0x10, 0x13, 0x16, 0x18,
  1531. 0x21, 0x24, 0x26, 0x29, 0x32, 0x34, 0x37, 0x40};
  1532. #endif // LONG
  1533.  
  1534. #else // not FAST_INTEGER
  1535.  
  1536. /*
  1537.  * #! /usr/bin/perl
  1538.  * print "__code unsigned char int2bcd[] = {\n";
  1539.  * for ($i=0, $n=1; $i<32; $i++, $n*=2) {
  1540.  *      $r = sprintf "%010u", $n;
  1541.  *      $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
  1542.  *      printf "0x%02d, 0x%02d, 0x%02d, 0x%02d, 0x%02d", $5, $4, $3, $2, $1;
  1543.  *      print ',' if $i < 31;
  1544.  *      printf "\t\t// %10u\n", $n;
  1545.  * }
  1546.  * print "}\n__code unsigned char int2bcd[] = {\n";
  1547.  * for ($i=0, $n=1; $i<16; $i++, $n*=2) {
  1548.  *      $r = sprintf "%06u", $n;
  1549.  *      $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
  1550.  *      printf "0x%02d, 0x%02d, 0x%02d", $3, $2, $1;
  1551.  *      print ',' if $i < 15;
  1552.  *      printf "\t\t// %10u\n", $n;
  1553.  * }
  1554.  * print "};\n";
  1555. */
  1556.  
  1557. #ifdef LONG
  1558. static __code unsigned char int2bcd[] = {
  1559. 0x01, 0x00, 0x00, 0x00, 0x00,           //          1
  1560. 0x02, 0x00, 0x00, 0x00, 0x00,           //          2
  1561. 0x04, 0x00, 0x00, 0x00, 0x00,           //          4
  1562. 0x08, 0x00, 0x00, 0x00, 0x00,           //          8
  1563. 0x16, 0x00, 0x00, 0x00, 0x00,           //         16
  1564. 0x32, 0x00, 0x00, 0x00, 0x00,           //         32
  1565. 0x64, 0x00, 0x00, 0x00, 0x00,           //         64
  1566. 0x28, 0x01, 0x00, 0x00, 0x00,           //        128
  1567. 0x56, 0x02, 0x00, 0x00, 0x00,           //        256
  1568. 0x12, 0x05, 0x00, 0x00, 0x00,           //        512
  1569. 0x24, 0x10, 0x00, 0x00, 0x00,           //       1024
  1570. 0x48, 0x20, 0x00, 0x00, 0x00,           //       2048
  1571. 0x96, 0x40, 0x00, 0x00, 0x00,           //       4096
  1572. 0x92, 0x81, 0x00, 0x00, 0x00,           //       8192
  1573. 0x84, 0x63, 0x01, 0x00, 0x00,           //      16384
  1574. 0x68, 0x27, 0x03, 0x00, 0x00,           //      32768
  1575. 0x36, 0x55, 0x06, 0x00, 0x00,           //      65536
  1576. 0x72, 0x10, 0x13, 0x00, 0x00,           //     131072
  1577. 0x44, 0x21, 0x26, 0x00, 0x00,           //     262144
  1578. 0x88, 0x42, 0x52, 0x00, 0x00,           //     524288
  1579. 0x76, 0x85, 0x04, 0x01, 0x00,           //    1048576
  1580. 0x52, 0x71, 0x09, 0x02, 0x00,           //    2097152
  1581. 0x04, 0x43, 0x19, 0x04, 0x00,           //    4194304
  1582. 0x08, 0x86, 0x38, 0x08, 0x00,           //    8388608
  1583. 0x16, 0x72, 0x77, 0x16, 0x00,           //   16777216
  1584. 0x32, 0x44, 0x55, 0x33, 0x00,           //   33554432
  1585. 0x64, 0x88, 0x10, 0x67, 0x00,           //   67108864
  1586. 0x28, 0x77, 0x21, 0x34, 0x01,           //  134217728
  1587. 0x56, 0x54, 0x43, 0x68, 0x02,           //  268435456
  1588. 0x12, 0x09, 0x87, 0x36, 0x05,           //  536870912
  1589. 0x24, 0x18, 0x74, 0x73, 0x10,           // 1073741824
  1590. 0x48, 0x36, 0x48, 0x47, 0x21            // 2147483648
  1591. };
  1592. #else // not LONG
  1593. static __code unsigned char int2bcd[] = {
  1594. 0x01, 0x00, 0x00,               //          1
  1595. 0x02, 0x00, 0x00,               //          2
  1596. 0x04, 0x00, 0x00,               //          4
  1597. 0x08, 0x00, 0x00,               //          8
  1598. 0x16, 0x00, 0x00,               //         16
  1599. 0x32, 0x00, 0x00,               //         32
  1600. 0x64, 0x00, 0x00,               //         64
  1601. 0x28, 0x01, 0x00,               //        128
  1602. 0x56, 0x02, 0x00,               //        256
  1603. 0x12, 0x05, 0x00,               //        512
  1604. 0x24, 0x10, 0x00,               //       1024
  1605. 0x48, 0x20, 0x00,               //       2048
  1606. 0x96, 0x40, 0x00,               //       4096
  1607. 0x92, 0x81, 0x00,               //       8192
  1608. 0x84, 0x63, 0x01,               //      16384
  1609. 0x68, 0x27, 0x03                //      32768
  1610. };
  1611. #endif // not LONG
  1612.  
  1613. #endif // not FAST_INTEGER
  1614.  
  1615.  
  1616. #ifdef FLOAT
  1617. #ifndef FLOAT_FIXED4
  1618.  
  1619. /*
  1620.  * #! /usr/bin/perl
  1621.  * for ($i=0, $f=0.5; $i<24; $i++) {
  1622.  *      $r = sprintf "%.8f", $f;
  1623.  *      $r =~ /0\.([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
  1624.  *      printf "0x%02d, 0x%02d, 0x%02d, 0x%02d", $4, $3, $2, $1;
  1625.  *      print ',' if $i < 23;
  1626.  *      $sum += $r;
  1627.  *      printf "\t\t// %.15f  %.8f\n", $f, $sum;
  1628.  *      $f /= 2;
  1629.  * }
  1630.  */
  1631.  
  1632. static __code unsigned char frac2bcd[] = {
  1633. 0x00, 0x00, 0x00, 0x50,         // 0.500000000000000  0.50000000
  1634. 0x00, 0x00, 0x00, 0x25,         // 0.250000000000000  0.75000000
  1635. 0x00, 0x00, 0x50, 0x12,         // 0.125000000000000  0.87500000
  1636. 0x00, 0x00, 0x25, 0x06,         // 0.062500000000000  0.93750000
  1637. 0x00, 0x50, 0x12, 0x03,         // 0.031250000000000  0.96875000
  1638. 0x00, 0x25, 0x56, 0x01,         // 0.015625000000000  0.98437500
  1639. 0x50, 0x12, 0x78, 0x00,         // 0.007812500000000  0.99218750
  1640. 0x25, 0x06, 0x39, 0x00,         // 0.003906250000000  0.99609375
  1641. 0x12, 0x53, 0x19, 0x00,         // 0.001953125000000  0.99804687
  1642. 0x56, 0x76, 0x09, 0x00,         // 0.000976562500000  0.99902343
  1643. 0x28, 0x88, 0x04, 0x00,         // 0.000488281250000  0.99951171
  1644. 0x14, 0x44, 0x02, 0x00,         // 0.000244140625000  0.99975585
  1645. 0x07, 0x22, 0x01, 0x00,         // 0.000122070312500  0.99987792
  1646. 0x04, 0x61, 0x00, 0x00,         // 0.000061035156250  0.99993896
  1647. 0x52, 0x30, 0x00, 0x00,         // 0.000030517578125  0.99996948
  1648. 0x26, 0x15, 0x00, 0x00,         // 0.000015258789062  0.99998474
  1649. 0x63, 0x07, 0x00, 0x00,         // 0.000007629394531  0.99999237
  1650. 0x81, 0x03, 0x00, 0x00,         // 0.000003814697266  0.99999618
  1651. 0x91, 0x01, 0x00, 0x00,         // 0.000001907348633  0.99999809
  1652. 0x95, 0x00, 0x00, 0x00,         // 0.000000953674316  0.99999904
  1653. 0x48, 0x00, 0x00, 0x00,         // 0.000000476837158  0.99999952
  1654. 0x24, 0x00, 0x00, 0x00,         // 0.000000238418579  0.99999976
  1655. 0x12, 0x00, 0x00, 0x00,         // 0.000000119209290  0.99999988
  1656. 0x06, 0x00, 0x00, 0x00,         // 0.000000059604645  0.99999994
  1657. 0x03, 0x00, 0x00, 0x00,         // 0.000000029802322  0.99999997
  1658. 0x01, 0x00, 0x00, 0x00,         // 0.000000014901161  0.99999998
  1659. 0x01, 0x00, 0x00, 0x00          // 0.000000007450581  0.99999999
  1660. };
  1661.  
  1662. #ifndef FLOAT_DEFAULT_FRAC_DIGITS
  1663. // TODO: Perhaps these should be tweaked a bit to take round up
  1664. // effects into account... or maybe give more default digits??
  1665. // Range                #digits
  1666. // 0.0001 - 0.0009999   7
  1667. // 0.001 - 0.009999     6       0.001 = 0x3A83126F  3A83
  1668. // 0.01 - 0.09999       5       0.01  = 0x3C23D70A  3C23
  1669. // 0.1 - 9.9999         4       0.1   = 0x3DCCCCCD, 3DCC
  1670. // 10.0 - 99.99         3       10.0  = 0x41200000  4120
  1671. // 100.0 - 999.99       2       100.0 = 0x42C80000  42C8
  1672. // 1000 - 9999.9        1       1000  = 0x447A0000  447A
  1673. // 10000+               0       10000 = 0x461C4000  461C
  1674. static __code unsigned int float_range_table[] = {
  1675. 65536 - 0x3A83,
  1676. 65536 - 0x3C23,
  1677. 65536 - 0x3DCC,
  1678. 65536 - 0x4120,
  1679. 65536 - 0x42C8,
  1680. 65536 - 0x447A,
  1681. 65536 - 0x461C
  1682. };
  1683. #endif
  1684.  
  1685. #else // using FLOAT_FIXED4
  1686.  
  1687. /*
  1688. * #! /usr/bin/perl
  1689. *     for ($i=0, $f=0.5; $i<14; $i++) {
  1690. *     $r = sprintf "%.4f", $f;
  1691. *     $r =~ /0\.([0-9][0-9])([0-9][0-9])/;
  1692. *     printf "0x%02d, 0x%02d", $2, $1;
  1693. *     print ',' if $i < 13;
  1694. *     $sum += $r;
  1695. *     printf "\t\t// %.15f  %.4f\n", $f, $sum;
  1696. *     $f /= 2;
  1697. * }
  1698. */
  1699.  
  1700. static __code unsigned char frac2bcd[] = {
  1701. 0x00, 0x50,             // 0.500000000000000  0.5000
  1702. 0x00, 0x25,             // 0.250000000000000  0.7500
  1703. 0x50, 0x12,             // 0.125000000000000  0.8750
  1704. 0x25, 0x06,             // 0.062500000000000  0.9375
  1705. 0x12, 0x03,             // 0.031250000000000  0.9687
  1706. 0x56, 0x01,             // 0.015625000000000  0.9843
  1707. 0x78, 0x00,             // 0.007812500000000  0.9921
  1708. 0x39, 0x00,             // 0.003906250000000  0.9960
  1709. 0x20, 0x00,             // 0.001953125000000  0.9980
  1710. 0x10, 0x00,             // 0.000976562500000  0.9990
  1711. 0x05, 0x00,             // 0.000488281250000  0.9995
  1712. 0x02, 0x00,             // 0.000244140625000  0.9997
  1713. 0x01, 0x00,             // 0.000122070312500  0.9998
  1714. 0x01, 0x00              // 0.000061035156250  0.9999
  1715. };
  1716.  
  1717. #endif // FLOAT_FIXED4
  1718. #endif // FLOAT
  1719.  
  1720.  
  1721. #endif // defines compatible with printf_fast
  1722.