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 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
|
/* -*- 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.
*/
/*
strtod.S is an addition to FPlib V 0.3.0 ported to avr-as
for details see readme.strtod
double[rP0:rP1:rP2:rP3] strtod(const char * s[rP0:rP1], char ** endptr[rP2:rP3] )
*----------------------------------------------------------------------------------------------
*/
#if !defined(DOXYGEN)
#include "gasava.inc"
#include "fplib.inc"
#define rFlags rSI0 /* */
#define rCh rSI1
; YH:YL pointer to actual char
; temp : rS3::rS0
#define rFracPower rS4
#define rDPshift rS5
#define rEndptrH rS6
#define rEndptrL rS7
#define bitNegative 7
#define bitPoint 6
#define bitDigit 5
#define bitExpSign 6
#ifndef _BV
#define _BV(x) (1 << (x))
#endif
PGM_SECTION
.L_10p1: DCB 0x41,0x20,0x00,0x00
.L_10p2: DCB 0x42,0xC8,0x00,0x00
.L_10p4: DCB 0x46,0x1C,0x40,0x00
.L_10p8: DCB 0x4C,0xBE,0xBC,0x20
.L_10p16: DCB 0x5A,0x0E,0x1B,0xCA
.L_10p32: DCB 0x74,0x9D,0xC5,0xAE
.L_10p_1: DCB 0x3D,0xCC,0xCC,0xCD
.L_10p_2: DCB 0x3C,0x23,0xD7,0x0A
.L_10p_4: DCB 0x38,0xD1,0xB7,0x17
.L_10p_8: DCB 0x32,0x2B,0xCC,0x77
.L_10p_16: DCB 0x24,0xE6,0x95,0x95
.L_10p_32: DCB 0x0A,0x4F,0xB1,0x1F
TEXT_SEG(fplib, strtod)
FUNCTION(atof)
GLOBAL(atof)
clr rP2
clr rP3 ; clear *endptr
.size atof, .-atof
ENDFUNC
FUNCTION(strtod)
GLOBAL(strtod)
rcall .L_strtod_prologue
MOV YL,rP1
MOV YH,rP0 ; load pointer to Y in case displacement is needed
PUSH rP2
PUSH rP3 ; needed at end of function
MOV rEndptrH,YH
MOV rEndptrL,YL ; assume no valid float at all
; skip white space
1:
LD rCh,Y+
CPI rCh,' '
BREQ 1b
CPI rCh,'\t'
BREQ 1b
CPI rCh,'\v'
BREQ 1b
CPI rCh,'\f'
BREQ 1b
CPI rCh,'\n'
BREQ 1b
CPI rCh,'\r'
BREQ 1b
; now scan fraction
RCALL .L_scanSign
RCALL .L_scanDigits
; if T set now there must be a fraction failure : rA still 0!
BRTS 99f
RCALL _U(__floatunssisf)
BST rFlags,bitNegative
BLD rA3,7 ; set sign
MOV rS3,rA3
MOV rS2,rA2
MOV rS1,rA1
MOV rS0,rA0
; now scan for exponent
CLR rA2 ; preset exponent
ORI rCh,0x20 ; 'E' -> 'e'
CPI rCh,'e'
BRNE 4f ; is there any ?
LD rCh,Y+
RCALL .L_scanSign
RCALL .L_scanExponent
TST rA3
BREQ 3f
SBRC rFlags,bitNegative ; set sign
RJMP .L_underflow
RJMP .L_overflow
3:
SBRC rFlags,bitNegative ; set sign
NEG rA2
4:
; now evaluate fp number
; we got a string -123.456e+2
; what we have is fraction(rS3::rS0) = 123456.0 with rFracPower = 5
; exponent(rA2) = +2 with rDPshift = -3
; the result is fraction * 10**(exponent+rDPshift)
; overflow/underflow control must include rFracPower
LDI ZL,LOW(.L_10p1)
LDI ZH,HIGH(.L_10p1) ; pointer to array with 10^n
#define rExp rFlags
MOV rExp,rA2
MOV rA3,rS3
MOV rA2,rS2
MOV rA1,rS1
MOV rA0,rS0 ; move fraction to rA
ANDI rA3,0x7F ; positive
CP rA3,rA2
CPC rA2,rA1
CPC rA1,rA0
CPC rA0,__zero_reg__
BREQ 99f ; test for zero
ADD rExp,rDPshift ; exponent correction
BRPL .L_expPositive
.L_expNegative:
NEG rExp
ADIW ZL,(.L_10p_1-.L_10p1)
MOV rA3,rExp
SUB rA3,rFracPower
CPI rA3,39
BRGE .L_underflow
RJMP .L_combineExponent
.L_expPositive:
MOV rA3,rExp
ADD rA3,rFracPower
CPI rA3,39
BRGE .L_overflow
; RJMP _combineExponent
.L_combineExponent:
MOV rA3,rS3 ; load right sign again
.L_expPower10:
TST rExp
BREQ 99f
ASR rExp
BRCC .L_nextPower
RCALL __fp_flashconst ; load constnat to B
PUSH R30
PUSH R31
RCALL _U(__mulsf3) ; AX *= BX, sign stays untouched
POP R31
POP R30
#ifdef __ERRNO__
BST rA2,7 ; if ERRNO
MOV rB3,rA3 ; check for overflow / underflow
ADD rB3,rB3
BLD rB3,0
TST rB3
BREQ .L_underflow
CPI rB3,0xFF
BREQ .L_overflow
#endif
RJMP .L_expPower10
.L_nextPower:
ADIW ZL,4
RJMP .L_expPower10
99:
POP ZL
POP ZH
CPI ZL,0
CPC ZL,ZH
BREQ 1f
ST Z+,rEndptrL
ST Z,rEndptrH
1:
LDI ZL,18-6 ; number of all 'pushed' registers - not pushed ones
IN YL,_SFR_IO_ADDR(SPL)
IN YH,_SFR_IO_ADDR(SPH)
EPILOGUE_RESTORES(6)
.L_overflow:
MOV rA3,rS3 ; correct
ORI rA3,0x7F
LDI rA2,0x7F
SER rA1
SER rA0
#ifdef __ERRNO__
RJMP 1f
#else
RJMP 99b
#endif
.L_underflow:
RCALL _U(__fp_zero)
#ifdef __ERRNO__
1:
extern errno
LDI rB3,ERANGE
STS errno,rB3
STS errno+1,__zero_reg__
#endif
RJMP 99b
.L_scanSign:
CLR rFlags
CPI rCh,'+'
BREQ 1f
CPI rCh,'-'
BRNE 2f
ORI rFlags,_BV(bitNegative) ; negative sign
1:
LD rCh,Y+
2:
RET
.L_scanExponent:
CLR rA2 ; initialize rA3::rA2 with 0
CLR rA3
1:
CPI rCh,'0'
BRLT 10f
BRNE 2f ; look for leading zeros
SBRS rFlags,bitDigit
RJMP 4f ; no valid digits yet -> skip zero
2:
CPI rCh,'9'+1
BRGE 10f ; no digit, no integer part
ORI rFlags,_BV(bitDigit)
TST rA3
BRNE 3f ; overflow allready
; mul rA3::rA2 by 10 and add rCh
XCALL __mulhi_const_10 ; r25:r24 *= 10
ANDI rCh,0x0F
ADD rA2,rCh
adc rA3,__zero_reg__
3:
MOV rEndptrH,YH
MOV rEndptrL,YL ; valid exponent up to now
4:
LD rCh,Y+
RJMP 1b
10:
RET
.L_scanDigits:
SET
RCALL _U(__fp_zero) ; initialize result with 0.0
CLR rFracPower
DEC rFracPower
CLR rDPshift
1: ; scan until (possibly) decimal point found
CPI rCh,'.'
BRNE 2f
SBRC rFlags,bitPoint
RJMP 10f ; just found the second point
ORI rFlags,_BV(bitPoint)
RJMP 6f
2:
CPI rCh,'0'
BRLT 10f
BRNE 3f ; look for leading zeros
CLT
SBRS rFlags,bitDigit
RJMP 4f ; leading zero, but check rDPshift if left of dp
3:
CPI rCh,'9'+1
BRGE 10f ; no digit, no integer part
ORI rFlags,_BV(bitDigit)
CPI rA3,0x0F ; 0xF FF FF FF = 268 435 455 -> min 8 digits precision
BRGE 5f ; truncate ?
INC rFracPower
; mul rA3::rA0 by 10 and add rCh
CLT ; digit validates fraction
CLR rB3
CLR rB2
CLR rB1
LDI rB0,10
XCALL __mulsi3
ANDI rCh,0x0F
ADD rA0,rCh
adc rA1,__zero_reg__
adc rA2,__zero_reg__
adc rA3,__zero_reg__
MOV rEndptrH,YH
MOV rEndptrL,YL ; valid float up to now
4:
SBRC rFlags,bitPoint
; scan left of decimal point : decrement exponent
DEC rDPshift
RJMP 6f
5:
; scan vor dem Komma, aber keine Digits mehr auswerten : inkrementiere
SBRS rFlags,bitPoint
INC rDPshift
6:
LD rCh,Y+
RJMP 1b
10:
RET
.L_strtod_prologue:
clr XL ; no locals
clr XH
pop ZH
pop ZL
PROLOGUE_SAVES(6)
.size strtod, .-strtod
ENDFUNC
#endif /* not DOXYGEN */
|