1 /*-------------------------------------------------------------------------
2 printf_fast.c - Fast printf routine for use with sdcc/mcs51
4 Copyright (C) 2004, Paul Stoffregen, paul@pjrc.com
6 This library is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this library; see the file COPYING. If not, write to the
18 Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
21 As a special exception, if you link this library with other files,
22 some of which are compiled with SDCC, to produce an executable,
23 this library does not by itself cause the resulting executable to
24 be covered by the GNU General Public License. This exception does
25 not however invalidate any other reasons why the executable file
26 might be covered by the GNU General Public License.
27 -------------------------------------------------------------------------*/
29 /******************************************************************/
31 /** Major features. These determine what capabilities your **/
32 /** compiled printf_fast will have. **/
34 /******************************************************************/
36 // Include support for 32 bit base 10 integers (%ld and %lu). Without
37 // this, you won't be able to print 32 bit integers as base 10. They
38 // will appear in hexadecimal.
41 // Include support for floating point numbers (%f). Don't forget to
42 // enable LONG above, if you want to print floats greater than
43 // 65535.997. You can have 6 good digits after the decimal point,
44 // or an 8th if a small error is ok. +/- 2^32 to 1/10^8 isn't the
45 // full dynamic range of 32 bit floats, but it covers the most
46 // commonly used range. Adds about 500-600 bytes of code.
49 // Include support for minimum field widths (%8d, %20s, %12.5f)
52 // Include fast integer conversion. Without this, a compact but slower
53 // algorithm is used to convert integers (%d, %u, int part of %f).
54 // Even the slow algorithm is much faster than a typical C implementation
55 // based on repetitive division by 10. If you enable this, you get an
56 // extremely fast version (only 8 table lookups and 8 adds to convert a
57 // 32 bit integer), but it costs extra code space for larger lookup
58 // tables and optimized non-looping code.
62 /******************************************************************/
64 /** Minor tweaks. These provide small code savings, with **/
65 /** a partial loss of functionality. **/
67 /******************************************************************/
70 // If you enabled FLOAT, enabling this replaces the normal %f float
71 // output with a very compact version that always prints 4 fractional
72 // digits and does not have round off. Zero will print as "0.0000",
73 // and 1.999997 will print as "1.9999" (not rounded up to 2). The
74 // 4th digit is not accurate (+/- 2). This simpler version also
75 // avoids using 5 bytes of internal data memory. Code size is about
77 //#define FLOAT_FIXED4
79 // If you used FLOAT (not FLOAT_FIXED4), this will remove the smart
80 // default number of digits code. When you use "%f" without a field
81 // width, normally the smart default width code chooses a good number
82 // of digits based on size of the number. If you enabled FIELD_WIDTH
83 // and use a number, like "%.5f", this smart default code is never
84 // used anyway. Saves about 40 bytes of code.
85 //#define FLOAT_DEFAULT_FRAC_DIGITS 6
87 // If you used FLOAT (not FLOAT_FIXED4) and you do not specify a
88 // field width, normally trailing zeros are trimmed. Using this
89 // removes that feature (saves only a few bytes).
90 //#define DO_NOT_TRIM_TRAILING_ZEROS
92 // Omit saving and restoring registers when calling putchar(). If you
93 // are desperate for a little more code space, this will give you a
94 // small savings. You MUST define putchar() with #pragma callee_saves,
95 // or implement it in assembly and avoid changing the registers.
96 //#define PUTCHAR_CALLEE_SAVES
99 /* extern void putchar(char ); */
101 // Warning: using static/global variables makes these functions NON-reentrant!
102 // reentrant keyword is only used for parameter passing method
104 static __bit long_flag
, short_flag
, print_zero_flag
, negative_flag
;
107 static __bit field_width_flag
;
108 static __bit leading_zero_flag
;
109 static __data
unsigned char field_width
;
113 #define __SDCC_FLOAT_LIB
115 static __bit continue_float
;
117 static __data
unsigned char frac_field_width
;
118 static __data
unsigned char float_frac_bcd
[4];
119 // TODO: can float_frac_bcd be overlaid with temps used by trig functions
125 static __data
unsigned int i2bcd_tmp
; // slow 32 int conversion needs temp space
131 #define PRINTF_FAST printf_fast
135 #if !defined(__SDCC_mcs51) || defined(__SDCC_USE_XSTACK) || defined(_SDCC_NO_ASM_LIB_FUNCS)
136 // Does printf_fast really work on ds390 and ds400?
137 // If it does, enable them in the line above
138 #if defined(__SDCC_USE_XSTACK)
139 #warning "printf_fast not built, does not support --xstack"
140 #elif defined(_SDCC_NO_ASM_LIB_FUNCS)
141 #warning "printf_fast not built, _SDCC_NO_ASM_LIB_FUNCS defined"
143 #else // defines are compatible with printf_fast
146 void PRINTF_FAST(__code
const char *fmt
, ...) __reentrant
148 fmt
; /* suppress unreferenced variable warning */
153 mov a
, _bp
// r0 will point to va_args (stack)
155 mov r0
, a
// r0 points to MSB of fmt
158 mov dpl
, @r0
// dptr has address of fmt
163 movc a
, @a
+dptr
// get next byte of fmt string
165 //cjne a, #'%', printf_normal
166 cjne a
, #37, printf_normal
174 clr _field_width_flag
175 clr _leading_zero_flag
176 mov r1
, #_field_width
185 movc a
, @a
+dptr
// get next byte of data format
188 /* parse and consume the field width digits, even if */
189 /* we don't build the code to make use of them */
197 cjne a
, _field_width
, printf_digit_2
198 setb _leading_zero_flag
200 setb _field_width_flag
208 sjmp printf_format_loop
215 //cjne a, #'l', printf_format_h
216 cjne a
, #108, printf_format_h
218 sjmp printf_format_loop
221 //cjne a, #'h', printf_format_s
222 cjne a
, #104, printf_format_s
224 sjmp printf_format_loop
227 //cjne a, #'s', printf_format_d
228 cjne a
, #115, printf_format_d
232 //cjne a, #'d', printf_format_u
233 cjne a
, #100, printf_format_u
238 //cjne a, #'u', printf_format_c
239 cjne a
, #117, printf_format_c
244 //cjne a, #'c', printf_format_x
245 cjne a
, #99, printf_format_x
247 mov a
, @r0
// Acc has the character to print
252 //cjne a, #'x', printf_format_f
253 cjne a
, #120, printf_format_f
258 //cjne a, #'f', printf_format_dot
259 cjne a
, #102, printf_format_dot
264 //cjne a, #'.', printf_normal
265 cjne a
, #46, printf_normal
268 mov r1
, #ar3 // parse frac field, but discard if FIXED4
270 mov r1
, #_frac_field_width
274 sjmp printf_format_loop
280 ljmp printf_main_loop
286 /* print a string... just grab each byte with __gptrget */
287 /* the user much pass a 24 bit generic pointer */
290 push dph
// save addr in fmt onto stack
292 mov b
, @r0
// b has type of address (generic *)
296 mov dpl
, @r0
// dptr has address of user's string
300 jnb _field_width_flag
, printf_str_loop
301 clr _leading_zero_flag
// never leading zeros for strings
310 jnz printf_str_fw_loop
315 #endif // FIELD_WIDTH
324 pop dpl
// restore addr within fmt
326 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 /* never use the "just print zero" shortcut if we're printing */
429 /* the integer part of a float (fixes bug 1255403) */
430 jb _continue_float
, printf_uint_begin
433 jnb _field_width_flag
, printf_uint_zero
443 ljmp printf_main_loop
448 lcall printf_int2bcd
// bcd number in r3/r2/r7/r6/r5
452 jnb _field_width_flag
, printf_uifw_end
456 jnb _long_flag
, printf_uifw_16
479 jb _short_flag
, printf_uifw_8
498 //r1 has the number of digits for the number
500 mov c
, _negative_flag
505 #ifndef PUTCHAR_CALLEE_SAVES
515 #ifndef PUTCHAR_CALLEE_SAVES
527 #endif // FIELD_WIDTH
531 jnb _negative_flag
, printf_uint_pos
532 #ifdef PUTCHAR_CALLEE_SAVES
554 #endif // PUTCHAR_CALLEE_SAVES
557 jb _short_flag
, printf_uint8
559 jnb _long_flag
, printf_uint16
567 lcall printf_phex_msn
569 lcall printf_phex_lsn
571 lcall printf_phex_msn
573 lcall printf_phex_lsn
576 lcall printf_phex_msn
588 lcall printf_phex_lsn
590 lcall printf_phex_msn
598 lcall printf_phex_lsn
600 lcall printf_phex_msn
602 lcall printf_phex_lsn
607 jnb _continue_float
, 0002$
611 ljmp printf_main_loop
616 // Print a float the easy way. First, extract the integer part and
617 // use the integer printing code. Then extract the fractional part,
618 // convert each bit to 4 digit BCD, and print the BCD sum. Absolutely
619 // no field width control, always 4 digits printed past the decimal
620 // point. No round off. 1.9999987 prints as 1.9999, not 2.0000.
623 jnb _field_width_flag
, print_float_begin
631 push ar0
// keep r0 safe, will need it again
632 lcall printf_get_float
634 mov a
, #158 // check for large float we can't print
636 jnc print_float_size_ok
637 printf_float_too_big
:
638 // TODO: should print some sort of overflow error??
640 ljmp printf_format_loop
649 jnz printf_float_too_big
651 lcall printf_uint
// print the integer portion
655 // now that the integer part is printed, we need to refetch the
656 // float from the va_args and extract the fractional part
658 lcall printf_get_float
663 cjne a
, #126, print_float_frac_lshift
664 sjmp print_float_frac
// input between 0.5 to 0.9999
665 print_float_frac_lshift
:
666 jc print_float_frac_rshift
667 //Acc (exponent) is greater than 126 (input >= 1.0)
670 print_float_lshift_loop
:
681 djnz r5
, print_float_lshift_loop
682 sjmp print_float_frac
683 print_float_frac_rshift
:
684 //Acc (exponent) is less than 126 (input < 0.5)
689 // now we've got the fractional part, so now is the time to
690 // convert to BCD... just convert each bit to BCD using a
691 // lookup table and BCD sum them together
696 mov dptr
, #_frac2bcd // FLOAT_FIXED4 version (14 entries)
697 print_float_frac_loop
:
704 jnc print_float_frac_skip
715 print_float_frac_skip
:
718 djnz r7
, print_float_frac_loop
719 // the BCD sum is in dptr, so all we've got to do is output
720 // all 4 digits. No trailing zero suppression, no nice round
721 // off (impossible to change the integer part since we already
725 setb _print_zero_flag
727 lcall printf_phex_msn
729 lcall printf_phex_lsn
731 lcall printf_phex_msn
733 lcall printf_phex_lsn
737 ljmp printf_main_loop
739 #else // not FLOAT_FIXED4
743 // Print a float the not-as-easy way, with a configurable number of
744 // fractional digits (up to 8) and proper round-off (up to 7 digits).
745 // First, extract the fractional part, convert to BCD, and then add
746 // the scaled round-off. Store the rounded fractional digits and
747 // their carry. Then extract the integer portion, increment it if
748 // the rounding caused a carry. Use the integer printing to output
749 // the integer, and then output the stored fractional digits. This
750 // approach requires 5 bytes of internal RAM to store the 8 fractional
751 // digits and the number of them we'll actually print. This code is
752 // a couple hundred bytes larger and a bit slower than the FIXED4
753 // version, but it gives very nice results.
756 jnb _field_width_flag
, print_float_default_width
757 // The caller specified exact field width, so use it. Need to
758 // convert the whole float digits into the integer portion only.
761 subb a
, _frac_field_width
763 jnc print_float_begin
765 sjmp print_float_begin
767 print_float_default_width
:
768 // The caller didn't specify field width (or FIELD_WIDTH is
769 // not defined so it's ignored). We've still got to know
770 // how many fractional digits are going to print, so we can
771 // round off properly.
772 #ifdef FLOAT_DEFAULT_FRAC_DIGITS
773 mov _frac_field_width
, #FLOAT_DEFAULT_FRAC_DIGITS
775 // default fractional field width (between 0 to 7)
776 // attempt to scale the default number of fractional digits
777 // based on the magnitude of the float
779 anl a
, #0x7F // ignore sign bit
780 mov r2
, a
// r2 is first byte of float
782 mov ar3
, @r0
// r3 is second byte of float
786 mov dptr
, #_float_range_table
788 print_float_default_loop
:
796 jnc print_float_default_done
798 djnz r5
, print_float_default_loop
799 print_float_default_done
:
800 mov _frac_field_width
, r5
803 #endif // not FLOAT_DEFAULT_FRAC_DIGITS
806 push ar0
// keep r0 safe, will need it again
807 lcall printf_get_float
811 cjne a
, #126, print_float_frac_lshift
812 sjmp print_float_frac
// input between 0.5 to 0.9999
814 print_float_frac_lshift
:
815 jc print_float_frac_rshift
816 //Acc (exponent) is greater than 126 (input >= 1.0)
819 print_float_lshift_loop
:
830 djnz r5
, print_float_lshift_loop
831 sjmp print_float_frac
832 print_float_frac_rshift
:
833 //Acc (exponent) is less than 126 (input < 0.5)
838 // Convert the fraction in r4/r3/r2/r1 into 8 BCD digits in r0/r7/r6/r5
845 mov dptr
, #_frac2bcd // FLOAT version (27 entries)
846 print_float_frac_loop
:
859 jnc print_float_frac_skip
880 print_float_frac_skip
:
885 djnz b
, print_float_frac_loop
886 print_float_frac_roundoff
:
887 // Now it's time to round-off the BCD digits to the desired precision.
889 mov r4
, #0x50 // r4/r3/r2/r1 = 0.5 (bcd rounding)
893 mov a
, _frac_field_width
897 mov dph
, r0
// fs_rshift_a will overwrite r0 & dpl
898 lcall fs_rshift_a
// divide r4/r3/r2/r1 by 10^frac_field_width
900 add a
, r1
// add rounding to fractional part
902 mov _float_frac_bcd
+3, a
// and store it for later use
906 mov _float_frac_bcd
+2, a
910 mov _float_frac_bcd
+1, a
914 mov _float_frac_bcd
+0, a
915 mov sign_b
, c
// keep fractional carry in sign_b
919 // Time to work on the integer portion... fetch the float again, check
920 // size (exponent), scale to integer, add the fraction's carry, and
921 // let the integer printing code do all the work.
923 lcall printf_get_float
926 mov a
, #158 // check for large float we can't print
928 jnc print_float_size_ok
929 printf_float_too_big
:
930 // TODO: should print some sort of overflow error??
932 ljmp printf_format_loop
937 jnb sign_b
, print_float_do_int
938 // if we get here, the fractional round off caused the
939 // integer part to increment. Add 1 for a proper result
954 jc printf_float_too_big
959 jnz printf_float_too_big
962 lcall printf_uint
// print the integer portion
965 print_float_frac_width
:
966 // Now all we have to do is output the fractional digits that
967 // were previous computed and stored in memory.
969 jb _field_width_flag
, print_float_do_frac
971 #ifndef DO_NOT_TRIM_TRAILING_ZEROS
972 // if the user did not explicitly set a
973 // field width, trim off trailing zeros
974 print_float_frac_trim
:
975 mov a
, _frac_field_width
976 jz print_float_do_frac
977 lcall get_float_frac_digit
978 jnz print_float_do_frac
979 djnz _frac_field_width
, print_float_frac_trim
983 mov a
, _frac_field_width
989 setb _print_zero_flag
990 print_float_do_frac_loop
:
993 lcall get_float_frac_digit
994 lcall printf_phex_lsn
996 cjne a
, _frac_field_width
, print_float_do_frac_loop
1000 ljmp printf_main_loop
1003 // acc=1 for tenths, acc=2 for hundredths, etc
1004 get_float_frac_digit
:
1009 add a
, #_float_frac_bcd
1012 jb psw
.5, get_float_frac_digit_done
1014 get_float_frac_digit_done
:
1018 #endif // end of normal FLOAT code (not FLOAT_FIXED4)
1021 // These helper functions are used, regardless of which type of
1022 // FLOAT code is used.
1027 lcall pm2_entry_phex
1029 lcall pm2_entry_cout
1032 lcall pm2_entry_cout
1036 // Fetch a float from the va_args and put it into
1037 // r7(exp) r4/r3/r2(mant) and also clear r1 and preset
1049 mov _negative_flag
, c
1051 jz printf_get_float_2
1067 /* read an integer into r1/r2/r3/r4, and msb into r5 */
1073 jb _short_flag
, printf_get_done
1078 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
1385 jnb _leading_zero_flag
, printf_space_output
1388 printf_space_output
:
1389 lcall printf_putchar
1393 jnz printf_space_loop
1397 /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
1404 jnb _print_zero_flag
, printf_ret
1406 setb _print_zero_flag
1412 #ifdef PUTCHAR_CALLEE_SAVES
1432 /* print a zero if all the calls to print the digits ended up */
1433 /* being leading zeros */
1436 jb _print_zero_flag
, printf_ret
1449 * for ($d=0; $d < 8; $d++) {
1451 * for ($p=0; $p < 5; $p++) {
1452 * last unless (((16 ** $d) * 15) / (10 ** ($p * 2))) % 100;
1453 * printf "code unsigned char int2bcd_%d_%d[15] = {", $d, $p;
1454 * for ($i=0; $i < 16; $i++) {
1456 * (((16 ** $d) * $i) / (10 ** ($p * 2))) % 100;
1457 * print ", " if $i < 15;
1465 static __code
unsigned char int2bcd_0
[] = {
1466 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1467 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1469 static __code
unsigned char int2bcd_1
[] = {
1470 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1471 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1472 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1473 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02};
1476 static __code
unsigned char int2bcd_2
[] = {
1477 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1478 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1479 0x00, 0x02, 0x05, 0x07, 0x10, 0x12, 0x15, 0x17,
1480 0x20, 0x23, 0x25, 0x28, 0x30, 0x33, 0x35, 0x38};
1482 static __code
unsigned char int2bcd_3
[] = {
1483 0x00, 0x96, 0x92, 0x88, 0x84, 0x80, 0x76, 0x72,
1484 0x68, 0x64, 0x60, 0x56, 0x52, 0x48, 0x44, 0x40,
1485 0x00, 0x40, 0x81, 0x22, 0x63, 0x04, 0x45, 0x86,
1486 0x27, 0x68, 0x09, 0x50, 0x91, 0x32, 0x73, 0x14,
1487 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02,
1488 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06};
1491 static __code
unsigned char int2bcd_4
[] = {
1492 0x00, 0x36, 0x72, 0x08, 0x44, 0x80, 0x16, 0x52,
1493 0x88, 0x24, 0x60, 0x96, 0x32, 0x68, 0x04, 0x40,
1494 0x00, 0x55, 0x10, 0x66, 0x21, 0x76, 0x32, 0x87,
1495 0x42, 0x98, 0x53, 0x08, 0x64, 0x19, 0x75, 0x30,
1496 0x00, 0x06, 0x13, 0x19, 0x26, 0x32, 0x39, 0x45,
1497 0x52, 0x58, 0x65, 0x72, 0x78, 0x85, 0x91, 0x98};
1499 static __code
unsigned char int2bcd_5
[] = {
1500 0x00, 0x76, 0x52, 0x28, 0x04, 0x80, 0x56, 0x32,
1501 0x08, 0x84, 0x60, 0x36, 0x12, 0x88, 0x64, 0x40,
1502 0x00, 0x85, 0x71, 0x57, 0x43, 0x28, 0x14, 0x00,
1503 0x86, 0x71, 0x57, 0x43, 0x29, 0x14, 0x00, 0x86,
1504 0x00, 0x04, 0x09, 0x14, 0x19, 0x24, 0x29, 0x34,
1505 0x38, 0x43, 0x48, 0x53, 0x58, 0x63, 0x68, 0x72,
1506 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1507 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
1509 static __code
unsigned char int2bcd_6
[] = {
1510 0x00, 0x16, 0x32, 0x48, 0x64, 0x80, 0x96, 0x12,
1511 0x28, 0x44, 0x60, 0x76, 0x92, 0x08, 0x24, 0x40,
1512 0x00, 0x72, 0x44, 0x16, 0x88, 0x60, 0x32, 0x05,
1513 0x77, 0x49, 0x21, 0x93, 0x65, 0x38, 0x10, 0x82,
1514 0x00, 0x77, 0x55, 0x33, 0x10, 0x88, 0x66, 0x44,
1515 0x21, 0x99, 0x77, 0x54, 0x32, 0x10, 0x88, 0x65,
1516 0x00, 0x16, 0x33, 0x50, 0x67, 0x83, 0x00, 0x17,
1517 0x34, 0x50, 0x67, 0x84, 0x01, 0x18, 0x34, 0x51,
1518 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
1519 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02};
1521 static __code
unsigned char int2bcd_7
[] = {
1522 0x00, 0x56, 0x12, 0x68, 0x24, 0x80, 0x36, 0x92,
1523 0x48, 0x04, 0x60, 0x16, 0x72, 0x28, 0x84, 0x40,
1524 0x00, 0x54, 0x09, 0x63, 0x18, 0x72, 0x27, 0x81,
1525 0x36, 0x91, 0x45, 0x00, 0x54, 0x09, 0x63, 0x18,
1526 0x00, 0x43, 0x87, 0x30, 0x74, 0x17, 0x61, 0x04,
1527 0x48, 0x91, 0x35, 0x79, 0x22, 0x66, 0x09, 0x53,
1528 0x00, 0x68, 0x36, 0x05, 0x73, 0x42, 0x10, 0x79,
1529 0x47, 0x15, 0x84, 0x52, 0x21, 0x89, 0x58, 0x26,
1530 0x00, 0x02, 0x05, 0x08, 0x10, 0x13, 0x16, 0x18,
1531 0x21, 0x24, 0x26, 0x29, 0x32, 0x34, 0x37, 0x40};
1534 #else // not FAST_INTEGER
1538 * print "__code unsigned char int2bcd[] = {\n";
1539 * for ($i=0, $n=1; $i<32; $i++, $n*=2) {
1540 * $r = sprintf "%010u", $n;
1541 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1542 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d, 0x%02d", $5, $4, $3, $2, $1;
1543 * print ',' if $i < 31;
1544 * printf "\t\t// %10u\n", $n;
1546 * print "}\n__code unsigned char int2bcd[] = {\n";
1547 * for ($i=0, $n=1; $i<16; $i++, $n*=2) {
1548 * $r = sprintf "%06u", $n;
1549 * $r =~ /([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1550 * printf "0x%02d, 0x%02d, 0x%02d", $3, $2, $1;
1551 * print ',' if $i < 15;
1552 * printf "\t\t// %10u\n", $n;
1558 static __code
unsigned char int2bcd
[] = {
1559 0x01, 0x00, 0x00, 0x00, 0x00, // 1
1560 0x02, 0x00, 0x00, 0x00, 0x00, // 2
1561 0x04, 0x00, 0x00, 0x00, 0x00, // 4
1562 0x08, 0x00, 0x00, 0x00, 0x00, // 8
1563 0x16, 0x00, 0x00, 0x00, 0x00, // 16
1564 0x32, 0x00, 0x00, 0x00, 0x00, // 32
1565 0x64, 0x00, 0x00, 0x00, 0x00, // 64
1566 0x28, 0x01, 0x00, 0x00, 0x00, // 128
1567 0x56, 0x02, 0x00, 0x00, 0x00, // 256
1568 0x12, 0x05, 0x00, 0x00, 0x00, // 512
1569 0x24, 0x10, 0x00, 0x00, 0x00, // 1024
1570 0x48, 0x20, 0x00, 0x00, 0x00, // 2048
1571 0x96, 0x40, 0x00, 0x00, 0x00, // 4096
1572 0x92, 0x81, 0x00, 0x00, 0x00, // 8192
1573 0x84, 0x63, 0x01, 0x00, 0x00, // 16384
1574 0x68, 0x27, 0x03, 0x00, 0x00, // 32768
1575 0x36, 0x55, 0x06, 0x00, 0x00, // 65536
1576 0x72, 0x10, 0x13, 0x00, 0x00, // 131072
1577 0x44, 0x21, 0x26, 0x00, 0x00, // 262144
1578 0x88, 0x42, 0x52, 0x00, 0x00, // 524288
1579 0x76, 0x85, 0x04, 0x01, 0x00, // 1048576
1580 0x52, 0x71, 0x09, 0x02, 0x00, // 2097152
1581 0x04, 0x43, 0x19, 0x04, 0x00, // 4194304
1582 0x08, 0x86, 0x38, 0x08, 0x00, // 8388608
1583 0x16, 0x72, 0x77, 0x16, 0x00, // 16777216
1584 0x32, 0x44, 0x55, 0x33, 0x00, // 33554432
1585 0x64, 0x88, 0x10, 0x67, 0x00, // 67108864
1586 0x28, 0x77, 0x21, 0x34, 0x01, // 134217728
1587 0x56, 0x54, 0x43, 0x68, 0x02, // 268435456
1588 0x12, 0x09, 0x87, 0x36, 0x05, // 536870912
1589 0x24, 0x18, 0x74, 0x73, 0x10, // 1073741824
1590 0x48, 0x36, 0x48, 0x47, 0x21 // 2147483648
1593 static __code
unsigned char int2bcd
[] = {
1594 0x01, 0x00, 0x00, // 1
1595 0x02, 0x00, 0x00, // 2
1596 0x04, 0x00, 0x00, // 4
1597 0x08, 0x00, 0x00, // 8
1598 0x16, 0x00, 0x00, // 16
1599 0x32, 0x00, 0x00, // 32
1600 0x64, 0x00, 0x00, // 64
1601 0x28, 0x01, 0x00, // 128
1602 0x56, 0x02, 0x00, // 256
1603 0x12, 0x05, 0x00, // 512
1604 0x24, 0x10, 0x00, // 1024
1605 0x48, 0x20, 0x00, // 2048
1606 0x96, 0x40, 0x00, // 4096
1607 0x92, 0x81, 0x00, // 8192
1608 0x84, 0x63, 0x01, // 16384
1609 0x68, 0x27, 0x03 // 32768
1613 #endif // not FAST_INTEGER
1617 #ifndef FLOAT_FIXED4
1621 * for ($i=0, $f=0.5; $i<24; $i++) {
1622 * $r = sprintf "%.8f", $f;
1623 * $r =~ /0\.([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])/;
1624 * printf "0x%02d, 0x%02d, 0x%02d, 0x%02d", $4, $3, $2, $1;
1625 * print ',' if $i < 23;
1627 * printf "\t\t// %.15f %.8f\n", $f, $sum;
1632 static __code
unsigned char frac2bcd
[] = {
1633 0x00, 0x00, 0x00, 0x50, // 0.500000000000000 0.50000000
1634 0x00, 0x00, 0x00, 0x25, // 0.250000000000000 0.75000000
1635 0x00, 0x00, 0x50, 0x12, // 0.125000000000000 0.87500000
1636 0x00, 0x00, 0x25, 0x06, // 0.062500000000000 0.93750000
1637 0x00, 0x50, 0x12, 0x03, // 0.031250000000000 0.96875000
1638 0x00, 0x25, 0x56, 0x01, // 0.015625000000000 0.98437500
1639 0x50, 0x12, 0x78, 0x00, // 0.007812500000000 0.99218750
1640 0x25, 0x06, 0x39, 0x00, // 0.003906250000000 0.99609375
1641 0x12, 0x53, 0x19, 0x00, // 0.001953125000000 0.99804687
1642 0x56, 0x76, 0x09, 0x00, // 0.000976562500000 0.99902343
1643 0x28, 0x88, 0x04, 0x00, // 0.000488281250000 0.99951171
1644 0x14, 0x44, 0x02, 0x00, // 0.000244140625000 0.99975585
1645 0x07, 0x22, 0x01, 0x00, // 0.000122070312500 0.99987792
1646 0x04, 0x61, 0x00, 0x00, // 0.000061035156250 0.99993896
1647 0x52, 0x30, 0x00, 0x00, // 0.000030517578125 0.99996948
1648 0x26, 0x15, 0x00, 0x00, // 0.000015258789062 0.99998474
1649 0x63, 0x07, 0x00, 0x00, // 0.000007629394531 0.99999237
1650 0x81, 0x03, 0x00, 0x00, // 0.000003814697266 0.99999618
1651 0x91, 0x01, 0x00, 0x00, // 0.000001907348633 0.99999809
1652 0x95, 0x00, 0x00, 0x00, // 0.000000953674316 0.99999904
1653 0x48, 0x00, 0x00, 0x00, // 0.000000476837158 0.99999952
1654 0x24, 0x00, 0x00, 0x00, // 0.000000238418579 0.99999976
1655 0x12, 0x00, 0x00, 0x00, // 0.000000119209290 0.99999988
1656 0x06, 0x00, 0x00, 0x00, // 0.000000059604645 0.99999994
1657 0x03, 0x00, 0x00, 0x00, // 0.000000029802322 0.99999997
1658 0x01, 0x00, 0x00, 0x00, // 0.000000014901161 0.99999998
1659 0x01, 0x00, 0x00, 0x00 // 0.000000007450581 0.99999999
1662 #ifndef FLOAT_DEFAULT_FRAC_DIGITS
1663 // TODO: Perhaps these should be tweaked a bit to take round up
1664 // effects into account... or maybe give more default digits??
1666 // 0.0001 - 0.0009999 7
1667 // 0.001 - 0.009999 6 0.001 = 0x3A83126F 3A83
1668 // 0.01 - 0.09999 5 0.01 = 0x3C23D70A 3C23
1669 // 0.1 - 9.9999 4 0.1 = 0x3DCCCCCD, 3DCC
1670 // 10.0 - 99.99 3 10.0 = 0x41200000 4120
1671 // 100.0 - 999.99 2 100.0 = 0x42C80000 42C8
1672 // 1000 - 9999.9 1 1000 = 0x447A0000 447A
1673 // 10000+ 0 10000 = 0x461C4000 461C
1674 static __code
unsigned int float_range_table
[] = {
1685 #else // using FLOAT_FIXED4
1689 * for ($i=0, $f=0.5; $i<14; $i++) {
1690 * $r = sprintf "%.4f", $f;
1691 * $r =~ /0\.([0-9][0-9])([0-9][0-9])/;
1692 * printf "0x%02d, 0x%02d", $2, $1;
1693 * print ',' if $i < 13;
1695 * printf "\t\t// %.15f %.4f\n", $f, $sum;
1700 static __code
unsigned char frac2bcd
[] = {
1701 0x00, 0x50, // 0.500000000000000 0.5000
1702 0x00, 0x25, // 0.250000000000000 0.7500
1703 0x50, 0x12, // 0.125000000000000 0.8750
1704 0x25, 0x06, // 0.062500000000000 0.9375
1705 0x12, 0x03, // 0.031250000000000 0.9687
1706 0x56, 0x01, // 0.015625000000000 0.9843
1707 0x78, 0x00, // 0.007812500000000 0.9921
1708 0x39, 0x00, // 0.003906250000000 0.9960
1709 0x20, 0x00, // 0.001953125000000 0.9980
1710 0x10, 0x00, // 0.000976562500000 0.9990
1711 0x05, 0x00, // 0.000488281250000 0.9995
1712 0x02, 0x00, // 0.000244140625000 0.9997
1713 0x01, 0x00, // 0.000122070312500 0.9998
1714 0x01, 0x00 // 0.000061035156250 0.9999
1717 #endif // FLOAT_FIXED4
1721 #endif // defines compatible with printf_fast