|
|
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 "arith.s" ! 26: ! 27: .ident "@(#)kern-fp:arith.s 1.1" ! 28: //$tt(*80387 emulator + + + arithmetic + + +*) ! 29: // ************************************************************************ ! 30: // ! 31: // a r i t h . m o d ! 32: // ================= ! 33: // ! 34: // =============================================================== ! 35: // intel corporation proprietary information ! 36: // this software is supplied under the terms of a license ! 37: // agreement or non-disclosure agreement with intel corporation ! 38: // and may not be copied or disclosed except in accordance with ! 39: // the terms of that agreement. ! 40: // =============================================================== ! 41: // ! 42: // function: ! 43: // implements add, subtract, multiply, and divide. ! 44: // ! 45: // public procedures: ! 46: // move_op_to_result overflow_response ! 47: // underflow_response put_max_nan ! 48: // put_indefinite arith ! 49: // ! 50: // ************************************************************************* ! 51: // ! 52: //...March 3, 1987... ! 53: // ! 54: // .file *a_mar* ! 55: #include "fp_e80387.h" ! 56: //$eject ! 57: //...declare status register segment... ! 58: // ! 59: .data //a_msr segment rw public ! 60: // extrn sr_masks ! 61: //a_msr ends ! 62: // ! 63: .text //a_med segment er public ! 64: // assume %ds:a_med ! 65: // extrn addition_normalize,round ! 66: // extrn gradual_underflow,put_result ! 67: // extrn pop_free,subadd,mult ! 68: // extrn divid,set_up_indefinite,test_4w ! 69: // extrn special_round_test,directed_round_test ! 70: // extrn get_precision,u_masked_,set_i_masked_ ! 71: // extrn d_masked_,affine_infinity_,i_masked_ ! 72: // extrn o_masked_,set_p_error,set_u_error ! 73: // extrn set_o_error,set_z_masked_,set_d_masked_ ! 74: // extrn set_stk_u_error,d_error_,get_rnd_control ! 75: // ! 76: .globl put_indefinite ! 77: .globl move_op_to_result ! 78: .globl put_max_nan ! 79: .globl overflow_response ! 80: .globl underflow_response ! 81: .globl arith ! 82: .globl norm_denorm ! 83: .globl put_arith_result ! 84: .globl set_up_nan_return ! 85: //$eject ! 86: // ! 87: //...define some floating point constants... ! 88: // ! 89: indefinite_pattern: ! 90: .value 0,0,0,0x0c000,0x0ffff ! 91: infinity_pattern: ! 92: .value 0,0,0,0x8000,0x7fff ! 93: zero_pattern: ! 94: .value 0,0,0,0,0 ! 95: max_valid_pattern: ! 96: .value 0x0ffff,0x0ffff,0x0ffff,0x0ffff,0x7ffe ! 97: arith_table: ! 98: .long subadd,subadd,mult,divid ! 99: // ! 100: //...the following jump tables refer to the following op1/op2 cases ! 101: // ! 102: // (where v=valid, z=zero, f=infinity, and d=denormal): ! 103: // v/v,v/z,v/f,v/d,z/v,z/z,z/f,z/d,f/v,f/z,f/f,f/d,d/v,d/z,d/f and d/d, ! 104: // in that order .. ! 105: //add_table ! 106: special_table: ! 107: .long handle_non_special_cases,handle_non_special_cases ! 108: .long second_operand,only_op2_denormd ! 109: .long handle_non_special_cases,handle_non_special_cases ! 110: .long second_operand,only_op2_denormd ! 111: .long first_operand,first_operand ! 112: .long add_sub_infinities,derror_with_first_operand ! 113: .long only_op1_denormd,only_op1_denormd ! 114: .long derror_with_second_operand,both_ops_denormd ! 115: //sub_table ! 116: .long handle_non_special_cases,handle_non_special_cases ! 117: .long neg_second_operand,only_op2_denormd ! 118: .long handle_non_special_cases,handle_non_special_cases ! 119: .long neg_second_operand,only_op2_denormd ! 120: .long first_operand,first_operand ! 121: .long add_sub_infinities,derror_with_first_operand ! 122: .long only_op1_denormd,only_op1_denormd ! 123: .long derror_with_neg_second_operand,both_ops_denormd ! 124: //mul_table ! 125: .long handle_non_special_cases,exor_signed_zero ! 126: .long exor_signed_infinity,only_op2_denormd ! 127: .long exor_signed_zero,exor_signed_zero ! 128: .long invalid_error_detected,denormd_exor_signed_zero ! 129: .long exor_signed_infinity,invalid_error_detected ! 130: .long exor_signed_infinity,denormd_exor_signed_infinity ! 131: .long only_op1_denormd,denormd_exor_signed_zero ! 132: .long denormd_exor_signed_infinity,both_ops_denormd ! 133: //div_table ! 134: .long handle_non_special_cases,divide_by_zero ! 135: .long exor_signed_zero,only_op2_denormd ! 136: .long exor_signed_zero,invalid_error_detected ! 137: .long exor_signed_zero,denormd_exor_signed_zero ! 138: .long exor_signed_infinity,exor_signed_infinity ! 139: .long invalid_error_detected,denormd_exor_signed_infinity ! 140: .long only_op1_denormd,divide_by_zero ! 141: .long denormd_exor_signed_zero,both_ops_denormd ! 142: // ! 143: //$eject ! 144: // put_indefinite: ! 145: // ! 146: // function: ! 147: // sets unpacked result to indefinite. ! 148: // ! 149: // inputs: ! 150: // ! 151: // outputs: ! 152: // result set to indefinite; tag set to invalid. ! 153: // ! 154: // data accessed: ! 155: // - result_sign result_tag ! 156: // ! 157: // data changed: ! 158: // - result ! 159: // ! 160: ALIGN ! 161: put_indefinite: //proc ! 162: mov $indefinite_pattern,%esi ! 163: movb negative,result_sign(%ebp) ! 164: // note that entry points below do not affect result_sign. ! 165: put_inv_tag: ! 166: movb inv,result_tag(%ebp) // fall into set_constant_result ! 167: set_constant_result: ! 168: lea offset_result+4(%ebp),%edi ! 169: // push %ds // save a?msr ! 170: // push %cs ! 171: // pop %ds ! 172: // push %ss ! 173: // pop %es ! 174: ! 175: /* FAST_MOVSL */ ! 176: movl %cs:0(%esi),%ecx ! 177: movl %ecx,%ss:0(%edi) ! 178: movl %cs:4(%esi),%ecx ! 179: movl %ecx,%ss:4(%edi) ! 180: // addl $8,%esi ! 181: ! 182: mov %ecx,result_dword_frac(%ebp) // clear ls dword ! 183: mov %cs:8(%esi),%eax // move exponent ! 184: movw %ax,result_expon(%ebp) // to result ! 185: // pop %ds // reload a?msr ! 186: ret ! 187: //put_indefinite endp ! 188: //$eject ! 189: // move_op_to_result: ! 190: // ! 191: // function: ! 192: // moves operand to result. ! 193: // ! 194: // inputs: ! 195: // assumes ss:(ebp).esi points to op1 or op2 ! 196: // ! 197: // outputs: ! 198: // result in result ! 199: // ! 200: // data accessed: ! 201: // - expon1 offset_result ! 202: // - result_expon ! 203: // ! 204: // data changed: ! 205: // - result ! 206: // ! 207: ALIGN ! 208: move_op_to_result: //proc ! 209: // push %ds // save a?msr ! 210: add %ebp,%esi ! 211: // push %ss ! 212: // pop %ds ! 213: // push %ss ! 214: // pop %es ! 215: lea offset_result(%ebp),%edi ! 216: mov $((offset_operand2-offset_operand1)>>2),%ecx ! 217: ! 218: /* FAST_MOVSL */ ! 219: 1: ! 220: movl %ss:0(%esi),%eax ! 221: movl %eax,%ss:0(%edi) ! 222: addl $4,%esi ! 223: addl $4,%edi ! 224: decl %ecx ! 225: testl %ecx,%ecx ! 226: jg 1b ! 227: ! 228: // pop %ds // reload a?msr ! 229: ret ! 230: //move_op_to_result endp ! 231: //$eject ! 232: // overflow_response: ! 233: // ! 234: // function: ! 235: // responds to detected overflow. ! 236: // ! 237: // inputs: ! 238: // ! 239: // outputs: ! 240: // overflow error indication(s) set when appropriate ! 241: // correct masked or unmasked result ! 242: // ! 243: // data accessed: ! 244: // - result_sign result_tag ! 245: // - result_expon msb_result ! 246: // ! 247: // data changed: ! 248: // - result ! 249: // ! 250: // procedures called: ! 251: // special_round_test set_o_error ! 252: // o_masked? set_p_error ! 253: // ! 254: // ! 255: ALIGN ! 256: overflow_response: //proc ! 257: orb overflow_mask, %gs:sr_errors //set overflow error ! 258: testb overflow_mask, %gs:sr_masks ! 259: jnz masked_overflow // branch if ovflw masked ! 260: // note that p_error may have been set by the first rounding of the result, ! 261: // and that rounded result will now have its exponents bias adjusted: ! 262: reduce_exponent: ! 263: subl wrap_around_constant,dword_result_expon // subtract ! 264: cmpl $0x7fff, dword_result_expon //wrap around constant ! 265: jge masked_overflow // bad! should give qnan indefinite ! 266: unmasked_ov_un_rounds: ! 267: cmpb true, rnd1_inexact //detect inexact result ! 268: jne give_valid_o_result // if exact, branch to replace source ! 269: orb $inexact_mask, %gs:sr_errors // else, set p_error ! 270: cmpb true, added_one //was rounding done by adding one ! 271: jne give_valid_o_result // if not branch to replace source ! 272: orb $a_mask, %gs:sr_flags // else set A_bit ! 273: jmp give_valid_o_result ! 274: ALIGN ! 275: masked_overflow: ! 276: orb $inexact_mask, %gs:sr_errors //set p_error ! 277: call get_rnd_control ! 278: cmpb rnd_to_zero,%al ! 279: je put_max_valid ! 280: movb result_sign(%ebp),%al // check for special ! 281: call special_round_test // rounding case ! 282: jnz put_max_valid ! 283: orb $a_mask, %gs:sr_flags //set a_bit ! 284: put_infinity: ! 285: mov $infinity_pattern,%esi ! 286: jmp put_inv_tag ! 287: ALIGN ! 288: put_max_valid: ! 289: // mov (ebp).result_tag, valid ! 290: movl $0x00007ffe,dword_result_expon ! 291: movl $0,result_dword_frac(%ebp) ! 292: movl $0x0ffffffff,result_dword_frac+frac64(%ebp) ! 293: movl $0x0ffffffff,result_dword_frac+frac32(%ebp) ! 294: cmpb $add_op,operation_type(%ebp) ! 295: jl give_valid_o_result ! 296: cmpb $div_op,operation_type(%ebp) ! 297: jg give_valid_o_result ! 298: movb $precision_mask,%dl // load precision field mask ! 299: andb %gs:sr_controls,%dl // mask in precision control ! 300: cmpb prec53,%dl ! 301: jg give_valid_o_result ! 302: je purge_11_bits ! 303: movl $0,result_dword_frac+frac64(%ebp) ! 304: movl $0x0ffffff00,result_dword_frac+frac32(%ebp) ! 305: jmp give_valid_o_result ! 306: ALIGN ! 307: purge_11_bits: ! 308: andl $0x0fffff800,result_dword_frac+frac64(%ebp) ! 309: ! 310: // mov esi, offset max_valid_pattern ; set result to max ! 311: // jmp set_constant_result ; valid number ! 312: ! 313: give_valid_o_result: ! 314: movb valid,result_tag(%ebp) ! 315: ret ! 316: //overflow_response endp ! 317: //$eject ! 318: // underflow_response: ! 319: // ! 320: // function: ! 321: // responds to a detected underflow ! 322: // ! 323: // inputs: ! 324: // ! 325: // outputs: ! 326: // sets underflow error indication(s) if appropiate ! 327: // correct masked or unmasked results in result ! 328: // ! 329: // data accessed: ! 330: // - offset_result result_sign ! 331: // - result_tag result_expon ! 332: // - result_word_frac ! 333: // ! 334: // data changed: ! 335: // - result ! 336: // ! 337: // procedures called: ! 338: // directed_round_test gradual_underflow ! 339: // round test_4w ! 340: // set_u_error u_masked? ! 341: // get_precision ! 342: // ! 343: ALIGN ! 344: underflow_response: //proc ! 345: testb underflow_mask, %gs:sr_masks //is underflow masked ! 346: jnz do_grad_underflow // yes, dont set flag ! 347: orb underflow_mask, %gs:sr_errors //no, set error flag ! 348: increase_exponent: ! 349: addl wrap_around_constant,dword_result_expon // add wrap-around ! 350: cmp $0, dword_result_expon //wrap_around constant ! 351: jg unmasked_ov_un_rounds // bad! shuld give qnan indef ! 352: subl wrap_around_constant, dword_result_expon // subtract ! 353: do_grad_underflow: ! 354: mov $offset_result,%edi // do gradual underflow ! 355: mov $0x0001,%eax // minimum expon is 0001 ! 356: call gradual_underflow ! 357: call get_precision ! 358: movb true,%al ! 359: mov $offset_result,%edi // do second round ! 360: call round ! 361: cmpw $0, rnd_history ! 362: je prepare_zero_expon ! 363: orb underflow_mask + inexact_mask, %gs:sr_errors //set both errors ! 364: cmpb true, added_one // was rounding done by adding one ! 365: jne prepare_zero_expon //if not, branch for zero expon ! 366: orb $a_mask, %gs:sr_flags //else, set a_bit & if incrementing ! 367: testb $0x80, msb_result //The significand caused the most ! 368: jz prepare_zero_expon //significant bit of result_frac to ! 369: movb valid, result_tag(%ebp) // be set, tag result *valid* & return ! 370: ret ! 371: ALIGN ! 372: prepare_zero_expon: ! 373: xor %eax, %eax ! 374: clear_expon: ! 375: mov %eax,dword_result_expon // set exponent to zero ! 376: mov $result_dword_frac+4,%edi ! 377: call test_4w // if fraction nonzero, ! 378: movb denormd,result_tag(%ebp) ! 379: jnz accept_tag // tag as denormal ! 380: movb special,result_tag(%ebp) // else, tag as zero ! 381: accept_tag: ! 382: ret ! 383: //underflow_response endp ! 384: //$eject ! 385: // norm_denorm: ! 386: // ! 387: // function: ! 388: // normalizes an unpacked operand presumed to have been tagged ! 389: // *denormd*. includes case in which operand is so tagged because ! 390: // it was a single or double format denormal, which has already ! 391: // been normalized in the course of extending it to unpacked format. ! 392: // also includes case in which operand is a pseudo-denormal. ! 393: // ! 394: // inputs: edi points to the offset of the record to be normalized. ! 395: // ! 396: // outputs: ! 397: // 8 bytes beginning at (ebp + edi + frac64) are left shifted until ! 398: // the bit in position b63 is set. ! 399: // the 32 bit exponent field is 1 - shift_count ! 400: // ! 401: // data accessed: ! 402: // - dword ptr (ebp + edi + expon) ! 403: // - byte ptr (ebp + edi + msb) ! 404: // - dword ptr (ebp + edi + frac32), dword ptr (ebp + edi + frac64) ! 405: // ! 406: // data changed: ! 407: // - dword ptr (ebp + edi + expon) ! 408: // - byte ptr (ebp + edi + msb) ! 409: // - dword ptr (ebp + edi + frac32), dword ptr (ebp + edi + frac64) ! 410: // ! 411: // procedures called: ! 412: // ! 413: // ! 414: ALIGN ! 415: norm_denorm: //proc ! 416: cmp $0,expon(%ebp,%edi) ! 417: jne norm_denorm_done ! 418: movl $1,expon(%ebp,%edi) ! 419: testb $0x80,msb(%ebp,%edi) ! 420: jnz norm_denorm_done ! 421: norm_64_bits: ! 422: bsrl frac32(%ebp,%edi),%ecx ! 423: jz top_32_zero ! 424: mov frac64(%ebp,%edi),%eax ! 425: sub $31,%ecx ! 426: neg %ecx ! 427: shldl %cl,%eax,frac32(%ebp,%edi) ! 428: shll %cl,frac64(%ebp,%edi) ! 429: adjust_dword_expon: ! 430: sub %ecx,expon(%ebp,%edi) // adjust exponent ! 431: norm_denorm_done: ! 432: ret ! 433: ALIGN ! 434: top_32_zero: ! 435: mov frac64(%ebp,%edi),%eax ! 436: bsrl %eax,%ecx ! 437: sub $31,%ecx ! 438: neg %ecx ! 439: shll %cl,%eax ! 440: mov %eax,frac32(%ebp,%edi) ! 441: movl $0,frac64(%ebp,%edi) ! 442: add $32,%ecx ! 443: jmp adjust_dword_expon ! 444: //norm_denorm endp ! 445: //$eject ! 446: // ! 447: // arith: ! 448: // ! 449: // function: ! 450: // main procedure for implementation of 80387 add, subtract, ! 451: // multiply, and divide instructions ! 452: // ! 453: // inputs: ! 454: // assumes operation type, operand(s), and unpacked ! 455: // status variables are set up ! 456: // ! 457: // outputs ! 458: // result of operation in result ! 459: // ! 460: // data accessed: ! 461: // - operation_type offset_operand1 ! 462: // - sign1 tag1 ! 463: // - expon1 offset_operand2 ! 464: // - sign2 tag2 ! 465: // - expon2 offset_result ! 466: // - result_sign result_tag ! 467: // - result_expon result_word_frac ! 468: // ! 469: // data changed: ! 470: // - result ! 471: // ! 472: // procedures called: ! 473: // put_indefinite affine_infinity? ! 474: // put_max_valid move_op_to_result ! 475: // overflow_response underflow_response ! 476: // put_max_nan divid ! 477: // set_up_indefinite round ! 478: // addition_normalized put_result ! 479: // pop_free subadd ! 480: // mult test_4w ! 481: // i_masked? d_error? ! 482: // d_masked? i_error? ! 483: // get_precision set_i_masked? ! 484: // set_z_masked? set_d_masked? ! 485: // ! 486: // ! 487: ALIGN ! 488: arith: //proc ! 489: // assume %ds:a_msr ! 490: jz weed_out_special_cases // branch if no stack error ! 491: call set_stk_u_error // stack underflow occurred ! 492: testb invalid_mask,%gs:sr_masks ! 493: jz go_home // if unmasked, return ! 494: call put_indefinite // otherwise, result = indefinite ! 495: jmp finish_up ! 496: ALIGN ! 497: weed_out_special_cases: ! 498: andb $~a_mask, %gs:sr_flags //clear a_bit initially ! 499: movb tag1(%ebp),%al // both operands valid? ! 500: orb tag2(%ebp),%al ! 501: jnz special_cases // no, special case ! 502: handle_non_special_cases: ! 503: movzbl operation_type(%ebp),%ebx// call sub/add/mul/div ! 504: subb $add_op,%bl // to do the operation ! 505: shlw $2,%bx ! 506: call *%cs:arith_table(%ebx) ! 507: // the following three instructions are residue of warning mode arithmetic: ! 508: // call i_error? ; invalid if attempted ! 509: // jz no_invalid_error; division by denormal ! 510: // jmp invalid_error_detected ! 511: no_invalid_error: ! 512: mov $offset_result,%edi // round result ! 513: call get_precision // (indicate first, not ! 514: movb false,%al // second, round) ! 515: call round ! 516: mov $offset_result,%edi // re-normalize ! 517: // movb $4,%ah / (num words in frac=4) ! 518: call addition_normalize // (al contains overflow ! 519: mov dword_result_expon,%eax // indication from round) ! 520: cmp $0x7ffe,%eax // overflow iff ! 521: jg overflow_happened // expon > 7ffeh ! 522: cmp $0,%eax // check underflow if ! 523: jl underflow_happened // expon < 0 ! 524: call give_valid_o_result // set tag to valid ! 525: and %eax,%eax // check underflow if ! 526: jnz report_rounds // expon = 0 and frac <> 0 ! 527: mov $result_dword_frac+4,%edi //expon=0 ! 528: call test_4w ! 529: jnz underflow_happened ! 530: movb special,result_tag(%ebp) // result is truly zero ! 531: report_rounds: ! 532: cmpb true, rnd1_inexact //detect inexact result ! 533: jne finish_up //if exact, branch ! 534: orb $inexact_mask, %gs:sr_errors //else, set p_error ! 535: cmpb true, added_one //was rounding done by adding one ! 536: jne finish_up //if not, branch ! 537: orb $a_mask, %gs:sr_flags // else, set a_bit ! 538: finish_up: ! 539: mov $offset_result,%edi ! 540: mov offset_result_rec,%esi ! 541: jmp put_arith_result ! 542: ALIGN ! 543: // ! 544: both_ops_denormd: ! 545: orb denorm_mask, %gs:sr_errors ! 546: testb denorm_mask, %gs:sr_masks ! 547: jz go_home ! 548: mov $offset_operand1,%edi ! 549: call norm_denorm ! 550: op2_denormd: ! 551: mov $offset_operand2,%edi ! 552: call norm_denorm ! 553: jmp handle_non_special_cases ! 554: ALIGN ! 555: only_op1_denormd: ! 556: orb denorm_mask, %gs:sr_errors ! 557: testb denorm_mask, %gs:sr_masks ! 558: jz go_home ! 559: mov $offset_operand1,%edi ! 560: call norm_denorm ! 561: jmp handle_non_special_cases ! 562: ALIGN ! 563: only_op2_denormd: ! 564: orb denorm_mask, %gs:sr_errors ! 565: testb denorm_mask, %gs:sr_masks ! 566: jz go_home ! 567: jmp op2_denormd ! 568: ALIGN ! 569: // ! 570: overflow_happened: ! 571: call overflow_response // here, overflow is certain. ! 572: jmp finish_up ! 573: ALIGN ! 574: go_home: ! 575: ret ! 576: underflow_happened: ! 577: call underflow_response ! 578: jmp finish_up ! 579: ALIGN ! 580: special_cases: ! 581: testb $0x10,%al // al contains (ebp).tag1 or (ebp).tag2 ! 582: jz op1_nan_ ! 583: orb invalid_mask, %gs:sr_errors ! 584: testb invalid_mask, %gs:sr_masks ! 585: jz go_home ! 586: mov $offset_operand1,%edi ! 587: call set_up_indefinite ! 588: mov offset_result_rec,%esi ! 589: jmp put_arith_result ! 590: ALIGN ! 591: op1_nan_: // here, neither op is unsupported. ! 592: cmpb inv,tag1(%ebp) ! 593: je op1_snan_ ! 594: cmpb inv,tag2(%ebp) ! 595: jne non_nan_supp_ops ! 596: jmp signal_invalid_ ! 597: ALIGN ! 598: op1_snan_: ! 599: testb $0x40,msb_frac1 ! 600: jz invalid_operand ! 601: op2_also_nan_: ! 602: cmpb inv,tag2(%ebp) ! 603: jne set_up_nan_return ! 604: signal_invalid_: ! 605: testb $0x40,msb_frac2 ! 606: jnz set_up_nan_return ! 607: invalid_operand: ! 608: orb invalid_mask, %gs:sr_errors ! 609: testb invalid_mask, %gs:sr_masks ! 610: jz go_home // i-error, if unmasked ! 611: set_up_nan_return: ! 612: mov offset_result_rec,%esi // result=max(nan1,nan2) ! 613: cmpb inv, tag1(%ebp) ! 614: je check_tag2 ! 615: mov $offset_operand2, %edi ! 616: jmp install_hi_bits ! 617: ALIGN ! 618: check_tag2: ! 619: cmpb inv, tag2(%ebp) ! 620: je put_max_nan ! 621: mov $offset_operand1, %edi ! 622: jmp install_hi_bits ! 623: ALIGN ! 624: put_max_nan: ! 625: movb sign1(%ebp),%al // set result to larger ! 626: movb sign2(%ebp),%ah // magnitude result ! 627: push %eax // save signs ! 628: andb $0x7f,msb_frac1 ! 629: andb $0x7f,msb_frac2 ! 630: subtract_fracs: ! 631: movb positive,sign1(%ebp) // subtract the absolute ! 632: movb positive,sign2(%ebp) // values of the two ops ! 633: movb $sub_op,operation_type(%ebp) ! 634: push %esi ! 635: call subadd ! 636: pop %esi ! 637: pop %eax ! 638: movb %al,sign1(%ebp) // restore sign1 and give ! 639: mov $offset_operand1,%edi // operand1 as answer ! 640: cmpb positive,result_sign(%ebp) // if difference is + ! 641: je install_hi_bits ! 642: movb %ah,sign2(%ebp) // restore sign2 and give ! 643: mov $offset_operand2,%edi // operand2 as answer ! 644: install_hi_bits: ! 645: orb $0x0c0,msb(%ebp,%edi) ! 646: put_arith_result: ! 647: call put_result ! 648: jmp pop_free ! 649: ALIGN ! 650: non_nan_supp_ops: ! 651: movb tag2(%ebp),%bl ! 652: movb tag1(%ebp),%bh ! 653: testb $0x04,%bh ! 654: jz op2_denorm_ ! 655: movb $3,%bh // indicate op1 is denorm ! 656: op2_denorm_: ! 657: testb $0x04,%bl ! 658: jz get_index ! 659: movb $3,%bl // indicate op2 is denorm ! 660: get_index: ! 661: and $0x0303,%ebx // form index to special operation table ! 662: // bx=4*(4*masked_tag1 + masked_tag2), ! 663: // where masked_tag = 0 for valid, ! 664: shlb $2,%bh // 1 for zero, ! 665: //2 for infinity ! 666: addb %bh,%bl // 3 for denormd ! 667: xorb %bh,%bh ! 668: shl $2,%ebx ! 669: mov $0x40fb,%eax // 64 byte/table -add_op ! 670: addb operation_type(%ebp),%al // al = normalized type ! 671: mulb %ah // (e)ax = operation offset ! 672: add %eax,%ebx // (e)bx = case offset ! 673: jmp *%cs:special_table(%ebx) // jump to special case ! 674: ALIGN ! 675: exit_arith: ! 676: ret ! 677: derror_with_first_operand: ! 678: orb denorm_mask, %gs:sr_errors ! 679: testb denorm_mask, %gs:sr_masks ! 680: jz exit_arith // if unmasked, return ! 681: first_operand: ! 682: mov $offset_operand1,%esi // give first operand as ! 683: jmp set_result_to_operand // result ! 684: ALIGN ! 685: derror_with_neg_second_operand: ! 686: orb denorm_mask, %gs:sr_errors ! 687: testb denorm_mask, %gs:sr_masks ! 688: jz exit_arith // if unmasked, return ! 689: neg_second_operand: ! 690: notb sign2(%ebp) // negate second operand ! 691: jmp second_operand // result ! 692: ALIGN ! 693: derror_with_second_operand: ! 694: orb denorm_mask, %gs:sr_errors ! 695: testb denorm_mask, %gs:sr_masks ! 696: jz exit_arith // if unmasked, return ! 697: second_operand: ! 698: mov $offset_operand2,%esi //give second operand ! 699: set_result_to_operand: ! 700: call move_op_to_result ! 701: jmp go_to_finish_up ! 702: ALIGN ! 703: //divide_into_zero: ; this section, for pseudo-zeroes, was ! 704: // xor ax,ax ; commented out when they became unsupp. ! 705: // mov edi,offset word_frac2 + 2 ; if frac2 = 0, invalid ! 706: // call test_4w ; else, zero and xor ! 707: // jz invalid_error_detected ; signs as the result ! 708: denormd_exor_signed_zero: ! 709: orb denorm_mask, %gs:sr_errors ! 710: testb denorm_mask, %gs:sr_masks ! 711: jz exit_arith // if unmasked, return ! 712: exor_signed_zero: ! 713: mov $zero_pattern,%esi ! 714: call set_constant_result ! 715: movb special,result_tag(%ebp) ! 716: jmp set_exor_sign ! 717: ALIGN ! 718: denormd_exor_signed_infinity: ! 719: orb denorm_mask, %gs:sr_errors ! 720: testb denorm_mask, %gs:sr_masks ! 721: jz exit_arith // if unmasked, return ! 722: jmp exor_signed_infinity ! 723: ALIGN ! 724: divide_by_zero: ! 725: orb zero_divide_mask, %gs:sr_errors ! 726: testb zero_divide_mask, %gs:sr_masks ! 727: jz exit_arith // if unmasked, return ! 728: exor_signed_infinity: ! 729: call put_infinity // else, give infinity ! 730: set_exor_sign: ! 731: movb positive,result_sign(%ebp) // set sign to exclusive ! 732: movb sign1(%ebp),%ah // or of operand signs ! 733: cmpb sign2(%ebp),%ah ! 734: je go_to_finish_up ! 735: notb result_sign(%ebp) ! 736: go_to_finish_up: ! 737: jmp finish_up ! 738: ALIGN ! 739: add_sub_infinities: ! 740: movb sign2(%ebp),%ah // add or sub magnitude? ! 741: cmpb $sub_op,operation_type(%ebp) // add mag if add_op and ! 742: jne add_or_sub_mag_ // signs same, else sub ! 743: notb %ah // comp sign2 if sub ! 744: add_or_sub_mag_: ! 745: cmpb sign1(%ebp),%ah ! 746: je first_operand // first op res if add_mag ! 747: invalid_error_detected: ! 748: orb invalid_mask, %gs:sr_errors ! 749: testb invalid_mask, %gs:sr_masks ! 750: jz exit_arith ! 751: call put_indefinite // if masked, indefinite ! 752: jmp finish_up // otherwise, just return ! 753: ALIGN ! 754: // ! 755: //arith endp ! 756: // ! 757: //a_med ends ! 758: // ! 759: // end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.