Annotation of coherent/b/kernel/emulator/reg_u_div.S, revision 1.1.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.