Annotation of kernel/machdep/i386/fp_emul/fp_round.s, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.