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