|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: .file "round.s" ! 26: ! 27: .ident "@(#)kern-fp:round.s 1.1" ! 28: ! 29: //$tt(*80387 emulator + + + r o u n d + + + *) ! 30: // ********************************************************************** ! 31: // ! 32: // r o u n d . m o d ! 33: // ================= ! 34: // ! 35: // =============================================================== ! 36: // intel corporation proprietary information ! 37: // this software is supplied under the terms of a license ! 38: // agreement or non-disclosure agreement with intel corporation ! 39: // and may not be copied nor disclosed except in accordance with ! 40: // the terms of that agreement. ! 41: // =============================================================== ! 42: // ! 43: // function: ! 44: // implements all rounding modes for all precisions ! 45: // ! 46: // public procedures: ! 47: // round special_round_test ! 48: // directed_round_test ! 49: // ! 50: // internal procedures: ! 51: // prec16_case prec24_case ! 52: // prec32_case prec53_case ! 53: // prec64_case ! 54: // ! 55: // *************************************************************************** ! 56: // ! 57: //...october 31, 1986... ! 58: // ! 59: // .file *a_mro* ! 60: // ! 61: //$nolist ! 62: #include "fp_e80387.h" ! 63: //$list ! 64: //...declare status register segment... ! 65: // ! 66: .data //a_msr segment rw public ! 67: // extrn %gs:sr_flags ! 68: //a_msr ends ! 69: // ! 70: // assume %ds:a_msr ! 71: // ! 72: .text //a_med segment er public ! 73: // ! 74: // extrn get_rnd_control ! 75: // ! 76: .globl round ! 77: .globl directed_round_test ! 78: .globl special_round_test ! 79: // ! 80: // *********************************************************************** ! 81: // prec16_case: ! 82: // ************ ! 83: // function: ! 84: // sets up for rounding to 16 bits. ! 85: // ! 86: // inputs: ! 87: // assumes edi points to operand record. ! 88: // ! 89: // outputs: ! 90: // sets: dl if round or sticky bit set ! 91: // dh if guard bit set ! 92: // ah if lsb set ! 93: // cl to number of rounded bytes ! 94: // ch to pattern to add to low byte for rounding ! 95: // and clears the guard, round, and sticky bytes. ! 96: // doesnt affect al. ! 97: // ! 98: // data accessed: ! 99: // ! 100: // data changed: ! 101: // ! 102: // procecures called: ! 103: // ! 104: // ************************************************************************* ! 105: ALIGN ! 106: prec16_case: //proc ; initially, assume all guard, ! 107: xchg frac80+4(%ebp,%edi),%ecx// round, and sticky info zero ! 108: and %ecx,%ecx // examine and clear grst word ! 109: jns get_round_sticky_16 ! 110: notb %dh // et guard byte ! 111: get_round_sticky_16: ! 112: and $0x7fffffff,%ecx ! 113: or frac80(%ebp,%edi),%ecx ! 114: orw (%ebp,%edi),%cx ! 115: jz get_lsb_16 ! 116: notb %dl // set round-sticky byte ! 117: get_lsb_16: ! 118: xorb %ah,%ah // initially, assume lsb is zero ! 119: testb $0x01,frac80+8(%ebp,%edi) ! 120: jz set_rnd_info_16 ! 121: notb %ah // set lsb byte ! 122: movl $0,frac80(%ebp,%edi) ! 123: movw $0,(%ebp,%edi) ! 124: set_rnd_info_16: ! 125: mov $0x0102,%ecx // the rounded result has 2 bytes ! 126: ret // the pattern to add is 01h ! 127: //prec16_case endp ! 128: // ! 129: // ************************************************************************* ! 130: // prec24_case: ! 131: // ************ ! 132: // function: ! 133: // sets up for rounding to 24 bits. ! 134: // ! 135: // inputs: ! 136: // assumes edi points to operand record. ! 137: // ! 138: // outputs: ! 139: // sets: dl if round or sticky bit set ! 140: // dh if guard bit set ! 141: // ah if lsb set ! 142: // cl to number of rounded bytes ! 143: // ch to pattern to add to low byte for rounding ! 144: // and clears the guard, round, and sticky bytes. ! 145: // doesnt affect al. ! 146: // ! 147: // data accessed: ! 148: // ! 149: // data changed: ! 150: // ! 151: // ************************************************************************* ! 152: ALIGN ! 153: prec24_case: //proc ; initially, assume all guard, ! 154: xchgb frac32(%ebp,%edi),%cl // round, and sticky info zero ! 155: andb %cl,%cl // examine and clear grst word ! 156: jns get_round_sticky_24 ! 157: notb %dh // set guard byte ! 158: get_round_sticky_24: ! 159: andb $0x7f,%cl ! 160: or frac64(%ebp,%edi),%ecx ! 161: or (%ebp,%edi),%ecx ! 162: jz get_lsb_24 ! 163: notb %dl // set round-sticky byte ! 164: get_lsb_24: ! 165: xorb %ah,%ah // initially, assume lsb is zero ! 166: testb $0x01,frac32+1(%ebp,%edi) ! 167: jz clear_sticky_bytes_24 ! 168: notb %ah // set lsb byte ! 169: clear_sticky_bytes_24: ! 170: movl $0,frac64(%ebp,%edi) ! 171: movl $0,(%ebp,%edi) ! 172: mov $0x0103,%ecx // the rounded result has 3 bytes ! 173: ret // the pattern to add is 01h ! 174: //prec24_case endp ! 175: // ! 176: // ***************************************************************************** ! 177: // prec32_case: ! 178: // ************ ! 179: // function: ! 180: // sets up for rounding to 32 bits. ! 181: // ! 182: // inputs: ! 183: // assumes edi points to operand record. ! 184: // ! 185: // outputs: ! 186: // sets: dl if round or sticky bit set ! 187: // dh if guard bit set ! 188: // ah if lsb set ! 189: // cl to number of rounded bytes ! 190: // ch to pattern to add to low byte for rounding ! 191: // and clears the guard, round, and sticky bytes. ! 192: // doesnt affect al. ! 193: // ! 194: // data accessed: ! 195: // ! 196: // data changed: ! 197: // ! 198: // ************************************************************************* ! 199: ALIGN ! 200: prec32_case: //proc ; initially, assume all guard, ! 201: xchg frac64(%ebp,%edi),%ecx // round, and sticky info zero ! 202: and %ecx,%ecx ! 203: jns get_round_sticky_32 ! 204: notb %dh // set guard byte ! 205: get_round_sticky_32: ! 206: and $0x7fffffff,%ecx ! 207: or (%ebp,%edi),%ecx ! 208: jz get_lsb_32 ! 209: notb %dl // set round-sticky byte ! 210: get_lsb_32: ! 211: xorb %ah,%ah // initially, assume lsb is zero ! 212: testb $0x01,frac32(%ebp,%edi) ! 213: jz clear_sticky_bytes_32 ! 214: not_ah_clear_32: ! 215: notb %ah // set lsb byte ! 216: clear_sticky_bytes_32: ! 217: movl $0,(%ebp,%edi) ! 218: mov $0x0104,%ecx// the rounded result has 4 bytes ! 219: ret // the pattern to add is 01h ! 220: //prec32_case endp ! 221: // ! 222: // *********************************************************************** ! 223: // prec53_case: ! 224: // *********** ! 225: // function: ! 226: // sets up for rounding to 53 bits. ! 227: // ! 228: // inputs: ! 229: // assumes edi points to operand record. ! 230: // ! 231: // outputs: ! 232: // sets: dl if round or sticky bit set ! 233: // dh if guard bit set ! 234: // ah if lsb set ! 235: // cl to number of rounded bytes ! 236: // ch to pattern to add to low byte for rounding ! 237: // and clears the guard, round, and sticky bytes. ! 238: // doesnt affect al. ! 239: // ! 240: // data accessed: ! 241: // ! 242: // data changed: ! 243: // ! 244: // *************************************************************************** ! 245: ALIGN ! 246: prec53_case: //proc ; initially, assume all guard, ! 247: mov frac64(%ebp,%edi),%ecx // round, and sticky info zero ! 248: testb $0x04,%ch // examine guard bit ! 249: jz get_round_sticky_53 ! 250: notb %dh // set guard byte ! 251: get_round_sticky_53: ! 252: and $0x03ff,%ecx ! 253: or (%ebp,%edi),%ecx ! 254: jz get_lsb_53 ! 255: notb %dl // set round-sticky byte ! 256: get_lsb_53: ! 257: xorb %ah,%ah // initially, assume lsb is zero ! 258: testb $0x08,frac64+1(%ebp,%edi) ! 259: jz clear_grst_bits_53 ! 260: notb %ah // set lsb byte ! 261: clear_grst_bits_53: ! 262: movl $0,(%ebp,%edi) ! 263: andw $0x0f800,frac64(%ebp,%edi) ! 264: mov $0x0807,%ecx// the rounded result has 7 bytes ! 265: ret // the pattern to add is 08h ! 266: //prec53_case endp ! 267: // ! 268: // **************************************************************************** ! 269: // prec64_case: ! 270: // ************ ! 271: // function: ! 272: // sets up for rounding to 64 bits. ! 273: // ! 274: // inputs: ! 275: // assumes edi points to operand record. ! 276: // ! 277: // outputs: ! 278: // sets: dl if round or sticky bit set ! 279: // dh if guard bit set ! 280: // ah if lsb set ! 281: // cl to number of rounded bytes ! 282: // ch to pattern to add to low byte for rounding ! 283: // and clears the guard, round, and sticky bytes. ! 284: // doesnt affect al. ! 285: // ! 286: // data accessed: ! 287: // ! 288: // data changed: ! 289: // ! 290: // ************************************************************************* ! 291: ALIGN ! 292: prec64_case: //proc ; initially assume all guard, ! 293: xchg (%ebp,%edi),%ecx // round, and sticky info zero ! 294: and %ecx,%ecx // examine and clear grst word ! 295: jns get_round_sticky_64 ! 296: notb %dh // set guard byte ! 297: get_round_sticky_64: ! 298: and $0x7fffffff,%ecx ! 299: jz get_lsb_64 ! 300: notb %dl // set round-sticky byte ! 301: get_lsb_64: ! 302: xorb %ah,%ah // initially, assume lsb is zero ! 303: testb $0x01,frac64(%ebp,%edi) ! 304: jz set_round_info_64 ! 305: notb %ah // set lsb byte ! 306: set_round_info_64: ! 307: mov $0x0108,%ecx // rounded result has 8 bytes ! 308: common_return: ! 309: ret // the pattern to add is 01h ! 310: //prec64_case endp ! 311: // ! 312: // ********************************************************************** ! 313: // round: ! 314: // ***** ! 315: // function: ! 316: // implements rounding. ! 317: // ! 318: // inputs: ! 319: // assumes: edi points to record to round, ! 320: // dl contains rounding precision, ! 321: // al is true if second rounding, false if first. ! 322: // ! 323: // outputs: ! 324: // on return, al is true if there was an high-bit carry-out ! 325: // as a result of incrementing the significand to do the rounding. ! 326: // ! 327: // data accessed: ! 328: // added_one ! 329: // ! 330: // data changed: ! 331: // added_one ! 332: // ! 333: // procedures called: ! 334: // prec16_case prec24_case ! 335: // prec32_case prec53_case ! 336: // prec64_case get_rnd_control ! 337: // ! 338: // ************************************************************************ ! 339: precn_case: ! 340: .long prec24_case,prec32_case,prec53_case,prec64_case,prec16_case ! 341: // ! 342: rnd_case: ! 343: .long case_rnd_to_even,case_rnd_down,case_rnd_up,case_rnd_to_zero ! 344: // ! 345: ALIGN ! 346: round: //proc ; access unpacked status info ! 347: xorb %dh,%dh // set to zero the following: ! 348: movswl %dx,%esi // cl to num bytes in rnd frac ! 349: shl $2,%esi // ch to pattern to add to low ! 350: xorw %dx,%dx // byte in rounding ! 351: xor %ecx,%ecx // dl if round or sticky set ! 352: // mov (ebp+edi),dx ;*** zeroing low word ! 353: call *%cs:precn_case(%esi) // dh if grd set, ah if lsb set ! 354: andw %dx,%dx // if dl and dh both zero, then ! 355: jnz inexact_case // result is exact ! 356: cmpb true,%al ! 357: movb %dl,%al // no carry out from rounding ! 358: jne exact_1st_rnd ! 359: movb %al,rnd2_inexact ! 360: ret ! 361: ALIGN ! 362: exact_1st_rnd: ! 363: movw %dx,rnd_history ! 364: movb %al,added_one // clear flag, no overflow ! 365: ret ! 366: ALIGN ! 367: // ! 368: inexact_case: ! 369: cmpb true,%al ! 370: jne inexact_1st_rnd ! 371: movb %al,rnd2_inexact ! 372: jmp get_rnd_case ! 373: ALIGN ! 374: inexact_1st_rnd: ! 375: movw true,rnd_history// makes rnd1_inexact true, rnd2_inexact false ! 376: get_rnd_case: ! 377: push %eax // save lsb/2nd rounding flags ! 378: call get_rnd_control // round different rnd_control ! 379: movzbl %al,%ebx // cases separately ! 380: pop %eax // reload lsb/2nd rounding flags ! 381: jmp *%cs:rnd_case(%ebx) ! 382: ALIGN ! 383: case_rnd_up: ! 384: notb %bh //if + increment, else truncate ! 385: case_rnd_down: ! 386: cmpb %bh,sign(%ebp,%edi) //increment if neg, ! 387: jne do_increment // truncate if pos ! 388: jmp case_rnd_to_zero ! 389: ALIGN ! 390: case_rnd_to_even: ! 391: movb %dl,%bh // save round-sticky info in bh ! 392: orb %ah,%dl // if guard and (round or sticky ! 393: cmpb true,%al // or lsb), set dx to round up ! 394: jne do_add_ // if 2nd round, if ((lsb=added) ! 395: // mov bl, added_one ; and not (round or sticky) ! 396: // cmp al, rnd1_inexact ; and ((added=1) or last round ! 397: // jne p_error_0 ; inexact)), round in opposite ! 398: // mov bl, al ; al is true (0ffh), hence so is bl ! 399: // the preceding four instructions are equivalent to the next one ! 400: movb rnd1_inexact,%bl ! 401: p_error_0: ! 402: cmpw $0x00ff,%bx // unless first round was inexact and ! 403: jne do_add_ // current round-sticky bits are clear, ! 404: // decide how to round as for first round ! 405: cmpb added_one,%ah // else, dh (guard) must be true here because ! 406: // exact second rounds were ruled out earlier ! 407: jne do_add_ // branch if ah <> added_one ! 408: incw %dx // here, dh = guard, dl = lsb ! 409: jz case_rnd_to_zero // truncate ! 410: jmp do_increment ! 411: ALIGN ! 412: do_add_: ! 413: incw %dx ! 414: jz do_increment ! 415: case_rnd_to_zero: ! 416: movb false,%al // clear flag, indicate nothing ! 417: movb %al,added_one // added in round (al = false) ! 418: // and %gs:sr_flags,not a_mask ; clear the a-bit ---> defer ! 419: jmp set_inexact ! 420: ALIGN ! 421: do_increment: ! 422: // or %gs:sr_flags,a_mask ; set the a-bit ---> defer ! 423: movb true,added_one // set flag for 1 added in round ! 424: movb %ch,%dl // put pattern to add in dl ! 425: xorb %ch,%ch // ecx = num bytes in rounded res ! 426: mov $12,%ebx ! 427: sub %ecx,%ebx // ebx = num of low byte ! 428: add %ebx,%edi // edi = true offset ! 429: xorb %al,%al ! 430: addb %dl,(%ebp,%edi) // add pattern to low byte and ! 431: inc %edi // propogate carries ! 432: dec %ecx ! 433: FALLSTHRU ! 434: inc_loop: ! 435: adcb %al,(%ebp,%edi) ! 436: inc %edi ! 437: LOOP(inc_loop) ! 438: sbbb %al,%al // set al if carry set ! 439: sub $12,%edi // restore edi to entry value ! 440: set_inexact: ! 441: // jmp set_p_error ---> defer ! 442: ret ! 443: //round endp ! 444: // ! 445: // **************************************************************************** ! 446: // special_round_test: ! 447: // ****************** ! 448: // function: ! 449: // test for rounding toward zero. ! 450: // ! 451: // inputs: ! 452: // assumes sign to be in al upon entry. ! 453: // ! 454: // outputs: ! 455: // returns true (in al) and clears zf if: ! 456: // (rnd_down and sign is positive) or ! 457: // (rnd_up and sign is negative); ! 458: // else returns false (in al) and sets zf. ! 459: // ! 460: // data accessed: ! 461: // ! 462: // data changed: ! 463: // ! 464: // procedures called: ! 465: // get_rnd_control ! 466: // ! 467: // ************************************************************************** ! 468: ALIGN ! 469: special_round_test: //proc ! 470: movb %al,%ah // save sign ! 471: call get_rnd_control //get rounding mode ! 472: cmpb rnd_down,%al ! 473: jne round_up_ // branch if not down ! 474: andb %ah,%ah ! 475: jz is_true // true if +rnd_down ! 476: is_false: ! 477: xorb %al,%al // sets zf. ! 478: ret ! 479: ALIGN ! 480: round_up_: ! 481: cmpb rnd_up,%al ! 482: jne is_false // branch if not up ! 483: andb %ah,%ah ! 484: jz is_false // branch if +rnd_up ! 485: is_true: ! 486: orb true,%al // clears zf. ! 487: exit_round_test: ! 488: ret ! 489: //special_round_test endp ! 490: // ! 491: // ************************************************************************** ! 492: // directed_round_test: ! 493: // ******************* ! 494: // function: ! 495: // test for round control (up or down). ! 496: // ! 497: // inputs: ! 498: // none ! 499: // ! 500: // outputs: ! 501: // returns true (in al) and clears zf if the round control ! 502: // is rnd_up or rnd_down. otherwise, returns false and sets zf. ! 503: // ! 504: // data accessed: ! 505: // ! 506: // data changed: ! 507: // ! 508: // procedures called: ! 509: // get_rnd_conrol ! 510: // ! 511: // ************************************************************************* ! 512: ALIGN ! 513: directed_round_test: //proc ! 514: call get_rnd_control ! 515: cmpb rnd_down,%al ! 516: je is_true ! 517: cmpb rnd_up,%al ! 518: je is_true ! 519: jmp is_false ! 520: //directed_round_test endp ! 521: // ! 522: //a_med ends ! 523: // ! 524: // end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.