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