flag fields are u_int's
[unix-history] / usr / src / lib / libc / vax / stdlib / atof.s
CommitLineData
586c39b1
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
493b70ca
KB
3 * All rights reserved.
4 *
019bea33 5 * %sccs.include.redist.c%
586c39b1
DF
6 */
7
f4f66d2c 8#if defined(LIBC_SCCS) && !defined(lint)
019bea33 9 .asciz "@(#)atof.s 5.6 (Berkeley) %G%"
f4f66d2c 10#endif /* LIBC_SCCS and not lint */
6e3894e8
SL
11
12#include "DEFS.h"
13
14/*
15 * atof: convert ascii to floating
16 *
17 * C usage:
18 *
19 * double atof (s)
20 * char *s;
21 *
22 * Register usage:
23 *
24 * r0-1: value being developed
25 * r2: first section: pointer to the next character
26 * second section: binary exponent
27 * r3: flags
28 * r4: first section: the current character
29 * second section: scratch
30 * r5: the decimal exponent
31 * r6-7: scratch
6e3894e8 32 */
fe7347b7
SL
33 .set msign,0 # mantissa has negative sign
34 .set esign,1 # exponent has negative sign
35 .set decpt,2 # decimal point encountered
36
dadab5a2 37ENTRY(atof, R6|R7)
6e3894e8
SL
38/*
39 * Initialization
40 */
fe7347b7
SL
41 clrl r3 # All flags start out false
42 movl 4(ap),r2 # Address the first character
43 clrl r5 # Clear starting exponent
6e3894e8
SL
44/*
45 * Skip leading white space
46 */
fe7347b7
SL
47sk0: movzbl (r2)+,r4 # Fetch the next (first) character
48 cmpb $' ,r4 # Is it blank?
49 jeql sk0 # ...yes
50 cmpb r4,$8 # 8 is lowest of white-space group
51 jlss sk1 # Jump if char too low to be white space
52 cmpb r4,$13 # 13 is highest of white-space group
53 jleq sk0 # Jump if character is white space
54sk1:
6e3894e8
SL
55/*
56 * Check for a sign
57 */
fe7347b7
SL
58 cmpb $'+,r4 # Positive sign?
59 jeql cs1 # ... yes
60 cmpb $'-,r4 # Negative sign?
61 jneq cs2 # ... no
62 bisb2 $1<msign,r3 # Indicate a negative mantissa
63cs1: movzbl (r2)+,r4 # Skip the character
64cs2:
6e3894e8
SL
65/*
66 * Accumulate digits, keeping track of the exponent
67 */
fe7347b7
SL
68 clrq r0 # Clear the accumulator
69ad0: cmpb r4,$'0 # Do we have a digit?
70 jlss ad4 # ... no, too small
71 cmpb r4,$'9
72 jgtr ad4 # ... no, too large
6e3894e8
SL
73/*
74 * We got a digit. Accumulate it
75 */
fe7347b7
SL
76 cmpl r1,$214748364 # Would this digit cause overflow?
77 jgeq ad1 # ... yes
6e3894e8
SL
78/*
79 * Multiply (r0,r1) by 10. This is done by developing
80 * (r0,r1)*2 in (r6,r7), shifting (r0,r1) left three bits,
81 * and adding the two quadwords.
82 */
fe7347b7
SL
83 ashq $1,r0,r6 # (r6,r7)=(r0,r1)*2
84 ashq $3,r0,r0 # (r0,r1)=(r0,r1)*8
85 addl2 r6,r0 # Add low halves
86 adwc r7,r1 # Add high halves
6e3894e8
SL
87/*
88 * Add in the digit
89 */
fe7347b7
SL
90 subl2 $'0,r4 # Get the digit value
91 addl2 r4,r0 # Add it into the accumulator
92 adwc $0,r1 # Possible carry into high half
93 jbr ad2 # Join common code
6e3894e8
SL
94/*
95 * Here when the digit won't fit in the accumulator
96 */
fe7347b7 97ad1: incl r5 # Ignore the digit, bump exponent
6e3894e8
SL
98/*
99 * If we have seen a decimal point, decrease the exponent by 1
100 */
fe7347b7
SL
101ad2: jbc $decpt,r3,ad3 # Jump if decimal point not seen
102 decl r5 # Decrease exponent
103ad3:
6e3894e8
SL
104/*
105 * Fetch the next character, back for more
106 */
fe7347b7
SL
107 movzbl (r2)+,r4 # Fetch
108 jbr ad0 # Try again
6e3894e8
SL
109/*
110 * Not a digit. Could it be a decimal point?
111 */
fe7347b7
SL
112ad4: cmpb r4,$'. # If it's not a decimal point, either it's
113 jneq ad5 # the end of the number or the start of
114 # the exponent.
115 jbcs $decpt,r3,ad3 # If it IS a decimal point, we record that
116 # we've seen one, and keep collecting
117 # digits if it is the first one.
6e3894e8
SL
118/*
119 * Check for an exponent
120 */
fe7347b7
SL
121ad5: clrl r6 # Initialize the exponent accumulator
122
123 cmpb r4,$'e # We allow both lower case e
124 jeql ex1 # ... and ...
125 cmpb r4,$'E # upper-case E
126 jneq ex7
6e3894e8
SL
127/*
128 * Does the exponent have a sign?
129 */
fe7347b7
SL
130ex1: movzbl (r2)+,r4 # Get next character
131 cmpb r4,$'+ # Positive sign?
132 jeql ex2 # ... yes ...
133 cmpb r4,$'- # Negative sign?
134 jneq ex3 # ... no ...
135 bisb2 $1<esign,r3 # Indicate exponent is negative
136ex2: movzbl (r2)+,r4 # Grab the next character
6e3894e8
SL
137/*
138 * Accumulate exponent digits in r6
139 */
fe7347b7
SL
140ex3: cmpb r4,$'0 # A digit is within the range
141 jlss ex4 # '0' through
142 cmpb r4,$'9 # '9',
143 jgtr ex4 # inclusive.
144 cmpl r6,$214748364 # Exponent outrageously large already?
145 jgeq ex2 # ... yes
146 moval (r6)[r6],r6 # r6 *= 5
147 movaw -'0(r4)[r6],r6 # r6 = r6 * 2 + r4 - '0'
148 jbr ex2 # Go 'round again
149ex4:
6e3894e8
SL
150/*
151 * Now get the final exponent and force it within a reasonable
152 * range so our scaling loops don't take forever for values
153 * that will ultimately cause overflow or underflow anyway.
154 * A tight check on over/underflow will be done by ldexp.
155 */
fe7347b7
SL
156 jbc $esign,r3,ex5 # Jump if exponent not negative
157 mnegl r6,r6 # If sign, negate exponent
158ex5: addl2 r6,r5 # Add given exponent to calculated exponent
159 cmpl r5,$-100 # Absurdly small?
160 jgtr ex6 # ... no
161 movl $-100,r5 # ... yes, force within limit
162ex6: cmpl r5,$100 # Absurdly large?
163 jlss ex7 # ... no
164 movl $100,r5 # ... yes, force within bounds
165ex7:
6e3894e8
SL
166/*
167 * Our number has now been reduced to a mantissa and an exponent.
168 * The mantissa is a 63-bit positive binary integer in r0,r1,
169 * and the exponent is a signed power of 10 in r5. The msign
170 * bit in r3 will be on if the mantissa should ultimately be
171 * considered negative.
172 *
173 * We now have to convert it to a standard format floating point
174 * number. This will be done by accumulating a binary exponent
175 * in r2, as we progressively get r5 closer to zero.
176 *
177 * Don't bother scaling if the mantissa is zero
178 */
fe7347b7
SL
179 movq r0,r0 # Mantissa zero?
180 jeql exit # ... yes
181
182 clrl r2 # Initialize binary exponent
183 tstl r5 # Which way to scale?
184 jleq sd0 # Scale down if decimal exponent <= 0
6e3894e8
SL
185/*
186 * Scale up by "multiplying" r0,r1 by 10 as many times as necessary,
187 * as follows:
188 *
189 * Step 1: Shift r0,r1 right as necessary to ensure that no
190 * overflow can occur when multiplying.
191 */
fe7347b7
SL
192su0: cmpl r1,$429496729 # Compare high word to (2**31)/5
193 jlss su1 # Jump out if guaranteed safe
194 ashq $-1,r0,r0 # Else shift right one bit
195 incl r2 # bump exponent to compensate
196 jbr su0 # and go back to test again.
6e3894e8
SL
197/*
198 * Step 2: Multiply r0,r1 by 5, by appropriate shifting and
199 * double-precision addition
200 */
fe7347b7
SL
201su1: ashq $2,r0,r6 # (r6,r7) := (r0,r1) * 4
202 addl2 r6,r0 # Add low-order halves
203 adwc r7,r1 # and high-order halves
6e3894e8
SL
204/*
205 * Step 3: Increment the binary exponent to take care of the final
206 * factor of 2, and go back if we still need to scale more.
207 */
fe7347b7
SL
208 incl r2 # Increment the exponent
209 sobgtr r5,su0 # and back for more (maybe)
210
211 jbr cm0 # Merge to build final value
212
6e3894e8
SL
213/*
214 * Scale down. We must "divide" r0,r1 by 10 as many times
215 * as needed, as follows:
216 *
217 * Step 0: Right now, the condition codes reflect the state
218 * of r5. If it's zero, we are done.
219 */
fe7347b7 220sd0: jeql cm0 # If finished, build final number
6e3894e8
SL
221/*
222 * Step 1: Shift r0,r1 left until the high-order bit (not counting
223 * the sign bit) is nonzero, so that the division will preserve
224 * as much precision as possible.
225 */
fe7347b7
SL
226 tstl r1 # Is the entire high-order half zero?
227 jneq sd2 # ...no, go shift one bit at a time
228 ashq $30,r0,r0 # ...yes, shift left 30,
229 subl2 $30,r2 # decrement the exponent to compensate,
230 # and now it's known to be safe to shift
231 # at least once more.
232sd1: ashq $1,r0,r0 # Shift (r0,r1) left one, and
233 decl r2 # decrement the exponent to compensate
234sd2: jbc $30,r1,sd1 # If the high-order bit is off, go shift
6e3894e8
SL
235/*
236 * Step 2: Divide the high-order part of (r0,r1) by 5,
237 * giving a quotient in r1 and a remainder in r7.
238 */
fe7347b7
SL
239sd3: movl r1,r6 # Copy the high-order part
240 clrl r7 # Zero-extend to 64 bits
241 ediv $5,r6,r1,r7 # Divide (cannot overflow)
6e3894e8
SL
242/*
243 * Step 3: Divide the low-order part of (r0,r1) by 5,
244 * using the remainder from step 2 for rounding.
245 * Note that the result of this computation is unsigned,
246 * so we have to allow for the fact that an ordinary division
247 * by 5 could overflow. We make allowance by dividing by 10,
248 * multiplying the quotient by 2, and using the remainder
249 * to adjust the modified quotient.
250 */
fe7347b7
SL
251 addl3 $2,r0,r6 # Dividend is low part of (r0,r1) plus
252 adwc $0,r7 # 2 for rounding plus
253 # (2**32) * previous remainder
254 ediv $10,r6,r0,r6 # r0 := quotient, r6 := remainder.
255 addl2 r0,r0 # Make r0 result of dividing by 5
256 cmpl r6,$5 # If remainder is 5 or greater,
257 jlss sd4 # increment the adjustted quotient.
258 incl r0
6e3894e8
SL
259/*
260 * Step 4: Increment the decimal exponent, decrement the binary
261 * exponent (to make the division by 5 into a division by 10),
262 * and back for another iteration.
263 */
fe7347b7
SL
264sd4: decl r2 # Binary exponent
265 aoblss $0,r5,sd2
6e3894e8
SL
266/*
267 * We now have the following:
268 *
269 * r0: low-order half of a 64-bit integer
270 * r1: high-order half of the same 64-bit integer
271 * r2: a binary exponent
272 *
273 * Our final result is the integer represented by (r0,r1)
274 * multiplied by 2 to the power contained in r2.
275 * We will transform (r0,r1) into a floating-point value,
276 * set the sign appropriately, and let ldexp do the
277 * rest of the work.
278 *
279 * Step 1: if the high-order bit (excluding the sign) of
280 * the high-order half (r1) is 1, then we have 63 bits of
281 * fraction, too many to convert easily. However, we also
282 * know we won't need them all, so we will just throw the
283 * low-order bit away (and adjust the exponent appropriately).
284 */
fe7347b7
SL
285cm0: jbc $30,r1,cm1 # jump if no adjustment needed
286 ashq $-1,r0,r0 # lose the low-order bit
287 incl r2 # increase the exponent to compensate
6e3894e8
SL
288/*
289 * Step 2: split the 62-bit number in (r0,r1) into two
290 * 31-bit positive quantities
291 */
fe7347b7
SL
292cm1: ashq $1,r0,r0 # put the high-order bits in r1
293 # and a 0 in the bottom of r0
294 rotl $-1,r0,r0 # right-justify the bits in r0
295 # moving the 0 from the ashq
296 # into the sign bit.
6e3894e8
SL
297/*
298 * Step 3: convert both halves to floating point
299 */
fe7347b7
SL
300 cvtld r0,r6 # low-order part in r6-r7
301 cvtld r1,r0 # high-order part in r0-r1
6e3894e8
SL
302/*
303 * Step 4: multiply the high order part by 2**31 and combine them
304 */
fe7347b7
SL
305 muld2 two31,r0 # multiply
306 addd2 r6,r0 # combine
6e3894e8
SL
307/*
308 * Step 5: if appropriate, negate the floating value
309 */
fe7347b7
SL
310 jbc $msign,r3,cm2 # Jump if mantissa not signed
311 mnegd r0,r0 # If negative, make it so
6e3894e8
SL
312/*
313 * Step 6: call ldexp to complete the job
314 */
fe7347b7
SL
315cm2: pushl r2 # Put exponent in parameter list
316 movd r0,-(sp) # and also mantissa
317 calls $3,_ldexp # go combine them
318
6e3894e8 319exit:
6e3894e8 320 ret
dadab5a2
SL
321
322 .align 2
323two31: .word 0x5000 # 2 ** 31
324 .word 0 # (=2147483648)
325 .word 0 # in floating-point
326 .word 0 # (so atof doesn't have to convert it)