Annotation of kernel/machdep/i386/fp_emul/fp_round.s, revision 1.1.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.