1 /* Fast printf routine for use with sdcc/mcs51
2 * Copyright (c) 2004, Paul Stoffregen, paul@pjrc.com
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 /******************************************************************/
21 /** Major features. These determine what capabilities your **/
22 /** compiled printf_fast will have. **/
24 /******************************************************************/
26 // Include support for 32 bit base 10 integers (%ld and %lu). Without
27 // this, you won't be able to print 32 bit integers as base 10. They
28 // will appear in hexadecimal.
31 // Include support for floating point numbers (%f). Don't forget to
32 // enable LONG above, if you want to print floats greater than
33 // 65535.997. You can have 6 good digits after the decimal point,
34 // or an 8th if a small error is ok. +/- 2^32 to 1/10^8 isn't the
35 // full dynamic range of 32 bit floats, but it covers the most
36 // commonly used range. Adds about 500-600 bytes of code.
39 // Include support for minimum field widths (%8d, %20s, %12.5f)
42 // Include fast integer conversion. Without this, a compact but slower
43 // algorithm is used to convert integers (%d, %u, int part of %f).
44 // Even the slow algorithm is much faster than a typical C implementation
45 // based on repetitive division by 10. If you enable this, you get an
46 // extremely fast version (only 8 table lookups and 8 adds to convert a
47 // 32 bit integer), but it costs extra code space for larger lookup
48 // tables and optimized non-looping code.
52 /******************************************************************/
54 /** Minor tweaks. These provide small code savings, with **/
55 /** a partial loss of functionality. **/
57 /******************************************************************/
60 // If you enabled FLOAT, enabling this replaces the normal %f float
61 // output with a very compact version that always prints 4 fractional
62 // digits and does not have round off. Zero will print as "0.0000",
63 // and 1.999997 will print as "1.9999" (not rounded up to 2). The
64 // 4th digit is not accurate (+/- 2). This simpler version also
65 // avoids using 5 bytes of internal data memory. Code size is about
67 //#define FLOAT_FIXED4
69 // If you used FLOAT (not FLOAT_FIXED4), this will remove the smart
70 // default number of digits code. When you use "%f" without a field
71 // width, normally the smart default width code chooses a good number
72 // of digits based on size of the number. If you enabled FIELD_WIDTH
73 // and use a number, like "%.5f", this smart default code is never
74 // used anyway. Saves about 40 bytes of code.
75 //#define FLOAT_DEFAULT_FRAC_DIGITS 6
77 // If you used FLOAT (not FLOAT_FIXED4) and you do not specify a
78 // field width, normally trailing zeros are trimmed. Using this
79 // removes that feature (saves only a few bytes).
80 //#define DO_NOT_TRIM_TRAILING_ZEROS
82 // Omit saving and restoring registers when calling putchar(). If you
83 // are desparate for a little more code space, this will give you a
84 // small savings. You MUST define putchar() with #pragma callee_saves,
85 // or implement it in assembly and avoid changing the registers.
86 //#define PUTCHAR_CALLEE_SAVES
89 /* extern void putchar(char ); */
91 // Warning: using static/global variables makes these functions NON-reentrant!
92 // reentrant keyword is only used for parameter passing method
94 static bit long_flag, short_flag, print_zero_flag, negative_flag;
97 static bit field_width_flag;
98 static bit leading_zero_flag;
99 static data unsigned char field_width;
103 #define SDCC_FLOAT_LIB
105 static bit continue_float;
107 static data unsigned char frac_field_width;
108 static data unsigned char float_frac_bcd[4];
109 // TODO: can float_frac_bcd be overlaid with temps used by trig functions
115 static data unsigned int i2bcd_tmp; // slow 32 int conversion needs temp space
122 #define PRINTF_FAST printf_fast
126 #if !defined(SDCC_mcs51) || defined(SDCC_USE_XSTACK) || defined(_SDCC_NO_ASM_LIB_FUNCS)
127 // Does printf_fast really work on ds390 and ds400?
128 // If it does, enable them in the line above
129 #if defined(SDCC_USE_XSTACK)
130 #warning "printf_fast not built, does not support --xstack"
131 #elif defined(_SDCC_NO_ASM_LIB_FUNCS)
132 #warning "printf_fast not built, _SDCC_NO_ASM_LIB_FUNCS defined"
134 #else // defines are compatible with printf_fast
137 void PRINTF_FAST(code char *fmt, ...) reentrant
139 fmt; /* suppress unreferenced variable warning */
144 mov a, _bp // r0 will point to va_args (stack)
146 mov r0, a // r0 points to MSB of fmt
149 mov dpl, @r0 // dptr has address of fmt
155 movc a, @a+dptr // get next byte of fmt string
157 //cjne a, #'%', printf_normal
158 cjne a, #37, printf_normal
166 clr _field_width_flag
167 clr _leading_zero_flag
168 mov r1, #_field_width
177 movc a, @a+dptr // get next byte of data format
180 /* parse and consume the field width digits, even if */
181 /* we don't build the code to make use of them */
189 cjne a, _field_width, printf_digit_2
190 setb _leading_zero_flag
192 setb _field_width_flag
200 sjmp printf_format_loop
208 //cjne a, #'l', printf_format_h
209 cjne a, #108, printf_format_h
211 sjmp printf_format_loop
214 //cjne a, #'h', printf_format_s
215 cjne a, #104, printf_format_s
217 sjmp printf_format_loop
220 //cjne a, #'s', printf_format_d
221 cjne a, #115, printf_format_d
225 //cjne a, #'d', printf_format_u
226 cjne a, #100, printf_format_u
231 //cjne a, #'u', printf_format_c
232 cjne a, #117, printf_format_c
237 //cjne a, #'c', printf_format_x
238 cjne a, #99, printf_format_x
239 mov a, @r0 // Acc has the character to print
244 //cjne a, #'x', printf_format_f
245 cjne a, #120, printf_format_f
250 //cjne a, #'f', printf_format_dot
251 cjne a, #102, printf_format_dot
256 //cjne a, #'.', printf_normal
257 cjne a, #46, printf_normal
260 mov r1, #ar3 // parse frac field, but discard if FIXED4
262 mov r1, #_frac_field_width
266 sjmp printf_format_loop
272 ljmp printf_main_loop
282 /* print a string... just grab each byte with __gptrget */
283 /* the user much pass a 24 bit generic pointer */
286 push dph // save addr in fmt onto stack
288 mov b, @r0 // b has type of address (generic *)
292 mov dpl, @r0 // dptr has address of user's string
296 jnb _field_width_flag, printf_str_loop
297 clr _leading_zero_flag // never leading zeros for strings
306 jnz printf_str_fw_loop
311 #endif // FIELD_WIDTH
320 pop dpl // restore addr withing fmt
322 ljmp printf_main_loop
331 /* printing in hex is easy because sdcc pushes the LSB first */
335 jb _short_flag, printf_hex_end
337 jnb _long_flag, printf_hex_end
342 ljmp printf_main_loop
345 lcall printf_phex_msn
366 /* printing an integer is not so easy. For a signed int */
367 /* check if it is negative and print the minus sign and */
368 /* invert it to a positive integer */
372 jnb acc.7, printf_uint /* check if negative */
374 mov a, r1 /* invert integer */
378 jb _short_flag, printf_uint
383 jnb _long_flag, printf_uint
394 /* printing integers is a lot of work... because it takes so */
395 /* long, the first thing to do is make sure we're doing as */
396 /* little work as possible, then convert the binary int to */
397 /* packed BCD, and finally print each digit of the BCD number */
401 jb _short_flag, printf_uint_ck8
402 jnb _long_flag, printf_uint_ck16
404 /* it's a 32 bit int... but if the upper 16 bits are zero */
405 /* we can treat it like a 16 bit integer and convert much faster */
408 jnz printf_uint_begin
410 jnz printf_uint_begin
413 jnz printf_ld_in_hex // print long integer as hex
414 mov a, r4 // rather than just the low 16 bits
419 /* it's a 16 bit int... but if the upper 8 bits are zero */
420 /* we can treat it like a 8 bit integer and convert much faster */
422 jnz printf_uint_begin
425 /* it's an 8 bit int... if it's zero, it's a lot faster to just */
426 /* print the digit zero and skip all the hard work! */
428 jnz printf_uint_begin
430 jnb _field_width_flag, printf_uint_zero
441 jnb _continue_float, 0001$
445 ljmp printf_main_loop
452 lcall printf_int2bcd // bcd number in r3/r2/r7/r6/r5
456 jnb _field_width_flag, printf_uifw_end
460 jnb _long_flag, printf_uifw_16
483 jb _short_flag, printf_uifw_8
502 ;r1 has the number of digits for the number
504 mov c, _negative_flag
509 #ifndef PUTCHAR_CALLEE_SAVES
519 #ifndef PUTCHAR_CALLEE_SAVES
531 #endif // FIELD_WIDTH
535 jnb _negative_flag, printf_uint_pos
536 #ifdef PUTCHAR_CALLEE_SAVES
558 #endif // PUTCHAR_CALLEE_SAVES
561 jb _short_flag, printf_uint8
563 jnb _long_flag, printf_uint16
571 lcall printf_phex_msn
573 lcall printf_phex_lsn
575 lcall printf_phex_msn
577 lcall printf_phex_lsn
580 lcall printf_phex_msn
592 lcall printf_phex_lsn
594 lcall printf_phex_msn
602 lcall printf_phex_lsn
604 lcall printf_phex_msn
606 lcall printf_phex_lsn
611 jnb _continue_float, 0002$
615 ljmp printf_main_loop
626 // Print a float the easy way. First, extract the integer part and
627 // use the integer printing code. Then extract the fractional part,
628 // convert each bit to 4 digit BCD, and print the BCD sum. Absolutely
629 // no field width control, always 4 digits printed past the decimal
630 // point. No round off. 1.9999987 prints as 1.9999, not 2.0000.
633 jnb _field_width_flag, print_float_begin
641 push ar0 // keep r0 safe, will need it again
642 lcall printf_get_float
644 mov a, #158 // check for large float we can't print
646 jnc print_float_size_ok
647 printf_float_too_big:
648 // TODO: should print some sort of overflow error??
650 ljmp printf_format_loop
659 jnz printf_float_too_big
661 lcall printf_uint // print the integer portion
665 // now that the integer part is printed, we need to refetch the
666 // float from the va_args and extract the fractional part
668 lcall printf_get_float
673 cjne a, #126, print_float_frac_lshift
674 sjmp print_float_frac // input between 0.5 to 0.9999
675 print_float_frac_lshift:
676 jc print_float_frac_rshift
677 //Acc (exponent) is greater than 126 (input >= 1.0)
680 print_float_lshift_loop:
691 djnz r5, print_float_lshift_loop
692 sjmp print_float_frac
693 print_float_frac_rshift:
694 //Acc (exponent) is less than 126 (input < 0.5)
699 // now we've got the fractional part, so now is the time to
700 // convert to BCD... just convert each bit to BCD using a
701 // lookup table and BCD sum them together
706 mov dptr, #_frac2bcd // FLOAT_FIXED4 version (14 entries)
707 print_float_frac_loop:
714 jnc print_float_frac_skip
725 print_float_frac_skip:
728 djnz r7, print_float_frac_loop
729 // the BCD sum is in dptr, so all we've got to do is output
730 // all 4 digits. No trailing zero suppression, no nice round
731 // off (impossible to change the integer part since we already
735 setb _print_zero_flag
737 lcall printf_phex_msn
739 lcall printf_phex_lsn
741 lcall printf_phex_msn
743 lcall printf_phex_lsn
747 ljmp printf_main_loop
749 #else // not FLOAT_FIXED4
755 // Print a float the not-as-easy way, with a configurable number of
756 // fractional digits (up to 8) and proper round-off (up to 7 digits).
757 // First, extract the fractional part, convert to BCD, and then add
758 // the scaled round-off. Store the rounded fractional digits and
759 // their carry. Then extract the integer portion, increment it if
760 // the rounding caused a carry. Use the integer printing to output
761 // the integer, and then output the stored fractional digits. This
762 // approach requires 5 bytes of internal RAM to store the 8 fractional
763 // digits and the number of them we'll actually print. This code is
764 // a couple hundred bytes larger and a bit slower than the FIXED4
765 // version, but it gives very nice results.
768 jnb _field_width_flag, print_float_default_width
769 // The caller specified exact field width, so use it. Need to
770 // convert the whole float digits into the integer portion only.
773 subb a, _frac_field_width
775 jnc print_float_begin
777 sjmp print_float_begin
779 print_float_default_width:
780 // The caller didn't specify field width (or FIELD_WIDTH is
781 // not defined so it's ignored). We've still got to know
782 // how many fractional digits are going to print, so we can
783 // round off properly.
784 #ifdef FLOAT_DEFAULT_FRAC_DIGITS
785 mov _frac_field_width, #FLOAT_DEFAULT_FRAC_DIGITS
787 // default fractional field width (between 0 to 7)
788 // attempt to scale the default number of fractional digits
789 // based on the magnitude of the float
790 mov ar1, r0 // r0 points to first byte of float
791 dec r1 // r1 points to second byte of float
794 mov dptr, #_float_range_table
796 print_float_default_loop:
804 jnc print_float_default_done
806 djnz r5, print_float_default_loop
807 print_float_default_done:
808 mov _frac_field_width, r5
811 #endif // not FLOAT_DEFAULT_FRAC_DIGITS
814 push ar0 // keep r0 safe, will need it again
815 lcall printf_get_float
819 cjne a, #126, print_float_frac_lshift
820 sjmp print_float_frac // input between 0.5 to 0.9999
822 print_float_frac_lshift:
823 jc print_float_frac_rshift
824 //Acc (exponent) is greater than 126 (input >= 1.0)
827 print_float_lshift_loop:
838 djnz r5, print_float_lshift_loop
839 sjmp print_float_frac
840 print_float_frac_rshift:
841 //Acc (exponent) is less than 126 (input < 0.5)
846 // Convert the fraction in r4/r3/r2/r1 into 8 BCD digits in r0/r7/r6/r5
853 mov dptr, #_frac2bcd // FLOAT version (27 entries)
854 print_float_frac_loop:
867 jnc print_float_frac_skip
888 print_float_frac_skip:
893 djnz b, print_float_frac_loop
894 print_float_frac_roundoff:
895 // Now it's time to round-off the BCD digits to the desired precision.
897 mov r4, #0x50 // r4/r3/r2/r1 = 0.5 (bcd rounding)
901 mov a, _frac_field_width
905 mov dph, r0 // fs_rshift_a will overwrite r0 & dpl
906 lcall fs_rshift_a // divide r4/r3/r2/r1 by 10^frac_field_width
908 add a, r1 // add rounding to fractional part
910 mov _float_frac_bcd+3, a // and store it for later use
914 mov _float_frac_bcd+2, a
918 mov _float_frac_bcd+1, a
922 mov _float_frac_bcd+0, a
923 mov sign_b, c // keep fractional carry in sign_b
927 // Time to work on the integer portion... fetch the float again, check
928 // size (exponent), scale to integer, add the fraction's carry, and
929 // let the integer printing code do all the work.
931 lcall printf_get_float
934 mov a, #158 // check for large float we can't print
936 jnc print_float_size_ok
937 printf_float_too_big:
938 // TODO: should print some sort of overflow error??
939 ljmp printf_format_loop
944 jnb sign_b, print_float_do_int
945 // if we get here, the fractional round off caused the
946 // integer part to increment. Add 1 for a proper result
961 jc printf_float_too_big
966 jnz printf_float_too_big
969 lcall printf_uint // print the integer portion
972 print_float_frac_width:
973 // Now all we have to do is output the fractional digits that
974 // were previous computed and stored in memory.
976 jb _field_width_flag, print_float_do_frac
978 #ifndef DO_NOT_TRIM_TRAILING_ZEROS
979 // if the user did not explicitly set a
980 // field width, trim off trailing zeros
981 print_float_frac_trim:
982 mov a, _frac_field_width
983 jz print_float_do_frac
984 lcall get_float_frac_digit
985 jnz print_float_do_frac
986 djnz _frac_field_width, print_float_frac_trim
990 mov a, _frac_field_width
996 setb _print_zero_flag
997 print_float_do_frac_loop:
1000 lcall get_float_frac_digit
1001 lcall printf_phex_lsn
1003 cjne a, _frac_field_width, print_float_do_frac_loop
1007 ljmp printf_main_loop
1011 // acc=1 for tenths, acc=2 for hundredths, etc
1012 get_float_frac_digit:
1017 add a, #_float_frac_bcd
1020 jb psw.5, get_float_frac_digit_done
1022 get_float_frac_digit_done:
1029 #endif // end of normal FLOAT code (not FLOAT_FIXED4)
1032 // These helper functions are used, regardless of which type of
1033 // FLOAT code is used.
1038 lcall pm2_entry_phex
1040 lcall pm2_entry_cout
1043 lcall pm2_entry_cout
1047 // Fetch a float from the va_args and put it into
1048 // r7(exp) r4/r3/r2(mant) and also clear r1 and preset
1060 mov _negative_flag, c
1062 jz printf_get_float_2
1089 /* read an integer into r1/r2/r3/r4, and msb into r5 */
1095 jb _short_flag, printf_get_done
1100 jnb _long_flag, printf_get_done
1118 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1119 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1120 * process, to avoid needing extra memory for the result (and
1121 * r1 gets used for temporary storage). dptr is overwritten,
1122 * but r0 is not changed.
1137 jnb _short_flag, printf_i2bcd_16 // if 8 bit int, we're done
1144 mov dptr, #_int2bcd_2
1160 mov dptr, #_int2bcd_3
1178 jb _long_flag, printf_i2bcd_32 // if 16 bit int, we're done
1187 mov dptr, #_int2bcd_4
1212 mov dptr, #_int2bcd_5
1239 mov dptr, #_int2bcd_6
1241 lcall printf_bcd_add10 // saves 27 bytes, costs 5 cycles
1247 mov dptr, #_int2bcd_7
1281 #else // not FAST_INTEGER
1283 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1284 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1285 * process, to avoid needing extra memory for the result (and
1286 * r1 gets used for temporary storage). dptr is overwritten,
1287 * but r0 is not changed.
1294 jb _short_flag, printf_int2bcd_begin
1296 jnb _long_flag, printf_int2bcd_begin
1298 printf_int2bcd_begin:
1304 mov (_i2bcd_tmp + 0), a
1305 mov (_i2bcd_tmp + 1), a
1320 jnc print_i2bcd_skip
1338 addc a, (_i2bcd_tmp + 0)
1340 mov (_i2bcd_tmp + 0), a
1343 addc a, (_i2bcd_tmp + 1)
1345 mov (_i2bcd_tmp + 1), a
1352 djnz b, printf_i2bcd_loop
1353 mov r2, (_i2bcd_tmp + 0)
1354 mov r3, (_i2bcd_tmp + 1)
1361 jb _short_flag, printf_int2bcd_begin
1363 printf_int2bcd_begin:
1377 jnc printf_i2bcd_add_skip
1393 printf_i2bcd_add_skip:
1397 djnz b, printf_i2bcd_loop
1403 #endif // not FAST_INTEGER
1421 jnb _leading_zero_flag, printf_space_output
1424 printf_space_output:
1425 lcall printf_putchar
1429 jnz printf_space_loop
1437 /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
1444 jnb _print_zero_flag, printf_ret
1446 setb _print_zero_flag
1452 #ifdef PUTCHAR_CALLEE_SAVES
1472 /* print a zero if all the calls to print the digits ended up */
1473 /* being leading zeros */
1476 jb _print_zero_flag, printf_ret
1489 * for ($d=0; $d < 8; $d++) {
1491 * for ($p=0; $p < 5; $p++) {
1492 * last unless (((16 ** $d) * 15) / (10 ** ($p * 2))) % 100;
1493 * printf "code unsigned char int2bcd_%d_%d[15] = {", $d, $p;
1494 * for ($i=0; $i < 16; $i++) {
1496 * (((16 ** $d) * $i) / (10 ** ($p * 2))) % 100;
1497 * print ", " if $i < 15;
1505 static code unsigned char int2bcd_0[] = {
1506 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1507 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1509 static code unsigned char int2bcd_1[] = {
1510 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1511 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1512 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1513 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02};
1516 static code unsigned char int2bcd_2[] = {
1517 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1518 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1519 0x00, 0x02, 0x05, 0x07, 0x10, 0x12, 0x15, 0x17,
1520 0x20, 0x23, 0x25, 0x28, 0x30, 0x33, 0x35, 0x38};
1522 static code unsigned char int2bcd_3[] = {
1523 0x00, 0x96, 0x92, 0x88, 0x84, 0x80, 0x76, 0x72,
1524 0x68, 0x64, 0x60, 0x56, 0x52, 0x48, 0x44, 0x40,
1525 0x00, 0x40, 0x81, 0x22, 0x63, 0x04, 0x45, 0x86,
1526 0x27, 0x68, 0x09, 0x50, 0x91, 0x32, 0x73, 0x14,
1527 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02,
1528 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06};
1531 static code unsigned char int2bcd_4[] = {
1532 0x00, 0x36, 0x72, 0x08, 0x44, 0x80, 0x16, 0x52,
1533 0x88, 0x24, 0x60, 0x96, 0x32, 0x68, 0x04, 0x40,
1534 0x00, 0x55, 0x10, 0x66, 0x21, 0x76, 0x32, 0x87,
1535 0x42, 0x98, 0x53, 0x08, 0x64, 0x19, 0x75, 0x30,
1536 0x00, 0x06, 0x13, 0x19, 0x26, 0x32, 0x39, 0x45,
1537 0x52, 0x58, 0x65, 0x72, 0x78, 0x85, 0x91, 0x98};
1539 static code unsigned char int2bcd_5[] = {
1540 0x00, 0x76, 0x52, 0x28, 0x04, 0x80, 0x56, 0x32,
1541 0x08, 0x84, 0x60, 0x36, 0x12, 0x88, 0x64, 0x40,
1542 0x00, 0x85, 0x71, 0x57, 0x43, 0x28, 0x14, 0x00,
1543 0x86, 0x71, 0x57, 0x43, 0x29, 0x14, 0x00, 0x86,
1544 0x00, 0x04, 0x09, 0x14, 0x19, 0x24, 0x29, 0x34,
1545 0x38, 0x43, 0x48, 0x53, 0x58, 0x63, 0x68, 0x72,
1546 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1547 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1549 static code unsigned char int2bcd_6[] = {
1550 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1551 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1552 0x00, 0x72, 0x44, 0x16, 0x88, 0x60, 0x32, 0x05,
1553 0x77, 0x49, 0x21, 0x93, 0x65, 0x38, 0x10, 0x82,
1554 0x00, 0x77, 0x55, 0x33, 0x10, 0x88, 0x66, 0x44,
1555 0x21, 0x99, 0x77, 0x54, 0x32, 0x10, 0x88, 0x65,
1556 0x00, 0x16, 0x33, 0x50, 0x67, 0x83, 0x00, 0x17,
1557 0x34, 0x50, 0x67, 0x84, 0x01, 0x18, 0x34, 0x51,
1558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
1559 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02};
1561 static code unsigned char int2bcd_7[] = {
1562 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1563 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1564 0x00, 0x54, 0x09, 0x63, 0x18, 0x72, 0x27, 0x81,
1565 0x36, 0x91, 0x45, 0x00, 0x54, 0x09, 0x63, 0x18,
1566 0x00, 0x43, 0x87, 0x30, 0x74, 0x17, 0x61, 0x04,
1567 0x48, 0x91, 0x35, 0x79, 0x22, 0x66, 0x09, 0x53,
1568 0x00, 0x68, 0x36, 0x05, 0x73, 0x42, 0x10, 0x79,
1569 0x47, 0x15, 0x84, 0x52, 0x21, 0x89, 0x58, 0x26,
1570 0x00, 0x02, 0x05, 0x08, 0x10, 0x13, 0x16, 0x18,
1571 0x21, 0x24, 0x26, 0x29, 0x32, 0x34, 0x37, 0x40};
1574 #else // not FAST_INTEGER
1578 * print "code unsigned char int2bcd[] = {\n";
1579 * for ($i=0, $n=1; $i<32; $i++, $n*=2) {
1580 * $r = sprintf "%010u", $n;
1581 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1582 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d, 0x%02d", $5, $4, $3, $2, $1;
1583 * print ',' if $i < 31;
1584 * printf "\t\t// %10u\n", $n;
1586 * print "}\ncode unsigned char int2bcd[] = {\n";
1587 * for ($i=0, $n=1; $i<16; $i++, $n*=2) {
1588 * $r = sprintf "%06u", $n;
1589 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1590 * printf "0x%02d, 0x%02d, 0x%02d", $3, $2, $1;
1591 * print ',' if $i < 15;
1592 * printf "\t\t// %10u\n", $n;
1598 static code unsigned char int2bcd[] = {
1599 0x01, 0x00, 0x00, 0x00, 0x00, // 1
1600 0x02, 0x00, 0x00, 0x00, 0x00, // 2
1601 0x04, 0x00, 0x00, 0x00, 0x00, // 4
1602 0x08, 0x00, 0x00, 0x00, 0x00, // 8
1603 0x16, 0x00, 0x00, 0x00, 0x00, // 16
1604 0x32, 0x00, 0x00, 0x00, 0x00, // 32
1605 0x64, 0x00, 0x00, 0x00, 0x00, // 64
1606 0x28, 0x01, 0x00, 0x00, 0x00, // 128
1607 0x56, 0x02, 0x00, 0x00, 0x00, // 256
1608 0x12, 0x05, 0x00, 0x00, 0x00, // 512
1609 0x24, 0x10, 0x00, 0x00, 0x00, // 1024
1610 0x48, 0x20, 0x00, 0x00, 0x00, // 2048
1611 0x96, 0x40, 0x00, 0x00, 0x00, // 4096
1612 0x92, 0x81, 0x00, 0x00, 0x00, // 8192
1613 0x84, 0x63, 0x01, 0x00, 0x00, // 16384
1614 0x68, 0x27, 0x03, 0x00, 0x00, // 32768
1615 0x36, 0x55, 0x06, 0x00, 0x00, // 65536
1616 0x72, 0x10, 0x13, 0x00, 0x00, // 131072
1617 0x44, 0x21, 0x26, 0x00, 0x00, // 262144
1618 0x88, 0x42, 0x52, 0x00, 0x00, // 524288
1619 0x76, 0x85, 0x04, 0x01, 0x00, // 1048576
1620 0x52, 0x71, 0x09, 0x02, 0x00, // 2097152
1621 0x04, 0x43, 0x19, 0x04, 0x00, // 4194304
1622 0x08, 0x86, 0x38, 0x08, 0x00, // 8388608
1623 0x16, 0x72, 0x77, 0x16, 0x00, // 16777216
1624 0x32, 0x44, 0x55, 0x33, 0x00, // 33554432
1625 0x64, 0x88, 0x10, 0x67, 0x00, // 67108864
1626 0x28, 0x77, 0x21, 0x34, 0x01, // 134217728
1627 0x56, 0x54, 0x43, 0x68, 0x02, // 268435456
1628 0x12, 0x09, 0x87, 0x36, 0x05, // 536870912
1629 0x24, 0x18, 0x74, 0x73, 0x10, // 1073741824
1630 0x48, 0x36, 0x48, 0x47, 0x21 // 2147483648
1633 static code unsigned char int2bcd[] = {
1634 0x01, 0x00, 0x00, // 1
1635 0x02, 0x00, 0x00, // 2
1636 0x04, 0x00, 0x00, // 4
1637 0x08, 0x00, 0x00, // 8
1638 0x16, 0x00, 0x00, // 16
1639 0x32, 0x00, 0x00, // 32
1640 0x64, 0x00, 0x00, // 64
1641 0x28, 0x01, 0x00, // 128
1642 0x56, 0x02, 0x00, // 256
1643 0x12, 0x05, 0x00, // 512
1644 0x24, 0x10, 0x00, // 1024
1645 0x48, 0x20, 0x00, // 2048
1646 0x96, 0x40, 0x00, // 4096
1647 0x92, 0x81, 0x00, // 8192
1648 0x84, 0x63, 0x01, // 16384
1649 0x68, 0x27, 0x03 // 32768
1653 #endif // not FAST_INTEGER
1659 #ifndef FLOAT_FIXED4
1663 * for ($i=0, $f=0.5; $i<24; $i++) {
1664 * $r = sprintf "%.8f", $f;
1665 * $r =~ /0\.([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1666 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d", $4, $3, $2, $1;
1667 * print ',' if $i < 23;
1669 * printf "\t\t// %.15f %.8f\n", $f, $sum;
1674 static code unsigned char frac2bcd[] = {
1675 0x00, 0x00, 0x00, 0x50, // 0.500000000000000 0.50000000
1676 0x00, 0x00, 0x00, 0x25, // 0.250000000000000 0.75000000
1677 0x00, 0x00, 0x50, 0x12, // 0.125000000000000 0.87500000
1678 0x00, 0x00, 0x25, 0x06, // 0.062500000000000 0.93750000
1679 0x00, 0x50, 0x12, 0x03, // 0.031250000000000 0.96875000
1680 0x00, 0x25, 0x56, 0x01, // 0.015625000000000 0.98437500
1681 0x50, 0x12, 0x78, 0x00, // 0.007812500000000 0.99218750
1682 0x25, 0x06, 0x39, 0x00, // 0.003906250000000 0.99609375
1683 0x12, 0x53, 0x19, 0x00, // 0.001953125000000 0.99804687
1684 0x56, 0x76, 0x09, 0x00, // 0.000976562500000 0.99902343
1685 0x28, 0x88, 0x04, 0x00, // 0.000488281250000 0.99951171
1686 0x14, 0x44, 0x02, 0x00, // 0.000244140625000 0.99975585
1687 0x07, 0x22, 0x01, 0x00, // 0.000122070312500 0.99987792
1688 0x04, 0x61, 0x00, 0x00, // 0.000061035156250 0.99993896
1689 0x52, 0x30, 0x00, 0x00, // 0.000030517578125 0.99996948
1690 0x26, 0x15, 0x00, 0x00, // 0.000015258789062 0.99998474
1691 0x63, 0x07, 0x00, 0x00, // 0.000007629394531 0.99999237
1692 0x81, 0x03, 0x00, 0x00, // 0.000003814697266 0.99999618
1693 0x91, 0x01, 0x00, 0x00, // 0.000001907348633 0.99999809
1694 0x95, 0x00, 0x00, 0x00, // 0.000000953674316 0.99999904
1695 0x48, 0x00, 0x00, 0x00, // 0.000000476837158 0.99999952
1696 0x24, 0x00, 0x00, 0x00, // 0.000000238418579 0.99999976
1697 0x12, 0x00, 0x00, 0x00, // 0.000000119209290 0.99999988
1698 0x06, 0x00, 0x00, 0x00, // 0.000000059604645 0.99999994
1699 0x03, 0x00, 0x00, 0x00, // 0.000000029802322 0.99999997
1700 0x01, 0x00, 0x00, 0x00, // 0.000000014901161 0.99999998
1701 0x01, 0x00, 0x00, 0x00 // 0.000000007450581 0.99999999
1704 #ifndef FLOAT_DEFAULT_FRAC_DIGITS
1705 // TODO: Perhaps these should be tweaked a bit to take round up
1706 // effects into account... or maybe give more default digits??
1708 // 0.0001 - 0.0009999 7
1709 // 0.001 - 0.009999 6 0.001 = 0x3A83126F 3A83
1710 // 0.01 - 0.09999 5 0.01 = 0x3C23D70A 3C23
1711 // 0.1 - 9.9999 4 0.1 = 0x3DCCCCCD, 3DCC
1712 // 10.0 - 99.99 3 10.0 = 0x41200000 4120
1713 // 100.0 - 999.99 2 100.0 = 0x42C80000 42C8
1714 // 1000 - 9999.9 1 1000 = 0x447A0000 447A
1715 // 10000+ 0 10000 = 0x461C4000 461C
1716 static code unsigned int float_range_table[] = {
1727 #else // using FLOAT_FIXED4
1731 * for ($i=0, $f=0.5; $i<14; $i++) {
1732 * $r = sprintf "%.4f", $f;
1733 * $r =~ /0\.([0-9][0-9])([0-9][0-9])/;
1734 * printf "0x%02d, 0x%02d", $2, $1;
1735 * print ',' if $i < 13;
1737 * printf "\t\t// %.15f %.4f\n", $f, $sum;
1742 static code unsigned char frac2bcd[] = {
1743 0x00, 0x50, // 0.500000000000000 0.5000
1744 0x00, 0x25, // 0.250000000000000 0.7500
1745 0x50, 0x12, // 0.125000000000000 0.8750
1746 0x25, 0x06, // 0.062500000000000 0.9375
1747 0x12, 0x03, // 0.031250000000000 0.9687
1748 0x56, 0x01, // 0.015625000000000 0.9843
1749 0x78, 0x00, // 0.007812500000000 0.9921
1750 0x39, 0x00, // 0.003906250000000 0.9960
1751 0x20, 0x00, // 0.001953125000000 0.9980
1752 0x10, 0x00, // 0.000976562500000 0.9990
1753 0x05, 0x00, // 0.000488281250000 0.9995
1754 0x02, 0x00, // 0.000244140625000 0.9997
1755 0x01, 0x00, // 0.000122070312500 0.9998
1756 0x01, 0x00 // 0.000061035156250 0.9999
1759 #endif // FLOAT_FIXED4
1763 #endif // defines compatible with printf_fast