Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1702 | - | 1 | /* Copyright (c) 2005, Dmitry Xmelkov |
2 | All rights reserved. |
||
3 | |||
4 | Redistribution and use in source and binary forms, with or without |
||
5 | modification, are permitted provided that the following conditions are met: |
||
6 | |||
7 | * Redistributions of source code must retain the above copyright |
||
8 | notice, this list of conditions and the following disclaimer. |
||
9 | * Redistributions in binary form must reproduce the above copyright |
||
10 | notice, this list of conditions and the following disclaimer in |
||
11 | the documentation and/or other materials provided with the |
||
12 | distribution. |
||
13 | * Neither the name of the copyright holders nor the names of |
||
14 | contributors may be used to endorse or promote products derived |
||
15 | from this software without specific prior written permission. |
||
16 | |||
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||
18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
||
21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
||
22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
||
23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||
26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||
27 | POSSIBILITY OF SUCH DAMAGE. */ |
||
28 | |||
29 | /* $Id: ftoa_engine.S,v 1.3 2009/04/01 23:11:00 arcanum Exp $ */ |
||
30 | |||
31 | #ifndef __DOXYGEN__ |
||
32 | |||
33 | #include "macros.inc" |
||
34 | #include "ftoa_engine.h" |
||
35 | |||
36 | #if defined(__AVR_HAVE_LPMX__) && __AVR_HAVE_LPMX__ |
||
37 | # define AVR_ENH_LPM 1 |
||
38 | #else |
||
39 | # define AVR_ENH_LPM 0 |
||
40 | #endif |
||
41 | |||
42 | /* |
||
43 | int __ftoa_engine (double val, char *buf, |
||
44 | unsigned char prec, unsigned char maxdgs) |
||
45 | Input: |
||
46 | val - value to convert |
||
47 | buf - output buffer address |
||
48 | prec - precision: number of decimal digits is 'prec + 1' |
||
49 | maxdgs - (0 if unused) precision restriction for "%f" specification |
||
50 | |||
51 | Output: |
||
52 | return - decimal exponent of first digit |
||
53 | buf[0] - flags (FTOA_***) |
||
54 | buf[1],... - decimal digits |
||
55 | Number of digits: |
||
56 | maxdgs == 0 ? prec+1 : |
||
57 | (buf[0] & FTOA_CARRY) == 0 || buf[1] != '1' ? |
||
58 | aver(1, maxdgs+exp, prec+1) : |
||
59 | aver(1, masdgs+exp-1, prec+1) |
||
60 | |||
61 | Notes: |
||
62 | * Output string is not 0-terminated. For possibility of user's buffer |
||
63 | usage in any case. |
||
64 | * If used, 'maxdgs' is a number of digits for value with zero exponent. |
||
65 | */ |
||
66 | |||
67 | /* Input */ |
||
68 | #define maxdgs r16 |
||
69 | #define prec r18 |
||
70 | #define buf_lo r20 |
||
71 | #define buf_hi r21 |
||
72 | #define val_lo r22 |
||
73 | #define val_hi r23 |
||
74 | #define val_hlo r24 |
||
75 | #define val_hhi r25 |
||
76 | |||
77 | /* Float value parse */ |
||
78 | #define flag r19 |
||
79 | |||
80 | /* Multiplication of mantisses */ |
||
81 | #define exp_sv r17 |
||
82 | #define mlt_1 r19 /* lowest result byte */ |
||
83 | #define mlt_2 r14 |
||
84 | #define mlt_3 r15 |
||
85 | #define mlt_4 r20 |
||
86 | #define mlt_5 r21 |
||
87 | #define mlt_6 r28 |
||
88 | #define mlt_7 r29 |
||
89 | |||
90 | /* Conversion to string */ |
||
91 | #define pwr_2 r1 /* lowest byte of 'powr10' element */ |
||
92 | #define pwr_3 r17 |
||
93 | #define pwr_4 r19 |
||
94 | #define pwr_5 r22 |
||
95 | #define pwr_6 r25 |
||
96 | #define pwr_7 r0 |
||
97 | #define digit r23 |
||
98 | #define exp10 r24 |
||
99 | |||
100 | /* Fixed */ |
||
101 | #define zero r1 |
||
102 | |||
103 | /* ASSEMBLY_CLIB_SECTION */ |
||
104 | |||
105 | .global __ftoa_engine |
||
106 | .type __ftoa_engine, "function" |
||
107 | __ftoa_engine: |
||
108 | |||
109 | /* -------------------------------------------------------------------- |
||
110 | Float value parse. |
||
111 | */ |
||
112 | ; limit 'prec' |
||
113 | cpi prec, 8 |
||
114 | brlo 1f |
||
115 | ldi prec, 7 |
||
116 | 1: |
||
117 | ; init. |
||
118 | clr flag |
||
119 | X_movw XL, buf_lo |
||
120 | ; val_hhi := exponent, sign test and remove |
||
121 | #if FTOA_MINUS != 1 |
||
122 | # error FTOA_MINUS must be 1: add with carry used |
||
123 | #endif |
||
124 | lsl val_hhi |
||
125 | adc flag, zero ; FTOA_MINUS |
||
126 | sbrc val_hlo, 7 |
||
127 | ori val_hhi, 1 |
||
128 | ; zero test |
||
129 | adiw val_hlo, 0 |
||
130 | cpc val_lo, zero |
||
131 | cpc val_hi, zero |
||
132 | brne 3f |
||
133 | ; return 0 |
||
134 | ori flag, FTOA_ZERO |
||
135 | subi prec, -2 |
||
136 | 2: st X+, flag |
||
137 | ldi flag, '0' |
||
138 | dec prec |
||
139 | brne 2b |
||
140 | ret ; r24,r25 == 0 |
||
141 | 3: |
||
142 | ; infinity, NaN ? |
||
143 | #if FTOA_NAN != 2 * FTOA_INF |
||
144 | # error Must: FTOA_NAN == 2*FTOA_INF: 'rjmp' is absent |
||
145 | #endif |
||
146 | cpi val_hhi, 0xff |
||
147 | brlo 6f |
||
148 | cpi val_hlo, 0x80 |
||
149 | cpc val_hi, zero |
||
150 | cpc val_lo, zero |
||
151 | breq 5f |
||
152 | subi flag, -FTOA_INF ; FTOA_NAN |
||
153 | 5: subi flag, -FTOA_INF |
||
154 | 6: |
||
155 | ; write flags byte |
||
156 | st X+, flag |
||
157 | ; hidden bit |
||
158 | cpi val_hhi, 1 |
||
159 | brlo 7f ; if subnormal value |
||
160 | ori val_hlo, 0x80 |
||
161 | 7: adc val_hhi, zero |
||
162 | ; pushes |
||
163 | push r29 |
||
164 | push r28 |
||
165 | push r17 |
||
166 | push r16 |
||
167 | push r15 |
||
168 | push r14 |
||
169 | |||
170 | /* -------------------------------------------------------------------- |
||
171 | Multiplication of mantisses (val and table). |
||
172 | At the begin: |
||
173 | val_hlo .. val_lo - input value mantisse |
||
174 | val_hhi - input value exponent |
||
175 | X - second byte address (string begin) |
||
176 | At the end: |
||
177 | mlt_7 .. mlt_2 - multiplication result |
||
178 | exp10 - decimal exponent |
||
179 | */ |
||
180 | |||
181 | ; save |
||
182 | mov exp_sv, val_hhi |
||
183 | ; Z := & base10[exp / 8] (sizeof(base10[0]) == 5) |
||
184 | andi val_hhi, ~7 |
||
185 | lsr val_hhi ; (exp/8) * 4 |
||
186 | mov ZL, val_hhi |
||
187 | lsr val_hhi |
||
188 | lsr val_hhi ; exp/8 |
||
189 | add ZL, val_hhi ; (exp/8) * 5 |
||
190 | clr ZH |
||
191 | subi ZL, lo8(-(.L_base10)) |
||
192 | sbci ZH, hi8(-(.L_base10)) |
||
193 | ; highest mantissa byte (mult. shifting prepare) |
||
194 | clr val_hhi |
||
195 | ; result initializ. |
||
196 | clr mlt_1 |
||
197 | clr mlt_2 |
||
198 | clr mlt_3 |
||
199 | X_movw mlt_4, mlt_2 |
||
200 | X_movw mlt_6, mlt_2 |
||
201 | |||
202 | ; multiply to 1-st table byte |
||
203 | #if AVR_ENH_LPM |
||
204 | lpm r0, Z+ |
||
205 | #else |
||
206 | lpm |
||
207 | adiw ZL, 1 |
||
208 | #endif |
||
209 | sec ; for loop end control |
||
210 | ror r0 |
||
211 | ; addition |
||
212 | 10: brcc 11f |
||
213 | add mlt_1, val_lo |
||
214 | adc mlt_2, val_hi |
||
215 | adc mlt_3, val_hlo |
||
216 | adc mlt_4, val_hhi |
||
217 | adc mlt_5, zero |
||
218 | ; arg shift |
||
219 | 11: lsl val_lo |
||
220 | rol val_hi |
||
221 | rol val_hlo |
||
222 | rol val_hhi |
||
223 | ; next bit |
||
224 | lsr r0 |
||
225 | brne 10b |
||
226 | |||
227 | ; second table byte |
||
228 | #if AVR_ENH_LPM |
||
229 | lpm r0, Z+ ; C flag is stay 1 |
||
230 | #else |
||
231 | lpm |
||
232 | adiw ZL, 1 |
||
233 | sec |
||
234 | #endif |
||
235 | ror r0 |
||
236 | ; addition |
||
237 | 12: brcc 13f |
||
238 | add mlt_2, val_hi ; val_hi is the least byte now |
||
239 | adc mlt_3, val_hlo |
||
240 | adc mlt_4, val_hhi |
||
241 | adc mlt_5, val_lo |
||
242 | adc mlt_6, zero |
||
243 | ; arg shift |
||
244 | 13: lsl val_hi |
||
245 | rol val_hlo |
||
246 | rol val_hhi |
||
247 | rol val_lo |
||
248 | ; next bit |
||
249 | lsr r0 |
||
250 | brne 12b |
||
251 | |||
252 | ; 3-t table byte |
||
253 | #if AVR_ENH_LPM |
||
254 | lpm r0, Z+ ; C flag is stay 1 |
||
255 | #else |
||
256 | lpm |
||
257 | adiw ZL, 1 |
||
258 | sec |
||
259 | #endif |
||
260 | ror r0 |
||
261 | ; addition |
||
262 | 14: brcc 15f |
||
263 | add mlt_3, val_hlo ; val_hlo is the least byte now |
||
264 | adc mlt_4, val_hhi |
||
265 | adc mlt_5, val_lo |
||
266 | adc mlt_6, val_hi |
||
267 | adc mlt_7, zero |
||
268 | ; arg shift |
||
269 | 15: lsl val_hlo |
||
270 | rol val_hhi |
||
271 | rol val_lo |
||
272 | rol val_hi |
||
273 | ; next bit |
||
274 | lsr r0 |
||
275 | brne 14b |
||
276 | |||
277 | ; 4-t table byte |
||
278 | #if AVR_ENH_LPM |
||
279 | lpm r0, Z+ ; C flag is stay 1 |
||
280 | #else |
||
281 | lpm |
||
282 | #endif |
||
283 | ror r0 |
||
284 | ; addition |
||
285 | 16: brcc 17f |
||
286 | add mlt_4, val_hhi ; val_hhi is the least byte now |
||
287 | adc mlt_5, val_lo |
||
288 | adc mlt_6, val_hi |
||
289 | adc mlt_7, val_hlo |
||
290 | ; arg shift |
||
291 | 17: lsl val_hhi |
||
292 | rol val_lo |
||
293 | rol val_hi |
||
294 | rol val_hlo |
||
295 | ; next bit |
||
296 | lsr r0 |
||
297 | brne 16b |
||
298 | |||
299 | ; decimal exponent |
||
300 | #if AVR_ENH_LPM |
||
301 | lpm exp10, Z |
||
302 | #else |
||
303 | adiw ZL, 1 |
||
304 | lpm |
||
305 | mov exp10, r0 |
||
306 | #endif |
||
307 | |||
308 | ; result shift: mlt_7..2 >>= (~exp & 7) |
||
309 | com exp_sv |
||
310 | andi exp_sv, 7 |
||
311 | breq 19f |
||
312 | 18: lsr mlt_7 |
||
313 | ror mlt_6 |
||
314 | ror mlt_5 |
||
315 | ror mlt_4 |
||
316 | ror mlt_3 |
||
317 | ror mlt_2 |
||
318 | dec exp_sv |
||
319 | brne 18b |
||
320 | 19: |
||
321 | |||
322 | /* -------------------------------------------------------------------- |
||
323 | Conversion to string. |
||
324 | |||
325 | Registers usage: |
||
326 | mlt_7 .. mlt_2 - new mantissa (multiplication result) |
||
327 | pwr_7 .. pwr_2 - 'powr10' table element |
||
328 | Z - 'powr10' table pointer |
||
329 | X - output string pointer |
||
330 | maxdgs - number of digits |
||
331 | prec - number of digits stays to output |
||
332 | exp10 - decimal exponent |
||
333 | digit - conversion process |
||
334 | |||
335 | At the end: |
||
336 | X - end of buffer (nonfilled byte) |
||
337 | exp10 - corrected dec. exponent |
||
338 | mlt_7 .. mlt_2 - remainder |
||
339 | pwr_7 .. pwr_2 - last powr10[] element |
||
340 | |||
341 | Notes: |
||
342 | * It is possible to leave out powr10'x table with subnormal value. |
||
343 | Result: accuracy degrease on the rounding phase. No matter: high |
||
344 | precision with subnormals is not needed. (Now 0x00000001 is converted |
||
345 | exactly on prec = 5, i.e. 6 digits.) |
||
346 | */ |
||
347 | |||
348 | ; to find first digit |
||
349 | ldi ZL, lo8(.L_powr10) |
||
350 | ldi ZH, hi8(.L_powr10) |
||
351 | set |
||
352 | ; 'pwr10' element reading |
||
353 | .L_digit: |
||
354 | X_lpm pwr_2, Z+ |
||
355 | X_lpm pwr_3, Z+ |
||
356 | X_lpm pwr_4, Z+ |
||
357 | X_lpm pwr_5, Z+ |
||
358 | X_lpm pwr_6, Z+ |
||
359 | X_lpm pwr_7, Z+ |
||
360 | ; 'digit' init. |
||
361 | ldi digit, '0' - 1 |
||
362 | ; subtraction loop |
||
363 | 20: inc digit |
||
364 | sub mlt_2, pwr_2 |
||
365 | sbc mlt_3, pwr_3 |
||
366 | sbc mlt_4, pwr_4 |
||
367 | sbc mlt_5, pwr_5 |
||
368 | sbc mlt_6, pwr_6 |
||
369 | sbc mlt_7, pwr_7 |
||
370 | brsh 20b |
||
371 | ; restore mult |
||
372 | add mlt_2, pwr_2 |
||
373 | adc mlt_3, pwr_3 |
||
374 | adc mlt_4, pwr_4 |
||
375 | adc mlt_5, pwr_5 |
||
376 | adc mlt_6, pwr_6 |
||
377 | adc mlt_7, pwr_7 |
||
378 | ; analisys |
||
379 | brtc 25f |
||
380 | cpi digit, '0' |
||
381 | brne 21f ; this is the first digit finded |
||
382 | dec exp10 |
||
383 | rjmp .L_digit |
||
384 | ; now is the first digit |
||
385 | 21: clt |
||
386 | ; number of digits |
||
387 | subi maxdgs, 1 |
||
388 | brlo 23f ; maxdgs was 0 |
||
389 | add maxdgs, exp10 |
||
390 | brpl 22f |
||
391 | clr maxdgs |
||
392 | 22: cp maxdgs, prec |
||
393 | brsh 23f |
||
394 | mov prec, maxdgs |
||
395 | 23: inc prec |
||
396 | mov maxdgs, prec |
||
397 | ; operate digit |
||
398 | 25: cpi digit, '0' + 10 |
||
399 | brlo 27f |
||
400 | ; overflow, digit > '9' |
||
401 | ldi digit, '9' |
||
402 | 26: st X+, digit |
||
403 | dec prec |
||
404 | brne 26b |
||
405 | rjmp .L_up |
||
406 | ; write digit |
||
407 | 27: st X+, digit |
||
408 | dec prec |
||
409 | brne .L_digit |
||
410 | |||
411 | /* -------------------------------------------------------------------- |
||
412 | Rounding. |
||
413 | */ |
||
414 | .L_round: |
||
415 | ; pwr10 /= 2 |
||
416 | lsr pwr_7 |
||
417 | ror pwr_6 |
||
418 | ror pwr_5 |
||
419 | ror pwr_4 |
||
420 | ror pwr_3 |
||
421 | ror pwr_2 |
||
422 | ; mult -= pwr10 (half of last 'pwr10' value) |
||
423 | sub mlt_2, pwr_2 |
||
424 | sbc mlt_3, pwr_3 |
||
425 | sbc mlt_4, pwr_4 |
||
426 | sbc mlt_5, pwr_5 |
||
427 | sbc mlt_6, pwr_6 |
||
428 | sbc mlt_7, pwr_7 |
||
429 | ; rounding direction? |
||
430 | brlo .L_rest |
||
431 | ; round to up |
||
432 | .L_up: |
||
433 | inc prec |
||
434 | ld digit, -X |
||
435 | inc digit |
||
436 | cpi digit, '9' + 1 |
||
437 | brlo 31f |
||
438 | ldi digit, '0' |
||
439 | 31: st X, digit |
||
440 | cpse prec, maxdgs |
||
441 | brsh .L_up |
||
442 | ; it was a carry to master digit |
||
443 | ld digit, -X ; flags |
||
444 | ori digit, FTOA_CARRY ; 'C' is not changed |
||
445 | st X+, digit |
||
446 | brlo .L_rest ; above comparison |
||
447 | ; overflow |
||
448 | inc exp10 |
||
449 | ldi digit, '1' |
||
450 | 32: st X+, digit |
||
451 | ldi digit, '0' |
||
452 | dec prec |
||
453 | brne 32b |
||
454 | ; restore |
||
455 | .L_rest: |
||
456 | clr zero |
||
457 | pop r14 |
||
458 | pop r15 |
||
459 | pop r16 |
||
460 | pop r17 |
||
461 | pop r28 |
||
462 | pop r29 |
||
463 | ; return |
||
464 | clr r25 |
||
465 | sbrc exp10, 7 ; high byte |
||
466 | com r25 |
||
467 | ret |
||
468 | |||
469 | .size __ftoa_engine, . - __ftoa_engine |
||
470 | |||
471 | /* -------------------------------------------------------------------- |
||
472 | Tables. '.L_powr10' is placed first -- for subnormals stability. |
||
473 | */ |
||
474 | .section .progmem.data,"a",@progbits |
||
475 | |||
476 | .type .L_powr10, "object" |
||
477 | .L_powr10: |
||
478 | .byte 0, 64, 122, 16, 243, 90 ; 100000000000000 |
||
479 | .byte 0, 160, 114, 78, 24, 9 ; 10000000000000 |
||
480 | .byte 0, 16, 165, 212, 232, 0 ; 1000000000000 |
||
481 | .byte 0, 232, 118, 72, 23, 0 ; 100000000000 |
||
482 | .byte 0, 228, 11, 84, 2, 0 ; 10000000000 |
||
483 | .byte 0, 202, 154, 59, 0, 0 ; 1000000000 |
||
484 | .byte 0, 225, 245, 5, 0, 0 ; 100000000 |
||
485 | .byte 128, 150, 152, 0, 0, 0 ; 10000000 |
||
486 | .byte 64, 66, 15, 0, 0, 0 ; 1000000 |
||
487 | .byte 160, 134, 1, 0, 0, 0 ; 100000 |
||
488 | .byte 16, 39, 0, 0, 0, 0 ; 10000 |
||
489 | .byte 232, 3, 0, 0, 0, 0 ; 1000 |
||
490 | .byte 100, 0, 0, 0, 0, 0 ; 100 |
||
491 | .byte 10, 0, 0, 0, 0, 0 ; 10 |
||
492 | .byte 1, 0, 0, 0, 0, 0 ; 1 |
||
493 | .size .L_powr10, . - .L_powr10 |
||
494 | |||
495 | .type .L_base10, "object" |
||
496 | .L_base10: |
||
497 | .byte 44, 118, 216, 136, -36 ; 2295887404 |
||
498 | .byte 103, 79, 8, 35, -33 ; 587747175 |
||
499 | .byte 193, 223, 174, 89, -31 ; 1504632769 |
||
500 | .byte 177, 183, 150, 229, -29 ; 3851859889 |
||
501 | .byte 228, 83, 198, 58, -26 ; 986076132 |
||
502 | .byte 81, 153, 118, 150, -24 ; 2524354897 |
||
503 | .byte 230, 194, 132, 38, -21 ; 646234854 |
||
504 | .byte 137, 140, 155, 98, -19 ; 1654361225 |
||
505 | .byte 64, 124, 111, 252, -17 ; 4235164736 |
||
506 | .byte 188, 156, 159, 64, -14 ; 1084202172 |
||
507 | .byte 186, 165, 111, 165, -12 ; 2775557562 |
||
508 | .byte 144, 5, 90, 42, -9 ; 710542736 |
||
509 | .byte 92, 147, 107, 108, -7 ; 1818989404 |
||
510 | .byte 103, 109, 193, 27, -4 ; 465661287 |
||
511 | .byte 224, 228, 13, 71, -2 ; 1192092896 |
||
512 | .byte 245, 32, 230, 181, 0 ; 3051757813 |
||
513 | .byte 208, 237, 144, 46, 3 ; 781250000 |
||
514 | .byte 0, 148, 53, 119, 5 ; 2000000000 |
||
515 | .byte 0, 128, 132, 30, 8 ; 512000000 |
||
516 | .byte 0, 0, 32, 78, 10 ; 1310720000 |
||
517 | .byte 0, 0, 0, 200, 12 ; 3355443200 |
||
518 | .byte 51, 51, 51, 51, 15 ; 858993459 |
||
519 | .byte 152, 110, 18, 131, 17 ; 2199023256 |
||
520 | .byte 65, 239, 141, 33, 20 ; 562949953 |
||
521 | .byte 137, 59, 230, 85, 22 ; 1441151881 |
||
522 | .byte 207, 254, 230, 219, 24 ; 3689348815 |
||
523 | .byte 209, 132, 75, 56, 27 ; 944473297 |
||
524 | .byte 247, 124, 29, 144, 29 ; 2417851639 |
||
525 | .byte 164, 187, 228, 36, 32 ; 618970020 |
||
526 | .byte 50, 132, 114, 94, 34 ; 1584563250 |
||
527 | .byte 129, 0, 201, 241, 36 ; 4056481921 |
||
528 | .byte 236, 161, 229, 61, 39 ; 1038459372 |
||
529 | .size .L_base10, . - .L_base10 |
||
530 | |||
531 | .end |
||
532 | #endif /* !__DOXYGEN__ */ |