|
|
1.1 root 1: //////////
2: / rts87.s
3: / cc386 80x87 runtime support.
4: / N.B. Converted 6/29/92 by steve from 8087 .a86 source, not tested!
5: / Conversion is incomplete!
6: / Operand lengths should be explicit for each opcode!
7: //////////
8:
9: .text
10:
11: .globl _cfcc
12: .globl _tstcc
13: .globl _tstccp
14: .globl _dp87
15: .globl _fdcvt
16: .globl _vdcvt
17: .globl _ldcvt
18: .globl _udcvt
19: .globl _idcvt
20: .globl _dfcvt
21: .globl _dvcvt
22: .globl _dlcvt
23: .globl _ducvt
24: .globl _dicvt
25: .globl ldexp
26: .globl frexp
27: .globl modf
28:
29: / The following should be unnecessary but...
30: .globl _fvcvt
31: .globl _flcvt
32: .globl _fucvt
33: .globl _ficvt
34:
35: iw87 .word 0x0fbf / chop control word
36: cwdown .word 0x07ff / round down control word
37: two .word 2 / constant 2
38:
39: //////////
40: / _tstcc() Test and copy floating condition codes.
41: / _tstccp() Test and pop and copy floating condition codes.
42: / _cfcc() Copy floating condition codes.+
43: /
44: / _tstcc() tests the 80x87 stacktop against 0 and then does a _cfcc().
45: / _tstccp() tests the 80x87 stacktop against 0, pops, and then does a _cfcc.
46: / _cfcc() copies the C0 and C3 status flags from the 80x87
47: / into the C and Z flags of the 80x86.
48: / This uses the otherwise useless opcode that copies the flags
49: / from %AH in 8080 format.
50: /
51: / Input:
52: / 80x87 status word.
53: / Output:
54: / 80x86 flags.
55: //////////
56:
57: _tstcc:
58: ftst / test st against 0.
59: jmp _cfcc / and set the condition codes.
60: _tstccp:
61: ftst / test st against 0,
62: fstp %st / pop the 80x87 stack
63: / and fall through...
64: _cfcc:
65: / N.B. fstsw unimplemented in as386 of 7/1/92, so use fwait+fnstsw instead
66: / fstsw %ax / store the 80x87 status word to AX
67: fwait
68: fnstsw %ax / store the 80x87 status word to AX
69: fwait / and wait for it to finish up.
70: sahf / load cf and zf correctly.
71: ret / and return to caller.
72:
73: //////////
74: / _dp87() Double push from 80x87 stack.
75: /
76: / Move a double from the top of the 80x87 stack to the top of the system stack.
77: / There is some magic to keep the return address in one piece.
78: /
79: / Input:
80: / Double to push in %st.
81: / Outputs:
82: / NDP stack popped.
83: / Double on 80x86 stack.
84: //////////
85:
86: _dp87:
87: pop %eax / capture return address.
88: subl %esp, $8 / claim a double on stack and
89: fstpl (%esp) / pop 80x87 to memory.
90: fwait / make sure pop is completed.
91: ijmp %eax / return to the caller.
92:
93: //////////
94: / _dicvt() Convert integer to double.
95: / _ducvt() Convert unsigned integer 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: / These routines are called directly from compiled code for all
101: / widen conversions to double.
102: / Some of the simple widens can be
103: / compiled inline, but the unsigned widens and the signed
104: / widens when the object lacks an lvalue cannot be.
105: /
106: / Each routine is passed the source operand as any C
107: / argument would be passed.
108: / Each returns the result on the top of the 80x87 stack.
109: //////////
110:
111: _dicvt:
112: _ficvt:
113: fildl 4(%esp) / load up the integer.
114: ret / return.
115:
116: _ducvt:
117: _fucvt:
118: push %ebp / save
119: movl %ebp, %esp / sequence
120: push %eax / claim a long int.
121:
122: mov %eax, 4(%ebp) / fetch the unsigned int and
123: mov -4(%ebp), %eax / put in ls half.
124: mov -2(%ebp), $0 / zero extend.
125: fild -4(%ebp) / load and convert to double.
126:
127: mov %esp, %ebp / back up stack.
128: pop %ebp / standard
129: ret / return sequence.
130:
131: _dlcvt:
132: _flcvt:
133: fild 4(%esp) / load and convert the long.
134: ret / sequence.
135:
136: _dvcvt;
137: _fvcvt:
138: push %ebp / save
139: mov %ebp, %esp / sequence
140: sub %esp, $8 / claim a 64 bit integer.
141:
142: mov %eax, 4(%ebp) / low half of long
143: mov -8(%ebp), %eax / put in 64 bit integer.
144: mov %eax, 6(%ebp) / high half of long.
145: mov -6(%ebp), %eax / put in 64 bit integer.
146: mov -4(%ebp), $0 / zeros on the
147: mov -2(%ebp), $0 / end.
148: fild -8(%ebp) / load and convert to double.
149:
150: mov %esp, %ebp / standard
151: pop %ebp / c
152: ret / sequence.
153:
154: _dfcvt:
155: push %ebp / save
156: mov %ebp, %esp / sequence.
157: push %eax / claim a float.
158:
159: fld 4(%ebp) / grab double and
160: fstp -4(%ebp) / round to a single float.
161: fld -4(%ebp) / load result.
162:
163: mov %esp, %ebp / full.
164: pop %ebp / standard
165: ret / sequence.
166:
167: //////////
168: / _idcvt() convert double to integer
169: / _udcvt() convert double to unsigned integer
170: / _ldcvt() convert double to long integer
171: / _vdcvt() convert double to unsigned long integer
172: / _fdcvt() convert double to float
173: /
174: / this set of routines handle all shrinks from double. the task
175: / is a little harder than would be expected. the 80x87 is always
176: / shifted into chop mode, so that conversions work the way that
177: / you expect them to work.
178: /
179: / all of these routines take a double argument in the standard
180: / way, and return the result in the standard return location of
181: / objects of that type (%eax, dx%eax, tos).
182: //////////
183:
184: _idcvt:
185: push %ebp / save
186: mov %ebp, %esp / sequence.
187: push %eax / claim 2 words.
188:
189: / fstcw -2(%ebp) / save old control word
190: fwait
191: fnstcw -2(%ebp) / save old control word
192: fldcw iw87 / load chopping control word
193: fld 4(%ebp) / load up double and
194: fistp -4(%ebp) / convert to integer and
195: fldcw -2(%ebp) / put control word back.
196: mov %eax, -4(%ebp) / ax=result.
197:
198: mov %esp, %ebp / standard
199: pop %ebp / c
200: ret / sequence.
201:
202: _udcvt:
203: push %ebp / save
204: mov %ebp, %esp / sequence.
205: sub %esp, $6 / claim 3 words.
206:
207: / fstcw -2(%ebp) / save old control word
208: fwait
209: fnstcw -2(%ebp) / save old control word
210: fldcw iw87 / load chopping control word
211: fld 4(%ebp) / load up double and
212: fistp -6(%ebp) / convert to 32 bit integer and
213: fldcw -2(%ebp) / put control word back.
214: mov %eax, -6(%ebp) / ax=ls half of result.
215:
216: mov %esp, %ebp / standard
217: pop %ebp / c
218: ret / sequence.
219:
220: _ldcvt:
221: push %ebp / save
222: mov %ebp, %esp / sequence.
223: sub %esp, $6 / claim 3 words.
224:
225: / fstcw -2(%ebp) / save old control word
226: fwait
227: fnstcw -2(%ebp) / save old control word
228: fldcw iw87 / load chopping control word
229: fld 4(%ebp) / load up double and
230: fistp -6(%ebp) / convert to long and
231: fldcw -2(%ebp) / put control word back.
232: mov %eax, -6(%ebp) / dxax=the 32 bit
233: mov %edx, -4(%ebp) / result.
234:
235: mov %esp, %ebp / standard
236: pop %ebp / c
237: ret / sequence.
238:
239: _vdcvt:
240: push %ebp / save
241: mov %ebp, %esp / sequence.
242: sub %esp, $10 / claim 5 words.
243:
244: / fstcw -2(%ebp) / save old control word
245: fwait
246: fnstcw -2(%ebp) / save old control word
247: fldcw iw87 / load chopping control word
248: fldcw iw87 / load chopping control word
249: fld 4(%ebp) / load up double and
250: fistp -10(%ebp) / convert to integer and
251: fldcw -2(%ebp) / put control word back.
252: mov %eax, -10(%ebp) / dxax=unsigned long
253: mov %edx, -8(%ebp) / result.
254:
255: mov %esp, %ebp / standard
256: pop %ebp / c
257: ret / sequence.
258:
259: _fdcvt:
260: push %ebp / save
261: mov %ebp, %esp / sequence.
262: push %eax / claim 2 words.
263:
264: fld 4(%ebp) / load the double and
265: fstp -4(%ebp) / convert it to a float.
266: fld -4(%ebp) / load the float up.
267:
268: mov %esp, %ebp / standard
269: pop %ebp / c
270: ret / sequence.
271:
272: //////////
273: / ldexp() make a double.
274: /
275: / this routine assembles a double precision floating point number
276: / given a fraction and an integer exponent.
277: /
278: / calling sequence:
279: / double
280: / ldexp(fraction, exponent);
281: / double fraction;
282: / int exponent;
283: //////////
284:
285: ldexp:
286: push %ebp / save
287: mov %ebp, %esp / sequence.
288:
289: fild 12(%ebp) / exponent
290: fld 4(%ebp) / fraction
291: fscale / put it all together
292: fstp %st(1) / and pop stack
293:
294: pop %ebp / standard
295: ret / return.
296:
297: //////////
298: / frexp() split a double.
299: /
300: / this routine splits a double float into its fraction and its
301: / exponent. the "fxtract" instruction almost does the job. the
302: / ieee standard says that the significand is not from 0.5 to 1
303: / but from 1 to 2. the extracted significand and exponent must
304: / be adjusted (if non zero).
305: /
306: / calling sequence:
307: / double
308: / frexp(value, expp);
309: / double value;
310: / int *expp;
311: //////////
312:
313: frexp:
314: push %ebp / save
315: mov %ebp, %esp / sequence
316:
317: fld 4(%ebp) / load up the value
318: fxtract / split it
319: call _tstcc / check if the significand is zero.
320: je frexp0 / jump if it is.
321: fild two / divide the significand
322: fdivp %st(1), %st / by two and
323: fld1 / add 1 to the
324: faddp %st(2), %st / exponent.
325:
326: frexp0: fxch / move exponent to %st
327: mov %ebx, 12(%ebp) / save the exponent
328: fistp (%ebx) / through the supplied pointer.
329: fwait / make sure it is good.
330:
331: pop %ebp / standard
332: ret / return.
333:
334: //////////
335: / modf() split a double (another way!)
336: /
337: / calling sequence:
338: / double
339: / modf(value, intpart);
340: / double value;
341: / double *intpart;
342: //////////
343:
344: modf:
345: push %ebp / function
346: mov %ebp, %esp / sequence.
347: push %eax / claim one word.
348:
349: / fstcw -2(%ebp) / save the old control word and
350: fwait
351: fnstcw -2(%ebp) / save the old control word and
352: fldcw cwdown / load a new one that rounds down.
353: fld 4(%ebp) / pick up argument.
354: fld %st / %st=arg, %st(1)=arg.
355: frndint / %st=intpart, %st(1)=arg.
356: fsub %st(1), %st / %st=intpart, %st(1)=fracpart.
357: mov %ebx, 12(%ebp) / load integer pointer.
358: fstp (%ebx) / store intpart through it and pop.
359: fldcw -2(%ebp) / put old control word back.
360:
361: mov %esp, %ebp / standard
362: pop %ebp / c
363: ret / code
364:
365: / end of rts87.s
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.