|
|
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.