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 bit leading_zero_flag;
97 static data unsigned char field_width;
101 #define SDCC_FLOAT_LIB
103 static bit continue_float;
105 static data unsigned char frac_field_width;
106 static data unsigned char float_frac_bcd[4];
107 // TODO: can float_frac_bcd be overlaid with temps used by trig functions
113 static data unsigned int i2bcd_tmp; // slow 32 int conversion needs temp space
120 #define PRINTF_FAST printf_fast
124 #if !defined(SDCC_mcs51) || defined(SDCC_USE_XSTACK) || defined(_SDCC_NO_ASM_LIB_FUNCS)
125 // Does printf_fast really work on ds390 and ds400?
126 // If it does, enable them in the line above
127 #if defined(SDCC_USE_XSTACK)
128 #warning "printf_fast not built, does not support --xstack"
129 #elif defined(_SDCC_NO_ASM_LIB_FUNCS)
130 #warning "printf_fast not built, _SDCC_NO_ASM_LIB_FUNCS defined"
132 #else // defines are compatible with printf_fast
135 void PRINTF_FAST(code char *fmt, ...) reentrant
137 fmt; /* supress unreferenced variable warning */
142 mov a, _bp // r0 will point to va_args (stack)
144 mov r0, a // r0 points to MSB of fmt
147 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
206 //cjne a, #'l', printf_format_h
207 cjne a, #108, printf_format_h
209 sjmp printf_format_loop
212 //cjne a, #'h', printf_format_s
213 cjne a, #104, printf_format_s
215 sjmp printf_format_loop
218 //cjne a, #'s', printf_format_d
219 cjne a, #115, printf_format_d
223 //cjne a, #'d', printf_format_u
224 cjne a, #100, printf_format_u
229 //cjne a, #'u', printf_format_c
230 cjne a, #117, printf_format_c
235 //cjne a, #'c', printf_format_x
236 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
280 /* print a string... just grab each byte with __gptrget */
281 /* the user much pass a 24 bit generic pointer */
284 push dph // save addr in fmt onto stack
286 mov b, @r0 // b has type of address (generic *)
290 mov dpl, @r0 // dptr has address of user's string
294 jnb _field_width_flag, printf_str_loop
295 clr _leading_zero_flag // never leading zeros for strings
304 jnz printf_str_fw_loop
309 #endif // FIELD_WIDTH
318 pop dpl // restore addr withing fmt
320 ljmp printf_main_loop
329 /* printing in hex is easy because sdcc pushes the LSB first */
333 jb _short_flag, printf_hex_end
335 jnb _long_flag, printf_hex_end
340 ljmp printf_main_loop
343 lcall printf_phex_msn
364 /* printing an integer is not so easy. For a signed int */
365 /* check if it is negative and print the minus sign and */
366 /* invert it to a positive integer */
370 jnb acc.7, printf_uint /* check if negative */
372 mov a, r1 /* invert integer */
376 jb _short_flag, printf_uint
381 jnb _long_flag, printf_uint
392 /* printing integers is a lot of work... because it takes so */
393 /* long, the first thing to do is make sure we're doing as */
394 /* little work as possible, then convert the binary int to */
395 /* packed BCD, and finally print each digit of the BCD number */
399 jb _short_flag, printf_uint_ck8
400 jnb _long_flag, printf_uint_ck16
402 /* it's a 32 bit int... but if the upper 16 bits are zero */
403 /* we can treat it like a 16 bit integer and convert much faster */
406 jnz printf_uint_begin
408 jnz printf_uint_begin
411 jnz printf_ld_in_hex // print long integer as hex
412 mov a, r4 // rather than just the low 16 bits
417 /* it's a 16 bit int... but if the upper 8 bits are zero */
418 /* we can treat it like a 8 bit integer and convert much faster */
420 jnz printf_uint_begin
423 /* it's an 8 bit int... if it's zero, it's a lot faster to just */
424 /* print the digit zero and skip all the hard work! */
426 jnz printf_uint_begin
428 jnb _field_width_flag, printf_uint_zero
439 jnb _continue_float, 0001$
443 ljmp printf_main_loop
450 lcall printf_int2bcd // bcd number in r3/r2/r7/r6/r5
454 jnb _field_width_flag, printf_uifw_end
458 jnb _long_flag, printf_uifw_16
481 jb _short_flag, printf_uifw_8
500 ;r1 has the number of digits for the number
502 mov c, _negative_flag
507 #ifndef PUTCHAR_CALLEE_SAVES
517 #ifndef PUTCHAR_CALLEE_SAVES
529 #endif // FIELD_WIDTH
533 jnb _negative_flag, printf_uint_pos
534 #ifdef PUTCHAR_CALLEE_SAVES
556 #endif // PUTCHAR_CALLEE_SAVES
559 jb _short_flag, printf_uint8
561 jnb _long_flag, printf_uint16
569 lcall printf_phex_msn
571 lcall printf_phex_lsn
573 lcall printf_phex_msn
575 lcall printf_phex_lsn
578 lcall printf_phex_msn
590 lcall printf_phex_lsn
592 lcall printf_phex_msn
600 lcall printf_phex_lsn
602 lcall printf_phex_msn
604 lcall printf_phex_lsn
609 jnb _continue_float, 0002$
613 ljmp printf_main_loop
624 // Print a float the easy way. First, extract the integer part and
625 // use the integer printing code. Then extract the fractional part,
626 // convert each bit to 4 digit BCD, and print the BCD sum. Absolutely
627 // no field width control, always 4 digits printed past the decimal
628 // point. No round off. 1.9999987 prints as 1.9999, not 2.0000.
631 jnb _field_width_flag, print_float_begin
639 push ar0 // keep r0 safe, will need it again
640 lcall printf_get_float
642 mov a, #158 // check for large float we can't print
644 jnc print_float_size_ok
645 printf_float_too_big:
646 // TODO: should print some sort of overflow error??
648 ljmp printf_format_loop
657 jnz printf_float_too_big
659 lcall printf_uint // print the integer portion
663 // now that the integer part is printed, we need to refetch the
664 // float from the va_args and extract the fractional part
666 lcall printf_get_float
671 cjne a, #126, print_float_frac_lshift
672 sjmp print_float_frac // input between 0.5 to 0.9999
673 print_float_frac_lshift:
674 jc print_float_frac_rshift
675 //Acc (exponent) is greater than 126 (input >= 1.0)
678 print_float_lshift_loop:
689 djnz r5, print_float_lshift_loop
690 sjmp print_float_frac
691 print_float_frac_rshift:
692 //Acc (exponent) is less than 126 (input < 0.5)
697 // now we've got the fractional part, so now is the time to
698 // convert to BCD... just convert each bit to BCD using a
699 // lookup table and BCD sum them together
704 mov dptr, #_frac2bcd // FLOAT_FIXED4 version (14 entries)
705 print_float_frac_loop:
712 jnc print_float_frac_skip
723 print_float_frac_skip:
726 djnz r7, print_float_frac_loop
727 // the BCD sum is in dptr, so all we've got to do is output
728 // all 4 digits. No trailing zero suppression, no nice round
729 // off (impossible to change the integer part since we already
733 setb _print_zero_flag
735 lcall printf_phex_msn
737 lcall printf_phex_lsn
739 lcall printf_phex_msn
741 lcall printf_phex_lsn
745 ljmp printf_main_loop
747 #else // not FLOAT_FIXED4
753 // Print a float the not-as-easy way, with a configurable number of
754 // fractional digits (up to 8) and proper round-off (up to 7 digits).
755 // First, extract the fractional part, convert to BCD, and then add
756 // the scaled round-off. Store the rounded fractional digits and
757 // their carry. Then extract the integer portion, increment it if
758 // the rounding caused a carry. Use the integer printing to output
759 // the integer, and then output the stored fractional digits. This
760 // approach requires 5 bytes of internal RAM to store the 8 fractional
761 // digits and the number of them we'll actually print. This code is
762 // a couple hundred bytes larger and a bit slower than the FIXED4
763 // version, but it gives very nice results.
766 jnb _field_width_flag, print_float_default_width
767 // The caller specified exact field width, so use it. Need to
768 // convert the whole float digits into the integer portion only.
771 subb a, _frac_field_width
773 jnc print_float_begin
775 sjmp print_float_begin
777 print_float_default_width:
778 // The caller didn't specify field width (or FIELD_WIDTH is
779 // not defined so it's ignored). We've still got to know
780 // how many fractional digits are going to print, so we can
781 // round off properly.
782 #ifdef FLOAT_DEFAULT_FRAC_DIGITS
783 mov _frac_field_width, #FLOAT_DEFAULT_FRAC_DIGITS
785 // default fractional field width (between 0 to 7)
786 // attempt to scale the default number of fractional digits
787 // based on the magnitude of the float
788 mov ar1, r0 // r0 points to first byte of float
789 dec r1 // r1 points to second byte of float
792 mov dptr, #_float_range_table
794 print_float_default_loop:
802 jnc print_float_default_done
804 djnz r5, print_float_default_loop
805 print_float_default_done:
806 mov _frac_field_width, r5
809 #endif // not FLOAT_DEFAULT_FRAC_DIGITS
812 push ar0 // keep r0 safe, will need it again
813 lcall printf_get_float
817 cjne a, #126, print_float_frac_lshift
818 sjmp print_float_frac // input between 0.5 to 0.9999
820 print_float_frac_lshift:
821 jc print_float_frac_rshift
822 //Acc (exponent) is greater than 126 (input >= 1.0)
825 print_float_lshift_loop:
836 djnz r5, print_float_lshift_loop
837 sjmp print_float_frac
838 print_float_frac_rshift:
839 //Acc (exponent) is less than 126 (input < 0.5)
844 // Convert the fraction in r4/r3/r2/r1 into 8 BCD digits in r0/r7/r6/r5
851 mov dptr, #_frac2bcd // FLOAT version (27 entries)
852 print_float_frac_loop:
865 jnc print_float_frac_skip
886 print_float_frac_skip:
891 djnz b, print_float_frac_loop
892 print_float_frac_roundoff:
893 // Now it's time to round-off the BCD digits to the desired precision.
895 mov r4, #0x50 // r4/r3/r2/r1 = 0.5 (bcd rounding)
899 mov a, _frac_field_width
903 mov dph, r0 // fs_rshift_a will overwrite r0 & dpl
904 lcall fs_rshift_a // divide r4/r3/r2/r1 by 10^frac_field_width
906 add a, r1 // add rounding to fractional part
908 mov _float_frac_bcd+3, a // and store it for later use
912 mov _float_frac_bcd+2, a
916 mov _float_frac_bcd+1, a
920 mov _float_frac_bcd+0, a
921 mov sign_b, c // keep fractional carry in sign_b
925 // Time to work on the integer portion... fetch the float again, check
926 // size (exponent), scale to integer, add the fraction's carry, and
927 // let the integer printing code do all the work.
929 lcall printf_get_float
932 mov a, #158 // check for large float we can't print
934 jnc print_float_size_ok
935 printf_float_too_big:
936 // TODO: should print some sort of overflow error??
937 ljmp printf_format_loop
942 jnb sign_b, print_float_do_int
943 // if we get here, the fractional round off caused the
944 // integer part to increment. Add 1 for a proper result
959 jc printf_float_too_big
964 jnz printf_float_too_big
967 lcall printf_uint // print the integer portion
970 print_float_frac_width:
971 // Now all we have to do is output the fractional digits that
972 // were previous computed and stored in memory.
974 jb _field_width_flag, print_float_do_frac
976 #ifndef DO_NOT_TRIM_TRAILING_ZEROS
977 // if the user did not explicitly set a
978 // field width, trim off trailing zeros
979 print_float_frac_trim:
980 mov a, _frac_field_width
981 jz print_float_do_frac
982 lcall get_float_frac_digit
983 jnz print_float_do_frac
984 djnz _frac_field_width, print_float_frac_trim
988 mov a, _frac_field_width
994 setb _print_zero_flag
995 print_float_do_frac_loop:
998 lcall get_float_frac_digit
999 lcall printf_phex_lsn
1001 cjne a, _frac_field_width, print_float_do_frac_loop
1005 ljmp printf_main_loop
1009 // acc=1 for tenths, acc=2 for hundredths, etc
1010 get_float_frac_digit:
1015 add a, #_float_frac_bcd
1018 jb psw.5, get_float_frac_digit_done
1020 get_float_frac_digit_done:
1027 #endif // end of normal FLOAT code (not FLOAT_FIXED4)
1030 // These helper functions are used, regardless of which type of
1031 // FLOAT code is used.
1036 lcall pm2_entry_phex
1038 lcall pm2_entry_cout
1041 lcall pm2_entry_cout
1045 // Fetch a float from the va_args and put it into
1046 // r7(exp) r4/r3/r2(mant) and also clear r1 and preset
1058 mov _negative_flag, c
1060 jz printf_get_float_2
1087 /* read an integer into r1/r2/r3/r4, and msb into r5 */
1093 jb _short_flag, printf_get_done
1098 jnb _long_flag, printf_get_done
1116 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1117 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1118 * process, to avoid needing extra memory for the result (and
1119 * r1 gets used for temporary storage). dptr is overwritten,
1120 * but r0 is not changed.
1135 jnb _short_flag, printf_i2bcd_16 // if 8 bit int, we're done
1142 mov dptr, #_int2bcd_2
1158 mov dptr, #_int2bcd_3
1176 jb _long_flag, printf_i2bcd_32 // if 16 bit int, we're done
1185 mov dptr, #_int2bcd_4
1210 mov dptr, #_int2bcd_5
1237 mov dptr, #_int2bcd_6
1239 lcall printf_bcd_add10 // saves 27 bytes, costs 5 cycles
1245 mov dptr, #_int2bcd_7
1279 #else // not FAST_INTEGER
1281 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1282 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1283 * process, to avoid needing extra memory for the result (and
1284 * r1 gets used for temporary storage). dptr is overwritten,
1285 * but r0 is not changed.
1292 jb _short_flag, printf_int2bcd_begin
1294 jnb _long_flag, printf_int2bcd_begin
1296 printf_int2bcd_begin:
1302 mov (_i2bcd_tmp + 0), a
1303 mov (_i2bcd_tmp + 1), a
1318 jnc print_i2bcd_skip
1336 addc a, (_i2bcd_tmp + 0)
1338 mov (_i2bcd_tmp + 0), a
1341 addc a, (_i2bcd_tmp + 1)
1343 mov (_i2bcd_tmp + 1), a
1350 djnz b, printf_i2bcd_loop
1351 mov r2, (_i2bcd_tmp + 0)
1352 mov r3, (_i2bcd_tmp + 1)
1359 jb _short_flag, printf_int2bcd_begin
1361 printf_int2bcd_begin:
1375 jnc printf_i2bcd_add_skip
1391 printf_i2bcd_add_skip:
1395 djnz b, printf_i2bcd_loop
1401 #endif // not FAST_INTEGER
1419 jnb _leading_zero_flag, printf_space_output
1422 printf_space_output:
1423 lcall printf_putchar
1427 jnz printf_space_loop
1435 /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
1442 jnb _print_zero_flag, printf_ret
1444 setb _print_zero_flag
1450 #ifdef PUTCHAR_CALLEE_SAVES
1470 /* print a zero if all the calls to print the digits ended up */
1471 /* being leading zeros */
1474 jb _print_zero_flag, printf_ret
1487 * for ($d=0; $d < 8; $d++) {
1489 * for ($p=0; $p < 5; $p++) {
1490 * last unless (((16 ** $d) * 15) / (10 ** ($p * 2))) % 100;
1491 * printf "code unsigned char int2bcd_%d_%d[15] = {", $d, $p;
1492 * for ($i=0; $i < 16; $i++) {
1494 * (((16 ** $d) * $i) / (10 ** ($p * 2))) % 100;
1495 * print ", " if $i < 15;
1503 static code unsigned char int2bcd_0[] = {
1504 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1505 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1507 static code unsigned char int2bcd_1[] = {
1508 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1509 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1510 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1511 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02};
1514 static code unsigned char int2bcd_2[] = {
1515 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1516 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1517 0x00, 0x02, 0x05, 0x07, 0x10, 0x12, 0x15, 0x17,
1518 0x20, 0x23, 0x25, 0x28, 0x30, 0x33, 0x35, 0x38};
1520 static code unsigned char int2bcd_3[] = {
1521 0x00, 0x96, 0x92, 0x88, 0x84, 0x80, 0x76, 0x72,
1522 0x68, 0x64, 0x60, 0x56, 0x52, 0x48, 0x44, 0x40,
1523 0x00, 0x40, 0x81, 0x22, 0x63, 0x04, 0x45, 0x86,
1524 0x27, 0x68, 0x09, 0x50, 0x91, 0x32, 0x73, 0x14,
1525 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02,
1526 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06};
1529 static code unsigned char int2bcd_4[] = {
1530 0x00, 0x36, 0x72, 0x08, 0x44, 0x80, 0x16, 0x52,
1531 0x88, 0x24, 0x60, 0x96, 0x32, 0x68, 0x04, 0x40,
1532 0x00, 0x55, 0x10, 0x66, 0x21, 0x76, 0x32, 0x87,
1533 0x42, 0x98, 0x53, 0x08, 0x64, 0x19, 0x75, 0x30,
1534 0x00, 0x06, 0x13, 0x19, 0x26, 0x32, 0x39, 0x45,
1535 0x52, 0x58, 0x65, 0x72, 0x78, 0x85, 0x91, 0x98};
1537 static code unsigned char int2bcd_5[] = {
1538 0x00, 0x76, 0x52, 0x28, 0x04, 0x80, 0x56, 0x32,
1539 0x08, 0x84, 0x60, 0x36, 0x12, 0x88, 0x64, 0x40,
1540 0x00, 0x85, 0x71, 0x57, 0x43, 0x28, 0x14, 0x00,
1541 0x86, 0x71, 0x57, 0x43, 0x29, 0x14, 0x00, 0x86,
1542 0x00, 0x04, 0x09, 0x14, 0x19, 0x24, 0x29, 0x34,
1543 0x38, 0x43, 0x48, 0x53, 0x58, 0x63, 0x68, 0x72,
1544 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1545 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1547 static code unsigned char int2bcd_6[] = {
1548 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1549 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1550 0x00, 0x72, 0x44, 0x16, 0x88, 0x60, 0x32, 0x05,
1551 0x77, 0x49, 0x21, 0x93, 0x65, 0x38, 0x10, 0x82,
1552 0x00, 0x77, 0x55, 0x33, 0x10, 0x88, 0x66, 0x44,
1553 0x21, 0x99, 0x77, 0x54, 0x32, 0x10, 0x88, 0x65,
1554 0x00, 0x16, 0x33, 0x50, 0x67, 0x83, 0x00, 0x17,
1555 0x34, 0x50, 0x67, 0x84, 0x01, 0x18, 0x34, 0x51,
1556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
1557 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02};
1559 static code unsigned char int2bcd_7[] = {
1560 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1561 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1562 0x00, 0x54, 0x09, 0x63, 0x18, 0x72, 0x27, 0x81,
1563 0x36, 0x91, 0x45, 0x00, 0x54, 0x09, 0x63, 0x18,
1564 0x00, 0x43, 0x87, 0x30, 0x74, 0x17, 0x61, 0x04,
1565 0x48, 0x91, 0x35, 0x79, 0x22, 0x66, 0x09, 0x53,
1566 0x00, 0x68, 0x36, 0x05, 0x73, 0x42, 0x10, 0x79,
1567 0x47, 0x15, 0x84, 0x52, 0x21, 0x89, 0x58, 0x26,
1568 0x00, 0x02, 0x05, 0x08, 0x10, 0x13, 0x16, 0x18,
1569 0x21, 0x24, 0x26, 0x29, 0x32, 0x34, 0x37, 0x40};
1572 #else // not FAST_INTEGER
1576 * print "code unsigned char int2bcd[] = {\n";
1577 * for ($i=0, $n=1; $i<32; $i++, $n*=2) {
1578 * $r = sprintf "%010u", $n;
1579 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1580 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d, 0x%02d", $5, $4, $3, $2, $1;
1581 * print ',' if $i < 31;
1582 * printf "\t\t// %10u\n", $n;
1584 * print "}\ncode unsigned char int2bcd[] = {\n";
1585 * for ($i=0, $n=1; $i<16; $i++, $n*=2) {
1586 * $r = sprintf "%06u", $n;
1587 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1588 * printf "0x%02d, 0x%02d, 0x%02d", $3, $2, $1;
1589 * print ',' if $i < 15;
1590 * printf "\t\t// %10u\n", $n;
1596 static code unsigned char int2bcd[] = {
1597 0x01, 0x00, 0x00, 0x00, 0x00, // 1
1598 0x02, 0x00, 0x00, 0x00, 0x00, // 2
1599 0x04, 0x00, 0x00, 0x00, 0x00, // 4
1600 0x08, 0x00, 0x00, 0x00, 0x00, // 8
1601 0x16, 0x00, 0x00, 0x00, 0x00, // 16
1602 0x32, 0x00, 0x00, 0x00, 0x00, // 32
1603 0x64, 0x00, 0x00, 0x00, 0x00, // 64
1604 0x28, 0x01, 0x00, 0x00, 0x00, // 128
1605 0x56, 0x02, 0x00, 0x00, 0x00, // 256
1606 0x12, 0x05, 0x00, 0x00, 0x00, // 512
1607 0x24, 0x10, 0x00, 0x00, 0x00, // 1024
1608 0x48, 0x20, 0x00, 0x00, 0x00, // 2048
1609 0x96, 0x40, 0x00, 0x00, 0x00, // 4096
1610 0x92, 0x81, 0x00, 0x00, 0x00, // 8192
1611 0x84, 0x63, 0x01, 0x00, 0x00, // 16384
1612 0x68, 0x27, 0x03, 0x00, 0x00, // 32768
1613 0x36, 0x55, 0x06, 0x00, 0x00, // 65536
1614 0x72, 0x10, 0x13, 0x00, 0x00, // 131072
1615 0x44, 0x21, 0x26, 0x00, 0x00, // 262144
1616 0x88, 0x42, 0x52, 0x00, 0x00, // 524288
1617 0x76, 0x85, 0x04, 0x01, 0x00, // 1048576
1618 0x52, 0x71, 0x09, 0x02, 0x00, // 2097152
1619 0x04, 0x43, 0x19, 0x04, 0x00, // 4194304
1620 0x08, 0x86, 0x38, 0x08, 0x00, // 8388608
1621 0x16, 0x72, 0x77, 0x16, 0x00, // 16777216
1622 0x32, 0x44, 0x55, 0x33, 0x00, // 33554432
1623 0x64, 0x88, 0x10, 0x67, 0x00, // 67108864
1624 0x28, 0x77, 0x21, 0x34, 0x01, // 134217728
1625 0x56, 0x54, 0x43, 0x68, 0x02, // 268435456
1626 0x12, 0x09, 0x87, 0x36, 0x05, // 536870912
1627 0x24, 0x18, 0x74, 0x73, 0x10, // 1073741824
1628 0x48, 0x36, 0x48, 0x47, 0x21 // 2147483648
1631 static code unsigned char int2bcd[] = {
1632 0x01, 0x00, 0x00, // 1
1633 0x02, 0x00, 0x00, // 2
1634 0x04, 0x00, 0x00, // 4
1635 0x08, 0x00, 0x00, // 8
1636 0x16, 0x00, 0x00, // 16
1637 0x32, 0x00, 0x00, // 32
1638 0x64, 0x00, 0x00, // 64
1639 0x28, 0x01, 0x00, // 128
1640 0x56, 0x02, 0x00, // 256
1641 0x12, 0x05, 0x00, // 512
1642 0x24, 0x10, 0x00, // 1024
1643 0x48, 0x20, 0x00, // 2048
1644 0x96, 0x40, 0x00, // 4096
1645 0x92, 0x81, 0x00, // 8192
1646 0x84, 0x63, 0x01, // 16384
1647 0x68, 0x27, 0x03 // 32768
1651 #endif // not FAST_INTEGER
1657 #ifndef FLOAT_FIXED4
1661 * for ($i=0, $f=0.5; $i<24; $i++) {
1662 * $r = sprintf "%.8f", $f;
1663 * $r =~ /0\.([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1664 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d", $4, $3, $2, $1;
1665 * print ',' if $i < 23;
1667 * printf "\t\t// %.15f %.8f\n", $f, $sum;
1672 static code unsigned char frac2bcd[] = {
1673 0x00, 0x00, 0x00, 0x50, // 0.500000000000000 0.50000000
1674 0x00, 0x00, 0x00, 0x25, // 0.250000000000000 0.75000000
1675 0x00, 0x00, 0x50, 0x12, // 0.125000000000000 0.87500000
1676 0x00, 0x00, 0x25, 0x06, // 0.062500000000000 0.93750000
1677 0x00, 0x50, 0x12, 0x03, // 0.031250000000000 0.96875000
1678 0x00, 0x25, 0x56, 0x01, // 0.015625000000000 0.98437500
1679 0x50, 0x12, 0x78, 0x00, // 0.007812500000000 0.99218750
1680 0x25, 0x06, 0x39, 0x00, // 0.003906250000000 0.99609375
1681 0x12, 0x53, 0x19, 0x00, // 0.001953125000000 0.99804687
1682 0x56, 0x76, 0x09, 0x00, // 0.000976562500000 0.99902343
1683 0x28, 0x88, 0x04, 0x00, // 0.000488281250000 0.99951171
1684 0x14, 0x44, 0x02, 0x00, // 0.000244140625000 0.99975585
1685 0x07, 0x22, 0x01, 0x00, // 0.000122070312500 0.99987792
1686 0x04, 0x61, 0x00, 0x00, // 0.000061035156250 0.99993896
1687 0x52, 0x30, 0x00, 0x00, // 0.000030517578125 0.99996948
1688 0x26, 0x15, 0x00, 0x00, // 0.000015258789062 0.99998474
1689 0x63, 0x07, 0x00, 0x00, // 0.000007629394531 0.99999237
1690 0x81, 0x03, 0x00, 0x00, // 0.000003814697266 0.99999618
1691 0x91, 0x01, 0x00, 0x00, // 0.000001907348633 0.99999809
1692 0x95, 0x00, 0x00, 0x00, // 0.000000953674316 0.99999904
1693 0x48, 0x00, 0x00, 0x00, // 0.000000476837158 0.99999952
1694 0x24, 0x00, 0x00, 0x00, // 0.000000238418579 0.99999976
1695 0x12, 0x00, 0x00, 0x00, // 0.000000119209290 0.99999988
1696 0x06, 0x00, 0x00, 0x00, // 0.000000059604645 0.99999994
1697 0x03, 0x00, 0x00, 0x00, // 0.000000029802322 0.99999997
1698 0x01, 0x00, 0x00, 0x00, // 0.000000014901161 0.99999998
1699 0x01, 0x00, 0x00, 0x00 // 0.000000007450581 0.99999999
1702 #ifndef FLOAT_DEFAULT_FRAC_DIGITS
1703 // TODO: Perhaps these should be tweaked a bit to take round up
1704 // effects into account... or maybe give more default digits??
1706 // 0.0001 - 0.0009999 7
1707 // 0.001 - 0.009999 6 0.001 = 0x3A83126F 3A83
1708 // 0.01 - 0.09999 5 0.01 = 0x3C23D70A 3C23
1709 // 0.1 - 9.9999 4 0.1 = 0x3DCCCCCD, 3DCC
1710 // 10.0 - 99.99 3 10.0 = 0x41200000 4120
1711 // 100.0 - 999.99 2 100.0 = 0x42C80000 42C8
1712 // 1000 - 9999.9 1 1000 = 0x447A0000 447A
1713 // 10000+ 0 10000 = 0x461C4000 461C
1714 static code unsigned int float_range_table[] = {
1725 #else // using FLOAT_FIXED4
1729 * for ($i=0, $f=0.5; $i<14; $i++) {
1730 * $r = sprintf "%.4f", $f;
1731 * $r =~ /0\.([0-9][0-9])([0-9][0-9])/;
1732 * printf "0x%02d, 0x%02d", $2, $1;
1733 * print ',' if $i < 13;
1735 * printf "\t\t// %.15f %.4f\n", $f, $sum;
1740 static code unsigned char frac2bcd[] = {
1741 0x00, 0x50, // 0.500000000000000 0.5000
1742 0x00, 0x25, // 0.250000000000000 0.7500
1743 0x50, 0x12, // 0.125000000000000 0.8750
1744 0x25, 0x06, // 0.062500000000000 0.9375
1745 0x12, 0x03, // 0.031250000000000 0.9687
1746 0x56, 0x01, // 0.015625000000000 0.9843
1747 0x78, 0x00, // 0.007812500000000 0.9921
1748 0x39, 0x00, // 0.003906250000000 0.9960
1749 0x20, 0x00, // 0.001953125000000 0.9980
1750 0x10, 0x00, // 0.000976562500000 0.9990
1751 0x05, 0x00, // 0.000488281250000 0.9995
1752 0x02, 0x00, // 0.000244140625000 0.9997
1753 0x01, 0x00, // 0.000122070312500 0.9998
1754 0x01, 0x00 // 0.000061035156250 0.9999
1757 #endif // FLOAT_FIXED4
1761 #endif // defines compatible with printf_fast