|
|
1.1 root 1: //////////
2: / rts87.s
3: / cc386 80x87 runtime support.
4: //////////
5:
6: .text
7:
8: .globl _cfcc
9: .globl _tstcc
10: .globl _tstccp
11: .globl _dp87
12: .globl _fdcvt
13: .globl _vdcvt
14: .globl _ldcvt
15: .globl _pdcvt
16: .globl _udcvt
17: .globl _idcvt
18: .globl _dfcvt
19: .globl _dvcvt
20: .globl _dlcvt
21: .globl _ducvt
22: .globl _dicvt
23: .globl _dpcvt
24: .globl ldexp
25: .globl frexp
26: .globl modf
27:
28: / The following should be unnecessary but...
29: .globl _fvcvt
30: .globl _flcvt
31: .globl _fucvt
32: .globl _ficvt
33:
34: cwchop .word 0x0F3F / chop control word
35: two .word 2 / constant 2
36:
37: RASIZE = 4 / size of a return address
38: EBPSIZE = 4 / size of saved %ebp
39:
40: //////////
41: / _tstcc() Test %st and copy NDP condition codes.
42: / _tstccp() Test %st and pop and copy NDP condition codes.
43: / _cfcc() Copy NDP condition codes.
44: /
45: / _tstcc() tests %st against 0 and then does a _cfcc().
46: / _tstccp() tests %st against 0, pops it, and then does a _cfcc.
47: / _cfcc() copies the C0 and C3 status flags from the NDP
48: / into the Cf and Zf flags of the 80x86.
49: / This uses the otherwise useless opcode that copies the flags
50: / from %ah in 8080 format.
51: /
52: / Input:
53: / %st for _tstcc() and _tstccp(), NDP status word for _cfcc().
54: / Output:
55: / 80x86 flags Cf and Zf.
56: / NDP stack popped for _tstccp().
57: //////////
58:
59: _tstcc:
60: ftst / Test %st against 0
61: jmp _cfcc / and set the condition codes.
62: _tstccp:
63: ftst / Test st against 0,
64: fstp %st / pop the 80x87 stack,
65: / and fall through...
66: _cfcc:
67: fstsw %ax / Store the 80x87 status word to %eax
68: fwait / and wait for it to finish up.
69: sahf / Load Cf and Zf correctly.
70: ret
71:
72: //////////
73: / _dp87() Double push from NDP stacktop to 80x86 stack.
74: /
75: / Push a double from the NDP stacktop %st to the system stack.
76: / There is some magic to keep the return address in one piece.
77: /
78: / Input:
79: / Double in %st.
80: / Outputs:
81: / NDP stack popped.
82: / Double on 80x86 stack.
83: //////////
84:
85: _dp87:
86: pop %eax / Return address to %eax.
87: subl %esp, $8 / Claim a double on stack and
88: fstpl (%esp) / pop 80x87 to memory.
89: fwait / Make sure pop is completed.
90: ijmp %eax / Return to the caller.
91:
92: //////////
93: / _dicvt() Convert integer to double.
94: / _ducvt() Convert unsigned integer to double.
95: / _dpcvt() Convert pointer to double.
96: / _dlcvt() Convert long integer to double.
97: / _dvcvt() Convert unsigned long integer to double.
98: / _dfcvt() Convert float to double.
99: /
100: / Widen to double.
101: / Some simple widens can be compiled inline,
102: / but the unsigned widens and the signed
103: / widens when the object lacks an lvalue cannot be.
104: /
105: / Input:
106: / Operand passed in standard C fashion on 80x86 stack.
107: / Output:
108: / Result in %st.
109: //////////
110:
111: IARG = RASIZE
112:
113: _dicvt:
114: _ficvt:
115: _dlcvt:
116: _flcvt:
117: fildl IARG(%esp) / Load and convert the integer.
118: ret
119:
120: UARG = RASIZE+EBPSIZE
121: INT64 = -8 / Auto int64 offset.
122:
123: _ducvt:
124: _dpcvt:
125: _fucvt:
126: _dvcvt:
127: _fvcvt:
128: push %ebp
129: movl %ebp, %esp
130: subl %esp, $8 / Claim a 64 bit integer.
131:
132: movl %eax, UARG(%ebp) / Grab unsigned integer
133: movl INT64(%ebp), %eax / and store in 64 bit integer low half.
134: movl INT64+4(%ebp), $0 / Zero-extend to high half.
135: fildll INT64(%ebp) / Load and convert to double.
136:
137: movl %esp, %ebp
138: pop %ebp
139: ret
140:
141: DARG = RASIZE+EBPSIZE
142: FLOAT = -4 / Auto float offset.
143:
144: _dfcvt:
145: push %ebp
146: movl %ebp, %esp
147: push %eax / Claim a float.
148:
149: fldl DARG(%ebp) / Grab double and
150: fstps FLOAT(%ebp) / round to a float.
151: flds FLOAT(%ebp) / Load result.
152:
153: movl %esp, %ebp
154: pop %ebp
155: ret
156:
157: //////////
158: / _idcvt() Convert double to integer.
159: / _udcvt() Convert double to unsigned integer.
160: / _pdcvt() Convert double to pointer.
161: / _ldcvt() Convert double to long integer.
162: / _vdcvt() Convert double to unsigned long integer.
163: / _fdcvt() Convert double to float.
164: /
165: / Shrinks from double.
166: / The task is a little harder than would be expected.
167: / Shift the 80x87 into chop mode for integer conversions
168: / so that conversions work the right way.
169: /
170: / Input:
171: / Double argument on the 80x86 stack.
172: / Output:
173: / Result in %eax for [iulv]dcvt(), %st for _fdcvt().
174: //////////
175:
176: SAVECW = -6 / Auto saved control word offset.
177: INT = -4 / Auto int32 offset.
178:
179: _idcvt:
180: _ldcvt:
181: push %ebp
182: movl %ebp, %esp
183: subl %esp, $6 / Claim a word and a dword.
184:
185: fstcw SAVECW(%ebp) / Save old control word.
186: fldcw cwchop / Load chopping control word.
187: fldl DARG(%ebp) / Load up double and
188: fistpl INT(%ebp) / convert to integer and
189: fldcw SAVECW(%ebp) / put control word back.
190: movl %eax, INT(%ebp) / Result to %eax.
191:
192: movl %esp, %ebp
193: pop %ebp
194: ret
195:
196: SAVECW = -10 / Auto saved control word offset.
197: INT64 = -8 / Auto int64 offset.
198:
199: _pdcvt:
200: _udcvt:
201: _vdcvt:
202: push %ebp
203: movl %ebp, %esp
204: subl %esp, $10 / Claim a word and a 64-bit int.
205:
206: fstcw SAVECW(%ebp) / Save old control word.
207: fldcw cwchop / Load chopping control word.
208: fldl DARG(%ebp) / Load up double and
209: fistpll INT64(%ebp) / convert to integer and
210: fldcw SAVECW(%ebp) / put control word back.
211: movl %eax, INT64(%ebp) / Unsigned long result to %eax.
212: cmpl INT64+4(%ebp), $0 / If hi result dword is zero,
213: je ?0 / return lo result dword.
214: movl %eax, $-1 / Overflow, return UINTMAX.
215:
216: ?0:
217: movl %esp, %ebp
218: pop %ebp
219: ret
220:
221: FLOAT = -4 / Auto float offset.
222:
223: _fdcvt:
224: push %ebp
225: movl %ebp, %esp
226: push %eax / Claim a float.
227:
228: fldl DARG(%ebp) / Load the double and
229: fstps FLOAT(%ebp) / convert it to a float.
230: flds FLOAT(%ebp) / Load the float.
231:
232: movl %esp, %ebp
233: pop %ebp
234: ret
235:
236: //////////
237: / double
238: / ldexp(fraction, exponent) double fraction; int exponent;
239: /
240: / Assemble a double precision floating point number
241: / from the given fraction and integer exponent.
242: //////////
243:
244: FRAC = RASIZE+EBPSIZE
245: EXP = FRAC+8
246:
247: ldexp:
248: push %ebp
249: movl %ebp, %esp
250:
251: fildl EXP(%ebp) / Grab exponent
252: fldl FRAC(%ebp) / and fraction.
253: fscale / Put it all together
254: fstp %st(1) / and pop stack.
255:
256: pop %ebp
257: ret
258:
259: //////////
260: / double
261: / frexp(value, expp) double value; int *expp;
262: /
263: / Split a double float into its fraction and its exponent.
264: / The "fxtract" instruction almost does the job.
265: / The IEEE standard says that the significand is not from 0.5 to 1
266: / but from 1 to 2.
267: / The extracted significand and exponent must be adjusted if nonzero.
268: //////////
269:
270: VALUE = RASIZE+EBPSIZE
271: EXPP = VALUE+8
272:
273: frexp:
274: push %ebp
275: movl %ebp, %esp
276:
277: fldl VALUE(%ebp) / Load the value.
278: fxtract / Significand to %st, unbiased exp to %st1.
279: call _tstcc / Check if the significand is zero.
280: je frexp0 / Jump if it is.
281: filds two / %st=2.0, %st1=sig, %st2=exp.
282: fdivp %st(1), %st / %st=sig/2.0, %st1=exp.
283: fld1 / %st=1.0, %st1=sig/2.0, %st2=exp.
284: faddp %st(2), %st / %st=sig/2.0, %st1=exp+1.0.
285:
286: frexp0: / Significand in %st, exponent in %st1.
287: fxch / Exponent to %st, significand to %st1.
288: movl %eax, EXPP(%ebp) / Save the exponent
289: fistpl (%eax) / through the supplied pointer and pop.
290: fwait / Make sure it is good.
291:
292: pop %ebp
293: ret
294:
295: //////////
296: / double
297: / modf(value, intpart) double value; double *intpart;
298: /
299: / Split a double (another way!).
300: //////////
301:
302: VALUE = RASIZE+EBPSIZE
303: INTPART = VALUE+8
304: SAVECW = -2 / Auto saved control word offset.
305:
306: modf:
307: push %ebp
308: movl %ebp, %esp
309: push %eax / Claim one dword (only 2 bytes used).
310:
311: fstcw SAVECW(%ebp) / Save the old control word and
312: fldcw cwchop / load chopping control word.
313: fldl VALUE(%ebp) / Pick up argument.
314: fld %st / %st=arg, %st1=arg.
315: frndint / %st=intpart, %st1=arg.
316: fsub %st(1), %st / %st=intpart, %st1=fracpart.
317: movl %eax, INTPART(%ebp) / Load integer pointer.
318: fstpl (%eax) / Store intpart through it and pop.
319: fldcw SAVECW(%ebp) / Put old control word back.
320:
321: movl %esp, %ebp
322: pop %ebp
323: ret
324:
325: / end of rts87.s
326:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.