1 /* Fast printf routine for use with sdcc/mcs51
2 * Copyright (c) 2004, Paul Stoffregen, paul@pjrc.com
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 /******************************************************************/
21 /** Major features. These determine what capabilities your **/
22 /** compiled printf_fast will have. **/
24 /******************************************************************/
26 // Include support for 32 bit base 10 integers (%ld and %lu). Without
27 // this, you won't be able to print 32 bit integers as base 10. They
28 // will appear in hexadecimal.
31 // Include support for floating point numbers (%f). Don't forget to
32 // enable LONG above, if you want to print floats greater than
33 // 65535.997. You can have 6 good digits after the decimal point,
34 // or an 8th if a small error is ok. +/- 2^32 to 1/10^8 isn't the
35 // full dynamic range of 32 bit floats, but it covers the most
36 // commonly used range. Adds about 500-600 bytes of code.
39 // Include support for minimum field widths (%8d, %20s, %12.5f)
42 // Include fast integer conversion. Without this, a compact but slower
43 // algorithm is used to convert integers (%d, %u, int part of %f).
44 // Even the slow algorithm is much faster than a typical C implementation
45 // based on repetitive division by 10. If you enable this, you get an
46 // extremely fast version (only 8 table lookups and 8 adds to convert a
47 // 32 bit integer), but it costs extra code space for larger lookup
48 // tables and optimized non-looping code.
52 /******************************************************************/
54 /** Minor tweaks. These provide small code savings, with **/
55 /** a partial loss of functionality. **/
57 /******************************************************************/
60 // If you enabled FLOAT, enabling this replaces the normal %f float
61 // output with a very compact version that always prints 4 fractional
62 // digits and does not have round off. Zero will print as "0.0000",
63 // and 1.999997 will print as "1.9999" (not rounded up to 2). The
64 // 4th digit is not accurate (+/- 2). This simpler version also
65 // avoids using 5 bytes of internal data memory. Code size is about
67 //#define FLOAT_FIXED4
69 // If you used FLOAT (not FLOAT_FIXED4), this will remove the smart
70 // default number of digits code. When you use "%f" without a field
71 // width, normally the smart default width code chooses a good number
72 // of digits based on size of the number. If you enabled FIELD_WIDTH
73 // and use a number, like "%.5f", this smart default code is never
74 // used anyway. Saves about 40 bytes of code.
75 //#define FLOAT_DEFAULT_FRAC_DIGITS 6
77 // If you used FLOAT (not FLOAT_FIXED4) and you do not specify a
78 // field width, normally trailing zeros are trimmed. Using this
79 // removes that feature (saves only a few bytes).
80 //#define DO_NOT_TRIM_TRAILING_ZEROS
82 // Omit saving and restoring registers when calling putchar(). If you
83 // are desparate for a little more code space, this will give you a
84 // small savings. You MUST define putchar() with #pragma callee_saves,
85 // or implement it in assembly and avoid changing the registers.
86 //#define PUTCHAR_CALLEE_SAVES
89 /* extern void putchar(char ); */
91 // Warning: using static/global variables makes these functions NON-reentrant!
92 // reentrant keyword is only used for parameter passing method
94 static bit long_flag, short_flag, print_zero_flag, negative_flag;
97 static bit field_width_flag;
98 static bit leading_zero_flag;
99 static data unsigned char field_width;
103 #define SDCC_FLOAT_LIB
105 static bit continue_float;
107 static data unsigned char frac_field_width;
108 static data unsigned char float_frac_bcd[4];
109 // TODO: can float_frac_bcd be overlaid with temps used by trig functions
115 static data unsigned int i2bcd_tmp; // slow 32 int conversion needs temp space
122 #define PRINTF_FAST printf_fast
126 #if !defined(SDCC_mcs51) || defined(SDCC_USE_XSTACK) || defined(_SDCC_NO_ASM_LIB_FUNCS)
127 // Does printf_fast really work on ds390 and ds400?
128 // If it does, enable them in the line above
129 #if defined(SDCC_USE_XSTACK)
130 #warning "printf_fast not built, does not support --xstack"
131 #elif defined(_SDCC_NO_ASM_LIB_FUNCS)
132 #warning "printf_fast not built, _SDCC_NO_ASM_LIB_FUNCS defined"
134 #else // defines are compatible with printf_fast
137 void PRINTF_FAST(code char *fmt, ...) reentrant
139 fmt; /* suppress unreferenced variable warning */
144 mov a, _bp // r0 will point to va_args (stack)
146 mov r0, a // r0 points to MSB of fmt
149 mov dpl, @r0 // dptr has address of fmt
155 movc a, @a+dptr // get next byte of fmt string
157 //cjne a, #'%', printf_normal
158 cjne a, #37, printf_normal
166 clr _field_width_flag
167 clr _leading_zero_flag
168 mov r1, #_field_width
177 movc a, @a+dptr // get next byte of data format
180 /* parse and consume the field width digits, even if */
181 /* we don't build the code to make use of them */
189 cjne a, _field_width, printf_digit_2
190 setb _leading_zero_flag
192 setb _field_width_flag
200 sjmp printf_format_loop
208 //cjne a, #'l', printf_format_h
209 cjne a, #108, printf_format_h
211 sjmp printf_format_loop
214 //cjne a, #'h', printf_format_s
215 cjne a, #104, printf_format_s
217 sjmp printf_format_loop
220 //cjne a, #'s', printf_format_d
221 cjne a, #115, printf_format_d
225 //cjne a, #'d', printf_format_u
226 cjne a, #100, printf_format_u
231 //cjne a, #'u', printf_format_c
232 cjne a, #117, printf_format_c
237 //cjne a, #'c', printf_format_x
238 cjne a, #99, printf_format_x
240 mov a, @r0 // Acc has the character to print
245 //cjne a, #'x', printf_format_f
246 cjne a, #120, printf_format_f
251 //cjne a, #'f', printf_format_dot
252 cjne a, #102, printf_format_dot
257 //cjne a, #'.', printf_normal
258 cjne a, #46, printf_normal
261 mov r1, #ar3 // parse frac field, but discard if FIXED4
263 mov r1, #_frac_field_width
267 sjmp printf_format_loop
273 ljmp printf_main_loop
283 /* print a string... just grab each byte with __gptrget */
284 /* the user much pass a 24 bit generic pointer */
287 push dph // save addr in fmt onto stack
289 mov b, @r0 // b has type of address (generic *)
293 mov dpl, @r0 // dptr has address of user's string
297 jnb _field_width_flag, printf_str_loop
298 clr _leading_zero_flag // never leading zeros for strings
307 jnz printf_str_fw_loop
312 #endif // FIELD_WIDTH
321 pop dpl // restore addr withing fmt
323 ljmp printf_main_loop
332 /* printing in hex is easy because sdcc pushes the LSB first */
336 jb _short_flag, printf_hex_end
338 jnb _long_flag, printf_hex_end
343 ljmp printf_main_loop
346 lcall printf_phex_msn
367 /* printing an integer is not so easy. For a signed int */
368 /* check if it is negative and print the minus sign and */
369 /* invert it to a positive integer */
373 jnb acc.7, printf_uint /* check if negative */
375 mov a, r1 /* invert integer */
379 jb _short_flag, printf_uint
384 jnb _long_flag, printf_uint
395 /* printing integers is a lot of work... because it takes so */
396 /* long, the first thing to do is make sure we're doing as */
397 /* little work as possible, then convert the binary int to */
398 /* packed BCD, and finally print each digit of the BCD number */
402 jb _short_flag, printf_uint_ck8
403 jnb _long_flag, printf_uint_ck16
405 /* it's a 32 bit int... but if the upper 16 bits are zero */
406 /* we can treat it like a 16 bit integer and convert much faster */
409 jnz printf_uint_begin
411 jnz printf_uint_begin
414 jnz printf_ld_in_hex // print long integer as hex
415 mov a, r4 // rather than just the low 16 bits
420 /* it's a 16 bit int... but if the upper 8 bits are zero */
421 /* we can treat it like a 8 bit integer and convert much faster */
423 jnz printf_uint_begin
426 /* it's an 8 bit int... if it's zero, it's a lot faster to just */
427 /* print the digit zero and skip all the hard work! */
429 jnz printf_uint_begin
431 jnb _field_width_flag, printf_uint_zero
442 jnb _continue_float, 0001$
446 ljmp printf_main_loop
453 lcall printf_int2bcd // bcd number in r3/r2/r7/r6/r5
457 jnb _field_width_flag, printf_uifw_end
461 jnb _long_flag, printf_uifw_16
484 jb _short_flag, printf_uifw_8
503 ;r1 has the number of digits for the number
505 mov c, _negative_flag
510 #ifndef PUTCHAR_CALLEE_SAVES
520 #ifndef PUTCHAR_CALLEE_SAVES
532 #endif // FIELD_WIDTH
536 jnb _negative_flag, printf_uint_pos
537 #ifdef PUTCHAR_CALLEE_SAVES
559 #endif // PUTCHAR_CALLEE_SAVES
562 jb _short_flag, printf_uint8
564 jnb _long_flag, printf_uint16
572 lcall printf_phex_msn
574 lcall printf_phex_lsn
576 lcall printf_phex_msn
578 lcall printf_phex_lsn
581 lcall printf_phex_msn
593 lcall printf_phex_lsn
595 lcall printf_phex_msn
603 lcall printf_phex_lsn
605 lcall printf_phex_msn
607 lcall printf_phex_lsn
612 jnb _continue_float, 0002$
616 ljmp printf_main_loop
627 // Print a float the easy way. First, extract the integer part and
628 // use the integer printing code. Then extract the fractional part,
629 // convert each bit to 4 digit BCD, and print the BCD sum. Absolutely
630 // no field width control, always 4 digits printed past the decimal
631 // point. No round off. 1.9999987 prints as 1.9999, not 2.0000.
634 jnb _field_width_flag, print_float_begin
642 push ar0 // keep r0 safe, will need it again
643 lcall printf_get_float
645 mov a, #158 // check for large float we can't print
647 jnc print_float_size_ok
648 printf_float_too_big:
649 // TODO: should print some sort of overflow error??
651 ljmp printf_format_loop
660 jnz printf_float_too_big
662 lcall printf_uint // print the integer portion
666 // now that the integer part is printed, we need to refetch the
667 // float from the va_args and extract the fractional part
669 lcall printf_get_float
674 cjne a, #126, print_float_frac_lshift
675 sjmp print_float_frac // input between 0.5 to 0.9999
676 print_float_frac_lshift:
677 jc print_float_frac_rshift
678 //Acc (exponent) is greater than 126 (input >= 1.0)
681 print_float_lshift_loop:
692 djnz r5, print_float_lshift_loop
693 sjmp print_float_frac
694 print_float_frac_rshift:
695 //Acc (exponent) is less than 126 (input < 0.5)
700 // now we've got the fractional part, so now is the time to
701 // convert to BCD... just convert each bit to BCD using a
702 // lookup table and BCD sum them together
707 mov dptr, #_frac2bcd // FLOAT_FIXED4 version (14 entries)
708 print_float_frac_loop:
715 jnc print_float_frac_skip
726 print_float_frac_skip:
729 djnz r7, print_float_frac_loop
730 // the BCD sum is in dptr, so all we've got to do is output
731 // all 4 digits. No trailing zero suppression, no nice round
732 // off (impossible to change the integer part since we already
736 setb _print_zero_flag
738 lcall printf_phex_msn
740 lcall printf_phex_lsn
742 lcall printf_phex_msn
744 lcall printf_phex_lsn
748 ljmp printf_main_loop
750 #else // not FLOAT_FIXED4
756 // Print a float the not-as-easy way, with a configurable number of
757 // fractional digits (up to 8) and proper round-off (up to 7 digits).
758 // First, extract the fractional part, convert to BCD, and then add
759 // the scaled round-off. Store the rounded fractional digits and
760 // their carry. Then extract the integer portion, increment it if
761 // the rounding caused a carry. Use the integer printing to output
762 // the integer, and then output the stored fractional digits. This
763 // approach requires 5 bytes of internal RAM to store the 8 fractional
764 // digits and the number of them we'll actually print. This code is
765 // a couple hundred bytes larger and a bit slower than the FIXED4
766 // version, but it gives very nice results.
769 jnb _field_width_flag, print_float_default_width
770 // The caller specified exact field width, so use it. Need to
771 // convert the whole float digits into the integer portion only.
774 subb a, _frac_field_width
776 jnc print_float_begin
778 sjmp print_float_begin
780 print_float_default_width:
781 // The caller didn't specify field width (or FIELD_WIDTH is
782 // not defined so it's ignored). We've still got to know
783 // how many fractional digits are going to print, so we can
784 // round off properly.
785 #ifdef FLOAT_DEFAULT_FRAC_DIGITS
786 mov _frac_field_width, #FLOAT_DEFAULT_FRAC_DIGITS
788 // default fractional field width (between 0 to 7)
789 // attempt to scale the default number of fractional digits
790 // based on the magnitude of the float
791 mov ar1, r0 // r0 points to first byte of float
792 dec r1 // r1 points to second byte of float
795 mov dptr, #_float_range_table
797 print_float_default_loop:
805 jnc print_float_default_done
807 djnz r5, print_float_default_loop
808 print_float_default_done:
809 mov _frac_field_width, r5
812 #endif // not FLOAT_DEFAULT_FRAC_DIGITS
815 push ar0 // keep r0 safe, will need it again
816 lcall printf_get_float
820 cjne a, #126, print_float_frac_lshift
821 sjmp print_float_frac // input between 0.5 to 0.9999
823 print_float_frac_lshift:
824 jc print_float_frac_rshift
825 //Acc (exponent) is greater than 126 (input >= 1.0)
828 print_float_lshift_loop:
839 djnz r5, print_float_lshift_loop
840 sjmp print_float_frac
841 print_float_frac_rshift:
842 //Acc (exponent) is less than 126 (input < 0.5)
847 // Convert the fraction in r4/r3/r2/r1 into 8 BCD digits in r0/r7/r6/r5
854 mov dptr, #_frac2bcd // FLOAT version (27 entries)
855 print_float_frac_loop:
868 jnc print_float_frac_skip
889 print_float_frac_skip:
894 djnz b, print_float_frac_loop
895 print_float_frac_roundoff:
896 // Now it's time to round-off the BCD digits to the desired precision.
898 mov r4, #0x50 // r4/r3/r2/r1 = 0.5 (bcd rounding)
902 mov a, _frac_field_width
906 mov dph, r0 // fs_rshift_a will overwrite r0 & dpl
907 lcall fs_rshift_a // divide r4/r3/r2/r1 by 10^frac_field_width
909 add a, r1 // add rounding to fractional part
911 mov _float_frac_bcd+3, a // and store it for later use
915 mov _float_frac_bcd+2, a
919 mov _float_frac_bcd+1, a
923 mov _float_frac_bcd+0, a
924 mov sign_b, c // keep fractional carry in sign_b
928 // Time to work on the integer portion... fetch the float again, check
929 // size (exponent), scale to integer, add the fraction's carry, and
930 // let the integer printing code do all the work.
932 lcall printf_get_float
935 mov a, #158 // check for large float we can't print
937 jnc print_float_size_ok
938 printf_float_too_big:
939 // TODO: should print some sort of overflow error??
941 ljmp printf_format_loop
946 jnb sign_b, print_float_do_int
947 // if we get here, the fractional round off caused the
948 // integer part to increment. Add 1 for a proper result
963 jc printf_float_too_big
968 jnz printf_float_too_big
971 lcall printf_uint // print the integer portion
974 print_float_frac_width:
975 // Now all we have to do is output the fractional digits that
976 // were previous computed and stored in memory.
978 jb _field_width_flag, print_float_do_frac
980 #ifndef DO_NOT_TRIM_TRAILING_ZEROS
981 // if the user did not explicitly set a
982 // field width, trim off trailing zeros
983 print_float_frac_trim:
984 mov a, _frac_field_width
985 jz print_float_do_frac
986 lcall get_float_frac_digit
987 jnz print_float_do_frac
988 djnz _frac_field_width, print_float_frac_trim
992 mov a, _frac_field_width
998 setb _print_zero_flag
999 print_float_do_frac_loop:
1002 lcall get_float_frac_digit
1003 lcall printf_phex_lsn
1005 cjne a, _frac_field_width, print_float_do_frac_loop
1009 ljmp printf_main_loop
1013 // acc=1 for tenths, acc=2 for hundredths, etc
1014 get_float_frac_digit:
1019 add a, #_float_frac_bcd
1022 jb psw.5, get_float_frac_digit_done
1024 get_float_frac_digit_done:
1031 #endif // end of normal FLOAT code (not FLOAT_FIXED4)
1034 // These helper functions are used, regardless of which type of
1035 // FLOAT code is used.
1040 lcall pm2_entry_phex
1042 lcall pm2_entry_cout
1045 lcall pm2_entry_cout
1049 // Fetch a float from the va_args and put it into
1050 // r7(exp) r4/r3/r2(mant) and also clear r1 and preset
1062 mov _negative_flag, c
1064 jz printf_get_float_2
1091 /* read an integer into r1/r2/r3/r4, and msb into r5 */
1097 jb _short_flag, printf_get_done
1102 jnb _long_flag, printf_get_done
1120 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1121 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1122 * process, to avoid needing extra memory for the result (and
1123 * r1 gets used for temporary storage). dptr is overwritten,
1124 * but r0 is not changed.
1139 jnb _short_flag, printf_i2bcd_16 // if 8 bit int, we're done
1146 mov dptr, #_int2bcd_2
1162 mov dptr, #_int2bcd_3
1180 jb _long_flag, printf_i2bcd_32 // if 16 bit int, we're done
1189 mov dptr, #_int2bcd_4
1214 mov dptr, #_int2bcd_5
1241 mov dptr, #_int2bcd_6
1243 lcall printf_bcd_add10 // saves 27 bytes, costs 5 cycles
1249 mov dptr, #_int2bcd_7
1283 #else // not FAST_INTEGER
1285 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1286 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1287 * process, to avoid needing extra memory for the result (and
1288 * r1 gets used for temporary storage). dptr is overwritten,
1289 * but r0 is not changed.
1296 jb _short_flag, printf_int2bcd_begin
1298 jnb _long_flag, printf_int2bcd_begin
1300 printf_int2bcd_begin:
1306 mov (_i2bcd_tmp + 0), a
1307 mov (_i2bcd_tmp + 1), a
1322 jnc print_i2bcd_skip
1340 addc a, (_i2bcd_tmp + 0)
1342 mov (_i2bcd_tmp + 0), a
1345 addc a, (_i2bcd_tmp + 1)
1347 mov (_i2bcd_tmp + 1), a
1354 djnz b, printf_i2bcd_loop
1355 mov r2, (_i2bcd_tmp + 0)
1356 mov r3, (_i2bcd_tmp + 1)
1363 jb _short_flag, printf_int2bcd_begin
1365 printf_int2bcd_begin:
1379 jnc printf_i2bcd_add_skip
1395 printf_i2bcd_add_skip:
1399 djnz b, printf_i2bcd_loop
1405 #endif // not FAST_INTEGER
1423 jnb _leading_zero_flag, printf_space_output
1426 printf_space_output:
1427 lcall printf_putchar
1431 jnz printf_space_loop
1439 /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
1446 jnb _print_zero_flag, printf_ret
1448 setb _print_zero_flag
1454 #ifdef PUTCHAR_CALLEE_SAVES
1474 /* print a zero if all the calls to print the digits ended up */
1475 /* being leading zeros */
1478 jb _print_zero_flag, printf_ret
1491 * for ($d=0; $d < 8; $d++) {
1493 * for ($p=0; $p < 5; $p++) {
1494 * last unless (((16 ** $d) * 15) / (10 ** ($p * 2))) % 100;
1495 * printf "code unsigned char int2bcd_%d_%d[15] = {", $d, $p;
1496 * for ($i=0; $i < 16; $i++) {
1498 * (((16 ** $d) * $i) / (10 ** ($p * 2))) % 100;
1499 * print ", " if $i < 15;
1507 static code unsigned char int2bcd_0[] = {
1508 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1509 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1511 static code unsigned char int2bcd_1[] = {
1512 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1513 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1514 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1515 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02};
1518 static code unsigned char int2bcd_2[] = {
1519 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1520 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1521 0x00, 0x02, 0x05, 0x07, 0x10, 0x12, 0x15, 0x17,
1522 0x20, 0x23, 0x25, 0x28, 0x30, 0x33, 0x35, 0x38};
1524 static code unsigned char int2bcd_3[] = {
1525 0x00, 0x96, 0x92, 0x88, 0x84, 0x80, 0x76, 0x72,
1526 0x68, 0x64, 0x60, 0x56, 0x52, 0x48, 0x44, 0x40,
1527 0x00, 0x40, 0x81, 0x22, 0x63, 0x04, 0x45, 0x86,
1528 0x27, 0x68, 0x09, 0x50, 0x91, 0x32, 0x73, 0x14,
1529 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02,
1530 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06};
1533 static code unsigned char int2bcd_4[] = {
1534 0x00, 0x36, 0x72, 0x08, 0x44, 0x80, 0x16, 0x52,
1535 0x88, 0x24, 0x60, 0x96, 0x32, 0x68, 0x04, 0x40,
1536 0x00, 0x55, 0x10, 0x66, 0x21, 0x76, 0x32, 0x87,
1537 0x42, 0x98, 0x53, 0x08, 0x64, 0x19, 0x75, 0x30,
1538 0x00, 0x06, 0x13, 0x19, 0x26, 0x32, 0x39, 0x45,
1539 0x52, 0x58, 0x65, 0x72, 0x78, 0x85, 0x91, 0x98};
1541 static code unsigned char int2bcd_5[] = {
1542 0x00, 0x76, 0x52, 0x28, 0x04, 0x80, 0x56, 0x32,
1543 0x08, 0x84, 0x60, 0x36, 0x12, 0x88, 0x64, 0x40,
1544 0x00, 0x85, 0x71, 0x57, 0x43, 0x28, 0x14, 0x00,
1545 0x86, 0x71, 0x57, 0x43, 0x29, 0x14, 0x00, 0x86,
1546 0x00, 0x04, 0x09, 0x14, 0x19, 0x24, 0x29, 0x34,
1547 0x38, 0x43, 0x48, 0x53, 0x58, 0x63, 0x68, 0x72,
1548 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1549 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1551 static code unsigned char int2bcd_6[] = {
1552 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1553 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1554 0x00, 0x72, 0x44, 0x16, 0x88, 0x60, 0x32, 0x05,
1555 0x77, 0x49, 0x21, 0x93, 0x65, 0x38, 0x10, 0x82,
1556 0x00, 0x77, 0x55, 0x33, 0x10, 0x88, 0x66, 0x44,
1557 0x21, 0x99, 0x77, 0x54, 0x32, 0x10, 0x88, 0x65,
1558 0x00, 0x16, 0x33, 0x50, 0x67, 0x83, 0x00, 0x17,
1559 0x34, 0x50, 0x67, 0x84, 0x01, 0x18, 0x34, 0x51,
1560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
1561 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02};
1563 static code unsigned char int2bcd_7[] = {
1564 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1565 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1566 0x00, 0x54, 0x09, 0x63, 0x18, 0x72, 0x27, 0x81,
1567 0x36, 0x91, 0x45, 0x00, 0x54, 0x09, 0x63, 0x18,
1568 0x00, 0x43, 0x87, 0x30, 0x74, 0x17, 0x61, 0x04,
1569 0x48, 0x91, 0x35, 0x79, 0x22, 0x66, 0x09, 0x53,
1570 0x00, 0x68, 0x36, 0x05, 0x73, 0x42, 0x10, 0x79,
1571 0x47, 0x15, 0x84, 0x52, 0x21, 0x89, 0x58, 0x26,
1572 0x00, 0x02, 0x05, 0x08, 0x10, 0x13, 0x16, 0x18,
1573 0x21, 0x24, 0x26, 0x29, 0x32, 0x34, 0x37, 0x40};
1576 #else // not FAST_INTEGER
1580 * print "code unsigned char int2bcd[] = {\n";
1581 * for ($i=0, $n=1; $i<32; $i++, $n*=2) {
1582 * $r = sprintf "%010u", $n;
1583 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1584 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d, 0x%02d", $5, $4, $3, $2, $1;
1585 * print ',' if $i < 31;
1586 * printf "\t\t// %10u\n", $n;
1588 * print "}\ncode unsigned char int2bcd[] = {\n";
1589 * for ($i=0, $n=1; $i<16; $i++, $n*=2) {
1590 * $r = sprintf "%06u", $n;
1591 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1592 * printf "0x%02d, 0x%02d, 0x%02d", $3, $2, $1;
1593 * print ',' if $i < 15;
1594 * printf "\t\t// %10u\n", $n;
1600 static code unsigned char int2bcd[] = {
1601 0x01, 0x00, 0x00, 0x00, 0x00, // 1
1602 0x02, 0x00, 0x00, 0x00, 0x00, // 2
1603 0x04, 0x00, 0x00, 0x00, 0x00, // 4
1604 0x08, 0x00, 0x00, 0x00, 0x00, // 8
1605 0x16, 0x00, 0x00, 0x00, 0x00, // 16
1606 0x32, 0x00, 0x00, 0x00, 0x00, // 32
1607 0x64, 0x00, 0x00, 0x00, 0x00, // 64
1608 0x28, 0x01, 0x00, 0x00, 0x00, // 128
1609 0x56, 0x02, 0x00, 0x00, 0x00, // 256
1610 0x12, 0x05, 0x00, 0x00, 0x00, // 512
1611 0x24, 0x10, 0x00, 0x00, 0x00, // 1024
1612 0x48, 0x20, 0x00, 0x00, 0x00, // 2048
1613 0x96, 0x40, 0x00, 0x00, 0x00, // 4096
1614 0x92, 0x81, 0x00, 0x00, 0x00, // 8192
1615 0x84, 0x63, 0x01, 0x00, 0x00, // 16384
1616 0x68, 0x27, 0x03, 0x00, 0x00, // 32768
1617 0x36, 0x55, 0x06, 0x00, 0x00, // 65536
1618 0x72, 0x10, 0x13, 0x00, 0x00, // 131072
1619 0x44, 0x21, 0x26, 0x00, 0x00, // 262144
1620 0x88, 0x42, 0x52, 0x00, 0x00, // 524288
1621 0x76, 0x85, 0x04, 0x01, 0x00, // 1048576
1622 0x52, 0x71, 0x09, 0x02, 0x00, // 2097152
1623 0x04, 0x43, 0x19, 0x04, 0x00, // 4194304
1624 0x08, 0x86, 0x38, 0x08, 0x00, // 8388608
1625 0x16, 0x72, 0x77, 0x16, 0x00, // 16777216
1626 0x32, 0x44, 0x55, 0x33, 0x00, // 33554432
1627 0x64, 0x88, 0x10, 0x67, 0x00, // 67108864
1628 0x28, 0x77, 0x21, 0x34, 0x01, // 134217728
1629 0x56, 0x54, 0x43, 0x68, 0x02, // 268435456
1630 0x12, 0x09, 0x87, 0x36, 0x05, // 536870912
1631 0x24, 0x18, 0x74, 0x73, 0x10, // 1073741824
1632 0x48, 0x36, 0x48, 0x47, 0x21 // 2147483648
1635 static code unsigned char int2bcd[] = {
1636 0x01, 0x00, 0x00, // 1
1637 0x02, 0x00, 0x00, // 2
1638 0x04, 0x00, 0x00, // 4
1639 0x08, 0x00, 0x00, // 8
1640 0x16, 0x00, 0x00, // 16
1641 0x32, 0x00, 0x00, // 32
1642 0x64, 0x00, 0x00, // 64
1643 0x28, 0x01, 0x00, // 128
1644 0x56, 0x02, 0x00, // 256
1645 0x12, 0x05, 0x00, // 512
1646 0x24, 0x10, 0x00, // 1024
1647 0x48, 0x20, 0x00, // 2048
1648 0x96, 0x40, 0x00, // 4096
1649 0x92, 0x81, 0x00, // 8192
1650 0x84, 0x63, 0x01, // 16384
1651 0x68, 0x27, 0x03 // 32768
1655 #endif // not FAST_INTEGER
1661 #ifndef FLOAT_FIXED4
1665 * for ($i=0, $f=0.5; $i<24; $i++) {
1666 * $r = sprintf "%.8f", $f;
1667 * $r =~ /0\.([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1668 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d", $4, $3, $2, $1;
1669 * print ',' if $i < 23;
1671 * printf "\t\t// %.15f %.8f\n", $f, $sum;
1676 static code unsigned char frac2bcd[] = {
1677 0x00, 0x00, 0x00, 0x50, // 0.500000000000000 0.50000000
1678 0x00, 0x00, 0x00, 0x25, // 0.250000000000000 0.75000000
1679 0x00, 0x00, 0x50, 0x12, // 0.125000000000000 0.87500000
1680 0x00, 0x00, 0x25, 0x06, // 0.062500000000000 0.93750000
1681 0x00, 0x50, 0x12, 0x03, // 0.031250000000000 0.96875000
1682 0x00, 0x25, 0x56, 0x01, // 0.015625000000000 0.98437500
1683 0x50, 0x12, 0x78, 0x00, // 0.007812500000000 0.99218750
1684 0x25, 0x06, 0x39, 0x00, // 0.003906250000000 0.99609375
1685 0x12, 0x53, 0x19, 0x00, // 0.001953125000000 0.99804687
1686 0x56, 0x76, 0x09, 0x00, // 0.000976562500000 0.99902343
1687 0x28, 0x88, 0x04, 0x00, // 0.000488281250000 0.99951171
1688 0x14, 0x44, 0x02, 0x00, // 0.000244140625000 0.99975585
1689 0x07, 0x22, 0x01, 0x00, // 0.000122070312500 0.99987792
1690 0x04, 0x61, 0x00, 0x00, // 0.000061035156250 0.99993896
1691 0x52, 0x30, 0x00, 0x00, // 0.000030517578125 0.99996948
1692 0x26, 0x15, 0x00, 0x00, // 0.000015258789062 0.99998474
1693 0x63, 0x07, 0x00, 0x00, // 0.000007629394531 0.99999237
1694 0x81, 0x03, 0x00, 0x00, // 0.000003814697266 0.99999618
1695 0x91, 0x01, 0x00, 0x00, // 0.000001907348633 0.99999809
1696 0x95, 0x00, 0x00, 0x00, // 0.000000953674316 0.99999904
1697 0x48, 0x00, 0x00, 0x00, // 0.000000476837158 0.99999952
1698 0x24, 0x00, 0x00, 0x00, // 0.000000238418579 0.99999976
1699 0x12, 0x00, 0x00, 0x00, // 0.000000119209290 0.99999988
1700 0x06, 0x00, 0x00, 0x00, // 0.000000059604645 0.99999994
1701 0x03, 0x00, 0x00, 0x00, // 0.000000029802322 0.99999997
1702 0x01, 0x00, 0x00, 0x00, // 0.000000014901161 0.99999998
1703 0x01, 0x00, 0x00, 0x00 // 0.000000007450581 0.99999999
1706 #ifndef FLOAT_DEFAULT_FRAC_DIGITS
1707 // TODO: Perhaps these should be tweaked a bit to take round up
1708 // effects into account... or maybe give more default digits??
1710 // 0.0001 - 0.0009999 7
1711 // 0.001 - 0.009999 6 0.001 = 0x3A83126F 3A83
1712 // 0.01 - 0.09999 5 0.01 = 0x3C23D70A 3C23
1713 // 0.1 - 9.9999 4 0.1 = 0x3DCCCCCD, 3DCC
1714 // 10.0 - 99.99 3 10.0 = 0x41200000 4120
1715 // 100.0 - 999.99 2 100.0 = 0x42C80000 42C8
1716 // 1000 - 9999.9 1 1000 = 0x447A0000 447A
1717 // 10000+ 0 10000 = 0x461C4000 461C
1718 static code unsigned int float_range_table[] = {
1729 #else // using FLOAT_FIXED4
1733 * for ($i=0, $f=0.5; $i<14; $i++) {
1734 * $r = sprintf "%.4f", $f;
1735 * $r =~ /0\.([0-9][0-9])([0-9][0-9])/;
1736 * printf "0x%02d, 0x%02d", $2, $1;
1737 * print ',' if $i < 13;
1739 * printf "\t\t// %.15f %.4f\n", $f, $sum;
1744 static code unsigned char frac2bcd[] = {
1745 0x00, 0x50, // 0.500000000000000 0.5000
1746 0x00, 0x25, // 0.250000000000000 0.7500
1747 0x50, 0x12, // 0.125000000000000 0.8750
1748 0x25, 0x06, // 0.062500000000000 0.9375
1749 0x12, 0x03, // 0.031250000000000 0.9687
1750 0x56, 0x01, // 0.015625000000000 0.9843
1751 0x78, 0x00, // 0.007812500000000 0.9921
1752 0x39, 0x00, // 0.003906250000000 0.9960
1753 0x20, 0x00, // 0.001953125000000 0.9980
1754 0x10, 0x00, // 0.000976562500000 0.9990
1755 0x05, 0x00, // 0.000488281250000 0.9995
1756 0x02, 0x00, // 0.000244140625000 0.9997
1757 0x01, 0x00, // 0.000122070312500 0.9998
1758 0x01, 0x00 // 0.000061035156250 0.9999
1761 #endif // FLOAT_FIXED4
1765 #endif // defines compatible with printf_fast