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 jnb _field_width_flag, printf_uint_zero
429 jnb _continue_float, 0001$
433 ljmp printf_main_loop
439 lcall printf_int2bcd // bcd number in r3/r2/r7/r6/r5
443 jnb _field_width_flag, printf_uifw_end
447 jnb _long_flag, printf_uifw_16
470 jb _short_flag, printf_uifw_8
489 ;r1 has the number of digits for the number
491 mov c, _negative_flag
496 #ifndef PUTCHAR_CALLEE_SAVES
506 #ifndef PUTCHAR_CALLEE_SAVES
518 #endif // FIELD_WIDTH
522 jnb _negative_flag, printf_uint_pos
523 #ifdef PUTCHAR_CALLEE_SAVES
545 #endif // PUTCHAR_CALLEE_SAVES
548 jb _short_flag, printf_uint8
550 jnb _long_flag, printf_uint16
558 lcall printf_phex_msn
560 lcall printf_phex_lsn
562 lcall printf_phex_msn
564 lcall printf_phex_lsn
567 lcall printf_phex_msn
579 lcall printf_phex_lsn
581 lcall printf_phex_msn
589 lcall printf_phex_lsn
591 lcall printf_phex_msn
593 lcall printf_phex_lsn
598 jnb _continue_float, 0002$
602 ljmp printf_main_loop
607 // Print a float the easy way. First, extract the integer part and
608 // use the integer printing code. Then extract the fractional part,
609 // convert each bit to 4 digit BCD, and print the BCD sum. Absolutely
610 // no field width control, always 4 digits printed past the decimal
611 // point. No round off. 1.9999987 prints as 1.9999, not 2.0000.
614 jnb _field_width_flag, print_float_begin
622 push ar0 // keep r0 safe, will need it again
623 lcall printf_get_float
625 mov a, #158 // check for large float we can't print
627 jnc print_float_size_ok
628 printf_float_too_big:
629 // TODO: should print some sort of overflow error??
631 ljmp printf_format_loop
640 jnz printf_float_too_big
642 lcall printf_uint // print the integer portion
646 // now that the integer part is printed, we need to refetch the
647 // float from the va_args and extract the fractional part
649 lcall printf_get_float
654 cjne a, #126, print_float_frac_lshift
655 sjmp print_float_frac // input between 0.5 to 0.9999
656 print_float_frac_lshift:
657 jc print_float_frac_rshift
658 //Acc (exponent) is greater than 126 (input >= 1.0)
661 print_float_lshift_loop:
672 djnz r5, print_float_lshift_loop
673 sjmp print_float_frac
674 print_float_frac_rshift:
675 //Acc (exponent) is less than 126 (input < 0.5)
680 // now we've got the fractional part, so now is the time to
681 // convert to BCD... just convert each bit to BCD using a
682 // lookup table and BCD sum them together
687 mov dptr, #_frac2bcd // FLOAT_FIXED4 version (14 entries)
688 print_float_frac_loop:
695 jnc print_float_frac_skip
706 print_float_frac_skip:
709 djnz r7, print_float_frac_loop
710 // the BCD sum is in dptr, so all we've got to do is output
711 // all 4 digits. No trailing zero suppression, no nice round
712 // off (impossible to change the integer part since we already
716 setb _print_zero_flag
718 lcall printf_phex_msn
720 lcall printf_phex_lsn
722 lcall printf_phex_msn
724 lcall printf_phex_lsn
728 ljmp printf_main_loop
730 #else // not FLOAT_FIXED4
734 // Print a float the not-as-easy way, with a configurable number of
735 // fractional digits (up to 8) and proper round-off (up to 7 digits).
736 // First, extract the fractional part, convert to BCD, and then add
737 // the scaled round-off. Store the rounded fractional digits and
738 // their carry. Then extract the integer portion, increment it if
739 // the rounding caused a carry. Use the integer printing to output
740 // the integer, and then output the stored fractional digits. This
741 // approach requires 5 bytes of internal RAM to store the 8 fractional
742 // digits and the number of them we'll actually print. This code is
743 // a couple hundred bytes larger and a bit slower than the FIXED4
744 // version, but it gives very nice results.
747 jnb _field_width_flag, print_float_default_width
748 // The caller specified exact field width, so use it. Need to
749 // convert the whole float digits into the integer portion only.
752 subb a, _frac_field_width
754 jnc print_float_begin
756 sjmp print_float_begin
758 print_float_default_width:
759 // The caller didn't specify field width (or FIELD_WIDTH is
760 // not defined so it's ignored). We've still got to know
761 // how many fractional digits are going to print, so we can
762 // round off properly.
763 #ifdef FLOAT_DEFAULT_FRAC_DIGITS
764 mov _frac_field_width, #FLOAT_DEFAULT_FRAC_DIGITS
766 // default fractional field width (between 0 to 7)
767 // attempt to scale the default number of fractional digits
768 // based on the magnitude of the float
769 mov ar1, r0 // r0 points to first byte of float
770 dec r1 // r1 points to second byte of float
773 mov dptr, #_float_range_table
775 print_float_default_loop:
783 jnc print_float_default_done
785 djnz r5, print_float_default_loop
786 print_float_default_done:
787 mov _frac_field_width, r5
790 #endif // not FLOAT_DEFAULT_FRAC_DIGITS
793 push ar0 // keep r0 safe, will need it again
794 lcall printf_get_float
798 cjne a, #126, print_float_frac_lshift
799 sjmp print_float_frac // input between 0.5 to 0.9999
801 print_float_frac_lshift:
802 jc print_float_frac_rshift
803 //Acc (exponent) is greater than 126 (input >= 1.0)
806 print_float_lshift_loop:
817 djnz r5, print_float_lshift_loop
818 sjmp print_float_frac
819 print_float_frac_rshift:
820 //Acc (exponent) is less than 126 (input < 0.5)
825 // Convert the fraction in r4/r3/r2/r1 into 8 BCD digits in r0/r7/r6/r5
832 mov dptr, #_frac2bcd // FLOAT version (27 entries)
833 print_float_frac_loop:
846 jnc print_float_frac_skip
867 print_float_frac_skip:
872 djnz b, print_float_frac_loop
873 print_float_frac_roundoff:
874 // Now it's time to round-off the BCD digits to the desired precision.
876 mov r4, #0x50 // r4/r3/r2/r1 = 0.5 (bcd rounding)
880 mov a, _frac_field_width
884 mov dph, r0 // fs_rshift_a will overwrite r0 & dpl
885 lcall fs_rshift_a // divide r4/r3/r2/r1 by 10^frac_field_width
887 add a, r1 // add rounding to fractional part
889 mov _float_frac_bcd+3, a // and store it for later use
893 mov _float_frac_bcd+2, a
897 mov _float_frac_bcd+1, a
901 mov _float_frac_bcd+0, a
902 mov sign_b, c // keep fractional carry in sign_b
906 // Time to work on the integer portion... fetch the float again, check
907 // size (exponent), scale to integer, add the fraction's carry, and
908 // let the integer printing code do all the work.
910 lcall printf_get_float
913 mov a, #158 // check for large float we can't print
915 jnc print_float_size_ok
916 printf_float_too_big:
917 // TODO: should print some sort of overflow error??
919 ljmp printf_format_loop
924 jnb sign_b, print_float_do_int
925 // if we get here, the fractional round off caused the
926 // integer part to increment. Add 1 for a proper result
941 jc printf_float_too_big
946 jnz printf_float_too_big
949 lcall printf_uint // print the integer portion
952 print_float_frac_width:
953 // Now all we have to do is output the fractional digits that
954 // were previous computed and stored in memory.
956 jb _field_width_flag, print_float_do_frac
958 #ifndef DO_NOT_TRIM_TRAILING_ZEROS
959 // if the user did not explicitly set a
960 // field width, trim off trailing zeros
961 print_float_frac_trim:
962 mov a, _frac_field_width
963 jz print_float_do_frac
964 lcall get_float_frac_digit
965 jnz print_float_do_frac
966 djnz _frac_field_width, print_float_frac_trim
970 mov a, _frac_field_width
976 setb _print_zero_flag
977 print_float_do_frac_loop:
980 lcall get_float_frac_digit
981 lcall printf_phex_lsn
983 cjne a, _frac_field_width, print_float_do_frac_loop
987 ljmp printf_main_loop
990 // acc=1 for tenths, acc=2 for hundredths, etc
991 get_float_frac_digit:
996 add a, #_float_frac_bcd
999 jb psw.5, get_float_frac_digit_done
1001 get_float_frac_digit_done:
1005 #endif // end of normal FLOAT code (not FLOAT_FIXED4)
1008 // These helper functions are used, regardless of which type of
1009 // FLOAT code is used.
1014 lcall pm2_entry_phex
1016 lcall pm2_entry_cout
1019 lcall pm2_entry_cout
1023 // Fetch a float from the va_args and put it into
1024 // r7(exp) r4/r3/r2(mant) and also clear r1 and preset
1036 mov _negative_flag, c
1038 jz printf_get_float_2
1054 /* read an integer into r1/r2/r3/r4, and msb into r5 */
1060 jb _short_flag, printf_get_done
1065 jnb _long_flag, printf_get_done
1080 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1081 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1082 * process, to avoid needing extra memory for the result (and
1083 * r1 gets used for temporary storage). dptr is overwritten,
1084 * but r0 is not changed.
1099 jnb _short_flag, printf_i2bcd_16 // if 8 bit int, we're done
1106 mov dptr, #_int2bcd_2
1122 mov dptr, #_int2bcd_3
1140 jb _long_flag, printf_i2bcd_32 // if 16 bit int, we're done
1149 mov dptr, #_int2bcd_4
1174 mov dptr, #_int2bcd_5
1201 mov dptr, #_int2bcd_6
1203 lcall printf_bcd_add10 // saves 27 bytes, costs 5 cycles
1209 mov dptr, #_int2bcd_7
1243 #else // not FAST_INTEGER
1245 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1246 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1247 * process, to avoid needing extra memory for the result (and
1248 * r1 gets used for temporary storage). dptr is overwritten,
1249 * but r0 is not changed.
1256 jb _short_flag, printf_int2bcd_begin
1258 jnb _long_flag, printf_int2bcd_begin
1260 printf_int2bcd_begin:
1266 mov (_i2bcd_tmp + 0), a
1267 mov (_i2bcd_tmp + 1), a
1282 jnc print_i2bcd_skip
1300 addc a, (_i2bcd_tmp + 0)
1302 mov (_i2bcd_tmp + 0), a
1305 addc a, (_i2bcd_tmp + 1)
1307 mov (_i2bcd_tmp + 1), a
1314 djnz b, printf_i2bcd_loop
1315 mov r2, (_i2bcd_tmp + 0)
1316 mov r3, (_i2bcd_tmp + 1)
1323 jb _short_flag, printf_int2bcd_begin
1325 printf_int2bcd_begin:
1339 jnc printf_i2bcd_add_skip
1355 printf_i2bcd_add_skip:
1359 djnz b, printf_i2bcd_loop
1365 #endif // not FAST_INTEGER
1372 jnb _leading_zero_flag, printf_space_output
1375 printf_space_output:
1376 lcall printf_putchar
1380 jnz printf_space_loop
1384 /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
1391 jnb _print_zero_flag, printf_ret
1393 setb _print_zero_flag
1399 #ifdef PUTCHAR_CALLEE_SAVES
1419 /* print a zero if all the calls to print the digits ended up */
1420 /* being leading zeros */
1423 jb _print_zero_flag, printf_ret
1436 * for ($d=0; $d < 8; $d++) {
1438 * for ($p=0; $p < 5; $p++) {
1439 * last unless (((16 ** $d) * 15) / (10 ** ($p * 2))) % 100;
1440 * printf "code unsigned char int2bcd_%d_%d[15] = {", $d, $p;
1441 * for ($i=0; $i < 16; $i++) {
1443 * (((16 ** $d) * $i) / (10 ** ($p * 2))) % 100;
1444 * print ", " if $i < 15;
1452 static __code unsigned char int2bcd_0[] = {
1453 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1454 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1456 static __code unsigned char int2bcd_1[] = {
1457 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1458 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1459 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1460 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02};
1463 static __code unsigned char int2bcd_2[] = {
1464 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1465 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1466 0x00, 0x02, 0x05, 0x07, 0x10, 0x12, 0x15, 0x17,
1467 0x20, 0x23, 0x25, 0x28, 0x30, 0x33, 0x35, 0x38};
1469 static __code unsigned char int2bcd_3[] = {
1470 0x00, 0x96, 0x92, 0x88, 0x84, 0x80, 0x76, 0x72,
1471 0x68, 0x64, 0x60, 0x56, 0x52, 0x48, 0x44, 0x40,
1472 0x00, 0x40, 0x81, 0x22, 0x63, 0x04, 0x45, 0x86,
1473 0x27, 0x68, 0x09, 0x50, 0x91, 0x32, 0x73, 0x14,
1474 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02,
1475 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06};
1478 static __code unsigned char int2bcd_4[] = {
1479 0x00, 0x36, 0x72, 0x08, 0x44, 0x80, 0x16, 0x52,
1480 0x88, 0x24, 0x60, 0x96, 0x32, 0x68, 0x04, 0x40,
1481 0x00, 0x55, 0x10, 0x66, 0x21, 0x76, 0x32, 0x87,
1482 0x42, 0x98, 0x53, 0x08, 0x64, 0x19, 0x75, 0x30,
1483 0x00, 0x06, 0x13, 0x19, 0x26, 0x32, 0x39, 0x45,
1484 0x52, 0x58, 0x65, 0x72, 0x78, 0x85, 0x91, 0x98};
1486 static __code unsigned char int2bcd_5[] = {
1487 0x00, 0x76, 0x52, 0x28, 0x04, 0x80, 0x56, 0x32,
1488 0x08, 0x84, 0x60, 0x36, 0x12, 0x88, 0x64, 0x40,
1489 0x00, 0x85, 0x71, 0x57, 0x43, 0x28, 0x14, 0x00,
1490 0x86, 0x71, 0x57, 0x43, 0x29, 0x14, 0x00, 0x86,
1491 0x00, 0x04, 0x09, 0x14, 0x19, 0x24, 0x29, 0x34,
1492 0x38, 0x43, 0x48, 0x53, 0x58, 0x63, 0x68, 0x72,
1493 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1494 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1496 static __code unsigned char int2bcd_6[] = {
1497 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1498 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1499 0x00, 0x72, 0x44, 0x16, 0x88, 0x60, 0x32, 0x05,
1500 0x77, 0x49, 0x21, 0x93, 0x65, 0x38, 0x10, 0x82,
1501 0x00, 0x77, 0x55, 0x33, 0x10, 0x88, 0x66, 0x44,
1502 0x21, 0x99, 0x77, 0x54, 0x32, 0x10, 0x88, 0x65,
1503 0x00, 0x16, 0x33, 0x50, 0x67, 0x83, 0x00, 0x17,
1504 0x34, 0x50, 0x67, 0x84, 0x01, 0x18, 0x34, 0x51,
1505 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
1506 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02};
1508 static __code unsigned char int2bcd_7[] = {
1509 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1510 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1511 0x00, 0x54, 0x09, 0x63, 0x18, 0x72, 0x27, 0x81,
1512 0x36, 0x91, 0x45, 0x00, 0x54, 0x09, 0x63, 0x18,
1513 0x00, 0x43, 0x87, 0x30, 0x74, 0x17, 0x61, 0x04,
1514 0x48, 0x91, 0x35, 0x79, 0x22, 0x66, 0x09, 0x53,
1515 0x00, 0x68, 0x36, 0x05, 0x73, 0x42, 0x10, 0x79,
1516 0x47, 0x15, 0x84, 0x52, 0x21, 0x89, 0x58, 0x26,
1517 0x00, 0x02, 0x05, 0x08, 0x10, 0x13, 0x16, 0x18,
1518 0x21, 0x24, 0x26, 0x29, 0x32, 0x34, 0x37, 0x40};
1521 #else // not FAST_INTEGER
1525 * print "__code unsigned char int2bcd[] = {\n";
1526 * for ($i=0, $n=1; $i<32; $i++, $n*=2) {
1527 * $r = sprintf "%010u", $n;
1528 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1529 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d, 0x%02d", $5, $4, $3, $2, $1;
1530 * print ',' if $i < 31;
1531 * printf "\t\t// %10u\n", $n;
1533 * print "}\n__code unsigned char int2bcd[] = {\n";
1534 * for ($i=0, $n=1; $i<16; $i++, $n*=2) {
1535 * $r = sprintf "%06u", $n;
1536 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1537 * printf "0x%02d, 0x%02d, 0x%02d", $3, $2, $1;
1538 * print ',' if $i < 15;
1539 * printf "\t\t// %10u\n", $n;
1545 static __code unsigned char int2bcd[] = {
1546 0x01, 0x00, 0x00, 0x00, 0x00, // 1
1547 0x02, 0x00, 0x00, 0x00, 0x00, // 2
1548 0x04, 0x00, 0x00, 0x00, 0x00, // 4
1549 0x08, 0x00, 0x00, 0x00, 0x00, // 8
1550 0x16, 0x00, 0x00, 0x00, 0x00, // 16
1551 0x32, 0x00, 0x00, 0x00, 0x00, // 32
1552 0x64, 0x00, 0x00, 0x00, 0x00, // 64
1553 0x28, 0x01, 0x00, 0x00, 0x00, // 128
1554 0x56, 0x02, 0x00, 0x00, 0x00, // 256
1555 0x12, 0x05, 0x00, 0x00, 0x00, // 512
1556 0x24, 0x10, 0x00, 0x00, 0x00, // 1024
1557 0x48, 0x20, 0x00, 0x00, 0x00, // 2048
1558 0x96, 0x40, 0x00, 0x00, 0x00, // 4096
1559 0x92, 0x81, 0x00, 0x00, 0x00, // 8192
1560 0x84, 0x63, 0x01, 0x00, 0x00, // 16384
1561 0x68, 0x27, 0x03, 0x00, 0x00, // 32768
1562 0x36, 0x55, 0x06, 0x00, 0x00, // 65536
1563 0x72, 0x10, 0x13, 0x00, 0x00, // 131072
1564 0x44, 0x21, 0x26, 0x00, 0x00, // 262144
1565 0x88, 0x42, 0x52, 0x00, 0x00, // 524288
1566 0x76, 0x85, 0x04, 0x01, 0x00, // 1048576
1567 0x52, 0x71, 0x09, 0x02, 0x00, // 2097152
1568 0x04, 0x43, 0x19, 0x04, 0x00, // 4194304
1569 0x08, 0x86, 0x38, 0x08, 0x00, // 8388608
1570 0x16, 0x72, 0x77, 0x16, 0x00, // 16777216
1571 0x32, 0x44, 0x55, 0x33, 0x00, // 33554432
1572 0x64, 0x88, 0x10, 0x67, 0x00, // 67108864
1573 0x28, 0x77, 0x21, 0x34, 0x01, // 134217728
1574 0x56, 0x54, 0x43, 0x68, 0x02, // 268435456
1575 0x12, 0x09, 0x87, 0x36, 0x05, // 536870912
1576 0x24, 0x18, 0x74, 0x73, 0x10, // 1073741824
1577 0x48, 0x36, 0x48, 0x47, 0x21 // 2147483648
1580 static __code unsigned char int2bcd[] = {
1581 0x01, 0x00, 0x00, // 1
1582 0x02, 0x00, 0x00, // 2
1583 0x04, 0x00, 0x00, // 4
1584 0x08, 0x00, 0x00, // 8
1585 0x16, 0x00, 0x00, // 16
1586 0x32, 0x00, 0x00, // 32
1587 0x64, 0x00, 0x00, // 64
1588 0x28, 0x01, 0x00, // 128
1589 0x56, 0x02, 0x00, // 256
1590 0x12, 0x05, 0x00, // 512
1591 0x24, 0x10, 0x00, // 1024
1592 0x48, 0x20, 0x00, // 2048
1593 0x96, 0x40, 0x00, // 4096
1594 0x92, 0x81, 0x00, // 8192
1595 0x84, 0x63, 0x01, // 16384
1596 0x68, 0x27, 0x03 // 32768
1600 #endif // not FAST_INTEGER
1604 #ifndef FLOAT_FIXED4
1608 * for ($i=0, $f=0.5; $i<24; $i++) {
1609 * $r = sprintf "%.8f", $f;
1610 * $r =~ /0\.([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1611 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d", $4, $3, $2, $1;
1612 * print ',' if $i < 23;
1614 * printf "\t\t// %.15f %.8f\n", $f, $sum;
1619 static __code unsigned char frac2bcd[] = {
1620 0x00, 0x00, 0x00, 0x50, // 0.500000000000000 0.50000000
1621 0x00, 0x00, 0x00, 0x25, // 0.250000000000000 0.75000000
1622 0x00, 0x00, 0x50, 0x12, // 0.125000000000000 0.87500000
1623 0x00, 0x00, 0x25, 0x06, // 0.062500000000000 0.93750000
1624 0x00, 0x50, 0x12, 0x03, // 0.031250000000000 0.96875000
1625 0x00, 0x25, 0x56, 0x01, // 0.015625000000000 0.98437500
1626 0x50, 0x12, 0x78, 0x00, // 0.007812500000000 0.99218750
1627 0x25, 0x06, 0x39, 0x00, // 0.003906250000000 0.99609375
1628 0x12, 0x53, 0x19, 0x00, // 0.001953125000000 0.99804687
1629 0x56, 0x76, 0x09, 0x00, // 0.000976562500000 0.99902343
1630 0x28, 0x88, 0x04, 0x00, // 0.000488281250000 0.99951171
1631 0x14, 0x44, 0x02, 0x00, // 0.000244140625000 0.99975585
1632 0x07, 0x22, 0x01, 0x00, // 0.000122070312500 0.99987792
1633 0x04, 0x61, 0x00, 0x00, // 0.000061035156250 0.99993896
1634 0x52, 0x30, 0x00, 0x00, // 0.000030517578125 0.99996948
1635 0x26, 0x15, 0x00, 0x00, // 0.000015258789062 0.99998474
1636 0x63, 0x07, 0x00, 0x00, // 0.000007629394531 0.99999237
1637 0x81, 0x03, 0x00, 0x00, // 0.000003814697266 0.99999618
1638 0x91, 0x01, 0x00, 0x00, // 0.000001907348633 0.99999809
1639 0x95, 0x00, 0x00, 0x00, // 0.000000953674316 0.99999904
1640 0x48, 0x00, 0x00, 0x00, // 0.000000476837158 0.99999952
1641 0x24, 0x00, 0x00, 0x00, // 0.000000238418579 0.99999976
1642 0x12, 0x00, 0x00, 0x00, // 0.000000119209290 0.99999988
1643 0x06, 0x00, 0x00, 0x00, // 0.000000059604645 0.99999994
1644 0x03, 0x00, 0x00, 0x00, // 0.000000029802322 0.99999997
1645 0x01, 0x00, 0x00, 0x00, // 0.000000014901161 0.99999998
1646 0x01, 0x00, 0x00, 0x00 // 0.000000007450581 0.99999999
1649 #ifndef FLOAT_DEFAULT_FRAC_DIGITS
1650 // TODO: Perhaps these should be tweaked a bit to take round up
1651 // effects into account... or maybe give more default digits??
1653 // 0.0001 - 0.0009999 7
1654 // 0.001 - 0.009999 6 0.001 = 0x3A83126F 3A83
1655 // 0.01 - 0.09999 5 0.01 = 0x3C23D70A 3C23
1656 // 0.1 - 9.9999 4 0.1 = 0x3DCCCCCD, 3DCC
1657 // 10.0 - 99.99 3 10.0 = 0x41200000 4120
1658 // 100.0 - 999.99 2 100.0 = 0x42C80000 42C8
1659 // 1000 - 9999.9 1 1000 = 0x447A0000 447A
1660 // 10000+ 0 10000 = 0x461C4000 461C
1661 static __code unsigned int float_range_table[] = {
1672 #else // using FLOAT_FIXED4
1676 * for ($i=0, $f=0.5; $i<14; $i++) {
1677 * $r = sprintf "%.4f", $f;
1678 * $r =~ /0\.([0-9][0-9])([0-9][0-9])/;
1679 * printf "0x%02d, 0x%02d", $2, $1;
1680 * print ',' if $i < 13;
1682 * printf "\t\t// %.15f %.4f\n", $f, $sum;
1687 static __code unsigned char frac2bcd[] = {
1688 0x00, 0x50, // 0.500000000000000 0.5000
1689 0x00, 0x25, // 0.250000000000000 0.7500
1690 0x50, 0x12, // 0.125000000000000 0.8750
1691 0x25, 0x06, // 0.062500000000000 0.9375
1692 0x12, 0x03, // 0.031250000000000 0.9687
1693 0x56, 0x01, // 0.015625000000000 0.9843
1694 0x78, 0x00, // 0.007812500000000 0.9921
1695 0x39, 0x00, // 0.003906250000000 0.9960
1696 0x20, 0x00, // 0.001953125000000 0.9980
1697 0x10, 0x00, // 0.000976562500000 0.9990
1698 0x05, 0x00, // 0.000488281250000 0.9995
1699 0x02, 0x00, // 0.000244140625000 0.9997
1700 0x01, 0x00, // 0.000122070312500 0.9998
1701 0x01, 0x00 // 0.000061035156250 0.9999
1704 #endif // FLOAT_FIXED4
1708 #endif // defines compatible with printf_fast