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
121 #define PRINTF_FAST printf_fast
125 #if !defined(SDCC_mcs51) || defined(SDCC_USE_XSTACK) || defined(_SDCC_NO_ASM_LIB_FUNCS)
126 // Does printf_fast really work on ds390 and ds400?
127 // If it does, enable them in the line above
128 #if defined(SDCC_USE_XSTACK)
129 #warning "printf_fast not built, does not support --xstack"
130 #elif defined(_SDCC_NO_ASM_LIB_FUNCS)
131 #warning "printf_fast not built, _SDCC_NO_ASM_LIB_FUNCS defined"
133 #else // defines are compatible with printf_fast
136 void PRINTF_FAST(__code char *fmt, ...) __reentrant
138 fmt; /* suppress unreferenced variable warning */
143 mov a, _bp // r0 will point to va_args (stack)
145 mov r0, a // r0 points to MSB of fmt
148 mov dpl, @r0 // dptr has address of fmt
153 movc a, @a+dptr // get next byte of fmt string
155 //cjne a, #'%', printf_normal
156 cjne a, #37, printf_normal
164 clr _field_width_flag
165 clr _leading_zero_flag
166 mov r1, #_field_width
175 movc a, @a+dptr // get next byte of data format
178 /* parse and consume the field width digits, even if */
179 /* we don't build the code to make use of them */
187 cjne a, _field_width, printf_digit_2
188 setb _leading_zero_flag
190 setb _field_width_flag
198 sjmp printf_format_loop
205 //cjne a, #'l', printf_format_h
206 cjne a, #108, printf_format_h
208 sjmp printf_format_loop
211 //cjne a, #'h', printf_format_s
212 cjne a, #104, printf_format_s
214 sjmp printf_format_loop
217 //cjne a, #'s', printf_format_d
218 cjne a, #115, printf_format_d
222 //cjne a, #'d', printf_format_u
223 cjne a, #100, printf_format_u
228 //cjne a, #'u', printf_format_c
229 cjne a, #117, printf_format_c
234 //cjne a, #'c', printf_format_x
235 cjne a, #99, printf_format_x
237 mov a, @r0 // Acc has the character to print
242 //cjne a, #'x', printf_format_f
243 cjne a, #120, printf_format_f
248 //cjne a, #'f', printf_format_dot
249 cjne a, #102, printf_format_dot
254 //cjne a, #'.', printf_normal
255 cjne a, #46, printf_normal
258 mov r1, #ar3 // parse frac field, but discard if FIXED4
260 mov r1, #_frac_field_width
264 sjmp printf_format_loop
270 ljmp printf_main_loop
276 /* print a string... just grab each byte with __gptrget */
277 /* the user much pass a 24 bit generic pointer */
280 push dph // save addr in fmt onto stack
282 mov b, @r0 // b has type of address (generic *)
286 mov dpl, @r0 // dptr has address of user's string
290 jnb _field_width_flag, printf_str_loop
291 clr _leading_zero_flag // never leading zeros for strings
300 jnz printf_str_fw_loop
305 #endif // FIELD_WIDTH
314 pop dpl // restore addr withing fmt
316 ljmp printf_main_loop
319 /* printing in hex is easy because sdcc pushes the LSB first */
323 jb _short_flag, printf_hex_end
325 jnb _long_flag, printf_hex_end
330 ljmp printf_main_loop
333 lcall printf_phex_msn
354 /* printing an integer is not so easy. For a signed int */
355 /* check if it is negative and print the minus sign and */
356 /* invert it to a positive integer */
360 jnb acc.7, printf_uint /* check if negative */
362 mov a, r1 /* invert integer */
366 jb _short_flag, printf_uint
371 jnb _long_flag, printf_uint
382 /* printing integers is a lot of work... because it takes so */
383 /* long, the first thing to do is make sure we're doing as */
384 /* little work as possible, then convert the binary int to */
385 /* packed BCD, and finally print each digit of the BCD number */
389 jb _short_flag, printf_uint_ck8
390 jnb _long_flag, printf_uint_ck16
392 /* it's a 32 bit int... but if the upper 16 bits are zero */
393 /* we can treat it like a 16 bit integer and convert much faster */
396 jnz printf_uint_begin
398 jnz printf_uint_begin
401 jnz printf_ld_in_hex // print long integer as hex
402 mov a, r4 // rather than just the low 16 bits
407 /* it's a 16 bit int... but if the upper 8 bits are zero */
408 /* we can treat it like a 8 bit integer and convert much faster */
410 jnz printf_uint_begin
413 /* it's an 8 bit int... if it's zero, it's a lot faster to just */
414 /* print the digit zero and skip all the hard work! */
416 jnz printf_uint_begin
418 /* never use the "just print zero" shortcut if we're printing */
419 /* the integer part of a float (fixes bug 1255403) */
420 jb _continue_float, printf_uint_begin
423 jnb _field_width_flag, printf_uint_zero
433 ljmp printf_main_loop
438 lcall printf_int2bcd // bcd number in r3/r2/r7/r6/r5
442 jnb _field_width_flag, printf_uifw_end
446 jnb _long_flag, printf_uifw_16
469 jb _short_flag, printf_uifw_8
488 //r1 has the number of digits for the number
490 mov c, _negative_flag
495 #ifndef PUTCHAR_CALLEE_SAVES
505 #ifndef PUTCHAR_CALLEE_SAVES
517 #endif // FIELD_WIDTH
521 jnb _negative_flag, printf_uint_pos
522 #ifdef PUTCHAR_CALLEE_SAVES
544 #endif // PUTCHAR_CALLEE_SAVES
547 jb _short_flag, printf_uint8
549 jnb _long_flag, printf_uint16
557 lcall printf_phex_msn
559 lcall printf_phex_lsn
561 lcall printf_phex_msn
563 lcall printf_phex_lsn
566 lcall printf_phex_msn
578 lcall printf_phex_lsn
580 lcall printf_phex_msn
588 lcall printf_phex_lsn
590 lcall printf_phex_msn
592 lcall printf_phex_lsn
597 jnb _continue_float, 0002$
601 ljmp printf_main_loop
606 // Print a float the easy way. First, extract the integer part and
607 // use the integer printing code. Then extract the fractional part,
608 // convert each bit to 4 digit BCD, and print the BCD sum. Absolutely
609 // no field width control, always 4 digits printed past the decimal
610 // point. No round off. 1.9999987 prints as 1.9999, not 2.0000.
613 jnb _field_width_flag, print_float_begin
621 push ar0 // keep r0 safe, will need it again
622 lcall printf_get_float
624 mov a, #158 // check for large float we can't print
626 jnc print_float_size_ok
627 printf_float_too_big:
628 // TODO: should print some sort of overflow error??
630 ljmp printf_format_loop
639 jnz printf_float_too_big
641 lcall printf_uint // print the integer portion
645 // now that the integer part is printed, we need to refetch the
646 // float from the va_args and extract the fractional part
648 lcall printf_get_float
653 cjne a, #126, print_float_frac_lshift
654 sjmp print_float_frac // input between 0.5 to 0.9999
655 print_float_frac_lshift:
656 jc print_float_frac_rshift
657 //Acc (exponent) is greater than 126 (input >= 1.0)
660 print_float_lshift_loop:
671 djnz r5, print_float_lshift_loop
672 sjmp print_float_frac
673 print_float_frac_rshift:
674 //Acc (exponent) is less than 126 (input < 0.5)
679 // now we've got the fractional part, so now is the time to
680 // convert to BCD... just convert each bit to BCD using a
681 // lookup table and BCD sum them together
686 mov dptr, #_frac2bcd // FLOAT_FIXED4 version (14 entries)
687 print_float_frac_loop:
694 jnc print_float_frac_skip
705 print_float_frac_skip:
708 djnz r7, print_float_frac_loop
709 // the BCD sum is in dptr, so all we've got to do is output
710 // all 4 digits. No trailing zero suppression, no nice round
711 // off (impossible to change the integer part since we already
715 setb _print_zero_flag
717 lcall printf_phex_msn
719 lcall printf_phex_lsn
721 lcall printf_phex_msn
723 lcall printf_phex_lsn
727 ljmp printf_main_loop
729 #else // not FLOAT_FIXED4
733 // Print a float the not-as-easy way, with a configurable number of
734 // fractional digits (up to 8) and proper round-off (up to 7 digits).
735 // First, extract the fractional part, convert to BCD, and then add
736 // the scaled round-off. Store the rounded fractional digits and
737 // their carry. Then extract the integer portion, increment it if
738 // the rounding caused a carry. Use the integer printing to output
739 // the integer, and then output the stored fractional digits. This
740 // approach requires 5 bytes of internal RAM to store the 8 fractional
741 // digits and the number of them we'll actually print. This code is
742 // a couple hundred bytes larger and a bit slower than the FIXED4
743 // version, but it gives very nice results.
746 jnb _field_width_flag, print_float_default_width
747 // The caller specified exact field width, so use it. Need to
748 // convert the whole float digits into the integer portion only.
751 subb a, _frac_field_width
753 jnc print_float_begin
755 sjmp print_float_begin
757 print_float_default_width:
758 // The caller didn't specify field width (or FIELD_WIDTH is
759 // not defined so it's ignored). We've still got to know
760 // how many fractional digits are going to print, so we can
761 // round off properly.
762 #ifdef FLOAT_DEFAULT_FRAC_DIGITS
763 mov _frac_field_width, #FLOAT_DEFAULT_FRAC_DIGITS
765 // default fractional field width (between 0 to 7)
766 // attempt to scale the default number of fractional digits
767 // based on the magnitude of the float
769 anl a, #0x7F // ignore sign bit
770 mov r2, a // r2 is first byte of float
772 mov ar3, @r0 // r3 is second byte of float
776 mov dptr, #_float_range_table
778 print_float_default_loop:
786 jnc print_float_default_done
788 djnz r5, print_float_default_loop
789 print_float_default_done:
790 mov _frac_field_width, r5
793 #endif // not FLOAT_DEFAULT_FRAC_DIGITS
796 push ar0 // keep r0 safe, will need it again
797 lcall printf_get_float
801 cjne a, #126, print_float_frac_lshift
802 sjmp print_float_frac // input between 0.5 to 0.9999
804 print_float_frac_lshift:
805 jc print_float_frac_rshift
806 //Acc (exponent) is greater than 126 (input >= 1.0)
809 print_float_lshift_loop:
820 djnz r5, print_float_lshift_loop
821 sjmp print_float_frac
822 print_float_frac_rshift:
823 //Acc (exponent) is less than 126 (input < 0.5)
828 // Convert the fraction in r4/r3/r2/r1 into 8 BCD digits in r0/r7/r6/r5
835 mov dptr, #_frac2bcd // FLOAT version (27 entries)
836 print_float_frac_loop:
849 jnc print_float_frac_skip
870 print_float_frac_skip:
875 djnz b, print_float_frac_loop
876 print_float_frac_roundoff:
877 // Now it's time to round-off the BCD digits to the desired precision.
879 mov r4, #0x50 // r4/r3/r2/r1 = 0.5 (bcd rounding)
883 mov a, _frac_field_width
887 mov dph, r0 // fs_rshift_a will overwrite r0 & dpl
888 lcall fs_rshift_a // divide r4/r3/r2/r1 by 10^frac_field_width
890 add a, r1 // add rounding to fractional part
892 mov _float_frac_bcd+3, a // and store it for later use
896 mov _float_frac_bcd+2, a
900 mov _float_frac_bcd+1, a
904 mov _float_frac_bcd+0, a
905 mov sign_b, c // keep fractional carry in sign_b
909 // Time to work on the integer portion... fetch the float again, check
910 // size (exponent), scale to integer, add the fraction's carry, and
911 // let the integer printing code do all the work.
913 lcall printf_get_float
916 mov a, #158 // check for large float we can't print
918 jnc print_float_size_ok
919 printf_float_too_big:
920 // TODO: should print some sort of overflow error??
922 ljmp printf_format_loop
927 jnb sign_b, print_float_do_int
928 // if we get here, the fractional round off caused the
929 // integer part to increment. Add 1 for a proper result
944 jc printf_float_too_big
949 jnz printf_float_too_big
952 lcall printf_uint // print the integer portion
955 print_float_frac_width:
956 // Now all we have to do is output the fractional digits that
957 // were previous computed and stored in memory.
959 jb _field_width_flag, print_float_do_frac
961 #ifndef DO_NOT_TRIM_TRAILING_ZEROS
962 // if the user did not explicitly set a
963 // field width, trim off trailing zeros
964 print_float_frac_trim:
965 mov a, _frac_field_width
966 jz print_float_do_frac
967 lcall get_float_frac_digit
968 jnz print_float_do_frac
969 djnz _frac_field_width, print_float_frac_trim
973 mov a, _frac_field_width
979 setb _print_zero_flag
980 print_float_do_frac_loop:
983 lcall get_float_frac_digit
984 lcall printf_phex_lsn
986 cjne a, _frac_field_width, print_float_do_frac_loop
990 ljmp printf_main_loop
993 // acc=1 for tenths, acc=2 for hundredths, etc
994 get_float_frac_digit:
999 add a, #_float_frac_bcd
1002 jb psw.5, get_float_frac_digit_done
1004 get_float_frac_digit_done:
1008 #endif // end of normal FLOAT code (not FLOAT_FIXED4)
1011 // These helper functions are used, regardless of which type of
1012 // FLOAT code is used.
1017 lcall pm2_entry_phex
1019 lcall pm2_entry_cout
1022 lcall pm2_entry_cout
1026 // Fetch a float from the va_args and put it into
1027 // r7(exp) r4/r3/r2(mant) and also clear r1 and preset
1039 mov _negative_flag, c
1041 jz printf_get_float_2
1057 /* read an integer into r1/r2/r3/r4, and msb into r5 */
1063 jb _short_flag, printf_get_done
1068 jnb _long_flag, printf_get_done
1083 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1084 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1085 * process, to avoid needing extra memory for the result (and
1086 * r1 gets used for temporary storage). dptr is overwritten,
1087 * but r0 is not changed.
1102 jnb _short_flag, printf_i2bcd_16 // if 8 bit int, we're done
1109 mov dptr, #_int2bcd_2
1125 mov dptr, #_int2bcd_3
1143 jb _long_flag, printf_i2bcd_32 // if 16 bit int, we're done
1152 mov dptr, #_int2bcd_4
1177 mov dptr, #_int2bcd_5
1204 mov dptr, #_int2bcd_6
1206 lcall printf_bcd_add10 // saves 27 bytes, costs 5 cycles
1212 mov dptr, #_int2bcd_7
1246 #else // not FAST_INTEGER
1248 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1249 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1250 * process, to avoid needing extra memory for the result (and
1251 * r1 gets used for temporary storage). dptr is overwritten,
1252 * but r0 is not changed.
1259 jb _short_flag, printf_int2bcd_begin
1261 jnb _long_flag, printf_int2bcd_begin
1263 printf_int2bcd_begin:
1269 mov (_i2bcd_tmp + 0), a
1270 mov (_i2bcd_tmp + 1), a
1285 jnc print_i2bcd_skip
1303 addc a, (_i2bcd_tmp + 0)
1305 mov (_i2bcd_tmp + 0), a
1308 addc a, (_i2bcd_tmp + 1)
1310 mov (_i2bcd_tmp + 1), a
1317 djnz b, printf_i2bcd_loop
1318 mov r2, (_i2bcd_tmp + 0)
1319 mov r3, (_i2bcd_tmp + 1)
1326 jb _short_flag, printf_int2bcd_begin
1328 printf_int2bcd_begin:
1342 jnc printf_i2bcd_add_skip
1358 printf_i2bcd_add_skip:
1362 djnz b, printf_i2bcd_loop
1368 #endif // not FAST_INTEGER
1375 jnb _leading_zero_flag, printf_space_output
1378 printf_space_output:
1379 lcall printf_putchar
1383 jnz printf_space_loop
1387 /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
1394 jnb _print_zero_flag, printf_ret
1396 setb _print_zero_flag
1402 #ifdef PUTCHAR_CALLEE_SAVES
1422 /* print a zero if all the calls to print the digits ended up */
1423 /* being leading zeros */
1426 jb _print_zero_flag, printf_ret
1439 * for ($d=0; $d < 8; $d++) {
1441 * for ($p=0; $p < 5; $p++) {
1442 * last unless (((16 ** $d) * 15) / (10 ** ($p * 2))) % 100;
1443 * printf "code unsigned char int2bcd_%d_%d[15] = {", $d, $p;
1444 * for ($i=0; $i < 16; $i++) {
1446 * (((16 ** $d) * $i) / (10 ** ($p * 2))) % 100;
1447 * print ", " if $i < 15;
1455 static __code unsigned char int2bcd_0[] = {
1456 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1457 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1459 static __code unsigned char int2bcd_1[] = {
1460 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1461 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1462 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1463 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02};
1466 static __code unsigned char int2bcd_2[] = {
1467 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1468 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1469 0x00, 0x02, 0x05, 0x07, 0x10, 0x12, 0x15, 0x17,
1470 0x20, 0x23, 0x25, 0x28, 0x30, 0x33, 0x35, 0x38};
1472 static __code unsigned char int2bcd_3[] = {
1473 0x00, 0x96, 0x92, 0x88, 0x84, 0x80, 0x76, 0x72,
1474 0x68, 0x64, 0x60, 0x56, 0x52, 0x48, 0x44, 0x40,
1475 0x00, 0x40, 0x81, 0x22, 0x63, 0x04, 0x45, 0x86,
1476 0x27, 0x68, 0x09, 0x50, 0x91, 0x32, 0x73, 0x14,
1477 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02,
1478 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06};
1481 static __code unsigned char int2bcd_4[] = {
1482 0x00, 0x36, 0x72, 0x08, 0x44, 0x80, 0x16, 0x52,
1483 0x88, 0x24, 0x60, 0x96, 0x32, 0x68, 0x04, 0x40,
1484 0x00, 0x55, 0x10, 0x66, 0x21, 0x76, 0x32, 0x87,
1485 0x42, 0x98, 0x53, 0x08, 0x64, 0x19, 0x75, 0x30,
1486 0x00, 0x06, 0x13, 0x19, 0x26, 0x32, 0x39, 0x45,
1487 0x52, 0x58, 0x65, 0x72, 0x78, 0x85, 0x91, 0x98};
1489 static __code unsigned char int2bcd_5[] = {
1490 0x00, 0x76, 0x52, 0x28, 0x04, 0x80, 0x56, 0x32,
1491 0x08, 0x84, 0x60, 0x36, 0x12, 0x88, 0x64, 0x40,
1492 0x00, 0x85, 0x71, 0x57, 0x43, 0x28, 0x14, 0x00,
1493 0x86, 0x71, 0x57, 0x43, 0x29, 0x14, 0x00, 0x86,
1494 0x00, 0x04, 0x09, 0x14, 0x19, 0x24, 0x29, 0x34,
1495 0x38, 0x43, 0x48, 0x53, 0x58, 0x63, 0x68, 0x72,
1496 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1497 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1499 static __code unsigned char int2bcd_6[] = {
1500 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1501 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1502 0x00, 0x72, 0x44, 0x16, 0x88, 0x60, 0x32, 0x05,
1503 0x77, 0x49, 0x21, 0x93, 0x65, 0x38, 0x10, 0x82,
1504 0x00, 0x77, 0x55, 0x33, 0x10, 0x88, 0x66, 0x44,
1505 0x21, 0x99, 0x77, 0x54, 0x32, 0x10, 0x88, 0x65,
1506 0x00, 0x16, 0x33, 0x50, 0x67, 0x83, 0x00, 0x17,
1507 0x34, 0x50, 0x67, 0x84, 0x01, 0x18, 0x34, 0x51,
1508 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
1509 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02};
1511 static __code unsigned char int2bcd_7[] = {
1512 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1513 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1514 0x00, 0x54, 0x09, 0x63, 0x18, 0x72, 0x27, 0x81,
1515 0x36, 0x91, 0x45, 0x00, 0x54, 0x09, 0x63, 0x18,
1516 0x00, 0x43, 0x87, 0x30, 0x74, 0x17, 0x61, 0x04,
1517 0x48, 0x91, 0x35, 0x79, 0x22, 0x66, 0x09, 0x53,
1518 0x00, 0x68, 0x36, 0x05, 0x73, 0x42, 0x10, 0x79,
1519 0x47, 0x15, 0x84, 0x52, 0x21, 0x89, 0x58, 0x26,
1520 0x00, 0x02, 0x05, 0x08, 0x10, 0x13, 0x16, 0x18,
1521 0x21, 0x24, 0x26, 0x29, 0x32, 0x34, 0x37, 0x40};
1524 #else // not FAST_INTEGER
1528 * print "__code unsigned char int2bcd[] = {\n";
1529 * for ($i=0, $n=1; $i<32; $i++, $n*=2) {
1530 * $r = sprintf "%010u", $n;
1531 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1532 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d, 0x%02d", $5, $4, $3, $2, $1;
1533 * print ',' if $i < 31;
1534 * printf "\t\t// %10u\n", $n;
1536 * print "}\n__code unsigned char int2bcd[] = {\n";
1537 * for ($i=0, $n=1; $i<16; $i++, $n*=2) {
1538 * $r = sprintf "%06u", $n;
1539 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1540 * printf "0x%02d, 0x%02d, 0x%02d", $3, $2, $1;
1541 * print ',' if $i < 15;
1542 * printf "\t\t// %10u\n", $n;
1548 static __code unsigned char int2bcd[] = {
1549 0x01, 0x00, 0x00, 0x00, 0x00, // 1
1550 0x02, 0x00, 0x00, 0x00, 0x00, // 2
1551 0x04, 0x00, 0x00, 0x00, 0x00, // 4
1552 0x08, 0x00, 0x00, 0x00, 0x00, // 8
1553 0x16, 0x00, 0x00, 0x00, 0x00, // 16
1554 0x32, 0x00, 0x00, 0x00, 0x00, // 32
1555 0x64, 0x00, 0x00, 0x00, 0x00, // 64
1556 0x28, 0x01, 0x00, 0x00, 0x00, // 128
1557 0x56, 0x02, 0x00, 0x00, 0x00, // 256
1558 0x12, 0x05, 0x00, 0x00, 0x00, // 512
1559 0x24, 0x10, 0x00, 0x00, 0x00, // 1024
1560 0x48, 0x20, 0x00, 0x00, 0x00, // 2048
1561 0x96, 0x40, 0x00, 0x00, 0x00, // 4096
1562 0x92, 0x81, 0x00, 0x00, 0x00, // 8192
1563 0x84, 0x63, 0x01, 0x00, 0x00, // 16384
1564 0x68, 0x27, 0x03, 0x00, 0x00, // 32768
1565 0x36, 0x55, 0x06, 0x00, 0x00, // 65536
1566 0x72, 0x10, 0x13, 0x00, 0x00, // 131072
1567 0x44, 0x21, 0x26, 0x00, 0x00, // 262144
1568 0x88, 0x42, 0x52, 0x00, 0x00, // 524288
1569 0x76, 0x85, 0x04, 0x01, 0x00, // 1048576
1570 0x52, 0x71, 0x09, 0x02, 0x00, // 2097152
1571 0x04, 0x43, 0x19, 0x04, 0x00, // 4194304
1572 0x08, 0x86, 0x38, 0x08, 0x00, // 8388608
1573 0x16, 0x72, 0x77, 0x16, 0x00, // 16777216
1574 0x32, 0x44, 0x55, 0x33, 0x00, // 33554432
1575 0x64, 0x88, 0x10, 0x67, 0x00, // 67108864
1576 0x28, 0x77, 0x21, 0x34, 0x01, // 134217728
1577 0x56, 0x54, 0x43, 0x68, 0x02, // 268435456
1578 0x12, 0x09, 0x87, 0x36, 0x05, // 536870912
1579 0x24, 0x18, 0x74, 0x73, 0x10, // 1073741824
1580 0x48, 0x36, 0x48, 0x47, 0x21 // 2147483648
1583 static __code unsigned char int2bcd[] = {
1584 0x01, 0x00, 0x00, // 1
1585 0x02, 0x00, 0x00, // 2
1586 0x04, 0x00, 0x00, // 4
1587 0x08, 0x00, 0x00, // 8
1588 0x16, 0x00, 0x00, // 16
1589 0x32, 0x00, 0x00, // 32
1590 0x64, 0x00, 0x00, // 64
1591 0x28, 0x01, 0x00, // 128
1592 0x56, 0x02, 0x00, // 256
1593 0x12, 0x05, 0x00, // 512
1594 0x24, 0x10, 0x00, // 1024
1595 0x48, 0x20, 0x00, // 2048
1596 0x96, 0x40, 0x00, // 4096
1597 0x92, 0x81, 0x00, // 8192
1598 0x84, 0x63, 0x01, // 16384
1599 0x68, 0x27, 0x03 // 32768
1603 #endif // not FAST_INTEGER
1607 #ifndef FLOAT_FIXED4
1611 * for ($i=0, $f=0.5; $i<24; $i++) {
1612 * $r = sprintf "%.8f", $f;
1613 * $r =~ /0\.([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1614 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d", $4, $3, $2, $1;
1615 * print ',' if $i < 23;
1617 * printf "\t\t// %.15f %.8f\n", $f, $sum;
1622 static __code unsigned char frac2bcd[] = {
1623 0x00, 0x00, 0x00, 0x50, // 0.500000000000000 0.50000000
1624 0x00, 0x00, 0x00, 0x25, // 0.250000000000000 0.75000000
1625 0x00, 0x00, 0x50, 0x12, // 0.125000000000000 0.87500000
1626 0x00, 0x00, 0x25, 0x06, // 0.062500000000000 0.93750000
1627 0x00, 0x50, 0x12, 0x03, // 0.031250000000000 0.96875000
1628 0x00, 0x25, 0x56, 0x01, // 0.015625000000000 0.98437500
1629 0x50, 0x12, 0x78, 0x00, // 0.007812500000000 0.99218750
1630 0x25, 0x06, 0x39, 0x00, // 0.003906250000000 0.99609375
1631 0x12, 0x53, 0x19, 0x00, // 0.001953125000000 0.99804687
1632 0x56, 0x76, 0x09, 0x00, // 0.000976562500000 0.99902343
1633 0x28, 0x88, 0x04, 0x00, // 0.000488281250000 0.99951171
1634 0x14, 0x44, 0x02, 0x00, // 0.000244140625000 0.99975585
1635 0x07, 0x22, 0x01, 0x00, // 0.000122070312500 0.99987792
1636 0x04, 0x61, 0x00, 0x00, // 0.000061035156250 0.99993896
1637 0x52, 0x30, 0x00, 0x00, // 0.000030517578125 0.99996948
1638 0x26, 0x15, 0x00, 0x00, // 0.000015258789062 0.99998474
1639 0x63, 0x07, 0x00, 0x00, // 0.000007629394531 0.99999237
1640 0x81, 0x03, 0x00, 0x00, // 0.000003814697266 0.99999618
1641 0x91, 0x01, 0x00, 0x00, // 0.000001907348633 0.99999809
1642 0x95, 0x00, 0x00, 0x00, // 0.000000953674316 0.99999904
1643 0x48, 0x00, 0x00, 0x00, // 0.000000476837158 0.99999952
1644 0x24, 0x00, 0x00, 0x00, // 0.000000238418579 0.99999976
1645 0x12, 0x00, 0x00, 0x00, // 0.000000119209290 0.99999988
1646 0x06, 0x00, 0x00, 0x00, // 0.000000059604645 0.99999994
1647 0x03, 0x00, 0x00, 0x00, // 0.000000029802322 0.99999997
1648 0x01, 0x00, 0x00, 0x00, // 0.000000014901161 0.99999998
1649 0x01, 0x00, 0x00, 0x00 // 0.000000007450581 0.99999999
1652 #ifndef FLOAT_DEFAULT_FRAC_DIGITS
1653 // TODO: Perhaps these should be tweaked a bit to take round up
1654 // effects into account... or maybe give more default digits??
1656 // 0.0001 - 0.0009999 7
1657 // 0.001 - 0.009999 6 0.001 = 0x3A83126F 3A83
1658 // 0.01 - 0.09999 5 0.01 = 0x3C23D70A 3C23
1659 // 0.1 - 9.9999 4 0.1 = 0x3DCCCCCD, 3DCC
1660 // 10.0 - 99.99 3 10.0 = 0x41200000 4120
1661 // 100.0 - 999.99 2 100.0 = 0x42C80000 42C8
1662 // 1000 - 9999.9 1 1000 = 0x447A0000 447A
1663 // 10000+ 0 10000 = 0x461C4000 461C
1664 static __code unsigned int float_range_table[] = {
1675 #else // using FLOAT_FIXED4
1679 * for ($i=0, $f=0.5; $i<14; $i++) {
1680 * $r = sprintf "%.4f", $f;
1681 * $r =~ /0\.([0-9][0-9])([0-9][0-9])/;
1682 * printf "0x%02d, 0x%02d", $2, $1;
1683 * print ',' if $i < 13;
1685 * printf "\t\t// %.15f %.4f\n", $f, $sum;
1690 static __code unsigned char frac2bcd[] = {
1691 0x00, 0x50, // 0.500000000000000 0.5000
1692 0x00, 0x25, // 0.250000000000000 0.7500
1693 0x50, 0x12, // 0.125000000000000 0.8750
1694 0x25, 0x06, // 0.062500000000000 0.9375
1695 0x12, 0x03, // 0.031250000000000 0.9687
1696 0x56, 0x01, // 0.015625000000000 0.9843
1697 0x78, 0x00, // 0.007812500000000 0.9921
1698 0x39, 0x00, // 0.003906250000000 0.9960
1699 0x20, 0x00, // 0.001953125000000 0.9980
1700 0x10, 0x00, // 0.000976562500000 0.9990
1701 0x05, 0x00, // 0.000488281250000 0.9995
1702 0x02, 0x00, // 0.000244140625000 0.9997
1703 0x01, 0x00, // 0.000122070312500 0.9998
1704 0x01, 0x00 // 0.000061035156250 0.9999
1707 #endif // FLOAT_FIXED4
1711 #endif // defines compatible with printf_fast