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
118 void printf_fast(code char *fmt, ...) reentrant
120 fmt; /* supress unreferenced variable warning */
125 mov a, _bp // r0 will point to va_args (stack)
127 mov r0, a // r0 points to MSB of fmt
130 mov dpl, @r0 // dptr has address of fmt
136 movc a, @a+dptr // get next byte of fmt string
138 //cjne a, #'%', printf_normal
139 cjne a, #37, printf_normal
147 clr _field_width_flag
148 mov r1, #_field_width
157 movc a, @a+dptr // get next byte of data format
160 /* parse and consume the field width digits, even if */
161 /* we don't build the code to make use of them */
168 setb _field_width_flag
176 sjmp printf_format_loop
184 //cjne a, #'l', printf_format_h
185 cjne a, #108, printf_format_h
187 sjmp printf_format_loop
190 //cjne a, #'h', printf_format_s
191 cjne a, #104, printf_format_s
193 sjmp printf_format_loop
196 //cjne a, #'s', printf_format_d
197 cjne a, #115, printf_format_d
201 //cjne a, #'d', printf_format_u
202 cjne a, #100, printf_format_u
207 //cjne a, #'u', printf_format_c
208 cjne a, #117, printf_format_c
213 //cjne a, #'c', printf_format_x
214 cjne a, #99, printf_format_x
215 mov a, @r0 // Acc has the character to print
220 //cjne a, #'x', printf_format_f
221 cjne a, #120, printf_format_f
226 //cjne a, #'f', printf_format_dot
227 cjne a, #102, printf_format_dot
232 //cjne a, #'.', printf_normal
233 cjne a, #46, printf_normal
236 mov r1, #ar3 // parse frac field, but discard if FIXED4
238 mov r1, #_frac_field_width
242 sjmp printf_format_loop
248 ljmp printf_main_loop
258 /* print a string... just grab each byte with __gptrget */
259 /* the user much pass a 24 bit generic pointer */
262 push dph // save addr in fmt onto stack
264 mov b, @r0 // b has type of address (generic *)
268 mov dpl, @r0 // dptr has address of user's string
272 jnb _field_width_flag, printf_str_loop
281 jnz printf_str_fw_loop
286 #endif // FIELD_WIDTH
295 pop dpl // restore addr withing fmt
297 ljmp printf_main_loop
306 /* printing in hex is easy because sdcc pushes the LSB first */
310 jb _short_flag, printf_hex_end
312 jnb _long_flag, printf_hex_end
317 ljmp printf_main_loop
320 lcall printf_phex_msn
341 /* printing an integer is not so easy. For a signed int */
342 /* check if it is negative and print the minus sign and */
343 /* invert it to a positive integer */
347 jnb acc.7, printf_uint /* check if negative */
349 mov a, r1 /* invert integer */
353 jb _short_flag, printf_uint
358 jnb _long_flag, printf_uint
369 /* printing integers is a lot of work... because it takes so */
370 /* long, the first thing to do is make sure we're doing as */
371 /* little work as possible, then convert the binary int to */
372 /* packed BCD, and finally print each digit of the BCD number */
376 jb _short_flag, printf_uint_ck8
377 jnb _long_flag, printf_uint_ck16
379 /* it's a 32 bit int... but if the upper 16 bits are zero */
380 /* we can treat it like a 16 bit integer and convert much faster */
383 jnz printf_uint_begin
385 jnz printf_uint_begin
388 jnz printf_ld_in_hex // print long integer as hex
389 mov a, r4 // rather than just the low 16 bits
394 /* it's a 16 bit int... but if the upper 8 bits are zero */
395 /* we can treat it like a 8 bit integer and convert much faster */
397 jnz printf_uint_begin
400 /* it's an 8 bit int... if it's zero, it's a lot faster to just */
401 /* print the digit zero and skip all the hard work! */
403 jnz printf_uint_begin
405 jnb _field_width_flag, printf_uint_zero
416 jnb _continue_float, 0001$
420 ljmp printf_main_loop
427 lcall printf_int2bcd // bcd number in r3/r2/r7/r6/r5
431 jnb _field_width_flag, printf_uifw_end
435 jnb _long_flag, printf_uifw_16
458 jb _short_flag, printf_uifw_8
477 ;r1 has the number of digits for the number
479 mov c, _negative_flag
484 #ifndef PUTCHAR_CALLEE_SAVES
494 #ifndef PUTCHAR_CALLEE_SAVES
506 #endif // FIELD_WIDTH
510 jnb _negative_flag, printf_uint_pos
511 #ifdef PUTCHAR_CALLEE_SAVES
533 #endif // PUTCHAR_CALLEE_SAVES
536 jb _short_flag, printf_uint8
538 jnb _long_flag, printf_uint16
546 lcall printf_phex_msn
548 lcall printf_phex_lsn
550 lcall printf_phex_msn
552 lcall printf_phex_lsn
555 lcall printf_phex_msn
567 lcall printf_phex_lsn
569 lcall printf_phex_msn
577 lcall printf_phex_lsn
579 lcall printf_phex_msn
581 lcall printf_phex_lsn
586 jnb _continue_float, 0002$
590 ljmp printf_main_loop
601 // Print a float the easy way. First, extract the integer part and
602 // use the integer printing code. Then extract the fractional part,
603 // convert each bit to 4 digit BCD, and print the BCD sum. Absolutely
604 // no field width control, always 4 digits printed past the decimal
605 // point. No round off. 1.9999987 prints as 1.9999, not 2.0000.
608 jnb _field_width_flag, print_float_begin
616 push ar0 // keep r0 safe, will need it again
617 lcall printf_get_float
619 mov a, #158 // check for large float we can't print
621 jnc print_float_size_ok
622 printf_float_too_big:
623 // TODO: should print some sort of overflow error??
625 ljmp printf_format_loop
634 jnz printf_float_too_big
636 lcall printf_uint // print the integer portion
640 // now that the integer part is printed, we need to refetch the
641 // float from the va_args and extract the fractional part
643 lcall printf_get_float
648 cjne a, #126, print_float_frac_lshift
649 sjmp print_float_frac // input between 0.5 to 0.9999
650 print_float_frac_lshift:
651 jc print_float_frac_rshift
652 //Acc (exponent) is greater than 126 (input >= 1.0)
655 print_float_lshift_loop:
666 djnz r5, print_float_lshift_loop
667 sjmp print_float_frac
668 print_float_frac_rshift:
669 //Acc (exponent) is less than 126 (input < 0.5)
674 // now we've got the fractional part, so now is the time to
675 // convert to BCD... just convert each bit to BCD using a
676 // lookup table and BCD sum them together
681 mov dptr, #_frac2bcd // FLOAT_FIXED4 version (14 entries)
682 print_float_frac_loop:
689 jnc print_float_frac_skip
700 print_float_frac_skip:
703 djnz r7, print_float_frac_loop
704 // the BCD sum is in dptr, so all we've got to do is output
705 // all 4 digits. No trailing zero suppression, no nice round
706 // off (impossible to change the integer part since we already
710 setb _print_zero_flag
712 lcall printf_phex_msn
714 lcall printf_phex_lsn
716 lcall printf_phex_msn
718 lcall printf_phex_lsn
722 ljmp printf_main_loop
724 #else // not FLOAT_FIXED4
730 // Print a float the not-as-easy way, with a configurable number of
731 // fractional digits (up to 8) and proper round-off (up to 7 digits).
732 // First, extract the fractional part, convert to BCD, and then add
733 // the scaled round-off. Store the rounded fractional digits and
734 // their carry. Then extract the integer portion, increment it if
735 // the rounding caused a carry. Use the integer printing to output
736 // the integer, and then output the stored fractional digits. This
737 // approach requires 5 bytes of internal RAM to store the 8 fractional
738 // digits and the number of them we'll actually print. This code is
739 // a couple hundred bytes larger and a bit slower than the FIXED4
740 // version, but it gives very nice results.
743 jnb _field_width_flag, print_float_default_width
744 // The caller specified exact field width, so use it. Need to
745 // convert the whole float digits into the integer portion only.
748 subb a, _frac_field_width
750 jnc print_float_begin
752 sjmp print_float_begin
754 print_float_default_width:
755 // The caller didn't specify field width (or FIELD_WIDTH is
756 // not defined so it's ignored). We've still got to know
757 // how many fractional digits are going to print, so we can
758 // round off properly.
759 #ifdef FLOAT_DEFAULT_FRAC_DIGITS
760 mov _frac_field_width, #FLOAT_DEFAULT_FRAC_DIGITS
762 // default fractional field width (between 0 to 7)
763 // attempt to scale the default number of fractional digits
764 // based on the magnitude of the float
765 mov ar1, r0 // r0 points to first byte of float
766 dec r1 // r1 points to second byte of float
769 mov dptr, #_float_range_table
771 print_float_default_loop:
779 jnc print_float_default_done
781 djnz r5, print_float_default_loop
782 print_float_default_done:
783 mov _frac_field_width, r5
786 #endif // not FLOAT_DEFAULT_FRAC_DIGITS
789 push ar0 // keep r0 safe, will need it again
790 lcall printf_get_float
794 cjne a, #126, print_float_frac_lshift
795 sjmp print_float_frac // input between 0.5 to 0.9999
797 print_float_frac_lshift:
798 jc print_float_frac_rshift
799 //Acc (exponent) is greater than 126 (input >= 1.0)
802 print_float_lshift_loop:
813 djnz r5, print_float_lshift_loop
814 sjmp print_float_frac
815 print_float_frac_rshift:
816 //Acc (exponent) is less than 126 (input < 0.5)
821 // Convert the fraction in r4/r3/r2/r1 into 8 BCD digits in r0/r7/r6/r5
828 mov dptr, #_frac2bcd // FLOAT version (27 entries)
829 print_float_frac_loop:
842 jnc print_float_frac_skip
863 print_float_frac_skip:
868 djnz b, print_float_frac_loop
869 print_float_frac_roundoff:
870 // Now it's time to round-off the BCD digits to the desired precision.
872 mov r4, #0x50 // r4/r3/r2/r1 = 0.5 (bcd rounding)
876 mov a, _frac_field_width
880 mov dph, r0 // fs_rshift_a will overwrite r0 & dpl
881 lcall fs_rshift_a // divide r4/r3/r2/r1 by 10^frac_field_width
883 add a, r1 // add rounding to fractional part
885 mov _float_frac_bcd+3, a // and store it for later use
889 mov _float_frac_bcd+2, a
893 mov _float_frac_bcd+1, a
897 mov _float_frac_bcd+0, a
898 mov sign_b, c // keep fractional carry in sign_b
902 // Time to work on the integer portion... fetch the float again, check
903 // size (exponent), scale to integer, add the fraction's carry, and
904 // let the integer printing code do all the work.
906 lcall printf_get_float
909 mov a, #158 // check for large float we can't print
911 jnc print_float_size_ok
912 printf_float_too_big:
913 // TODO: should print some sort of overflow error??
914 ljmp printf_format_loop
919 jnb sign_b, print_float_do_int
920 // if we get here, the fractional round off caused the
921 // integer part to increment. Add 1 for a proper result
936 jc printf_float_too_big
941 jnz printf_float_too_big
944 lcall printf_uint // print the integer portion
947 print_float_frac_width:
948 // Now all we have to do is output the fractional digits that
949 // were previous computed and stored in memory.
951 jb _field_width_flag, print_float_do_frac
953 #ifndef DO_NOT_TRIM_TRAILING_ZEROS
954 // if the user did not explicitly set a
955 // field width, trim off trailing zeros
956 print_float_frac_trim:
957 mov a, _frac_field_width
958 jz print_float_do_frac
959 lcall get_float_frac_digit
960 jnz print_float_do_frac
961 djnz _frac_field_width, print_float_frac_trim
965 mov a, _frac_field_width
971 setb _print_zero_flag
972 print_float_do_frac_loop:
975 lcall get_float_frac_digit
976 lcall printf_phex_lsn
978 cjne a, _frac_field_width, print_float_do_frac_loop
982 ljmp printf_main_loop
986 // acc=1 for tenths, acc=2 for hundredths, etc
987 get_float_frac_digit:
992 add a, #_float_frac_bcd
995 jb psw.5, get_float_frac_digit_done
997 get_float_frac_digit_done:
1004 #endif // end of normal FLOAT code (not FLOAT_FIXED4)
1007 // These helper functions are used, regardless of which type of
1008 // FLOAT code is used.
1013 lcall pm2_entry_phex
1015 lcall pm2_entry_cout
1018 lcall pm2_entry_cout
1022 // Fetch a float from the va_args and put it into
1023 // r7(exp) r4/r3/r2(mant) and also clear r1 and preset
1035 mov _negative_flag, c
1037 jz printf_get_float_2
1064 /* read an integer into r1/r2/r3/r4, and msb into r5 */
1070 jb _short_flag, printf_get_done
1075 jnb _long_flag, printf_get_done
1093 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1094 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1095 * process, to avoid needing extra memory for the result (and
1096 * r1 gets used for temporary storage). dptr is overwritten,
1097 * but r0 is not changed.
1112 jnb _short_flag, printf_i2bcd_16 // if 8 bit int, we're done
1119 mov dptr, #_int2bcd_2
1135 mov dptr, #_int2bcd_3
1153 jb _long_flag, printf_i2bcd_32 // if 16 bit int, we're done
1162 mov dptr, #_int2bcd_4
1187 mov dptr, #_int2bcd_5
1214 mov dptr, #_int2bcd_6
1216 lcall printf_bcd_add10 // saves 27 bytes, costs 5 cycles
1222 mov dptr, #_int2bcd_7
1256 #else // not FAST_INTEGER
1258 /* convert binary number in r4/r3/r2/r1 into bcd packed number
1259 * in r3/r2/r7/r6/r5. The input number is destroyed in the
1260 * process, to avoid needing extra memory for the result (and
1261 * r1 gets used for temporary storage). dptr is overwritten,
1262 * but r0 is not changed.
1269 jb _short_flag, printf_int2bcd_begin
1271 jnb _long_flag, printf_int2bcd_begin
1273 printf_int2bcd_begin:
1279 mov (_i2bcd_tmp + 0), a
1280 mov (_i2bcd_tmp + 1), a
1295 jnc print_i2bcd_skip
1313 addc a, (_i2bcd_tmp + 0)
1315 mov (_i2bcd_tmp + 0), a
1318 addc a, (_i2bcd_tmp + 1)
1320 mov (_i2bcd_tmp + 1), a
1327 djnz b, printf_i2bcd_loop
1328 mov r2, (_i2bcd_tmp + 0)
1329 mov r3, (_i2bcd_tmp + 1)
1336 jb _short_flag, printf_int2bcd_begin
1338 printf_int2bcd_begin:
1352 jnc printf_i2bcd_add_skip
1368 printf_i2bcd_add_skip:
1372 djnz b, printf_i2bcd_loop
1378 #endif // not FAST_INTEGER
1396 lcall printf_putchar
1400 jnz printf_space_loop
1408 /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
1415 jnb _print_zero_flag, printf_ret
1417 setb _print_zero_flag
1423 #ifdef PUTCHAR_CALLEE_SAVES
1443 /* print a zero if all the calls to print the digits ended up */
1444 /* being leading zeros */
1447 jb _print_zero_flag, printf_ret
1460 * for ($d=0; $d < 8; $d++) {
1462 * for ($p=0; $p < 5; $p++) {
1463 * last unless (((16 ** $d) * 15) / (10 ** ($p * 2))) % 100;
1464 * printf "code unsigned char int2bcd_%d_%d[15] = {", $d, $p;
1465 * for ($i=0; $i < 16; $i++) {
1467 * (((16 ** $d) * $i) / (10 ** ($p * 2))) % 100;
1468 * print ", " if $i < 15;
1476 code unsigned char int2bcd_0[] = {
1477 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1478 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1480 code unsigned char int2bcd_1[] = {
1481 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1482 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1483 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1484 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02};
1487 code unsigned char int2bcd_2[] = {
1488 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1489 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1490 0x00, 0x02, 0x05, 0x07, 0x10, 0x12, 0x15, 0x17,
1491 0x20, 0x23, 0x25, 0x28, 0x30, 0x33, 0x35, 0x38};
1493 code unsigned char int2bcd_3[] = {
1494 0x00, 0x96, 0x92, 0x88, 0x84, 0x80, 0x76, 0x72,
1495 0x68, 0x64, 0x60, 0x56, 0x52, 0x48, 0x44, 0x40,
1496 0x00, 0x40, 0x81, 0x22, 0x63, 0x04, 0x45, 0x86,
1497 0x27, 0x68, 0x09, 0x50, 0x91, 0x32, 0x73, 0x14,
1498 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02,
1499 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06};
1502 code unsigned char int2bcd_4[] = {
1503 0x00, 0x36, 0x72, 0x08, 0x44, 0x80, 0x16, 0x52,
1504 0x88, 0x24, 0x60, 0x96, 0x32, 0x68, 0x04, 0x40,
1505 0x00, 0x55, 0x10, 0x66, 0x21, 0x76, 0x32, 0x87,
1506 0x42, 0x98, 0x53, 0x08, 0x64, 0x19, 0x75, 0x30,
1507 0x00, 0x06, 0x13, 0x19, 0x26, 0x32, 0x39, 0x45,
1508 0x52, 0x58, 0x65, 0x72, 0x78, 0x85, 0x91, 0x98};
1510 code unsigned char int2bcd_5[] = {
1511 0x00, 0x76, 0x52, 0x28, 0x04, 0x80, 0x56, 0x32,
1512 0x08, 0x84, 0x60, 0x36, 0x12, 0x88, 0x64, 0x40,
1513 0x00, 0x85, 0x71, 0x57, 0x43, 0x28, 0x14, 0x00,
1514 0x86, 0x71, 0x57, 0x43, 0x29, 0x14, 0x00, 0x86,
1515 0x00, 0x04, 0x09, 0x14, 0x19, 0x24, 0x29, 0x34,
1516 0x38, 0x43, 0x48, 0x53, 0x58, 0x63, 0x68, 0x72,
1517 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1518 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1520 code unsigned char int2bcd_6[] = {
1521 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1522 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1523 0x00, 0x72, 0x44, 0x16, 0x88, 0x60, 0x32, 0x05,
1524 0x77, 0x49, 0x21, 0x93, 0x65, 0x38, 0x10, 0x82,
1525 0x00, 0x77, 0x55, 0x33, 0x10, 0x88, 0x66, 0x44,
1526 0x21, 0x99, 0x77, 0x54, 0x32, 0x10, 0x88, 0x65,
1527 0x00, 0x16, 0x33, 0x50, 0x67, 0x83, 0x00, 0x17,
1528 0x34, 0x50, 0x67, 0x84, 0x01, 0x18, 0x34, 0x51,
1529 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
1530 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02};
1532 code unsigned char int2bcd_7[] = {
1533 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1534 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1535 0x00, 0x54, 0x09, 0x63, 0x18, 0x72, 0x27, 0x81,
1536 0x36, 0x91, 0x45, 0x00, 0x54, 0x09, 0x63, 0x18,
1537 0x00, 0x43, 0x87, 0x30, 0x74, 0x17, 0x61, 0x04,
1538 0x48, 0x91, 0x35, 0x79, 0x22, 0x66, 0x09, 0x53,
1539 0x00, 0x68, 0x36, 0x05, 0x73, 0x42, 0x10, 0x79,
1540 0x47, 0x15, 0x84, 0x52, 0x21, 0x89, 0x58, 0x26,
1541 0x00, 0x02, 0x05, 0x08, 0x10, 0x13, 0x16, 0x18,
1542 0x21, 0x24, 0x26, 0x29, 0x32, 0x34, 0x37, 0x40};
1545 #else // not FAST_INTEGER
1549 * print "code unsigned char int2bcd[] = {\n";
1550 * for ($i=0, $n=1; $i<32; $i++, $n*=2) {
1551 * $r = sprintf "%010u", $n;
1552 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1553 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d, 0x%02d", $5, $4, $3, $2, $1;
1554 * print ',' if $i < 31;
1555 * printf "\t\t// %10u\n", $n;
1557 * print "}\ncode unsigned char int2bcd[] = {\n";
1558 * for ($i=0, $n=1; $i<16; $i++, $n*=2) {
1559 * $r = sprintf "%06u", $n;
1560 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1561 * printf "0x%02d, 0x%02d, 0x%02d", $3, $2, $1;
1562 * print ',' if $i < 15;
1563 * printf "\t\t// %10u\n", $n;
1569 code unsigned char int2bcd[] = {
1570 0x01, 0x00, 0x00, 0x00, 0x00, // 1
1571 0x02, 0x00, 0x00, 0x00, 0x00, // 2
1572 0x04, 0x00, 0x00, 0x00, 0x00, // 4
1573 0x08, 0x00, 0x00, 0x00, 0x00, // 8
1574 0x16, 0x00, 0x00, 0x00, 0x00, // 16
1575 0x32, 0x00, 0x00, 0x00, 0x00, // 32
1576 0x64, 0x00, 0x00, 0x00, 0x00, // 64
1577 0x28, 0x01, 0x00, 0x00, 0x00, // 128
1578 0x56, 0x02, 0x00, 0x00, 0x00, // 256
1579 0x12, 0x05, 0x00, 0x00, 0x00, // 512
1580 0x24, 0x10, 0x00, 0x00, 0x00, // 1024
1581 0x48, 0x20, 0x00, 0x00, 0x00, // 2048
1582 0x96, 0x40, 0x00, 0x00, 0x00, // 4096
1583 0x92, 0x81, 0x00, 0x00, 0x00, // 8192
1584 0x84, 0x63, 0x01, 0x00, 0x00, // 16384
1585 0x68, 0x27, 0x03, 0x00, 0x00, // 32768
1586 0x36, 0x55, 0x06, 0x00, 0x00, // 65536
1587 0x72, 0x10, 0x13, 0x00, 0x00, // 131072
1588 0x44, 0x21, 0x26, 0x00, 0x00, // 262144
1589 0x88, 0x42, 0x52, 0x00, 0x00, // 524288
1590 0x76, 0x85, 0x04, 0x01, 0x00, // 1048576
1591 0x52, 0x71, 0x09, 0x02, 0x00, // 2097152
1592 0x04, 0x43, 0x19, 0x04, 0x00, // 4194304
1593 0x08, 0x86, 0x38, 0x08, 0x00, // 8388608
1594 0x16, 0x72, 0x77, 0x16, 0x00, // 16777216
1595 0x32, 0x44, 0x55, 0x33, 0x00, // 33554432
1596 0x64, 0x88, 0x10, 0x67, 0x00, // 67108864
1597 0x28, 0x77, 0x21, 0x34, 0x01, // 134217728
1598 0x56, 0x54, 0x43, 0x68, 0x02, // 268435456
1599 0x12, 0x09, 0x87, 0x36, 0x05, // 536870912
1600 0x24, 0x18, 0x74, 0x73, 0x10, // 1073741824
1601 0x48, 0x36, 0x48, 0x47, 0x21 // 2147483648
1604 code unsigned char int2bcd[] = {
1605 0x01, 0x00, 0x00, // 1
1606 0x02, 0x00, 0x00, // 2
1607 0x04, 0x00, 0x00, // 4
1608 0x08, 0x00, 0x00, // 8
1609 0x16, 0x00, 0x00, // 16
1610 0x32, 0x00, 0x00, // 32
1611 0x64, 0x00, 0x00, // 64
1612 0x28, 0x01, 0x00, // 128
1613 0x56, 0x02, 0x00, // 256
1614 0x12, 0x05, 0x00, // 512
1615 0x24, 0x10, 0x00, // 1024
1616 0x48, 0x20, 0x00, // 2048
1617 0x96, 0x40, 0x00, // 4096
1618 0x92, 0x81, 0x00, // 8192
1619 0x84, 0x63, 0x01, // 16384
1620 0x68, 0x27, 0x03 // 32768
1624 #endif // not FAST_INTEGER
1630 #ifndef FLOAT_FIXED4
1634 * for ($i=0, $f=0.5; $i<24; $i++) {
1635 * $r = sprintf "%.8f", $f;
1636 * $r =~ /0\.([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1637 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d", $4, $3, $2, $1;
1638 * print ',' if $i < 23;
1640 * printf "\t\t// %.15f %.8f\n", $f, $sum;
1645 code unsigned char frac2bcd[] = {
1646 0x00, 0x00, 0x00, 0x50, // 0.500000000000000 0.50000000
1647 0x00, 0x00, 0x00, 0x25, // 0.250000000000000 0.75000000
1648 0x00, 0x00, 0x50, 0x12, // 0.125000000000000 0.87500000
1649 0x00, 0x00, 0x25, 0x06, // 0.062500000000000 0.93750000
1650 0x00, 0x50, 0x12, 0x03, // 0.031250000000000 0.96875000
1651 0x00, 0x25, 0x56, 0x01, // 0.015625000000000 0.98437500
1652 0x50, 0x12, 0x78, 0x00, // 0.007812500000000 0.99218750
1653 0x25, 0x06, 0x39, 0x00, // 0.003906250000000 0.99609375
1654 0x12, 0x53, 0x19, 0x00, // 0.001953125000000 0.99804687
1655 0x56, 0x76, 0x09, 0x00, // 0.000976562500000 0.99902343
1656 0x28, 0x88, 0x04, 0x00, // 0.000488281250000 0.99951171
1657 0x14, 0x44, 0x02, 0x00, // 0.000244140625000 0.99975585
1658 0x07, 0x22, 0x01, 0x00, // 0.000122070312500 0.99987792
1659 0x04, 0x61, 0x00, 0x00, // 0.000061035156250 0.99993896
1660 0x52, 0x30, 0x00, 0x00, // 0.000030517578125 0.99996948
1661 0x26, 0x15, 0x00, 0x00, // 0.000015258789062 0.99998474
1662 0x63, 0x07, 0x00, 0x00, // 0.000007629394531 0.99999237
1663 0x81, 0x03, 0x00, 0x00, // 0.000003814697266 0.99999618
1664 0x91, 0x01, 0x00, 0x00, // 0.000001907348633 0.99999809
1665 0x95, 0x00, 0x00, 0x00, // 0.000000953674316 0.99999904
1666 0x48, 0x00, 0x00, 0x00, // 0.000000476837158 0.99999952
1667 0x24, 0x00, 0x00, 0x00, // 0.000000238418579 0.99999976
1668 0x12, 0x00, 0x00, 0x00, // 0.000000119209290 0.99999988
1669 0x06, 0x00, 0x00, 0x00, // 0.000000059604645 0.99999994
1670 0x03, 0x00, 0x00, 0x00, // 0.000000029802322 0.99999997
1671 0x01, 0x00, 0x00, 0x00, // 0.000000014901161 0.99999998
1672 0x01, 0x00, 0x00, 0x00 // 0.000000007450581 0.99999999
1675 #ifndef FLOAT_DEFAULT_FRAC_DIGITS
1676 // TODO: Perhaps these should be tweaked a bit to take round up
1677 // effects into account... or maybe give more default digits??
1679 // 0.0001 - 0.0009999 7
1680 // 0.001 - 0.009999 6 0.001 = 0x3A83126F 3A83
1681 // 0.01 - 0.09999 5 0.01 = 0x3C23D70A 3C23
1682 // 0.1 - 9.9999 4 0.1 = 0x3DCCCCCD, 3DCC
1683 // 10.0 - 99.99 3 10.0 = 0x41200000 4120
1684 // 100.0 - 999.99 2 100.0 = 0x42C80000 42C8
1685 // 1000 - 9999.9 1 1000 = 0x447A0000 447A
1686 // 10000+ 0 10000 = 0x461C4000 461C
1687 code unsigned int float_range_table[] = {
1698 #else // using FLOAT_FIXED4
1702 * for ($i=0, $f=0.5; $i<14; $i++) {
1703 * $r = sprintf "%.4f", $f;
1704 * $r =~ /0\.([0-9][0-9])([0-9][0-9])/;
1705 * printf "0x%02d, 0x%02d", $2, $1;
1706 * print ',' if $i < 13;
1708 * printf "\t\t// %.15f %.4f\n", $f, $sum;
1713 code unsigned char frac2bcd[] = {
1714 0x00, 0x50, // 0.500000000000000 0.5000
1715 0x00, 0x25, // 0.250000000000000 0.7500
1716 0x50, 0x12, // 0.125000000000000 0.8750
1717 0x25, 0x06, // 0.062500000000000 0.9375
1718 0x12, 0x03, // 0.031250000000000 0.9687
1719 0x56, 0x01, // 0.015625000000000 0.9843
1720 0x78, 0x00, // 0.007812500000000 0.9921
1721 0x39, 0x00, // 0.003906250000000 0.9960
1722 0x20, 0x00, // 0.001953125000000 0.9980
1723 0x10, 0x00, // 0.000976562500000 0.9990
1724 0x05, 0x00, // 0.000488281250000 0.9995
1725 0x02, 0x00, // 0.000244140625000 0.9997
1726 0x01, 0x00, // 0.000122070312500 0.9998
1727 0x01, 0x00 // 0.000061035156250 0.9999
1730 #endif // FLOAT_FIXED4