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