Subversion Repositories Projects

Rev

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__ */