dtoa.s
4.78 KB
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
/* --------------------------------------------------- */
/* | Copyright (c) 1986 MIPS Computer Systems, Inc. | */
/* | All Rights Reserved. | */
/* --------------------------------------------------- */
/* $Header: /root/leakn64/depot/rf/sw/bbplayer/apps/gng/cpu/fpu/dtoa.s,v 1.1.1.2 2002/10/29 08:05:52 blythe Exp $ */
#include <regdef.h>
/* _dtoa (buffer, ndigit, x, fflag) */
/* Store sign, ndigits of x, and null in buffer. Digits are in ascii.
1 <= ndigits <= 17. Return exponent. If fflag set then generate
Fortran F-format; i.e. ndigits after decimal point. */
.globl _dtoa
.ent _dtoa
_dtoa:
.frame sp, 0, t9
move t9, ra
/* Sign */
li t1, 32
#if MIPSEL
bgez a3, 1f
li t1, 45
1: sll t5, a3, 1
srl t0, a2, 31
or t5, t0
sll t4, a2, 1
#else
bgez a2, 1f
li t1, 45
1: sll t5, a2, 1
srl t0, a3, 31
or t5, t0
sll t4, a3, 1
#endif
sb t1, (a0)
addu a0, 1
/* log10 approximation */
li t2, 0x4D104D42 >> 21 # log10(2), shifted so . between hi/lo
subu t1, t5, 1023 << 21
bgez t1, 2f
addu t2, 1
2: mult t1, t2
srl t8, t5, 21
beq t8, 0, 10f
beq t8, 2047, 20f
/* Convert to fixed point number in range [1,100) by multiplication
by appropriate power of 10. */
sll t5, 11
srl t5, 11
or t5, 1 << 21
mfhi v0 # exponent
15: neg t0, v0
jal _tenscale
subu t8, 1023+20
addu t8, v1
neg t8
/* Extract first digit */
srl a2, t3, t8
sll a3, a2, t8
subu t3, a3
/* Handle F-format */
lw t4, 16(sp)
beq t4, 0, 19f
sltu t4, a2, 10
subu t4, v0
subu a1, t4
addu a1, 2
bgtz a1, 16f
#ifdef sgi
/* ok. format indicates NO digits will be produced. All
we want to do is "round", if necessary. */
bltu a2, 10, 99f
divu a2, 10
99:
/* correct digit in a2 to direct rounding. We know here
that we are rounding "up" to +- 1, so half is dropped.
(round to even (0))
*/
addu a2, 48 /* make ascii digit. */
sb a2, (a0) /* store the single digit. */
addu a0, 1
sb $0, (a0) /* null teminate. */
bltu a2, 48+6, 6f /* was it lt 6? - round down */
/* round up. Set the last digit to '9' and
later logic will realize we are rounding into 'sign' pos. */
li a2, 9+48
subu t1, a0, 1
sb a2, (t1)
b 7f
#else
li a1, 1
b 19f
#endif
16: ble a1, 17, 19f
li a1, 17
19:
addu a1, a0
bltu a2, 10, 3f
/* log10 approximation was low by 1, so we got first "digit" > 9 */
addu v0, 1
#if 1 /* is this necessary?? */
divu a3, a2, 10
remu a2, 10
addu a3, 48
#else /* or will this suffice?? */
li a3, 48+1
subu a2, 10
#endif
sb a3, (a0)
addu a0, 1
bne a0, a1, 3f
bltu a2, 5, 6f
bgtu a2, 5, 7f
b 55f
3: addu a2, 48
sb a2, (a0)
addu a0, 1
beq a0, a1, 5f
/* Now produce digits by multiplying fraction by 10 and taking
integer part. Actually multiply 5 (it's easier) and take
integer part from decreasing bit positions. */
4: srl t7, t0, 30
sll t5, t0, 2
not t6, t5
sltu t6, t6, t0
addu t4, t7, t6
addu t0, t5
srl t7, t1, 30
sll t5, t1, 2
not t6, t5
sltu t6, t6, t1
addu t1, t5
addu t7, t6
not t6, t4
sltu t6, t6, t1
addu t1, t4
addu t4, t7, t6
srl t7, t2, 30
sll t5, t2, 2
not t6, t5
sltu t6, t6, t2
addu t2, t5
addu t7, t6
not t6, t4
sltu t6, t6, t2
addu t2, t4
addu t4, t7, t6
sll t5, t3, 2
addu t3, t5
addu t3, t4
subu t8, 1
srl a2, t3, t8
sll a3, a2, t8
subu t3, a3
addu a2, 48
sb a2, (a0)
addu a0, 1
bne a0, a1, 4b
5: /* digit production complete. now round */
sb $0, (a0)
subu t8, 1
srl a3, t3, t8
beq a3, 0, 6f
55:
bne t2, 0, 7f
subu a3, t3, 1
bne t1, 0, 7f
and a3, t3
bne t0, 0, 7f
and a2, 1
bne a3, 0, 7f
bne a2, 0, 7f
6: /* round down, i.e. done */
j t9
7: /* round up (in ascii!) */
subu t1, a0, 1
75:
.set noreorder
lbu t0, (t1)
beq t0, 48+9, 8f
bltu t0, 48, 9f /* ' ' and '-' both < '0' */
addu t0, 1
.set reorder
sb t0, (t1)
j t9
8: li t0, 48
sb t0, (t1)
subu t1, 1
b 75b
9: /* tried to round into sign position */
li t0, 48+1
sb t0, 1(t1)
li t0, 48
sb t0, 0(a0)
sb $0, 1(a0)
addu v0, 1
j t9
10: /* output 0 or denorm */
bne t5, 0, 12f
bne t4, 0, 12f
/* zero */
lw t0, 16(sp) /* f format flag */
li t0, 48
addu a1, t0
blez a1, 40f
addu a1, a0
11: sb t0, (a0)
addu a0, 1
bne a0, a1, 11b
40: sb $0, (a0)
li v0, 0
j t9
12: /* denorm */
/* normalize with slow but small loop (denorm speed is unimportant) */
li t8, -1022
li t2, 1 << 21
13: subu t8, 1
sll t5, 1
srl t0, t4, 31
or t5, t0
sll t4, 1
and t0, t5, t2
beq t0, 0, 13b
14: /* log10 approximation */
sll t1, t8, 20
addu t1, t5
subu t1, t2
li t2, (0x4D104D42 >> 20) + 1
mult t1, t2
addu t8, 1023
mfhi v0
b 15b
20: /* output +-Infinity or Nan */
addu a1, a0
la t0, nan
bne t4, 0, 22f
sll t1, t5, 11
bne t1, 0, 22f
la t0, infinity
22: lbu t1, (t0)
addu a0, 1
sb t1, -1(a0)
beq t1, 0, 23f
addu t0, 1
bne a0, a1, 22b
23: li v0, 0x80000000
j t9
.end _dtoa
.rdata
infinity:
.asciiz "Infinity"
nan:
.asciiz "NaN"