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 /** comiled 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 hexidecimal.
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 ); */
92 static bit long_flag, short_flag, print_zero_flag, negative_flag;
95 static bit field_width_flag;
96 static data unsigned char field_width;
100 #define SDCC_FLOAT_LIB
102 static bit continue_float;
104 static data unsigned char frac_field_width;
105 static data unsigned char float_frac_bcd[4];
106 // TODO: can float_frac_bcd be overlaid with temps used by trig functions
112 static data unsigned int i2bcd_tmp; // slow 32 int conversion needs temp space
119 #define PRINTF_FAST printf_fast
123 #if !defined(SDCC_mcs51) || defined(SDCC_USE_XSTACK) || defined(_SDCC_NO_ASM_LIB_FUNCS)
124 // Does printf_fast really work on ds390 and ds400?
125 // If it does, enable them in the line above
126 #if defined(SDCC_USE_XSTACK)
127 #warning "printf_fast not built, does not support --xstack"
128 #elif defined(_SDCC_NO_ASM_LIB_FUNCS)
129 #warning "printf_fast not built, _SDCC_NO_ASM_LIB_FUNCS defined"
131 #else // defines are compatible with printf_fast
134 void PRINTF_FAST(code char *fmt, ...) reentrant
136 fmt; /* supress unreferenced variable warning */
141 mov a, _bp // r0 will point to va_args (stack)
143 mov r0, a // r0 points to MSB of fmt
146 mov dpl, @r0 // dptr has address of fmt
152 movc a, @a+dptr // get next byte of fmt string
154 //cjne a, #'%', printf_normal
155 cjne a, #37, printf_normal
163 clr _field_width_flag
164 mov r1, #_field_width
173 movc a, @a+dptr // get next byte of data format
176 /* parse and consume the field width digits, even if */
177 /* we don't build the code to make use of them */
184 setb _field_width_flag
192 sjmp printf_format_loop
200 //cjne a, #'l', printf_format_h
201 cjne a, #108, printf_format_h
203 sjmp printf_format_loop
206 //cjne a, #'h', printf_format_s
207 cjne a, #104, printf_format_s
209 sjmp printf_format_loop
212 //cjne a, #'s', printf_format_d
213 cjne a, #115, printf_format_d
217 //cjne a, #'d', printf_format_u
218 cjne a, #100, printf_format_u
223 //cjne a, #'u', printf_format_c
224 cjne a, #117, printf_format_c
229 //cjne a, #'c', printf_format_x
230 cjne a, #99, printf_format_x
231 mov a, @r0 // Acc has the character to print
236 //cjne a, #'x', printf_format_f
237 cjne a, #120, printf_format_f
242 //cjne a, #'f', printf_format_dot
243 cjne a, #102, printf_format_dot
248 //cjne a, #'.', printf_normal
249 cjne a, #46, printf_normal
252 mov r1, #ar3 // parse frac field, but discard if FIXED4
254 mov r1, #_frac_field_width
258 sjmp printf_format_loop
264 ljmp printf_main_loop
274 /* print a string... just grab each byte with __gptrget */
275 /* the user much pass a 24 bit generic pointer */
278 push dph // save addr in fmt onto stack
280 mov b, @r0 // b has type of address (generic *)
284 mov dpl, @r0 // dptr has address of user's string
288 jnb _field_width_flag, printf_str_loop
297 jnz printf_str_fw_loop
302 #endif // FIELD_WIDTH
311 pop dpl // restore addr withing fmt
313 ljmp printf_main_loop
322 /* printing in hex is easy because sdcc pushes the LSB first */
326 jb _short_flag, printf_hex_end
328 jnb _long_flag, printf_hex_end
333 ljmp printf_main_loop
336 lcall printf_phex_msn
357 /* printing an integer is not so easy. For a signed int */
358 /* check if it is negative and print the minus sign and */
359 /* invert it to a positive integer */
363 jnb acc.7, printf_uint /* check if negative */
365 mov a, r1 /* invert integer */
369 jb _short_flag, printf_uint
374 jnb _long_flag, printf_uint
385 /* printing integers is a lot of work... because it takes so */
386 /* long, the first thing to do is make sure we're doing as */
387 /* little work as possible, then convert the binary int to */
388 /* packed BCD, and finally print each digit of the BCD number */
392 jb _short_flag, printf_uint_ck8
393 jnb _long_flag, printf_uint_ck16
395 /* it's a 32 bit int... but if the upper 16 bits are zero */
396 /* we can treat it like a 16 bit integer and convert much faster */
399 jnz printf_uint_begin
401 jnz printf_uint_begin
404 jnz printf_ld_in_hex // print long integer as hex
405 mov a, r4 // rather than just the low 16 bits
410 /* it's a 16 bit int... but if the upper 8 bits are zero */
411 /* we can treat it like a 8 bit integer and convert much faster */
413 jnz printf_uint_begin
416 /* it's an 8 bit int... if it's zero, it's a lot faster to just */
417 /* print the digit zero and skip all the hard work! */
419 jnz printf_uint_begin
421 jnb _field_width_flag, printf_uint_zero
432 jnb _continue_float, 0001$
436 ljmp printf_main_loop
443 lcall printf_int2bcd // bcd number in r3/r2/r7/r6/r5
447 jnb _field_width_flag, printf_uifw_end
451 jnb _long_flag, printf_uifw_16
474 jb _short_flag, printf_uifw_8
493 ;r1 has the number of digits for the number
495 mov c, _negative_flag
500 #ifndef PUTCHAR_CALLEE_SAVES
510 #ifndef PUTCHAR_CALLEE_SAVES
522 #endif // FIELD_WIDTH
526 jnb _negative_flag, printf_uint_pos
527 #ifdef PUTCHAR_CALLEE_SAVES
549 #endif // PUTCHAR_CALLEE_SAVES
552 jb _short_flag, printf_uint8
554 jnb _long_flag, printf_uint16
562 lcall printf_phex_msn
564 lcall printf_phex_lsn
566 lcall printf_phex_msn
568 lcall printf_phex_lsn
571 lcall printf_phex_msn
583 lcall printf_phex_lsn
585 lcall printf_phex_msn
593 lcall printf_phex_lsn
595 lcall printf_phex_msn
597 lcall printf_phex_lsn
602 jnb _continue_float, 0002$
606 ljmp printf_main_loop
617 // Print a float the easy way. First, extract the integer part and
618 // use the integer printing code. Then extract the fractional part,
619 // convert each bit to 4 digit BCD, and print the BCD sum. Absolutely
620 // no field width control, always 4 digits printed past the decimal
621 // point. No round off. 1.9999987 prints as 1.9999, not 2.0000.
624 jnb _field_width_flag, print_float_begin
632 push ar0 // keep r0 safe, will need it again
633 lcall printf_get_float
635 mov a, #158 // check for large float we can't print
637 jnc print_float_size_ok
638 printf_float_too_big:
639 // TODO: should print some sort of overflow error??
641 ljmp printf_format_loop
650 jnz printf_float_too_big
652 lcall printf_uint // print the integer portion
656 // now that the integer part is printed, we need to refetch the
657 // float from the va_args and extract the fractional part
659 lcall printf_get_float
664 cjne a, #126, print_float_frac_lshift
665 sjmp print_float_frac // input between 0.5 to 0.9999
666 print_float_frac_lshift:
667 jc print_float_frac_rshift
668 //Acc (exponent) is greater than 126 (input >= 1.0)
671 print_float_lshift_loop:
682 djnz r5, print_float_lshift_loop
683 sjmp print_float_frac
684 print_float_frac_rshift:
685 //Acc (exponent) is less than 126 (input < 0.5)
690 // now we've got the fractional part, so now is the time to
691 // convert to BCD... just convert each bit to BCD using a
692 // lookup table and BCD sum them together
697 mov dptr, #_frac2bcd // FLOAT_FIXED4 version (14 entries)
698 print_float_frac_loop:
705 jnc print_float_frac_skip
716 print_float_frac_skip:
719 djnz r7, print_float_frac_loop
720 // the BCD sum is in dptr, so all we've got to do is output
721 // all 4 digits. No trailing zero suppression, no nice round
722 // off (impossible to change the integer part since we already
726 setb _print_zero_flag
728 lcall printf_phex_msn
730 lcall printf_phex_lsn
732 lcall printf_phex_msn
734 lcall printf_phex_lsn
738 ljmp printf_main_loop
740 #else // not FLOAT_FIXED4
746 // Print a float the not-as-easy way, with a configurable number of
747 // fractional digits (up to 8) and proper round-off (up to 7 digits).
748 // First, extract the fractional part, convert to BCD, and then add
749 // the scaled round-off. Store the rounded fractional digits and
750 // their carry. Then extract the integer portion, increment it if
751 // the rounding caused a carry. Use the integer printing to output
752 // the integer, and then output the stored fractional digits. This
753 // approach requires 5 bytes of internal RAM to store the 8 fractional
754 // digits and the number of them we'll actually print. This code is
755 // a couple hundred bytes larger and a bit slower than the FIXED4
756 // version, but it gives very nice results.
759 jnb _field_width_flag, print_float_default_width
760 // The caller specified exact field width, so use it. Need to
761 // convert the whole float digits into the integer portion only.
764 subb a, _frac_field_width
766 jnc print_float_begin
768 sjmp print_float_begin
770 print_float_default_width:
771 // The caller didn't specify field width (or FIELD_WIDTH is
772 // not defined so it's ignored). We've still got to know
773 // how many fractional digits are going to print, so we can
774 // round off properly.
775 #ifdef FLOAT_DEFAULT_FRAC_DIGITS
776 mov _frac_field_width, #FLOAT_DEFAULT_FRAC_DIGITS
778 // default fractional field width (between 0 to 7)
779 // attempt to scale the default number of fractional digits
780 // based on the magnitude of the float
781 mov ar1, r0 // r0 points to first byte of float
782 dec r1 // r1 points to second byte of float
785 mov dptr, #_float_range_table
787 print_float_default_loop:
795 jnc print_float_default_done
797 djnz r5, print_float_default_loop
798 print_float_default_done:
799 mov _frac_field_width, r5
802 #endif // not FLOAT_DEFAULT_FRAC_DIGITS
805 push ar0 // keep r0 safe, will need it again
806 lcall printf_get_float
810 cjne a, #126, print_float_frac_lshift
811 sjmp print_float_frac // input between 0.5 to 0.9999
813 print_float_frac_lshift:
814 jc print_float_frac_rshift
815 //Acc (exponent) is greater than 126 (input >= 1.0)
818 print_float_lshift_loop:
829 djnz r5, print_float_lshift_loop
830 sjmp print_float_frac
831 print_float_frac_rshift:
832 //Acc (exponent) is less than 126 (input < 0.5)
837 // Convert the fraction in r4/r3/r2/r1 into 8 BCD digits in r0/r7/r6/r5
844 mov dptr, #_frac2bcd // FLOAT version (27 entries)
845 print_float_frac_loop:
858 jnc print_float_frac_skip
879 print_float_frac_skip:
884 djnz b, print_float_frac_loop
885 print_float_frac_roundoff:
886 // Now it's time to round-off the BCD digits to the desired precision.
888 mov r4, #0x50 // r4/r3/r2/r1 = 0.5 (bcd rounding)
892 mov a, _frac_field_width
896 mov dph, r0 // fs_rshift_a will overwrite r0 & dpl
897 lcall fs_rshift_a // divide r4/r3/r2/r1 by 10^frac_field_width
899 add a, r1 // add rounding to fractional part
901 mov _float_frac_bcd+3, a // and store it for later use
905 mov _float_frac_bcd+2, a
909 mov _float_frac_bcd+1, a
913 mov _float_frac_bcd+0, a
914 mov sign_b, c // keep fractional carry in sign_b
918 // Time to work on the integer portion... fetch the float again, check
919 // size (exponent), scale to integer, add the fraction's carry, and
920 // let the integer printing code do all the work.
922 lcall printf_get_float
925 mov a, #158 // check for large float we can't print
927 jnc print_float_size_ok
928 printf_float_too_big:
929 // TODO: should print some sort of overflow error??
930 ljmp printf_format_loop
935 jnb sign_b, print_float_do_int
936 // if we get here, the fractional round off caused the
937 // integer part to increment. Add 1 for a proper result
952 jc printf_float_too_big
957 jnz printf_float_too_big
960 lcall printf_uint // print the integer portion
963 print_float_frac_width:
964 // Now all we have to do is output the fractional digits that
965 // were previous computed and stored in memory.
967 jb _field_width_flag, print_float_do_frac
969 #ifndef DO_NOT_TRIM_TRAILING_ZEROS
970 // if the user did not explicitly set a
971 // field width, trim off trailing zeros
972 print_float_frac_trim:
973 mov a, _frac_field_width
974 jz print_float_do_frac
975 lcall get_float_frac_digit
976 jnz print_float_do_frac
977 djnz _frac_field_width, print_float_frac_trim
981 mov a, _frac_field_width
987 setb _print_zero_flag
988 print_float_do_frac_loop:
991 lcall get_float_frac_digit
992 lcall printf_phex_lsn
994 cjne a, _frac_field_width, print_float_do_frac_loop
998 ljmp printf_main_loop
1002 // acc=1 for tenths, acc=2 for hundredths, etc
1003 get_float_frac_digit:
1008 add a, #_float_frac_bcd
1011 jb psw.5, get_float_frac_digit_done
1013 get_float_frac_digit_done:
1020 #endif // end of normal FLOAT code (not FLOAT_FIXED4)
1023 // These helper functions are used, regardless of which type of
1024 // FLOAT code is used.
1029 lcall pm2_entry_phex
1031 lcall pm2_entry_cout
1034 lcall pm2_entry_cout
1038 // Fetch a float from the va_args and put it into
1039 // r7(exp) r4/r3/r2(mant) and also clear r1 and preset
1051 mov _negative_flag, c
1053 jz printf_get_float_2
1080 /* read an integer into r1/r2/r3/r4, and msb into r5 */
1086 jb _short_flag, printf_get_done
1091 jnb _long_flag, printf_get_done
1109 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1110 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1111 * process, to avoid needing extra memory for the result (and
1112 * r1 gets used for temporary storage). dptr is overwritten,
1113 * but r0 is not changed.
1128 jnb _short_flag, printf_i2bcd_16 // if 8 bit int, we're done
1135 mov dptr, #_int2bcd_2
1151 mov dptr, #_int2bcd_3
1169 jb _long_flag, printf_i2bcd_32 // if 16 bit int, we're done
1178 mov dptr, #_int2bcd_4
1203 mov dptr, #_int2bcd_5
1230 mov dptr, #_int2bcd_6
1232 lcall printf_bcd_add10 // saves 27 bytes, costs 5 cycles
1238 mov dptr, #_int2bcd_7
1272 #else // not FAST_INTEGER
1274 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1275 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1276 * process, to avoid needing extra memory for the result (and
1277 * r1 gets used for temporary storage). dptr is overwritten,
1278 * but r0 is not changed.
1285 jb _short_flag, printf_int2bcd_begin
1287 jnb _long_flag, printf_int2bcd_begin
1289 printf_int2bcd_begin:
1295 mov (_i2bcd_tmp + 0), a
1296 mov (_i2bcd_tmp + 1), a
1311 jnc print_i2bcd_skip
1329 addc a, (_i2bcd_tmp + 0)
1331 mov (_i2bcd_tmp + 0), a
1334 addc a, (_i2bcd_tmp + 1)
1336 mov (_i2bcd_tmp + 1), a
1343 djnz b, printf_i2bcd_loop
1344 mov r2, (_i2bcd_tmp + 0)
1345 mov r3, (_i2bcd_tmp + 1)
1352 jb _short_flag, printf_int2bcd_begin
1354 printf_int2bcd_begin:
1368 jnc printf_i2bcd_add_skip
1384 printf_i2bcd_add_skip:
1388 djnz b, printf_i2bcd_loop
1394 #endif // not FAST_INTEGER
1412 lcall printf_putchar
1416 jnz printf_space_loop
1424 /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
1431 jnb _print_zero_flag, printf_ret
1433 setb _print_zero_flag
1439 #ifdef PUTCHAR_CALLEE_SAVES
1459 /* print a zero if all the calls to print the digits ended up */
1460 /* being leading zeros */
1463 jb _print_zero_flag, printf_ret
1476 * for ($d=0; $d < 8; $d++) {
1478 * for ($p=0; $p < 5; $p++) {
1479 * last unless (((16 ** $d) * 15) / (10 ** ($p * 2))) % 100;
1480 * printf "code unsigned char int2bcd_%d_%d[15] = {", $d, $p;
1481 * for ($i=0; $i < 16; $i++) {
1483 * (((16 ** $d) * $i) / (10 ** ($p * 2))) % 100;
1484 * print ", " if $i < 15;
1492 static code unsigned char int2bcd_0[] = {
1493 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1494 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1496 static code unsigned char int2bcd_1[] = {
1497 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1498 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1499 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1500 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02};
1503 static code unsigned char int2bcd_2[] = {
1504 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1505 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1506 0x00, 0x02, 0x05, 0x07, 0x10, 0x12, 0x15, 0x17,
1507 0x20, 0x23, 0x25, 0x28, 0x30, 0x33, 0x35, 0x38};
1509 static code unsigned char int2bcd_3[] = {
1510 0x00, 0x96, 0x92, 0x88, 0x84, 0x80, 0x76, 0x72,
1511 0x68, 0x64, 0x60, 0x56, 0x52, 0x48, 0x44, 0x40,
1512 0x00, 0x40, 0x81, 0x22, 0x63, 0x04, 0x45, 0x86,
1513 0x27, 0x68, 0x09, 0x50, 0x91, 0x32, 0x73, 0x14,
1514 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02,
1515 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06};
1518 static code unsigned char int2bcd_4[] = {
1519 0x00, 0x36, 0x72, 0x08, 0x44, 0x80, 0x16, 0x52,
1520 0x88, 0x24, 0x60, 0x96, 0x32, 0x68, 0x04, 0x40,
1521 0x00, 0x55, 0x10, 0x66, 0x21, 0x76, 0x32, 0x87,
1522 0x42, 0x98, 0x53, 0x08, 0x64, 0x19, 0x75, 0x30,
1523 0x00, 0x06, 0x13, 0x19, 0x26, 0x32, 0x39, 0x45,
1524 0x52, 0x58, 0x65, 0x72, 0x78, 0x85, 0x91, 0x98};
1526 static code unsigned char int2bcd_5[] = {
1527 0x00, 0x76, 0x52, 0x28, 0x04, 0x80, 0x56, 0x32,
1528 0x08, 0x84, 0x60, 0x36, 0x12, 0x88, 0x64, 0x40,
1529 0x00, 0x85, 0x71, 0x57, 0x43, 0x28, 0x14, 0x00,
1530 0x86, 0x71, 0x57, 0x43, 0x29, 0x14, 0x00, 0x86,
1531 0x00, 0x04, 0x09, 0x14, 0x19, 0x24, 0x29, 0x34,
1532 0x38, 0x43, 0x48, 0x53, 0x58, 0x63, 0x68, 0x72,
1533 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1534 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1536 static code unsigned char int2bcd_6[] = {
1537 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1538 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1539 0x00, 0x72, 0x44, 0x16, 0x88, 0x60, 0x32, 0x05,
1540 0x77, 0x49, 0x21, 0x93, 0x65, 0x38, 0x10, 0x82,
1541 0x00, 0x77, 0x55, 0x33, 0x10, 0x88, 0x66, 0x44,
1542 0x21, 0x99, 0x77, 0x54, 0x32, 0x10, 0x88, 0x65,
1543 0x00, 0x16, 0x33, 0x50, 0x67, 0x83, 0x00, 0x17,
1544 0x34, 0x50, 0x67, 0x84, 0x01, 0x18, 0x34, 0x51,
1545 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
1546 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02};
1548 static code unsigned char int2bcd_7[] = {
1549 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1550 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1551 0x00, 0x54, 0x09, 0x63, 0x18, 0x72, 0x27, 0x81,
1552 0x36, 0x91, 0x45, 0x00, 0x54, 0x09, 0x63, 0x18,
1553 0x00, 0x43, 0x87, 0x30, 0x74, 0x17, 0x61, 0x04,
1554 0x48, 0x91, 0x35, 0x79, 0x22, 0x66, 0x09, 0x53,
1555 0x00, 0x68, 0x36, 0x05, 0x73, 0x42, 0x10, 0x79,
1556 0x47, 0x15, 0x84, 0x52, 0x21, 0x89, 0x58, 0x26,
1557 0x00, 0x02, 0x05, 0x08, 0x10, 0x13, 0x16, 0x18,
1558 0x21, 0x24, 0x26, 0x29, 0x32, 0x34, 0x37, 0x40};
1561 #else // not FAST_INTEGER
1565 * print "code unsigned char int2bcd[] = {\n";
1566 * for ($i=0, $n=1; $i<32; $i++, $n*=2) {
1567 * $r = sprintf "%010u", $n;
1568 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1569 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d, 0x%02d", $5, $4, $3, $2, $1;
1570 * print ',' if $i < 31;
1571 * printf "\t\t// %10u\n", $n;
1573 * print "}\ncode unsigned char int2bcd[] = {\n";
1574 * for ($i=0, $n=1; $i<16; $i++, $n*=2) {
1575 * $r = sprintf "%06u", $n;
1576 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1577 * printf "0x%02d, 0x%02d, 0x%02d", $3, $2, $1;
1578 * print ',' if $i < 15;
1579 * printf "\t\t// %10u\n", $n;
1585 static code unsigned char int2bcd[] = {
1586 0x01, 0x00, 0x00, 0x00, 0x00, // 1
1587 0x02, 0x00, 0x00, 0x00, 0x00, // 2
1588 0x04, 0x00, 0x00, 0x00, 0x00, // 4
1589 0x08, 0x00, 0x00, 0x00, 0x00, // 8
1590 0x16, 0x00, 0x00, 0x00, 0x00, // 16
1591 0x32, 0x00, 0x00, 0x00, 0x00, // 32
1592 0x64, 0x00, 0x00, 0x00, 0x00, // 64
1593 0x28, 0x01, 0x00, 0x00, 0x00, // 128
1594 0x56, 0x02, 0x00, 0x00, 0x00, // 256
1595 0x12, 0x05, 0x00, 0x00, 0x00, // 512
1596 0x24, 0x10, 0x00, 0x00, 0x00, // 1024
1597 0x48, 0x20, 0x00, 0x00, 0x00, // 2048
1598 0x96, 0x40, 0x00, 0x00, 0x00, // 4096
1599 0x92, 0x81, 0x00, 0x00, 0x00, // 8192
1600 0x84, 0x63, 0x01, 0x00, 0x00, // 16384
1601 0x68, 0x27, 0x03, 0x00, 0x00, // 32768
1602 0x36, 0x55, 0x06, 0x00, 0x00, // 65536
1603 0x72, 0x10, 0x13, 0x00, 0x00, // 131072
1604 0x44, 0x21, 0x26, 0x00, 0x00, // 262144
1605 0x88, 0x42, 0x52, 0x00, 0x00, // 524288
1606 0x76, 0x85, 0x04, 0x01, 0x00, // 1048576
1607 0x52, 0x71, 0x09, 0x02, 0x00, // 2097152
1608 0x04, 0x43, 0x19, 0x04, 0x00, // 4194304
1609 0x08, 0x86, 0x38, 0x08, 0x00, // 8388608
1610 0x16, 0x72, 0x77, 0x16, 0x00, // 16777216
1611 0x32, 0x44, 0x55, 0x33, 0x00, // 33554432
1612 0x64, 0x88, 0x10, 0x67, 0x00, // 67108864
1613 0x28, 0x77, 0x21, 0x34, 0x01, // 134217728
1614 0x56, 0x54, 0x43, 0x68, 0x02, // 268435456
1615 0x12, 0x09, 0x87, 0x36, 0x05, // 536870912
1616 0x24, 0x18, 0x74, 0x73, 0x10, // 1073741824
1617 0x48, 0x36, 0x48, 0x47, 0x21 // 2147483648
1620 static code unsigned char int2bcd[] = {
1621 0x01, 0x00, 0x00, // 1
1622 0x02, 0x00, 0x00, // 2
1623 0x04, 0x00, 0x00, // 4
1624 0x08, 0x00, 0x00, // 8
1625 0x16, 0x00, 0x00, // 16
1626 0x32, 0x00, 0x00, // 32
1627 0x64, 0x00, 0x00, // 64
1628 0x28, 0x01, 0x00, // 128
1629 0x56, 0x02, 0x00, // 256
1630 0x12, 0x05, 0x00, // 512
1631 0x24, 0x10, 0x00, // 1024
1632 0x48, 0x20, 0x00, // 2048
1633 0x96, 0x40, 0x00, // 4096
1634 0x92, 0x81, 0x00, // 8192
1635 0x84, 0x63, 0x01, // 16384
1636 0x68, 0x27, 0x03 // 32768
1640 #endif // not FAST_INTEGER
1646 #ifndef FLOAT_FIXED4
1650 * for ($i=0, $f=0.5; $i<24; $i++) {
1651 * $r = sprintf "%.8f", $f;
1652 * $r =~ /0\.([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1653 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d", $4, $3, $2, $1;
1654 * print ',' if $i < 23;
1656 * printf "\t\t// %.15f %.8f\n", $f, $sum;
1661 static code unsigned char frac2bcd[] = {
1662 0x00, 0x00, 0x00, 0x50, // 0.500000000000000 0.50000000
1663 0x00, 0x00, 0x00, 0x25, // 0.250000000000000 0.75000000
1664 0x00, 0x00, 0x50, 0x12, // 0.125000000000000 0.87500000
1665 0x00, 0x00, 0x25, 0x06, // 0.062500000000000 0.93750000
1666 0x00, 0x50, 0x12, 0x03, // 0.031250000000000 0.96875000
1667 0x00, 0x25, 0x56, 0x01, // 0.015625000000000 0.98437500
1668 0x50, 0x12, 0x78, 0x00, // 0.007812500000000 0.99218750
1669 0x25, 0x06, 0x39, 0x00, // 0.003906250000000 0.99609375
1670 0x12, 0x53, 0x19, 0x00, // 0.001953125000000 0.99804687
1671 0x56, 0x76, 0x09, 0x00, // 0.000976562500000 0.99902343
1672 0x28, 0x88, 0x04, 0x00, // 0.000488281250000 0.99951171
1673 0x14, 0x44, 0x02, 0x00, // 0.000244140625000 0.99975585
1674 0x07, 0x22, 0x01, 0x00, // 0.000122070312500 0.99987792
1675 0x04, 0x61, 0x00, 0x00, // 0.000061035156250 0.99993896
1676 0x52, 0x30, 0x00, 0x00, // 0.000030517578125 0.99996948
1677 0x26, 0x15, 0x00, 0x00, // 0.000015258789062 0.99998474
1678 0x63, 0x07, 0x00, 0x00, // 0.000007629394531 0.99999237
1679 0x81, 0x03, 0x00, 0x00, // 0.000003814697266 0.99999618
1680 0x91, 0x01, 0x00, 0x00, // 0.000001907348633 0.99999809
1681 0x95, 0x00, 0x00, 0x00, // 0.000000953674316 0.99999904
1682 0x48, 0x00, 0x00, 0x00, // 0.000000476837158 0.99999952
1683 0x24, 0x00, 0x00, 0x00, // 0.000000238418579 0.99999976
1684 0x12, 0x00, 0x00, 0x00, // 0.000000119209290 0.99999988
1685 0x06, 0x00, 0x00, 0x00, // 0.000000059604645 0.99999994
1686 0x03, 0x00, 0x00, 0x00, // 0.000000029802322 0.99999997
1687 0x01, 0x00, 0x00, 0x00, // 0.000000014901161 0.99999998
1688 0x01, 0x00, 0x00, 0x00 // 0.000000007450581 0.99999999
1691 #ifndef FLOAT_DEFAULT_FRAC_DIGITS
1692 // TODO: Perhaps these should be tweaked a bit to take round up
1693 // effects into account... or maybe give more default digits??
1695 // 0.0001 - 0.0009999 7
1696 // 0.001 - 0.009999 6 0.001 = 0x3A83126F 3A83
1697 // 0.01 - 0.09999 5 0.01 = 0x3C23D70A 3C23
1698 // 0.1 - 9.9999 4 0.1 = 0x3DCCCCCD, 3DCC
1699 // 10.0 - 99.99 3 10.0 = 0x41200000 4120
1700 // 100.0 - 999.99 2 100.0 = 0x42C80000 42C8
1701 // 1000 - 9999.9 1 1000 = 0x447A0000 447A
1702 // 10000+ 0 10000 = 0x461C4000 461C
1703 static code unsigned int float_range_table[] = {
1714 #else // using FLOAT_FIXED4
1718 * for ($i=0, $f=0.5; $i<14; $i++) {
1719 * $r = sprintf "%.4f", $f;
1720 * $r =~ /0\.([0-9][0-9])([0-9][0-9])/;
1721 * printf "0x%02d, 0x%02d", $2, $1;
1722 * print ',' if $i < 13;
1724 * printf "\t\t// %.15f %.4f\n", $f, $sum;
1729 static code unsigned char frac2bcd[] = {
1730 0x00, 0x50, // 0.500000000000000 0.5000
1731 0x00, 0x25, // 0.250000000000000 0.7500
1732 0x50, 0x12, // 0.125000000000000 0.8750
1733 0x25, 0x06, // 0.062500000000000 0.9375
1734 0x12, 0x03, // 0.031250000000000 0.9687
1735 0x56, 0x01, // 0.015625000000000 0.9843
1736 0x78, 0x00, // 0.007812500000000 0.9921
1737 0x39, 0x00, // 0.003906250000000 0.9960
1738 0x20, 0x00, // 0.001953125000000 0.9980
1739 0x10, 0x00, // 0.000976562500000 0.9990
1740 0x05, 0x00, // 0.000488281250000 0.9995
1741 0x02, 0x00, // 0.000244140625000 0.9997
1742 0x01, 0x00, // 0.000122070312500 0.9998
1743 0x01, 0x00 // 0.000061035156250 0.9999
1746 #endif // FLOAT_FIXED4
1750 #endif // defines compatible with printf_fast