1
/* -*- Mode: Asm -*- */
3
/* Copyright (c) 2002 Michael Stumpf <mistumpf@de.pepperl-fuchs.com>
7
Redistribution and use in source and binary forms, with or without
8
modification, are permitted provided that the following conditions are met:
10
* Redistributions of source code must retain the above copyright
11
notice, this list of conditions and the following disclaimer.
13
* Redistributions in binary form must reproduce the above copyright
14
notice, this list of conditions and the following disclaimer in
15
the documentation and/or other materials provided with the
18
* Neither the name of the copyright holders nor the names of
19
contributors may be used to endorse or promote products derived
20
from this software without specific prior written permission.
22
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
POSSIBILITY OF SUCH DAMAGE.
35
/* $Id: dtostre.S,v 1.13 2005/09/13 13:29:54 joerg_wunsch Exp $ */
38
dtostre.S is an addition to FPlib V 0.3.0 ported to avr-as
39
for details see readme.dtostre
41
const char * dtostre( double f[r22::r25], char * s[r20:r21], byte prec[r18],
44
*------------------------------------------------------------------------------*/
46
#if !defined(__DOXYGEN__)
54
/* Verify assumptions implied in the code below. */
55
#if DTOSTR_ALWAYS_SIGN != 0x01
56
#error "DTOSTR_ALWAYS_SIGN must be 0x01"
58
#if DTOSTR_PLUS_SIGN != 0x02
59
#error "DTOSTR_PLUS_SIGN must be 0x02"
61
#if DTOSTR_UPPERCASE != 0x04
62
#error "DTOSTR_UPPERCASE must be 0x04"
65
#define FP_0_1 0x3dcccccd
66
#define FP_0_30103 0x3e9a209b
67
#define FP_0_5 0x3f000000
68
#define FP_10 0x41200000
70
TEXT_SEG(fplib, dtostre)
74
/* new call convention, move last two args of type "char" */
75
mov rP6, r18 /* rP6 == r19 */
76
mov rP7, r16 /* rP7 == r18 */
87
push rP4 ; return this
92
mov rSI0, rA3 ; copy sign
93
mov rSI1, rA2 ; and ..
100
ldi rSI1, '+' ; rSI1 = (flags & DTOSTRE_PLUS_SIGN?'+':' ')
101
sbrc rP7, 0 ; if (!(flags & DTOSTRE_ALWAYS_SIGN)) skip
106
sbrs rP7, 2 ; if DTOSTRE_UPPERCASE was set
110
tst rP6 ; if (prec == 0) don't print ".0"
117
2: st Y+, rA1 /* 'E' */
125
brne 4f ; check for zero and NaN
138
andi rA3, 0x7F ; now f is positive
142
ldi rSI1, '+' ; rSI1 = (flags & DTOSTRE_PLUS_SIGN?'+':' ')
143
sbrc rP7, 0 ; if (!(flags & DTOSTRE_ALWAYS_SIGN)) skip
147
mov rSI0, rP6 ; store prec
150
mov rS0, rA0 ; store dblno
155
; frexp(dblno, (int*) dest);
158
XCALL _U(frexp) ; destroys argument_1
160
; iexp = *(int*) dest * log10(2);
162
ldd rA1, Y+1 ; exponent
163
eor rA2, rA2 ; to longint argument
167
XCALL _U(__floatsisf) ; to float
168
FPLOAD(rB, FP_0_30103)
169
XCALL _U(__mulsf3) ; multiply
170
XCALL _U(__fixsfsi) ; to integer
171
mov rS4, rA0 ; save exponent, 1 byte only
177
; dblno *= pow(10.0, -(double) iexp)
178
XCALL _U(__floatsisf) ; to float
179
XCALL _U(__negsf2) ; negative
183
FPMOV(rB, rS) ; argument_2 = dblno
185
FPMOV(rS, rA) ; new dblno
187
; determine rounding:
188
; if (prec < ACCURACY) { t = .5; t *= 0.1**prec; dblno += t; }
192
eor rSI1, rSI1 ; for (rSI1 = 0; rSI1 < prec; rSI1++)
194
2: FPLOAD(rB, FP_0_1)
195
XCALL _U(__mulsf3) ; t *= 0.1
200
XCALL _U(__addsf3) ; dblno += t
201
FPMOV(rS, rA) ; new dblno
203
; The algorithm to determine the decimal exponent above has the
204
; potential to erroneously return an exponent that might be too
205
; large. So we need to give it a try before applying the rounding
206
; below. If we find the first digit to become 0, we decrease the
207
; exponent, and multiply our number again by 10.
213
ldd rSI1, Y+3 ; no need to convert from float to int,
214
tst rSI1 ; float 0.0 always has 0 in the MSB
220
FPMOV(rS, rA) ; dblno
224
; for (rSI1 = 0; rSI1 <= prec; rSI1++)
229
brcc 5f ; more digits than accuracy => pad 0s
231
; dblno = modf(dblno, (double *) dest) * 10.0;
232
FPMOV(rA, rS) ; next digit
238
FPMOV(rS, rA) ; dblno
240
; *dest++ = '0' + (char)(*(double *) dest);
245
XCALL _U(__fixsfsi) ; to long int
253
tst rSI0 ; if (prec == 0) don't print "."
261
8: ; loop test rSI1 <= rSI0
262
cp rSI0, rSI1 ; compare count - prec
267
sbrs rA2, 2 ; if DTOSTRE_UPPERCASE was set
269
ST Y+, rA1 ; put exponent
278
; dividend in r24, divisor in r22
280
ldi r22, 10 ; divisor
281
XCALL _U(__udivmodqi4)
282
; quotient in r24, remainder in r25
291
pop rByte ; char *dest
293
pop YL ; frame pointer
306
#endif /* not __DOXYGEN__ */