1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
|
/* -*- Mode: Asm -*-
Copyright (c) 2002, Reiner Patommel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
/* ----------------------------------------------------------------------------------
dtostrf.S
Contributors:
Created by Reiner Patommel
$Id: dtostrf.S,v 1.7 2004/03/05 22:17:01 joerg_wunsch Exp $
*-----------------------------------------------------------------------------------
* A = *dtostrf(double num, char width, char precision, char *str)
* Converts a double (float) to a string in the printf f format.
* This is a substitute for printf("%width.precisionf", num,)
* Width is the minimum width of the output string including '.' and possible sign.
* Precision is the number of digits required after the decimal point.
* If precision is < 0, the string is left adjusted with leading spaces.
* If precision is > 0, the string is right adjusted with trailing spaces.
* The number will be rounded based on precision.
*----------------------------------------------------------------------------------*/
#if !defined(DOXYGEN)
#include "gasava.inc"
#include "fplib.inc"
#include "macros.inc"
#define p_num_hi_hi r25
#define p_num_hi_lo r24
#define p_num_lo_hi r23
#define p_num_lo_lo r22
#define p_width r20
#define p_prec r18
#define p_str_hi r17
#define p_str_lo r16 /* parameters */
#define ret_hi r25
#define ret_lo r24 /* return value */
/*
* NB: r16 and r17 must not be
* clobbered, but we can easily
* restore them at return time since
* we are going to return the string
* pointer anyway.
*/
#define r_count r17 /* exponent and loop counter */
#define r_dp r16 /* position of decimal point */
TEXT_SEG(fplib, dtostrf)
FUNCTION(dtostrf)
GLOBAL(dtostrf)
push YH
push YL ; save frame pointer
push p_str_hi
push p_str_lo ; save &string
#if __AVR_ENHANCED__
movw YL, p_str_lo ; Y points to string
movw r16, p_num_hi_lo
#else
mov YH, p_str_hi
mov YL, p_str_lo ; Y points to string
mov r17, p_num_hi_hi
mov r16, p_num_hi_lo
#endif
add r16, r16
adc r17, r17
cpi r17, 0xff ; NAN ?
brne 1f
ldi rA3, 'N'
ldi rA2, 'A'
st Y+, rA3 ; 'N'
st Y+, rA2 ; 'A'
st Y+, rA3 ; 'N'
rjmp 10f
1: ; if (num < 0) {num = -num; *string = '-';}
push p_width ; save width
tst p_num_hi_hi ; num < 0?
brpl 1f
ldi r16, '-' ; num is negative
st Y+, r16 ; write '-' sign
andi rA3, 0x7F ; make num positive
1: ; num += (0.5 * 10^-p_precision);
mov r_dp, p_prec ; decimal point is at precision + 1
inc r_dp ; when counting down to 0
push p_num_hi_hi
push p_num_hi_lo
push p_num_lo_hi
push p_num_lo_lo ; save num
mov rA0, p_prec
clr rA1
clr rA2
clr rA3 ; A = precision
XCALL _U(__floatsisf) ; now A = (float)precision
ori rA3, 0x80 ; now A = (float) -precision
#if __AVR_ENHANCED__
movw rB2, rA2
movw rB0, rA0
#else
mov rB3, rA3
mov rB2, rA2
mov rB1, rA1
mov rB0, rA0 ; now B = (float) -precision
#endif
ldi rA3, 0x41
ldi rA2, 0x20
clr rA1
clr rA0 ; A = 10.0
XCALL _U(pow) ; now A = 10^ -precision
ldi rB3, 0xff
ldi rB2, 0xff ; rB3:rB2 = -1
XCALL _U(ldexp) ; now A = (0.5 * 10^-precision)
pop rB0
pop rB1
pop rB2
pop rB3 ; B = num
XCALL _U(__addsf3) ; now A = num + (0.5 * 10^-precision)
mov r_count, r_dp ; count becomes power10 + dp.
cpi r_dp, 1 ; force dp to 0 if dp = 1 i.e. precision = 0
brne 1f
clr r_dp
1: ; while (num >= 10.0) {num /= 10; count++;}
ldi rB3, 0x41
ldi rB2, 0x20
clr rB1
clr rB0 ; B = 10.0
cp rA0, rB0
cpc rA1, rB1
cpc rA2, rB2
cpc rA3, rB3 ; num >= 10.0?
brlt 2f
XCALL _U(__divsf3) ; num /= 10.0
inc r_count ; count++
rjmp 1b
2: ; for (i = count; i > 0; count--;)
push rA3 ; {n = num; n += '0'; *string++ = n; num -= n;
push rA2 ; num *= 10; if (i == dp) *string = '.';}
push rA1
push rA0
XCALL _U(__fixsfsi) ; convert num to long ( =n)
mov r21, rA0 ; n = num
subi r21, -'0' ; n += '0'
st Y+, r21 ; *string++ = n
XCALL _U(__floatsisf) ; convert n to float
pop rB0
pop rB1
pop rB2
pop rB3 ; B = num
XCALL _U(__subsf3) ; A = (A - B)
subi rA3, 0x80 ; A = -(A - B) = B - A -> num -= n
ldi rB3, 0x41
ldi rB2, 0x20
clr rB1
clr rB0 ; B = 10.0
XCALL _U(__mulsf3) ; num *= 10
cp r_count, r_dp ; decimal point here?
brne 3f
ldi r21 , '.'
st Y+, r21 ; write decimal point
3:
dec r_count
brne 2b
; adjust result
st Y, __zero_reg__ ; terminate string
pop r21 ; get width again
pop ZL ; Y points to end of string
pop ZH ; Z points to start of string
push ZH
push ZL ; save &string again
mov p_width, r21
tst p_width ; width < 0?
brpl 1f
com p_width ; make width positive
inc p_width
; Need // in next line to stop doxygen
; from thinking strlen is a variable.
1: ; // strlen = Y - Z
#if __AVR_ENHANCED__
movw rA2, YL
movw rA0, ZL
#else
mov rA3, YH
mov rA2, YL
mov rA1, ZH
mov rA0, ZL
#endif
sub rA2, rA0
sbc rA3, rA1 ; rA2 = strlen
mov r_count, p_width
sub r_count, rA2 ; r_count = # of leading/trailing spaces
ldi rA3, ' '
cp rA2, p_width ; if (strlen >= abs(width)) exit
brge 11f
tst r21 ; width < 0?
brmi 4f
; right adjust with leading spaces
adiw YL, 1 ; now Y points to end+1 of string
adiw ZL, 1
add ZL, p_width
adc ZH, __zero_reg__ ; now Z points to end+1 of final string
inc rA2 ; rA2 = strlen+1
2: ; right shift string
ld r21, -Y
st -Z, r21
dec rA2
brne 2b
3: ; make leading spaces
st -Z, rA3
dec r_count
brne 3b
rjmp 11f
4: ; left adjust -- make trailing spaces
st Y+, rA3
dec r_count
brne 4b
10:
st Y, __zero_reg__ ; terminate string
11:
pop ret_lo
pop ret_hi ; restore &string as return address
#if __AVR_ENHANCED__
movw p_str_lo, ret_lo
#else
mov p_str_lo, ret_lo
mov p_str_hi, ret_hi
#endif
pop YL
pop YH ; restore frame pointer
ret
ENDFUNC
;-----------------------------------------------------------------------------------
#endif /* not DOXYGEN */
|