|
|
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 "store.s" ! 26: ! 27: .ident "@(#)kern-fp:store.s 1.1" ! 28: ! 29: //$tt(*80387 emulator+++s t o r e+++*) ! 30: // *************************************************************************** ! 31: // ! 32: // s t o r e . 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 80387 store, fix, and storex instructions. ! 45: // ! 46: // public procedures: ! 47: // store fix16 fix32 fix64 move_op_to_op ! 48: // ! 49: // internal procedures: ! 50: // extended_store bcd_store ! 51: // single_real_store double_real_store ! 52: // store_valid int64_store ! 53: // int16_store int32_store ! 54: // ! 55: // ************************************************************************ ! 56: // ! 57: //...december 12, 1986.. ! 58: // ! 59: //$nolist ! 60: #include "fp_e80387.h" ! 61: //$list ! 62: .data //a_msr segment rw public ! 63: // extrn %gs:sr_masks,%gs:sr_flags,%gs:sr_errors,%gs:sr_controls ! 64: //a_msr ends ! 65: // ! 66: // assume %ds:a_msr ! 67: // ! 68: .text //a_med segment er public ! 69: // ! 70: // extrn pop_free,clear_6w,test_3w,subadd ! 71: // extrn gradual_underflow,right_shift_frac2_cl ! 72: // extrn special_round_test,directed_round_test ! 73: // extrn right_shift_result_cl,set_up_indefinite ! 74: // extrn right_shift_frac1_cl,sticky_right_shift ! 75: // extrn left_shift_frac1_cl,left_shift_result_cl ! 76: // extrn put_op1_result,divid,addition_normalize ! 77: // extrn round,get_precision,get_rnd_control ! 78: // extrn store_precision,set_i_error,i_masked_ ! 79: // extrn set_o_error,o_masked_,set_p_error ! 80: // extrn set_u_error,test_4w,subtraction_normalize ! 81: // extrn p_error_,clear_p_error,add_to_frac ! 82: // extrn move_constant,set_stk_u_error,norm_denorm ! 83: // extrn %gs:sr_mem_offset ! 84: // --------to be added for unix ! 85: //.. extrn fpfulong:far,fpfushort:far,fpsulong:far,fpsushort:far ! 86: // ! 87: .globl store ! 88: .globl fix16 ! 89: .globl fix32 ! 90: .globl fix64 ! 91: .globl move_op_to_op ! 92: // ! 93: store_routine: ! 94: .long single_real_store,double_real_store,int16_store ! 95: .long int32_store,int64_store,extended_store ! 96: .long int16_store,int16_store,bcd_store ! 97: // ! 98: // ************************************************************************* ! 99: // store: ! 100: // ****** ! 101: // function: ! 102: // implements all store instructions . ! 103: // ! 104: // inputs: ! 105: // operand1; format of result. ! 106: // ! 107: // outputs: ! 108: // operand in *result_format* stored in memory ! 109: // destination pointed to by es:di. ! 110: // ! 111: // data accessed: ! 112: // - result_rec_offset result_format ! 113: // - offset_operand1 ! 114: // ! 115: // data changed: ! 116: // - result record ! 117: // ! 118: // procedures called: ! 119: // set_up_indefinite store routine (result format) ! 120: // i_masked? ! 121: // ! 122: // **************************************************************************** ! 123: ALIGN ! 124: store: //proc ! 125: jz no_unmasked_stack_error // branch if no stack error ! 126: call set_stk_u_error // stack underflow occurred ! 127: testb invalid_mask,%gs:sr_masks // if unmasked, just exit ! 128: jz return // else, store indef set up ! 129: no_unmasked_stack_error: // in operand1 by fetch_an_op ! 130: andb $~a_mask,%gs:sr_flags // clear a-bit ! 131: get_result_loc: ! 132: cmpb $reg,result_location(%ebp) ! 133: jne store_to_memory // branch if memop ! 134: call put_op1_result // give opnd1 as result ! 135: jmp pop_free ! 136: ALIGN ! 137: store_to_memory: ! 138: movzbl result_format(%ebp),%ebx// call a different rtn ! 139: shll $2,%ebx // for each of the ! 140: cmp $8,%ebx ! 141: jge go_to_storer // do store of temporary real ! 142: cmpb unsupp,tag1(%ebp) // detect unsupported pattern ! 143: jne go_to_storer ! 144: orb invalid_mask,%gs:sr_errors // set i_error ! 145: testb invalid_mask,%gs:sr_masks // if unmasked, just exit ! 146: jz return // else, set up indef in ! 147: mov $offset_operand1,%edi // operand1. ! 148: call set_up_indefinite ! 149: go_to_storer: ! 150: jmp *%cs:store_routine(%ebx) // output formats ! 151: //store endp ! 152: // ! 153: // **************************************************************************** ! 154: // move_op_to_op: ! 155: // ! 156: // function: ! 157: // moves operand record (op1,op2,result_op,result2_op) to ! 158: // another op. ! 159: // ! 160: // inputs: ! 161: // ss:esi points to the source, and ! 162: // ss:edi points to the destination ! 163: // outputs: ! 164: // operand record in destination ! 165: // ! 166: // data accessed: ! 167: // operand or result variables ! 168: // ! 169: // data changed: ! 170: // operand or result variables ! 171: // ! 172: // ***************************************************************************** ! 173: ALIGN ! 174: move_op_to_op: //proc ! 175: // push %ds // save a?msr ! 176: // push %ss ! 177: // pop %ds ! 178: push %ss ! 179: pop %es ! 180: mov $((sign2-sign1)>> 2),%ecx / set record length ! 181: ! 182: /* FAST_MOVSL */ ! 183: push %eax ! 184: 1: ! 185: movl %ss:0(%esi),%eax ! 186: movl %eax,%es:0(%edi) ! 187: addl $4,%esi ! 188: addl $4,%edi ! 189: decl %ecx ! 190: testl %ecx,%ecx ! 191: jg 1b ! 192: ! 193: pop %eax ! 194: // pop %ds // reload a?msr ! 195: return: ! 196: ret ! 197: //move_op_to_op endp ! 198: // ! 199: // *************************************************************************** ! 200: // extended_store: ! 201: // *************** ! 202: // function: ! 203: // stores into double extended format. ! 204: // ! 205: // inputs: ! 206: // operand1 ! 207: // ! 208: // outputs: ! 209: // double extended operand in memory. ! 210: // stack popped if indicated ! 211: // ! 212: // data accessed: ! 213: // - mem_operand_pointer sign1 ! 214: // - expon1 word_frac1 ! 215: // ! 216: // data changed: ! 217: // ! 218: // procedures called: ! 219: // pop_free ! 220: // ! 221: // ***************************************************************************** ! 222: ALIGN ! 223: extended_store: //proc ! 224: les mem_operand_pointer(%ebp),%edi //move frac to memory ! 225: // push %ds // save a?msr ! 226: // push %ss ! 227: // pop %ds // set up source pointer ! 228: lea 2+word_frac1,%esi ! 229: ! 230: /* FAST_MOVSL */ ! 231: movl %ss:0(%esi),%ecx ! 232: movl %ecx,%es:0(%edi) ! 233: movl %ss:4(%esi),%ecx ! 234: movl %ecx,%es:4(%edi) ! 235: // addl $8,%esi ! 236: // addl $8,%edi ! 237: // movl $0,%ecx ! 238: ! 239: // pop %ds // reload a?msr ! 240: movb sign1(%ebp),%ah // merge sign & exponent ! 241: andw $0x8000,%ax // and move to memory ! 242: orw expon1(%ebp),%ax ! 243: movw %ax,%es:8(%edi) ! 244: ! 245: //.. ! 246: //.. pushad ! 247: //.. push es ! 248: //.. push edi ! 249: //.. push ax ! 250: //.. call fpsushort ! 251: //.. add esp,12 ! 252: //.. popad ! 253: //.. cld ! 254: jmp pop_free // pop stack, if needed ! 255: //extended_store endp ! 256: // ! 257: // **************************************************************************** ! 258: // bcd_store: ! 259: // ********** ! 260: // function: ! 261: // stores into bcd format ! 262: // ! 263: // inputs: ! 264: // operand1 ! 265: // ! 266: // outputs: ! 267: // bcd operand in memory; stack popped ! 268: // ! 269: // data accessed: ! 270: // - mem_operand_pointer operation_type ! 271: // - offset_operand1 sign1 ! 272: // - tag1 word_frac1 ! 273: // - msb_frac1 offset_operand1 ! 274: // - offset_operand2 sign2 ! 275: // - expon2 word_frac2 ! 276: // - offset_operand2 offset_result ! 277: // - result_expon result_word_frac ! 278: // - msb_result offset_result ! 279: // ! 280: // data changed: ! 281: // - operation_type word_frac1 ! 282: // - msb_frac1 sign2 ! 283: // - expon2 word_frac2 ! 284: // - result_word_frac msb_result ! 285: // ! 286: // procedures called: ! 287: // move_op_to_op right_shift_frac1_cl ! 288: // right_shift_frac2_cl right_shift_result_cl ! 289: // left_shift_frac1_cl left_shift_result_cl ! 290: // divid clear_6w ! 291: // pop_free test_4w ! 292: // add_to_frac move_constant ! 293: // ! 294: // ************************************************************************** ! 295: ten_18: ! 296: .value 0x0000,0x0000,0x0000,0x7640,0x6b3a,0x0de0b// frac for 10**18 ! 297: // ! 298: ALIGN ! 299: bcd_store: //proc ! 300: push %gs:sr_masks // save current precision ! 301: orb prec64,%gs:sr_controls // and set to 64-bit ! 302: cmpb special,tag1(%ebp) // separate bcd cases ! 303: jne finite_value_ ! 304: jmp store_signed_bcd ! 305: ALIGN ! 306: finite_value_: ! 307: cmpl $0x07fff,dword_expon1 // is it a finite number? ! 308: jne check_bcd_denorm // yes, branch to valid ! 309: invalid_bcd: ! 310: orb invalid_mask,%gs:sr_errors // set i_error ! 311: testb invalid_mask,%gs:sr_masks // is i_error unmasked? ! 312: jnz store_bcd_indef ! 313: jmp bcd_store_done // no, so exit at once ! 314: ALIGN ! 315: store_bcd_indef: // yes, store bcd_indef ! 316: movl $0, dword_frac1+frac80(%ebp) // clear low frac ! 317: movl $0x80000000, dword_frac1+6(%ebp)// set only ms bit of hi frac ! 318: movw $0x0ffff, 8+word_frac1 //set msw to all ones, ! 319: jmp store_bcd_result // and give as answer ! 320: ALIGN ! 321: check_bcd_denorm: ! 322: cmpb denormd,tag1(%ebp) // separate bcd cases ! 323: jne round_to_int ! 324: movl $0x0001,dword_expon1 // if masked d-error, make valid ! 325: movb valid,tag1(%ebp) ! 326: round_to_int: ! 327: mov $0x403e,%eax ! 328: cmp %eax,dword_expon1 // if expon >= 63, then number ! 329: jge invalid_bcd // is already too big for bcd ! 330: mov $offset_operand1,%edi // gradual uflow until expon=63 ! 331: push %edi ! 332: call gradual_underflow ! 333: pop %edi // round to precision 64 ! 334: movb prec64,%dl ! 335: movb false,%al ! 336: call round ! 337: detect_zero: ! 338: xor %eax,%eax ! 339: mov $dword_frac1+4,%edi // if fraction = 0, result = 0 ! 340: call test_4w ! 341: jnz below_10_to_18_ ! 342: mov %eax,dword_expon1 // set result to true zero ! 343: movb special,tag1(%ebp) ! 344: jmp store_bcd_round_data ! 345: ALIGN ! 346: below_10_to_18_: ! 347: mov 4(%ebp,%edi),%edx ! 348: cmp $0x0de0b6b3,%edx ! 349: ja invalid_bcd ! 350: mov (%ebp,%edi),%eax ! 351: jb divide_by_10_to_9 ! 352: cmp $0x0a7640000,%eax ! 353: jae invalid_bcd ! 354: divide_by_10_to_9: ! 355: movl $0,4(%ebp,%edi) // clear high dword of frac1 ! 356: movl $0,(%ebp,%edi)// clear low dword of 8 byte frac1 ! 357: sub $2,%edi // make edi point to 10 byte frac1 ! 358: mov $0x3b9aca00,%ebx // ten to the 9th, as hex ordinal ! 359: div %ebx ! 360: push %eax // save quotient ! 361: mov $4,%ecx ! 362: mov $100,%ebx ! 363: FALLSTHRU ! 364: next_pair_nibbles: ! 365: mov %edx,%eax ! 366: xor %edx,%edx ! 367: div %ebx ! 368: xchgl %edx,%eax ! 369: aam ! 370: second_half_loop_start: ! 371: shlb $4,%ah ! 372: orb %ah,%al ! 373: movb %al,(%ebp,%edi) ! 374: inc %edi ! 375: LOOP(next_pair_nibbles) ! 376: do_second_half_: ! 377: pop %eax ! 378: or %eax,%eax // is eax 0? ! 379: movb %dl,(%ebp,%edi) ! 380: jz store_bcd_round_data ! 381: push %edx ! 382: xor %edx,%edx ! 383: mov $10,%ecx ! 384: div %ecx ! 385: xchgl %edx,%eax ! 386: pop %ecx ! 387: movb %al, %ah ! 388: movb %cl, %al ! 389: push $0 ! 390: mov $5, %ecx ! 391: jmp second_half_loop_start ! 392: ALIGN ! 393: store_bcd_round_data: ! 394: cmpb true,rnd1_inexact ! 395: jne store_signed_bcd ! 396: orb $inexact_mask,%gs:sr_errors ! 397: cmpb true,added_one ! 398: jne store_signed_bcd ! 399: orb $a_mask,%gs:sr_flags ! 400: store_signed_bcd: ! 401: movb sign1(%ebp),%ah // set sign in bcd number ! 402: andb $0x080,%ah ! 403: movb %ah,msb_frac1 ! 404: store_bcd_result: ! 405: les %gs:sr_mem_offset,%edi //move frac1 to memory ! 406: // push %ds // save a?msr ! 407: // push %ss ! 408: // pop %ds ! 409: lea word_frac1,%esi ! 410: ! 411: /* FAST_MOVSL */ ! 412: movl %ss:0(%esi),%ecx ! 413: movl %ecx,%es:0(%edi) ! 414: movl %ss:4(%esi),%ecx ! 415: movl %ecx,%es:4(%edi) ! 416: movw %ss:8(%esi),%cx ! 417: movw %cx,%es:8(%edi) ! 418: // addl $10,%esi ! 419: // addl $10,%edi ! 420: // movl $0,%ecx ! 421: ! 422: // pop %ds // reload a?msr ! 423: call pop_free ! 424: bcd_store_done: ! 425: pop %gs:sr_masks // restore old setting ! 426: ret ! 427: //bcd_store endp ! 428: // ! 429: // ***************************************************************************** ! 430: // single_real_store: ! 431: // ****************** ! 432: // function: ! 433: // implements store to single-precision real format ! 434: // ! 435: // inputs: ! 436: // operand1 ! 437: // ! 438: // outputs: ! 439: // single_precision real in memory; ! 440: // stack popped if indicated. ! 441: // ! 442: // data accessed: ! 443: // - mem_operand_pointer offset_operand1 ! 444: // - sign1 tag1 ! 445: // - expon1 word_frac ! 446: // - msb_frac1 ! 447: // ! 448: // data changed: ! 449: // ! 450: // procedures called: ! 451: // round store_valid ! 452: // addition_normalized special_round_test ! 453: // directed_round_test gradual_underflow ! 454: // pop_free test_3w ! 455: // u_masked? set_o_error ! 456: // o_masked? set_p_error ! 457: // set_u_error set_i_masked? ! 458: // store_denormd ! 459: // ! 460: // ************************************************************************ ! 461: ALIGN ! 462: single_real_store: //proc ! 463: push $pop_free // return to pop_free ! 464: les mem_operand_pointer(%ebp),%edi //set es:di to memop ! 465: mov low_extended_expon_for_single,%esi ! 466: movb prec24,%dl // 24-bit precision ! 467: movb tag1(%ebp),%al // load op1 tag ! 468: cmpb valid,%al ! 469: je single_valid // detect valid, infinity, ! 470: cmpb denormd,%al // denormd, invalid, and ! 471: je single_denormd // special cases ! 472: cmpb inv,%al // check whether op1 is nan ! 473: jne single_special // branch unless op1 is nan ! 474: testb $0x40,msb_frac1 // check whether nan is quiet ! 475: jnz single_special // branch if nan is quiet ! 476: orb invalid_mask,%gs:sr_errors // set i_error for snan ! 477: testb invalid_mask,%gs:sr_masks // if unmasked, just exit ! 478: jz special_return // else, change to qnan ! 479: orb $0x40,msb_frac1 ! 480: single_special: ! 481: mov dword_frac1+frac32+1(%ebp),%ecx ! 482: and $0x807fffff,%ecx ! 483: movzbl expon1(%ebp),%eax ! 484: shl $23,%eax ! 485: or %ecx,%eax ! 486: mov %eax,%es:(%edi) ! 487: //.. ! 488: //.. pushad ! 489: //.. push es ! 490: //.. push edi ! 491: //.. push eax ! 492: //.. call fpsulong ! 493: //.. add esp, 12 ! 494: //.. popad ! 495: //.. cld ! 496: //.. ! 497: special_return: ! 498: ret ! 499: ALIGN ! 500: ! 501: single_denormd: ! 502: mov $offset_operand1,%edi // op1 is denormal or pseudo-denormal ! 503: call norm_denorm // dont set d_error; just normalize ! 504: single_valid: ! 505: mov high_extended_expon_for_single,%edi // load parameter ! 506: call store_valid ! 507: les mem_operand_pointer(%ebp),%edi // es:edi --> memop ! 508: jz single_infinity // zf = 1 => store infinity ! 509: js single_max // sf = 1 => store max ! 510: jc single_qnan // cf = 1 => store qnan ! 511: single_store: ! 512: mov dword_frac1+frac32+1(%ebp),%eax ! 513: and $0x80ffffff,%eax ! 514: test $0x00ffffff,%eax ! 515: jz single_store_it ! 516: and $0x807fffff,%eax ! 517: movzbl expon1(%ebp),%ecx ! 518: addb $0x80,%cl ! 519: shl $23,%ecx ! 520: or %ecx,%eax ! 521: single_store_it: ! 522: mov %eax,%es:(%edi) ! 523: //.. ! 524: //.. pushad ! 525: //.. push es ! 526: //.. push edi ! 527: //.. push eax ! 528: //.. call fpsulong ! 529: //.. add esp,12 ! 530: //.. popad ! 531: //.. cld ! 532: //.. ! 533: ret //do needed pop or free ! 534: ALIGN ! 535: ! 536: single_max: ! 537: mov $0x7fffff7f,%eax ! 538: jmp single_sign_on ! 539: ALIGN ! 540: single_infinity: ! 541: mov $0x8000007f,%eax ! 542: single_sign_on: ! 543: orb sign1(%ebp),%al ! 544: ror $8,%eax ! 545: jmp single_store_it ! 546: ALIGN ! 547: single_qnan: ! 548: movl $0xffffffff,%es:(%edi) ! 549: pop %eax // skip pop or free ! 550: ret // since this happens on error ! 551: ALIGN ! 552: ! 553: store_valid: ! 554: push %edi // stack high_expon ! 555: push %esi // stack low_expon ! 556: push %edx // stack prec control ! 557: movb false,%al // not second rounding ! 558: mov $offset_operand1,%edi // round to prec (dl) ! 559: // push edi ; round preserves edi ! 560: call round ! 561: // pop edi ! 562: call addition_normalize // and renormalize ! 563: pop %edx // unstack prec control ! 564: pop %esi // unstack low_expon ! 565: pop %edi // unstack high_expon ! 566: cmp %esi,dword_expon1 // is underflow possible? ! 567: jl store_underflow_ // < low_expon, so underflow possible ! 568: je decrement_exponent // no, = low_expon? ! 569: cmp %edi,dword_expon1 // no, > high_expon? ! 570: jle do_store_valid // no, store number ! 571: orb overflow_mask,%gs:sr_errors // set o_error ! 572: testb overflow_mask,%gs:sr_masks // if unmasked, violate ieee standard ! 573: jnz masked_overflow // and abort without rounding source ! 574: unmasked_ov_underflow: ! 575: // ! 576: // the commentized instructions immediately following are appropriate for ! 577: // unmasked over/underflow response in accord with the ieee standard. on the ! 578: // 80387, unmasked over/underflows on conversion leave for the trap handler the ! 579: // source operand, unmodified by rounding, exponent rebiasing, or anything else. ! 580: // therefore, to report that preliminary rounding was inexact or achieved by ! 581: // increasing the source seems inconsistent with the 80387s philosophy ! 582: // of entering an over/underflow trap handler with the 80387s state changed ! 583: // only insofar as the over/underflow flag has been set, so skip that report. ! 584: // ! 585: // cmp rnd1_inexact, true ; detect inexact result ! 586: // jne move_op1_to_87_tos ; if exact, branch to replace source ! 587: // or %gs:sr_errors, inexact_mask ; else, set i_error ! 588: // cmp added_one, true ; was rounding done by adding one? ! 589: // jne move_op1_to_87_tos ; if not, branch to replace source ! 590: // or %gs:sr_flags, a_mask ; else, set a_bit ! 591: //move_op1_to_87_tos: ! 592: // mov (ebp).result_location, stack_top ! 593: // pop %edi ; discard callers return address ! 594: // pop %edi ; discard pop_free address ! 595: // jmp put_op1_result ! 596: // ! 597: // Instead, we return a special error condition (sf=0 zf=0 cf=1) ! 598: // to our caller, to cause a quiet NaN to be generated, as the 80387 does. ! 599: movb $1, %ah ! 600: sahf ! 601: ret ! 602: ALIGN ! 603: ! 604: masked_overflow: ! 605: orb $inexact_mask,%gs:sr_errors // set inexact_error ! 606: movb %gs:sr_controls,%al // load control byte ! 607: andb $rnd_control_mask,%al // mask in rounding control ! 608: movb rnd_up,%ah ! 609: cmpb %al,%ah ! 610: js store_valid_done // branch if zf = 0 & sf = 1 ! 611: movb sign1(%ebp),%al // get sign of op1 ! 612: call special_round_test // after round test, cf=0 ! 613: pushf // (zf=0 sf=1)/(zf=1 sf=0) ! 614: js pop_store_valid_done // sf = 1 => store max ! 615: orb $a_mask,%gs:sr_flags // set a_bit ! 616: pop_store_valid_done: ! 617: popf // reload flags ! 618: store_valid_done: ! 619: ret // exit ! 620: ALIGN ! 621: store_underflow_: ! 622: testb underflow_mask,%gs:sr_masks // if underflow masked, ! 623: jnz check_masked_underflow // then branch to check for inexact ! 624: orb underflow_mask,%gs:sr_errors// else, set u_error ! 625: // ! 626: // after the underflow exception has been set, the response to unmasked ! 627: // underflow ought to be the same as that to unmasked overflow. ! 628: jmp unmasked_ov_underflow ! 629: ALIGN ! 630: ! 631: check_masked_underflow: ! 632: mov $offset_operand1,%edi // load op1 offset ! 633: mov %esi,%eax // load low exponent ! 634: push %edi // save op1 offset ! 635: push %edx // save prec control ! 636: call gradual_underflow // do gradual underflow ! 637: pop %edx // reload prec control ! 638: pop %edi // reload op1 offset ! 639: movb true,%al // perform second round ! 640: call round ! 641: cmpw $0,rnd_history // signal_u_error? ! 642: je decrement_exponent ! 643: orb underflow_mask+inexact_mask,%gs:sr_errors ! 644: decrement_exponent: ! 645: testb $0x80,msb_frac1 // test msb of fraction ! 646: jnz do_store_valid // dont decrement if 800..0h ! 647: decw expon1(%ebp) // else, decrement expon ! 648: do_store_valid: ! 649: cmpw $0,rnd_history // signal_p_error? ! 650: je adjust_flags ! 651: orb $inexact_mask,%gs:sr_errors // signal_p_error. ! 652: cmpb true,added_one // was rounding done by adding one? ! 653: jne adjust_flags // if not, branch to adjust flags ! 654: orb $a_mask,%gs:sr_flags // else, set a_bit ! 655: adjust_flags: ! 656: xor %eax,%eax // cf = 0, sf = 0, zf = 0 for ! 657: inc %eax // store valid exit ! 658: ret ! 659: ! 660: //single_real_store endp ! 661: // ! 662: // ************************************************************************ ! 663: // double_real_store: ! 664: // ****************** ! 665: // function: ! 666: // implements store to double-precision real format ! 667: // ! 668: // inputs: ! 669: // operand1 ! 670: // ! 671: // outputs: ! 672: // double precision real in memory; ! 673: // stack popped if indicated. ! 674: // ! 675: // data accessed: ! 676: // - mem_operand_pointer offset_operand1 ! 677: // - sign1 tag1 ! 678: // - expon1 word_frac1 ! 679: // - msb_frac1 offset_operand1 ! 680: // ! 681: // data changed: ! 682: // - sign1 word_frac1 ! 683: // ! 684: // procedures called: ! 685: // test_3w store_valid ! 686: // right_shift_frac1_cl pop_free ! 687: // double_zero double_fill ! 688: // store_denormd double_frac_mem ! 689: // ! 690: // *************************************************************************** ! 691: ALIGN ! 692: double_real_store: //proc ! 693: push $pop_free // return to pop_free ! 694: mov low_extended_expon_for_double,%esi ! 695: movb prec53,%dl // 53-bit precision ! 696: movb tag1(%ebp),%al // separate special cases ! 697: cmpb valid,%al ! 698: je double_valid ! 699: cmpb denormd,%al ! 700: je double_denormd ! 701: cmpb special,%al ! 702: jne inv_or_inf ! 703: movw $0x3c00,expon1(%ebp) ! 704: jmp double_frac_mem ! 705: ALIGN ! 706: inv_or_inf: ! 707: cmpb inv,%al ! 708: jne double_special ! 709: testb $0x40,msb_frac1 // check whether nan is quiet ! 710: jnz double_special // branch if nan is quiet ! 711: orb invalid_mask,%gs:sr_errors // set i_error for snan ! 712: testb invalid_mask,%gs:sr_masks // if unmasked, just exit ! 713: jnz make_dbl_qnan // else, change to qnan ! 714: dbl_special_return: ! 715: ret ! 716: ALIGN ! 717: make_dbl_qnan: ! 718: orb $0x40,msb_frac1 ! 719: double_special: ! 720: movw $0x3c00+0x07ff,expon1(%ebp) ! 721: jmp double_frac_mem // store frac to memory ! 722: ALIGN ! 723: double_denormd: ! 724: mov $offset_operand1,%edi // op1 is denormal or pseudo-denormal ! 725: call norm_denorm // dont set d_error; just normalize ! 726: double_valid: ! 727: mov high_extended_expon_for_double,%edi ! 728: call store_valid ! 729: jz double_infinity // zf = 1 ==> store infinity ! 730: js double_max // sf = 1 ==> store max ! 731: jc double_qnan // cf = 1 ==> store qnan ! 732: double_store: ! 733: movb 3+lsb_frac1,%al // else store double ! 734: cbtw ! 735: mov $dword_frac1+6,%edi ! 736: call test_3w ! 737: jz double_zero // store signed zero ! 738: double_frac_mem: ! 739: movb $3,%cl // start by shifting ! 740: call right_shift_frac1_cl // fraction right 3 bits ! 741: les mem_operand_pointer(%ebp),%edi // es:edi points to memop ! 742: // push %ds // save a?msr ! 743: // push %ss ! 744: // pop %ds // set up source pointer ! 745: lea 3+word_frac1,%esi // move frac to memory ! 746: ! 747: /* FAST_MOVSL */ ! 748: movl %ss:0(%esi),%ecx ! 749: movl %ecx,%es:0(%edi) ! 750: movw %ss:4(%esi),%ecx ! 751: movw %ecx,%es:4(%edi) ! 752: // addl $6,%esi ! 753: // addl $6,%edi ! 754: // movl $0,%ecx ! 755: ! 756: // pop %ds // reload a?msr ! 757: movw expon1(%ebp),%ax // fetch high-order word, ! 758: subw $0x3c00,%ax // with expon, sign, and ! 759: shlw $4,%ax // top 4 bits of fraction ! 760: andb $0x0f,msb_frac1 ! 761: orb msb_frac1,%al ! 762: andb $0x80,sign1(%ebp) ! 763: orb sign1(%ebp),%ah ! 764: movw %ax,%es:6(%edi) // es:di points to expon ! 765: //.. ! 766: //.. pushad ! 767: //.. push es ! 768: //.. push edi ! 769: //.. push ax ! 770: //.. call fpsushort ! 771: //.. add esp,12 ! 772: //.. popad ! 773: //.. cld ! 774: //.. ! 775: ! 776: ret // do pop or free ! 777: ALIGN ! 778: ! 779: double_zero: ! 780: xor %eax,%eax // store +/- 0 to memory ! 781: double_fill: ! 782: les mem_operand_pointer(%ebp),%edi // es:edi points to memop ! 783: mov %eax,%es:(%edi) ! 784: //.. ! 785: //.. pushad ! 786: //.. push es ! 787: //.. push edi ! 788: //.. push eax ! 789: //.. call fpsulong ! 790: //.. add esp,12 ! 791: //.. ! 792: ! 793: movw %ax,%es:4(%edi) ! 794: //.. ! 795: //.. push es ! 796: //.. push edi+4 ! 797: //.. push ax ! 798: //.. call fpsushort ! 799: //.. add esp,12 ! 800: //.. popad ! 801: //.. cld ! 802: //.. ! 803: movb sign1(%ebp),%ah ! 804: andb $0x80,%ah ! 805: double_expon: ! 806: movw %ax,%es:6(%edi) // store the exponent ! 807: //.. ! 808: //.. pushad ! 809: //.. push es ! 810: //.. push edi+12 ! 811: //.. push ax ! 812: //.. call fpsushort ! 813: //.. add esp,12 ! 814: //.. popad ! 815: //.. cld ! 816: //.. ! 817: ret ! 818: ALIGN ! 819: ! 820: double_max: ! 821: mov $0x0ffffffff,%eax // set fraction to ff..f ! 822: call double_fill ! 823: movw $0x7fef,%ax // set exponent to 7feh ! 824: orb sign1(%ebp),%ah // or sign bit ! 825: jmp double_expon ! 826: ALIGN ! 827: double_infinity: ! 828: call double_zero // first clear the memop ! 829: orw $0x7ff0,%es:6(%edi) // es:di -> memop ! 830: //.. ! 831: //.. pushad ! 832: //.. push es ! 833: //.. push edi+6 ! 834: //.. call fpfushort ! 835: //.. or ax,7ff0h ! 836: //.. push ax ! 837: //.. call fpsushort ! 838: //.. add esp,12 ! 839: //.. popad ! 840: //.. cld ! 841: //.. ! 842: ret ! 843: ALIGN ! 844: double_qnan: ! 845: mov $0xffffffff,%eax // set fraction to ff..f ! 846: call double_fill ! 847: movw $0xffff,%es:6(%edi) // es:di -> memop (set exp to ff..f) ! 848: pop %eax // skip pop or free ! 849: ret // since this happens on error ! 850: //double_real_store endp ! 851: // ! 852: // *********************************************************************** ! 853: // fix16: ! 854: // ! 855: // function: ! 856: // fixes valid number to a 16-bit integer. ! 857: // ! 858: // inputs: ! 859: // operand1 ! 860: // ! 861: // outputs: ! 862: // 16-bit integer in word_frac1 + 8; ! 863: // overflow indication in zf (zf:1 => no overflow) ! 864: // ! 865: // data accessed: ! 866: // - offset_operand1 sign1 ! 867: // - expon1 word_frac1 ! 868: // - offset_operand1 ! 869: // ! 870: // data changed: ! 871: // - word_frac1 extra_word_reg ! 872: // ! 873: // procedures called: ! 874: // sticky_right_shift round ! 875: // careful_round p_error? ! 876: // ! 877: // *************************************************************************** ! 878: ALIGN ! 879: fix16: //proc ! 880: mov high_int16_exponent,%ecx // calc shift amount ! 881: sub dword_expon1,%ecx // if expon1 > high expon ! 882: js no_fix16_ovf // then overflow (zf=0) ! 883: cmp max_int16_shift,%ecx // dont let shift amount ! 884: jbe do_shift_16 // exceed max_int16_shift ! 885: mov max_int16_shift,%ecx ! 886: do_shift_16: ! 887: mov $offset_operand1,%edi // shift frac1 by cl ! 888: xorb %al,%al ! 889: call sticky_right_shift ! 890: mov $offset_operand1,%edi // round to 16-bit prec ! 891: movb prec16,%dl ! 892: movb false,%al ! 893: call round ! 894: cmpb false,%al // overflow if al=true ! 895: jnz no_fix16_ovf // round cy out (zf=1) ! 896: cmpw $0x8000,8+word_frac1 ! 897: jb check_sign_16 // no overflow if < 8000h ! 898: ja no_fix16_ovf // else, overflow (zf=0) ! 899: cmpb negative,sign1(%ebp) // oflow if = 8000h and ! 900: jnz no_fix16_ovf // sign1 = pos (zf=0) ! 901: check_sign_16: ! 902: movb positive,%al // al is overflow flag ! 903: cmpb sign1(%ebp),%al // negate integer if ! 904: jz no_fix16_ovf // sign is neg (zf=1) ! 905: negw 8+word_frac1 ! 906: xorb %al,%al // no overflow (zf=1) ! 907: no_fix16_ovf: ! 908: ret ! 909: //fix16 endp ! 910: // ! 911: // *********************************************************************** ! 912: // int16_store: ! 913: // ! 914: // function: ! 915: // stores into 16-bit integer format ! 916: // ! 917: // inputs: ! 918: // operand1 ! 919: // ! 920: // outputs: ! 921: // 16-bit integer in memory operand location ! 922: // ! 923: // data accessed: ! 924: // - mem_operand_pointer tag1 ! 925: // - word_frac1 msb_frac1 ! 926: // - offset_operand1 extra_word_reg ! 927: // ! 928: // data changed: ! 929: // ! 930: // procedures called: ! 931: // fix16 pop_free ! 932: // invalid_or_special get_rnd_control ! 933: // set_i_error i_masked? ! 934: // set_p_error clear_p_error ! 935: // ! 936: // ************************************************************************ ! 937: ALIGN ! 938: int16_store: //proc ! 939: // ! 940: cmpb valid,tag1(%ebp) ! 941: je valid_16 ! 942: cmpb denormd,tag1(%ebp) ! 943: jne special_16 ! 944: valid_16: ! 945: call fix16 // make op1 a 16-bit int ! 946: jnz special_16 // if zf=0, oflow on fix ! 947: cmpw $0,rnd_history ! 948: je store_16 ! 949: orb $inexact_mask,%gs:sr_errors ! 950: cmpb true,added_one ! 951: jne store_16 ! 952: orb $a_mask,%gs:sr_flags ! 953: store_16: ! 954: movw 8+word_frac1,%ax // move integer to memory ! 955: pointer_16: ! 956: les mem_operand_pointer(%ebp),%edi //set es:di to location ! 957: finish_16: ! 958: movw %ax,%es:(%edi) // store integer to mem ! 959: //.. ! 960: //.. pushad ! 961: //.. push es ! 962: //.. push edi ! 963: //.. push ax ! 964: //.. call fpsushort ! 965: //.. add esp,12 ! 966: //.. popad ! 967: //.. cld ! 968: //.. ! 969: jmp pop_free // pop stack and go home ! 970: ALIGN ! 971: special_16: ! 972: xorw %ax,%ax ! 973: cmpb special,tag1(%ebp) // is operand tagged special? ! 974: je pointer_16 // yes, load memop ptr and exit ! 975: orb invalid_mask,%gs:sr_errors// no, set invalid error ! 976: movw $0x8000,%ax // load inv constant into ax ! 977: testb invalid_mask,%gs:sr_masks// is invalid error masked? ! 978: jnz pointer_16 // yes, store invalid constant ! 979: ret ! 980: //int16_store endp ! 981: // ! 982: // *********************************************************************** ! 983: // fix32: ! 984: // ! 985: // function: ! 986: // fixes valid number to a 32-bit integer. ! 987: // ! 988: // inputs: ! 989: // operand1 ! 990: // ! 991: // outputs: ! 992: // 32-bit integer in word_frac1 + 6; ! 993: // overflow indication in zf (zf:1 => no overflow) ! 994: // ! 995: // data accessed: ! 996: // - offset_operand1 sign1 ! 997: // - dword_expon1 word_frac1 ! 998: // - offset_operand1 ! 999: // ! 1000: // data changed: ! 1001: // - word_frac1 ! 1002: // ! 1003: // procedures called: ! 1004: // sticky_right_shift round ! 1005: // ! 1006: // *************************************************************************** ! 1007: ALIGN ! 1008: fix32: //proc ! 1009: mov high_int32_exponent,%ecx // calc shift amount ! 1010: sub dword_expon1,%ecx // if expon1 > high expon ! 1011: js no_fix32_ovf // then overflow (zf=0) ! 1012: cmp max_int32_shift,%ecx // dont let shift amount ! 1013: jbe do_shift_32 // exceed max_int32_shift ! 1014: mov max_int32_shift,%ecx ! 1015: do_shift_32: ! 1016: mov $offset_operand1,%edi // shift frac1 by cl ! 1017: xorb %al,%al ! 1018: call sticky_right_shift ! 1019: mov $offset_operand1,%edi // round to 16-bit prec ! 1020: movb prec32,%dl ! 1021: movb false,%al ! 1022: call round ! 1023: cmpb false,%al // overflow if al=true ! 1024: jnz no_fix32_ovf // round cy out (zf=1) ! 1025: cmpl $0x080000000,dword_frac1+frac32(%ebp) ! 1026: jb check_sign_32 // no overflow if < 80000000h ! 1027: ja no_fix32_ovf // else, overflow (zf=0) ! 1028: cmpb negative,sign1(%ebp) // oflow if = 80000000h and ! 1029: jnz no_fix32_ovf // sign1 = pos (zf=0) ! 1030: check_sign_32: ! 1031: movb positive,%al // al is overflow flag ! 1032: cmpb sign1(%ebp),%al // negate integer if ! 1033: jz no_fix32_ovf // sign is neg (zf=1) ! 1034: negl dword_frac1+frac32(%ebp) ! 1035: xorb %al,%al // no overflow (zf=1) ! 1036: no_fix32_ovf: ! 1037: ret ! 1038: //fix32 endp ! 1039: // ! 1040: // ************************************************************************** ! 1041: // int32_store: ! 1042: // ! 1043: // function: ! 1044: // stores into 32-bit integer format ! 1045: // ! 1046: // input: ! 1047: // operand1 ! 1048: // ! 1049: // output: ! 1050: // 32-bit integer in location pointed to by es:di. ! 1051: // ! 1052: // data accessed: ! 1053: // - mem_operand_pointer offset_operand1 ! 1054: // - sign1 tag1 ! 1055: // - expon1 word_frac1 ! 1056: // - msb_frac1 offset_operand1 ! 1057: // ! 1058: // data changed: ! 1059: // - word_frac1 ! 1060: // ! 1061: // procedures called: ! 1062: // pop_free ! 1063: // fix32 ! 1064: // ! 1065: // ************************************************************************** ! 1066: ALIGN ! 1067: int32_store: //proc ! 1068: cmpb valid,tag1(%ebp) ! 1069: je valid_32 ! 1070: cmpb denormd,tag1(%ebp) ! 1071: jne special_32 ! 1072: valid_32: ! 1073: call fix32 // make op1 a 32-bit int ! 1074: jnz special_32 // if zf=0, oflow on fix ! 1075: cmpw $0,rnd_history ! 1076: je store_32 ! 1077: orb $inexact_mask,%gs:sr_errors ! 1078: cmpb true,added_one ! 1079: jne store_32 ! 1080: orb $a_mask,%gs:sr_flags ! 1081: store_32: ! 1082: mov dword_frac1+frac32(%ebp),%eax // move integer to eax ! 1083: pointer_32: ! 1084: les mem_operand_pointer(%ebp),%edi //set es:di to location ! 1085: finish_32: ! 1086: mov %eax,%es:(%edi) // store integer to mem ! 1087: //.. ! 1088: //.. pushad ! 1089: //.. push es ! 1090: //.. push edi ! 1091: //.. push eax ! 1092: //.. call fpsulong ! 1093: //.. add esp,12 ! 1094: //.. popad ! 1095: //.. cld ! 1096: //.. ! 1097: jmp pop_free // pop stack and go home ! 1098: ALIGN ! 1099: special_32: ! 1100: xor %eax,%eax ! 1101: cmpb special,tag1(%ebp) // is operand tagged special? ! 1102: je pointer_32 // yes, load memop ptr and exit ! 1103: orb invalid_mask,%gs:sr_errors// no, set invalid error ! 1104: mov $0x080000000,%eax // load inv constant into ax ! 1105: testb invalid_mask,%gs:sr_masks// is invalid error masked? ! 1106: jnz pointer_32 // yes, store invalid constant ! 1107: ret ! 1108: //int32_store endp ! 1109: // ! 1110: // *********************************************************************** ! 1111: // fix64: ! 1112: // ! 1113: // function: ! 1114: // fixes valid number to a 64-bit integer. ! 1115: // ! 1116: // inputs: ! 1117: // operand1 ! 1118: // ! 1119: // outputs: ! 1120: // 64-bit integer in word_frac1 + 2; ! 1121: // overflow indication in zf (zf:1 => no overflow) ! 1122: // ! 1123: // data accessed: ! 1124: // - offset_operand1 sign1 ! 1125: // - dword_expon1 word_frac1 ! 1126: // - offset_operand1 ! 1127: // ! 1128: // data changed: ! 1129: // - word_frac1 ! 1130: // ! 1131: // procedures called: ! 1132: // sticky_right_shift round ! 1133: // ! 1134: // *************************************************************************** ! 1135: ALIGN ! 1136: fix64: //proc ! 1137: mov high_int64_exponent,%ecx // calc shift amount ! 1138: sub dword_expon1,%ecx // if expon1 > high expon ! 1139: js no_fix64_ovf // then overflow (zf=0) ! 1140: cmp max_int64_shift,%ecx // dont let shift amount ! 1141: jbe do_shift_64 // exceed max_int64_shift ! 1142: mov max_int64_shift,%ecx ! 1143: do_shift_64: ! 1144: mov $offset_operand1,%edi // shift frac1 by cl ! 1145: xorb %al,%al ! 1146: call sticky_right_shift ! 1147: mov $offset_operand1,%edi // round to 64-bit prec ! 1148: movb prec64,%dl ! 1149: movb false,%al ! 1150: call round ! 1151: cmpb false,%al // overflow if al=true ! 1152: jnz no_fix64_ovf // round cy out (zf=1) ! 1153: cmpl $0x080000000,dword_frac1+frac32(%ebp) ! 1154: jb check_sign_64 // no overflow if < 80000000h ! 1155: ja no_fix64_ovf // else, overflow (zf=0) ! 1156: cmp $0,dword_frac1+frac64(%ebp) ! 1157: jnz no_fix64_ovf ! 1158: cmpb negative,sign1(%ebp) // oflow if = 800..0h and ! 1159: jnz no_fix64_ovf // sign1 = pos (zf=0) ! 1160: check_sign_64: ! 1161: movb positive,%al // al is overflow flag ! 1162: cmpb sign1(%ebp),%al // negate integer if ! 1163: jz no_fix64_ovf // sign is neg (zf=1) ! 1164: xor %eax,%eax ! 1165: negl dword_frac1+frac64(%ebp) ! 1166: sbb dword_frac1+frac32(%ebp),%eax ! 1167: mov %eax,dword_frac1+frac32(%ebp) ! 1168: xorb %al,%al // no overflow (zf=1) ! 1169: no_fix64_ovf: ! 1170: ret ! 1171: //fix64 endp ! 1172: // ! 1173: // ***************************************************************************** ! 1174: // int64_store: ! 1175: // ************ ! 1176: // function: ! 1177: // stores into 64-bit integer format ! 1178: // ! 1179: // input: ! 1180: // operand1 ! 1181: // ! 1182: // output: ! 1183: // 64-bit integer in memory location pointed to by es:edi. ! 1184: // ! 1185: // data accessed: ! 1186: // - mem_operand_pointer offset_operand1 ! 1187: // - sign1 tag1 ! 1188: // - expon1 word_frac1 ! 1189: // - msb_frac1 offset_operand1 ! 1190: // ! 1191: // data changed: ! 1192: // - word_frac1 ! 1193: // ! 1194: // procedures called: ! 1195: // pop_free ! 1196: // ! 1197: // *************************************************************************** ! 1198: ALIGN ! 1199: int64_store: //proc ! 1200: cmpb valid,tag1(%ebp) ! 1201: je valid_64 ! 1202: cmpb denormd,tag1(%ebp) ! 1203: jne special_64 ! 1204: valid_64: ! 1205: call fix64 // make op1 a 64-bit int ! 1206: jnz special_64 // if zf=0, oflow on fix ! 1207: cmpw $0,rnd_history ! 1208: je store_64 ! 1209: orb $inexact_mask,%gs:sr_errors ! 1210: cmpb true,added_one ! 1211: jne store_64 ! 1212: orb $a_mask,%gs:sr_flags ! 1213: store_64: ! 1214: mov dword_frac1+frac64(%ebp),%eax // move integer to edx:eax ! 1215: mov dword_frac1+frac32(%ebp),%edx // move integer to edx:eax ! 1216: pointer_64: ! 1217: les mem_operand_pointer(%ebp),%edi //set es:edi to location ! 1218: finish_64: ! 1219: mov %eax,%es:(%edi) // store low integer to low mem ! 1220: //.. ! 1221: //.. pushad ! 1222: //.. push es ! 1223: //.. push edi ! 1224: //.. push eax ! 1225: //.. call fpsulong ! 1226: //.. add esp,12 ! 1227: //.. popad ! 1228: //.. cld ! 1229: //.. ! 1230: mov %edx,%es:4(%edi) // store high integer to high mem ! 1231: //.. ! 1232: //.. pushad ! 1233: //.. push es ! 1234: //.. push edi ! 1235: //.. push edx ! 1236: //.. call fpsulong ! 1237: //.. add esp,12 ! 1238: //.. popad ! 1239: //.. cld ! 1240: //.. ! 1241: jmp pop_free // pop stack and go home ! 1242: ALIGN ! 1243: special_64: ! 1244: xor %eax,%eax ! 1245: cltd ! 1246: cmpb special,tag1(%ebp) // is operand tagged special? ! 1247: je pointer_64 // yes, load memop ptr and exit ! 1248: orb invalid_mask,%gs:sr_errors// no, set invalid error ! 1249: mov $0x080000000,%edx // load inv constant into ax ! 1250: testb invalid_mask,%gs:sr_masks// is invalid error masked? ! 1251: jnz pointer_64 // yes, store invalid constant ! 1252: ret ! 1253: ! 1254: //int64_store endp ! 1255: // ! 1256: //a_med ends ! 1257: // ! 1258: // end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.