Annotation of coherent/b/kernel/emulator/reg_u_div.S, revision 1.1

1.1     ! root        1:        .file   "reg_u_div.S"
        !             2: /*---------------------------------------------------------------------------+
        !             3:  |  reg_u_div.S                                                              |
        !             4:  |                                                                           |
        !             5:  | Core division routines                                                    |
        !             6:  |                                                                           |
        !             7:  | Copyright (C) 1992    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
        !             8:  |                       Australia.  E-mail [email protected]    |
        !             9:  |                                                                           |
        !            10:  |                                                                           |
        !            11:  +---------------------------------------------------------------------------*/
        !            12: 
        !            13: /*---------------------------------------------------------------------------+
        !            14:  |  Kernel for the division routines.                                        |
        !            15:  |                                                                           |
        !            16:  |  void reg_u_div(unsigned long long *a, unsigned long long *a,             |
        !            17:  |                 FPU_REG *dest)                                            |
        !            18:  |                                                                           |
        !            19:  |  Does not compute the destination exponent, but does adjust it.           |
        !            20:  +---------------------------------------------------------------------------*/
        !            21: 
        !            22: #include "exception.h"
        !            23: #include "fpu_asm.h"
        !            24: 
        !            25: 
        !            26: #define        dSIGL(x)        (x)
        !            27: #define        dSIGH(x)        4(x)
        !            28: 
        !            29: 
        !            30: .data
        !            31: /*
        !            32:        Local storage:
        !            33:        Result:         accum_3:accum_2:accum_1:accum_0
        !            34:        Overflow flag:  ovfl_flag
        !            35:  */
        !            36:        .align 2,0
        !            37: accum_3:
        !            38:        .long   0
        !            39: accum_2:
        !            40:        .long   0
        !            41: accum_1:
        !            42:        .long   0
        !            43: accum_0:
        !            44:        .long   0
        !            45: result_1:
        !            46:        .long   0
        !            47: result_2:
        !            48:        .long   0
        !            49: ovfl_flag:
        !            50:        .byte   0
        !            51: 
        !            52: 
        !            53: .text
        !            54:        .align 2,144
        !            55: 
        !            56: .globl reg_u_div
        !            57: 
        !            58: .globl divide_kernel
        !            59: 
        !            60: reg_u_div:
        !            61:        pushl   %ebp
        !            62:        movl    %esp,%ebp
        !            63: 
        !            64:        pushl   %esi
        !            65:        pushl   %edi
        !            66:        pushl   %ebx
        !            67: 
        !            68:        movl    PARAM1,%esi     /* pointer to num */
        !            69:        movl    PARAM2,%ebx     /* pointer to denom */
        !            70:        movl    PARAM3,%edi     /* pointer to answer */
        !            71: 
        !            72: divide_kernel:
        !            73: #ifdef PARANOID
        !            74: //     testl   $0x80000000, dSIGH(%esi)
        !            75: //     je      xL_bugged
        !            76:        testl   $0x80000000, dSIGH(%ebx)
        !            77:        je      xL_bugged
        !            78: #endif PARANOID
        !            79: 
        !            80: /* Check if the denominator can be treated as having just 32 bits */
        !            81:        cmpl    $0,dSIGL(%ebx)
        !            82:        jnz     L_Full_Division /* Can't do a quick divide */
        !            83: 
        !            84: /* We should be able to zip through the division here */
        !            85:        movl    dSIGH(%ebx),%ecx        /* The denominator */
        !            86:        movl    dSIGH(%esi),%edx        /* Get the current num */
        !            87:        movl    dSIGL(%esi),%eax        /* Get the current num */
        !            88: 
        !            89:        cmpl    %ecx,%edx
        !            90:        setae   ovfl_flag       /* Keep a record */
        !            91:        jb      xL_no_adjust
        !            92: 
        !            93:        subl    %ecx,%edx       /* Prevent the overflow */
        !            94: 
        !            95: xL_no_adjust:
        !            96:        /* Divide the 64 bit number by the 32 bit denominator */
        !            97:        divl    %ecx
        !            98:        movl    %eax,SIGH(%edi) /* Put the result in the answer */
        !            99: 
        !           100:        /* Work on the remainder of the first division */
        !           101:        xorl    %eax,%eax
        !           102:        divl    %ecx
        !           103:        movl    %eax,SIGL(%edi) /* Put the result in the answer */
        !           104: 
        !           105:        /* Work on the remainder of the 64 bit division */
        !           106:        xorl    %eax,%eax
        !           107:        divl    %ecx
        !           108: 
        !           109:        testb   $255,ovfl_flag  /* was the num > denom ? */
        !           110:        je      xL_no_overflow
        !           111: 
        !           112:        /* Do the shifting here */
        !           113:        /* increase the exponent */
        !           114:        incl    EXP(%edi)
        !           115: 
        !           116:        /* shift the mantissa right one bit */
        !           117:        stc                     /* To set the ms bit */
        !           118:        rcrl    $1,SIGH(%edi)
        !           119:        rcrl    $1,SIGL(%edi)
        !           120:        rcrl    $1,%eax
        !           121: 
        !           122: xL_no_overflow:
        !           123:        cmpl    $0x80000000,%eax
        !           124:        jc      xL_no_round
        !           125:        jnz     xL_round_up
        !           126: 
        !           127:        /* "round to even" used */
        !           128:        testb   $1,SIGL(%edi)
        !           129:        jz      xL_no_round
        !           130: 
        !           131: xL_round_up:
        !           132:        addl    $1,SIGL(%edi)
        !           133:        adcl    $0,SIGH(%edi)
        !           134: 
        !           135: #ifdef PARANOID
        !           136:        jc      xL_bugged2
        !           137: #endif PARANOID
        !           138: 
        !           139: xL_no_round:
        !           140:        jmp     xL_done
        !           141: 
        !           142: 
        !           143: #ifdef PARANOID
        !           144: xL_bugged:
        !           145:        pushl   EX_INTERNAL|0x203
        !           146:        call    EXCEPTION
        !           147:        pop     %ebx
        !           148:        jmp     xL_exit
        !           149: 
        !           150: xL_bugged2:
        !           151:        pushl   EX_INTERNAL|0x204
        !           152:        call    EXCEPTION
        !           153:        pop     %ebx
        !           154:        jmp     xL_exit
        !           155: #endif PARANOID
        !           156: 
        !           157: 
        !           158: /*---------------------------------------------------------------------------+
        !           159:  |  Divide:   Return  arg1/arg2 to arg3.                                     |
        !           160:  |                                                                           |
        !           161:  |  This routine does not use the exponents of arg1 and arg2, but does       |
        !           162:  |  adjust the exponent of arg3.                                             |
        !           163:  |                                                                           |
        !           164:  |  The maximum returned value is (ignoring exponents)                       |
        !           165:  |               .ffffffff ffffffff                                          |
        !           166:  |               ------------------  =  1.ffffffff fffffffe                  |
        !           167:  |               .80000000 00000000                                          |
        !           168:  | and the minimum is                                                        |
        !           169:  |               .80000000 00000000                                          |
        !           170:  |               ------------------  =  .80000000 00000001   (rounded)       |
        !           171:  |               .ffffffff ffffffff                                          |
        !           172:  |                                                                           |
        !           173:  +---------------------------------------------------------------------------*/
        !           174: 
        !           175: 
        !           176: L_Full_Division:
        !           177:        movl    dSIGL(%esi),%eax        /* Save extended num in local register */
        !           178:        movl    %eax,accum_2
        !           179:        movl    dSIGH(%esi),%eax
        !           180:        movl    %eax,accum_3
        !           181:        xorl    %eax,%eax
        !           182:        movl    %eax,accum_1    /* zero the extension */
        !           183:        movl    %eax,accum_0    /* zero the extension */
        !           184: 
        !           185:        movl    dSIGL(%esi),%eax        /* Get the current num */
        !           186:        movl    dSIGH(%esi),%edx
        !           187: 
        !           188: /*----------------------------------------------------------------------*/
        !           189: /* Initialization done */
        !           190: /* Do the first 32 bits */
        !           191: 
        !           192:        movb    $0,ovfl_flag
        !           193:        cmpl    dSIGH(%ebx),%edx        /* Test for imminent overflow */
        !           194:        jb      L02
        !           195:        ja      L01
        !           196: 
        !           197:        cmpl    dSIGL(%ebx),%eax
        !           198:        jb      L02
        !           199: 
        !           200: L01:
        !           201: /* The numerator is greater or equal, would cause overflow */
        !           202:        setae   ovfl_flag               /* Keep a record */
        !           203: 
        !           204:        subl    dSIGL(%ebx),%eax
        !           205:        sbbl    dSIGH(%ebx),%edx        /* Prevent the overflow */
        !           206:        movl    %eax,accum_2
        !           207:        movl    %edx,accum_3
        !           208: 
        !           209: L02:
        !           210: /* At this point, we have a num < denom, with a record of
        !           211:    adjustment in ovfl_flag */
        !           212: 
        !           213:        /* We will divide by a number which is too large */
        !           214:        movl    dSIGH(%ebx),%ecx
        !           215:        addl    $1,%ecx
        !           216:        jnc     L04
        !           217: 
        !           218:        /* here we need to divide by 100000000h,
        !           219:           i.e., no division at all.. */
        !           220: 
        !           221:        mov     %edx,%eax
        !           222:        jmp     L05
        !           223: 
        !           224: L04:
        !           225:        divl    %ecx            /* Divide the numerator by the augmented
        !           226:                                   denom ms dw */
        !           227: 
        !           228: L05:
        !           229:        movl    %eax,result_2   /* Put the result in the answer */
        !           230: 
        !           231:        mull    dSIGH(%ebx)             /* mul by the ms dw of the denom */
        !           232: 
        !           233:        subl    %eax,accum_2    /* Subtract from the num local reg */
        !           234:        sbbl    %edx,accum_3
        !           235: 
        !           236:        movl    result_2,%eax   /* Get the result back */
        !           237:        mull    dSIGL(%ebx)             /* now mul the ls dw of the denom */
        !           238: 
        !           239:        subl    %eax,accum_1    /* Subtract from the num local reg */
        !           240:        sbbl    %edx,accum_2
        !           241:        sbbl    $0,accum_3
        !           242:        je      L10             /* Must check for non-zero result here */
        !           243: 
        !           244: #ifdef PARANOID
        !           245:        jb      L_bugged
        !           246: #endif PARANOID
        !           247: 
        !           248:        /* need to subtract another once of the denom */
        !           249:        incl    result_2                /* Correct the answer */
        !           250: 
        !           251:        movl    dSIGL(%ebx),%eax
        !           252:        movl    dSIGH(%ebx),%edx
        !           253:        subl    %eax,accum_1    /* Subtract from the num local reg */
        !           254:        sbbl    %edx,accum_2
        !           255: 
        !           256: #ifdef PARANOID
        !           257:        sbbl    $0,accum_3
        !           258:        jne     L_bugged        /* Must check for non-zero result here */
        !           259: #endif PARANOID
        !           260: 
        !           261: /*----------------------------------------------------------------------*/
        !           262: /* Half of the main problem is done, there is just a reduced numerator
        !           263:    to handle now */
        !           264: /* Work with the second 32 bits, accum_0 not used from now on */
        !           265: L10:
        !           266:        movl    accum_2,%edx    /* get the reduced num */
        !           267:        movl    accum_1,%eax
        !           268: 
        !           269:        /* need to check for possible subsequent overflow */
        !           270:        cmpl    dSIGH(%ebx),%edx
        !           271:        jb      L22
        !           272:        ja      L21
        !           273: 
        !           274:        cmpl    dSIGL(%ebx),%eax
        !           275:        jb      L22
        !           276: 
        !           277: L21:
        !           278: /* The numerator is greater or equal, would cause overflow */
        !           279:        /* prevent overflow */
        !           280:        subl    dSIGL(%ebx),%eax
        !           281:        sbbl    dSIGH(%ebx),%edx
        !           282:        movl    %edx,accum_2
        !           283:        movl    %eax,accum_1
        !           284: 
        !           285:        incl    result_2                /* Reflect the subtraction in the answer */
        !           286: 
        !           287: #ifdef PARANOID
        !           288:        je      L_bugged
        !           289: #endif PARANOID
        !           290: 
        !           291: L22:
        !           292:        cmpl    $0,%ecx
        !           293:        jnz     L24
        !           294: 
        !           295:        /* %ecx == 0, we are dividing by 1.0 */
        !           296:        mov     %edx,%eax
        !           297:        jmp     L25
        !           298: 
        !           299: L24:
        !           300:        divl    %ecx            /* Divide the numerator by the denom ms dw */
        !           301: 
        !           302: L25:
        !           303:        movl    %eax,result_1   /* Put the result in the answer */
        !           304: 
        !           305:        mull    dSIGH(%ebx)             /* mul by the ms dw of the denom */
        !           306: 
        !           307:        subl    %eax,accum_1    /* Subtract from the num local reg */
        !           308:        sbbl    %edx,accum_2
        !           309: 
        !           310: #ifdef PARANOID
        !           311:        jc      L_bugged
        !           312: #endif PARANOID
        !           313: 
        !           314:        movl    result_1,%eax   /* Get the result back */
        !           315:        mull    dSIGL(%ebx)             /* now mul the ls dw of the denom */
        !           316: 
        !           317:        /* Here we are throwing away some ls bits */
        !           318:        subl    %eax,accum_0    /* Subtract from the num local reg */
        !           319:        sbbl    %edx,accum_1    /* Subtract from the num local reg */
        !           320:        sbbl    $0,accum_2
        !           321: 
        !           322: #ifdef PARANOID
        !           323:        jc      L_bugged
        !           324: #endif PARANOID
        !           325: 
        !           326:        jz      L35             /* Just deal with rounding now */
        !           327: 
        !           328: #ifdef PARANOID
        !           329:        cmpl    $1,accum_2
        !           330:        jne     L_bugged
        !           331: #endif PARANOID
        !           332: 
        !           333: L32:
        !           334:        /* need to subtract another once of the denom */
        !           335:        movl    dSIGL(%ebx),%eax
        !           336:        movl    dSIGH(%ebx),%edx
        !           337:        subl    %eax,accum_0    /* Subtract from the num local reg */
        !           338:        sbbl    %edx,accum_1
        !           339:        sbbl    $0,accum_2
        !           340: 
        !           341: #ifdef PARANOID
        !           342:        jc      L_bugged
        !           343:        jne     L_bugged
        !           344: #endif PARANOID
        !           345: 
        !           346:        addl    $1,result_1     /* Correct the answer */
        !           347:        adcl    $0,result_2
        !           348: 
        !           349: #ifdef PARANOID
        !           350:        /* Do we ever really need this check? ***** */
        !           351:        jc      L_bugged        /* Must check for non-zero result here */
        !           352: #endif PARANOID
        !           353: 
        !           354: /*----------------------------------------------------------------------*/
        !           355: /* The division is essentially finished here, we just need to perform
        !           356:    tidying operations. */
        !           357: /* deal with the 3rd 32 bits */
        !           358: L35:
        !           359:        movl    accum_1,%edx    /* get the reduced num */
        !           360:        movl    accum_0,%eax
        !           361: 
        !           362:        /* need to check for possible subsequent overflow */
        !           363:        cmpl    dSIGH(%ebx),%edx
        !           364:        jb      L42
        !           365:        ja      L41
        !           366: 
        !           367:        cmpl    dSIGL(%ebx),%eax
        !           368:        jb      L42
        !           369: 
        !           370: L41:
        !           371:        /* prevent overflow */
        !           372:        subl    dSIGL(%ebx),%eax
        !           373:        sbbl    dSIGH(%ebx),%edx
        !           374:        movl    %edx,accum_1
        !           375:        movl    %eax,accum_0    /* ***** not needed unless extended rounding */
        !           376: 
        !           377:        addl    $1,result_1     /* Reflect the subtraction in the answer */
        !           378:        adcl    $0,result_2
        !           379:        jne     L42
        !           380:        jnc     L42
        !           381: 
        !           382:        /* This is a tricky spot, there is an overflow of the answer */
        !           383:        movb    $255,ovfl_flag          /* Overflow -> 1.000 */
        !           384:        
        !           385: L42:
        !           386:        /* Now test for rounding */
        !           387:        movl    accum_1,%edx    /* ms byte of accum extension */
        !           388: 
        !           389: L44:
        !           390:        cmpl    $0,%ecx
        !           391:        jnz     L241
        !           392: 
        !           393:        /* %ecx == 0, we are dividing by 1.0 */
        !           394:        mov     %edx,%eax
        !           395:        jmp     L251
        !           396: 
        !           397: L241:
        !           398:        divl    %ecx            /* Divide the numerator by the denom ms dw */
        !           399: 
        !           400: L251:
        !           401: /* We are now ready to deal with rounding, but first we must get
        !           402:    the bits properly aligned */
        !           403:        testb   $255,ovfl_flag  /* was the num > denom ? */
        !           404:        je      L45
        !           405: 
        !           406:        incl    EXP(%edi)
        !           407: 
        !           408:        /* shift the mantissa right one bit */
        !           409:        stc                     // Will set the ms bit
        !           410:        rcrl    $1,result_2
        !           411:        rcrl    $1,result_1
        !           412:        rcrl    $1,%eax
        !           413: 
        !           414: L45:
        !           415:        cmpl    $0x80000000,%eax
        !           416:        jc      xL_no_round_2           // No round up
        !           417:        jnz     xL_round_up_2
        !           418: 
        !           419:        /* "round to even" used here for now... */
        !           420:        testb   $1,result_1
        !           421:        jz      xL_no_round_2           // No round up
        !           422: 
        !           423: xL_round_up_2:
        !           424:        addl    $1,result_1
        !           425:        adcl    $0,result_2
        !           426: 
        !           427: #ifdef PARANOID
        !           428:        jc      L_bugged
        !           429: #endif PARANOID
        !           430: 
        !           431: xL_no_round_2:
        !           432:        movl    result_1,%eax
        !           433:        movl    %eax,SIGL(%edi)
        !           434:        movl    result_2,%eax
        !           435:        movl    %eax,SIGH(%edi)
        !           436: 
        !           437: xL_done:
        !           438:        decl    EXP(%edi)       /* binary point between 1st & 2nd bits */
        !           439: 
        !           440: xL_check_exponent:
        !           441:        cmpl    EXP_OVER,EXP(%edi)
        !           442:        jge     xL_overflow
        !           443: 
        !           444:        cmpl    EXP_UNDER,EXP(%edi)
        !           445:        jle     xL_underflow
        !           446: 
        !           447: xL_exit:
        !           448:        popl    %ebx
        !           449:        popl    %edi
        !           450:        popl    %esi
        !           451: 
        !           452:        leave
        !           453:        ret
        !           454: 
        !           455: 
        !           456: xL_overflow:
        !           457:        pushl   %edi
        !           458:        call    arith_overflow
        !           459:        popl    %ebx
        !           460:        jmp     xL_exit
        !           461: 
        !           462: xL_underflow:
        !           463:        pushl   %edi
        !           464:        call    arith_underflow
        !           465:        popl    %ebx
        !           466:        jmp     xL_exit
        !           467: 
        !           468: 
        !           469: #ifdef PARANOID
        !           470: /* The logic is wrong if we got here */
        !           471: L_bugged:
        !           472:        pushl   EX_INTERNAL|0x202
        !           473:        call    EXCEPTION
        !           474:        pop     %ebx
        !           475:        jmp     xL_exit
        !           476: #endif PARANOID

unix.superglobalmegacorp.com

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