added overflow exceptions in divisions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1521 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									d592d3033d
								
							
						
					
					
						commit
						45bbbb466c
					
				@ -1209,13 +1209,13 @@ void raise_exception(int exception_index)
 | 
				
			|||||||
#ifdef BUGGY_GCC_DIV64
 | 
					#ifdef BUGGY_GCC_DIV64
 | 
				
			||||||
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
 | 
					/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
 | 
				
			||||||
   call it from another function */
 | 
					   call it from another function */
 | 
				
			||||||
uint32_t div32(uint32_t *q_ptr, uint64_t num, uint32_t den)
 | 
					uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    *q_ptr = num / den;
 | 
					    *q_ptr = num / den;
 | 
				
			||||||
    return num % den;
 | 
					    return num % den;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den)
 | 
					int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    *q_ptr = num / den;
 | 
					    *q_ptr = num / den;
 | 
				
			||||||
    return num % den;
 | 
					    return num % den;
 | 
				
			||||||
@ -1224,8 +1224,8 @@ int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void helper_divl_EAX_T0(void)
 | 
					void helper_divl_EAX_T0(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    unsigned int den, q, r;
 | 
					    unsigned int den, r;
 | 
				
			||||||
    uint64_t num;
 | 
					    uint64_t num, q;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
 | 
					    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
 | 
				
			||||||
    den = T0;
 | 
					    den = T0;
 | 
				
			||||||
@ -1238,14 +1238,16 @@ void helper_divl_EAX_T0(void)
 | 
				
			|||||||
    q = (num / den);
 | 
					    q = (num / den);
 | 
				
			||||||
    r = (num % den);
 | 
					    r = (num % den);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					    if (q > 0xffffffff)
 | 
				
			||||||
 | 
					        raise_exception(EXCP00_DIVZ);
 | 
				
			||||||
    EAX = (uint32_t)q;
 | 
					    EAX = (uint32_t)q;
 | 
				
			||||||
    EDX = (uint32_t)r;
 | 
					    EDX = (uint32_t)r;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void helper_idivl_EAX_T0(void)
 | 
					void helper_idivl_EAX_T0(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int den, q, r;
 | 
					    int den, r;
 | 
				
			||||||
    int64_t num;
 | 
					    int64_t num, q;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
 | 
					    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
 | 
				
			||||||
    den = T0;
 | 
					    den = T0;
 | 
				
			||||||
@ -1258,6 +1260,8 @@ void helper_idivl_EAX_T0(void)
 | 
				
			|||||||
    q = (num / den);
 | 
					    q = (num / den);
 | 
				
			||||||
    r = (num % den);
 | 
					    r = (num % den);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					    if (q != (int32_t)q)
 | 
				
			||||||
 | 
					        raise_exception(EXCP00_DIVZ);
 | 
				
			||||||
    EAX = (uint32_t)q;
 | 
					    EAX = (uint32_t)q;
 | 
				
			||||||
    EDX = (uint32_t)r;
 | 
					    EDX = (uint32_t)r;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -3254,8 +3258,8 @@ static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* XXX: overflow support */
 | 
					/* return TRUE if overflow */
 | 
				
			||||||
static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
 | 
					static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint64_t q, r, a1, a0;
 | 
					    uint64_t q, r, a1, a0;
 | 
				
			||||||
    int i, qb;
 | 
					    int i, qb;
 | 
				
			||||||
@ -3268,6 +3272,8 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
 | 
				
			|||||||
        *plow = q;
 | 
					        *plow = q;
 | 
				
			||||||
        *phigh = r;
 | 
					        *phigh = r;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (a1 >= b)
 | 
				
			||||||
 | 
					            return 1;
 | 
				
			||||||
        /* XXX: use a better algorithm */
 | 
					        /* XXX: use a better algorithm */
 | 
				
			||||||
        for(i = 0; i < 64; i++) {
 | 
					        for(i = 0; i < 64; i++) {
 | 
				
			||||||
            a1 = (a1 << 1) | (a0 >> 63);
 | 
					            a1 = (a1 << 1) | (a0 >> 63);
 | 
				
			||||||
@ -3286,9 +3292,11 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
 | 
				
			|||||||
        *plow = a0;
 | 
					        *plow = a0;
 | 
				
			||||||
        *phigh = a1;
 | 
					        *phigh = a1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
 | 
					/* return TRUE if overflow */
 | 
				
			||||||
 | 
					static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int sa, sb;
 | 
					    int sa, sb;
 | 
				
			||||||
    sa = ((int64_t)*phigh < 0);
 | 
					    sa = ((int64_t)*phigh < 0);
 | 
				
			||||||
@ -3297,11 +3305,19 @@ static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
 | 
				
			|||||||
    sb = (b < 0);
 | 
					    sb = (b < 0);
 | 
				
			||||||
    if (sb)
 | 
					    if (sb)
 | 
				
			||||||
        b = -b;
 | 
					        b = -b;
 | 
				
			||||||
    div64(plow, phigh, b);
 | 
					    if (div64(plow, phigh, b) != 0)
 | 
				
			||||||
    if (sa ^ sb)
 | 
					        return 1;
 | 
				
			||||||
 | 
					    if (sa ^ sb) {
 | 
				
			||||||
 | 
					        if (*plow > (1ULL << 63))
 | 
				
			||||||
 | 
					            return 1;
 | 
				
			||||||
        *plow = - *plow;
 | 
					        *plow = - *plow;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (*plow >= (1ULL << 63))
 | 
				
			||||||
 | 
					            return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (sa)
 | 
					    if (sa)
 | 
				
			||||||
        *phigh = - *phigh;
 | 
					        *phigh = - *phigh;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void helper_mulq_EAX_T0(void)
 | 
					void helper_mulq_EAX_T0(void)
 | 
				
			||||||
@ -3344,7 +3360,8 @@ void helper_divq_EAX_T0(void)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    r0 = EAX;
 | 
					    r0 = EAX;
 | 
				
			||||||
    r1 = EDX;
 | 
					    r1 = EDX;
 | 
				
			||||||
    div64(&r0, &r1, T0);
 | 
					    if (div64(&r0, &r1, T0))
 | 
				
			||||||
 | 
					        raise_exception(EXCP00_DIVZ);
 | 
				
			||||||
    EAX = r0;
 | 
					    EAX = r0;
 | 
				
			||||||
    EDX = r1;
 | 
					    EDX = r1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -3357,7 +3374,8 @@ void helper_idivq_EAX_T0(void)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    r0 = EAX;
 | 
					    r0 = EAX;
 | 
				
			||||||
    r1 = EDX;
 | 
					    r1 = EDX;
 | 
				
			||||||
    idiv64(&r0, &r1, T0);
 | 
					    if (idiv64(&r0, &r1, T0))
 | 
				
			||||||
 | 
					        raise_exception(EXCP00_DIVZ);
 | 
				
			||||||
    EAX = r0;
 | 
					    EAX = r0;
 | 
				
			||||||
    EDX = r1;
 | 
					    EDX = r1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -328,7 +328,6 @@ void OPPROTO op_imulq_T0_T1(void)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* division, flags are undefined */
 | 
					/* division, flags are undefined */
 | 
				
			||||||
/* XXX: add exceptions for overflow */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OPPROTO op_divb_AL_T0(void)
 | 
					void OPPROTO op_divb_AL_T0(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -339,7 +338,10 @@ void OPPROTO op_divb_AL_T0(void)
 | 
				
			|||||||
    if (den == 0) {
 | 
					    if (den == 0) {
 | 
				
			||||||
        raise_exception(EXCP00_DIVZ);
 | 
					        raise_exception(EXCP00_DIVZ);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    q = (num / den) & 0xff;
 | 
					    q = (num / den);
 | 
				
			||||||
 | 
					    if (q > 0xff)
 | 
				
			||||||
 | 
					        raise_exception(EXCP00_DIVZ);
 | 
				
			||||||
 | 
					    q &= 0xff;
 | 
				
			||||||
    r = (num % den) & 0xff;
 | 
					    r = (num % den) & 0xff;
 | 
				
			||||||
    EAX = (EAX & ~0xffff) | (r << 8) | q;
 | 
					    EAX = (EAX & ~0xffff) | (r << 8) | q;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -353,7 +355,10 @@ void OPPROTO op_idivb_AL_T0(void)
 | 
				
			|||||||
    if (den == 0) {
 | 
					    if (den == 0) {
 | 
				
			||||||
        raise_exception(EXCP00_DIVZ);
 | 
					        raise_exception(EXCP00_DIVZ);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    q = (num / den) & 0xff;
 | 
					    q = (num / den);
 | 
				
			||||||
 | 
					    if (q != (int8_t)q)
 | 
				
			||||||
 | 
					        raise_exception(EXCP00_DIVZ);
 | 
				
			||||||
 | 
					    q &= 0xff;
 | 
				
			||||||
    r = (num % den) & 0xff;
 | 
					    r = (num % den) & 0xff;
 | 
				
			||||||
    EAX = (EAX & ~0xffff) | (r << 8) | q;
 | 
					    EAX = (EAX & ~0xffff) | (r << 8) | q;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -367,7 +372,10 @@ void OPPROTO op_divw_AX_T0(void)
 | 
				
			|||||||
    if (den == 0) {
 | 
					    if (den == 0) {
 | 
				
			||||||
        raise_exception(EXCP00_DIVZ);
 | 
					        raise_exception(EXCP00_DIVZ);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    q = (num / den) & 0xffff;
 | 
					    q = (num / den);
 | 
				
			||||||
 | 
					    if (q > 0xffff)
 | 
				
			||||||
 | 
					        raise_exception(EXCP00_DIVZ);
 | 
				
			||||||
 | 
					    q &= 0xffff;
 | 
				
			||||||
    r = (num % den) & 0xffff;
 | 
					    r = (num % den) & 0xffff;
 | 
				
			||||||
    EAX = (EAX & ~0xffff) | q;
 | 
					    EAX = (EAX & ~0xffff) | q;
 | 
				
			||||||
    EDX = (EDX & ~0xffff) | r;
 | 
					    EDX = (EDX & ~0xffff) | r;
 | 
				
			||||||
@ -382,7 +390,10 @@ void OPPROTO op_idivw_AX_T0(void)
 | 
				
			|||||||
    if (den == 0) {
 | 
					    if (den == 0) {
 | 
				
			||||||
        raise_exception(EXCP00_DIVZ);
 | 
					        raise_exception(EXCP00_DIVZ);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    q = (num / den) & 0xffff;
 | 
					    q = (num / den);
 | 
				
			||||||
 | 
					    if (q != (int16_t)q)
 | 
				
			||||||
 | 
					        raise_exception(EXCP00_DIVZ);
 | 
				
			||||||
 | 
					    q &= 0xffff;
 | 
				
			||||||
    r = (num % den) & 0xffff;
 | 
					    r = (num % den) & 0xffff;
 | 
				
			||||||
    EAX = (EAX & ~0xffff) | q;
 | 
					    EAX = (EAX & ~0xffff) | q;
 | 
				
			||||||
    EDX = (EDX & ~0xffff) | r;
 | 
					    EDX = (EDX & ~0xffff) | r;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user