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 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
|
/* -*- Mode: Asm -*- */
/* Copyright (c) 2002 Michael Stumpf <mistumpf@de.pepperl-fuchs.com>
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.
*/
/* $Id: dtostre.S,v 1.11 2004/11/10 21:04:46 arcanum Exp $ */
/*
dtostre.S is an addition to FPlib V 0.3.0 ported to avr-as
for details see readme.dtostre
const char * dtostre( double f[r22::r25], char * s[r20:r21], byte prec[r18],
byte flags[r16] )
*------------------------------------------------------------------------------*/
#if !defined(DOXYGEN)
#include "gasava.inc"
#include "fplib.inc"
#include <stdlib.h>
/* Verify assumptions implied in the code below. */
#if DTOSTR_ALWAYS_SIGN != 0x01
#error "DTOSTR_ALWAYS_SIGN must be 0x01"
#endif
#if DTOSTR_PLUS_SIGN != 0x02
#error "DTOSTR_PLUS_SIGN must be 0x02"
#endif
#if DTOSTR_UPPERCASE != 0x04
#error "DTOSTR_UPPERCASE must be 0x04"
#endif
#define FP_0_1 0x3dcccccd
#define FP_0_30103 0x3e9a209b
#define FP_0_5 0x3f000000
#define FP_10 0x41200000
TEXT_SEG(fplib, dtostre)
FUNCTION(dtostre)
GLOBAL(dtostre)
/* new call convention, move last two args of type "char" */
mov rP6, r18 /* rP6 == r19 */
mov rP7, r16 /* rP7 == r18 */
push r11
push r12
push r13
push r14
push r15
push r16
push r17
push YH
push YL
push rP4 ; return this
push rP5
mov YH, rP4
mov YL, rP5
mov rSI0, rA3 ; copy sign
mov rSI1, rA2 ; and ..
add rSI1, rSI1
adc rSI0, rSI0
brne 3f ; not zero
ldi rSI1, ' '
sbrc rP7, 1
ldi rSI1, '+' ; rSI1 = (flags & DTOSTRE_PLUS_SIGN?'+':' ')
sbrc rP7, 0 ; if (!(flags & DTOSTRE_ALWAYS_SIGN)) skip
st Y+, rSI1
ldi rA3, '0'
ldi rA2, '.'
ldi rA1, 'E'
sbrs rP7, 2 ; if DTOSTRE_UPPERCASE was set
ori rA1, 'E' ^ 'e'
ldi rA0, '+'
st Y+,rA3
tst rP6 ; if (prec == 0) don't print ".0"
breq 2f
dec rP6
st Y+,rA2
1: st Y+, rA3
dec rP6
brpl 1b
2: st Y+, rA1 /* 'E' */
st Y+, rA0 /* '+' */
st Y+, rA3 /* '0' */
st Y+, rA3 /* '0' */
rjmp 99f ; exit
3:
cpi rSI0, 0xff
brne 4f ; check for zero and NaN
ldi rA3, 'N'
ldi rA2, 'a'
st Y+, rA3 /* 'N' */
st Y+, rA2 /* 'a' */
st Y+, rA3 /* 'N' */
rjmp 99f ; exit
4: ; not NaN
tst rA3
brpl 5f
ldi rSI1, '-'
andi rA3, 0x7F ; now f is positive
rjmp 6f
5: ldi rSI1, ' '
sbrc rP7, 1
ldi rSI1, '+' ; rSI1 = (flags & DTOSTRE_PLUS_SIGN?'+':' ')
sbrc rP7, 0 ; if (!(flags & DTOSTRE_ALWAYS_SIGN)) skip
6:
st Y+, rSI1
mov rSI0, rP6 ; store prec
push rP7 ; and flags
mov rS0, rA0 ; store dblno
mov rS1, rA1
mov rS2, rA2
mov rS3, rA3
; frexp(dblno, (int*) dest);
mov rB2, YL
mov rB3, YH
XCALL _U(frexp) ; destroys argument_1
; iexp = *(int*) dest * log10(2);
ldd rA0, Y+0
ldd rA1, Y+1 ; exponent
eor rA2, rA2 ; to longint argument
sbrc rA1, 7
com rA2
mov rA3, rA2
XCALL _U(__floatsisf) ; to float
FPLOAD(rB, FP_0_30103)
XCALL _U(__mulsf3) ; multiply
XCALL _U(__fixsfsi) ; to integer
mov rS4, rA0 ; save exponent, 1 byte only
; if ( iexp != 0 )
tst rA0
breq 1f
; dblno *= pow(10.0, -(double) iexp)
XCALL _U(__floatsisf) ; to float
XCALL _U(__negsf2) ; negative
FPMOV(rB, rA)
FPLOAD(rA, FP_10)
XCALL _U(pow)
FPMOV(rB, rS) ; argument_2 = dblno
XCALL _U(__mulsf3)
FPMOV(rS, rA) ; new dblno
1:
; The algorithm to determine the decimal exponent above has the
; potential to erroneously return an exponent that might be too
; large. So we need to give it a try before applying the rounding
; below. If we find the first digit to become 0, we decrease the
; exponent, and multiply our number again by 10.
FPMOV(rA, rS)
mov rB2, YL
mov rB3, YH
XCALL _U(modf)
ldd rSI1, Y+3 ; no need to convert from float to int,
tst rSI1 ; float 0.0 always has 0 in the MSB
brne 1f
dec rS4 ; exp--
FPLOAD(rB, FP_10)
XCALL _U(__mulsf3)
FPMOV(rS, rA) ; dblno
rjmp 1b
1:
; determine rounding:
; if (prec < ACCURACY) { t = .5; t *= 0.1**prec; dblno += t; }
cpi rSI0, ACCURACY
brcc 1f
FPLOAD(rA, FP_0_5)
eor rSI1, rSI1 ; for (rSI1 = 0; rSI1 < prec; rSI1++)
rjmp 3f
2: FPLOAD(rB, FP_0_1)
XCALL _U(__mulsf3) ; t *= 0.1
inc rSI1
3: cp rSI1, rSI0
brlo 2b
FPMOV(rB, rS)
XCALL _U(__addsf3) ; dblno += t
FPMOV(rS, rA) ; new dblno
1:
; for (rSI1 = 0; rSI1 <= prec; rSI1++)
eor rSI1, rSI1
rjmp 8f
2:
cpi rSI1, ACCURACY
brcc 5f ; more digits than accuracy => pad 0s
; dblno = modf(dblno, (double *) dest) * 10.0;
FPMOV(rA, rS) ; next digit
mov rB2, YL
mov rB3, YH
XCALL _U(modf)
FPLOAD(rB, FP_10)
XCALL _U(__mulsf3)
FPMOV(rS, rA) ; dblno
; *dest++ = '0' + (char)(*(double *) dest);
ldd rA0, Y+0
ldd rA1, Y+1
ldd rA2, Y+2
ldd rA3, Y+3
XCALL _U(__fixsfsi) ; to long int
mov rA2, rA0
subi rA2, -'0'
st Y+, rA2
; if (i == 0)
tst rSI1
brne 7f
tst rSI0 ; if (prec == 0) don't print "."
breq 7f
ldi rA2, '.'
rjmp 6f
5: ; pad with zeros
ldi rA2, '0'
6: st Y+, rA2
7: inc rSI1 ; rSI1++
8: ; loop test rSI1 <= rSI0
cp rSI0, rSI1 ; compare count - prec
brcc 2b
pop rA2 ; and flags
ldi rA1, 'E'
sbrs rA2, 2 ; if DTOSTRE_UPPERCASE was set
ori rA1, 'E' ^ 'e'
ST Y+, rA1 ; put exponent
ldi rA1, '+' ;
tst rS4 ; exponent
brpl 1f
neg rS4
ldi rA1, '-'
1:
st Y+, rA1
; dividend in r24, divisor in r22
mov r24, rS4
ldi r22, 10 ; divisor
XCALL _U(__udivmodqi4)
; quotient in r24, remainder in r25
subi rByte, -'0'
st Y+, rByte
subi r25, -'0'
st Y+, r25
99:
st Y,__zero_reg__
pop rByte ; char *dest
pop r25
pop YL ; frame pointer
pop YH
pop r17
pop r16
pop r15
pop r14
pop r13
pop r12
pop r11
ret
ENDFUNC
#endif /* not DOXYGEN */
|