mirror of https://gitee.com/openkylin/qemu.git
Sparc: fix carry flag handling (Solaris bootblk fix)
The page 108 of the SPARC Version 8 Architecture Manual describes that addcc and addxcc shall compute carry flag the same way. The page 110 claims the same about subcc and subxcc instructions. This patch fixes carry computation in corner cases and removes redundant code. The most visible effect of the patch is enabling Solaris boot when using OBP. Signed-off-by: Artyom Tarasenko <atar4qemu@gmail.com> [blauwirbel@gmail.com: cleaned up formatting] Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
This commit is contained in:
parent
2d7adea4fe
commit
3e6ba50340
|
@ -912,11 +912,15 @@ static uint32_t compute_C_div(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline uint32_t get_C_add_icc(target_ulong dst, target_ulong src1)
|
||||
/* carry = (src1[31] & src2[31]) | ( ~dst[31] & (src1[31] | src2[31])) */
|
||||
static inline uint32_t get_C_add_icc(target_ulong dst, target_ulong src1,
|
||||
target_ulong src2)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if ((dst & 0xffffffffULL) < (src1 & 0xffffffffULL))
|
||||
if (((src1 & (1ULL << 31)) & (src2 & (1ULL << 31)))
|
||||
| ((~(dst & (1ULL << 31)))
|
||||
& ((src1 & (1ULL << 31)) | (src2 & (1ULL << 31)))))
|
||||
ret |= PSR_CARRY;
|
||||
return ret;
|
||||
}
|
||||
|
@ -931,21 +935,6 @@ static inline uint32_t get_V_add_icc(target_ulong dst, target_ulong src1,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_all_add(void)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_add_icc(CC_DST, CC_SRC);
|
||||
ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_add(void)
|
||||
{
|
||||
return get_C_add_icc(CC_DST, CC_SRC);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
|
||||
{
|
||||
|
@ -982,24 +971,19 @@ static uint32_t compute_C_add_xcc(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
static uint32_t compute_all_addx(void)
|
||||
static uint32_t compute_all_add(void)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_add_icc(CC_DST - CC_SRC2, CC_SRC);
|
||||
ret |= get_C_add_icc(CC_DST, CC_SRC);
|
||||
ret |= get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_addx(void)
|
||||
static uint32_t compute_C_add(void)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_C_add_icc(CC_DST - CC_SRC2, CC_SRC);
|
||||
ret |= get_C_add_icc(CC_DST, CC_SRC);
|
||||
return ret;
|
||||
return get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
|
@ -1038,7 +1022,7 @@ static uint32_t compute_all_tadd(void)
|
|||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_add_icc(CC_DST, CC_SRC);
|
||||
ret |= get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
|
@ -1046,7 +1030,7 @@ static uint32_t compute_all_tadd(void)
|
|||
|
||||
static uint32_t compute_C_tadd(void)
|
||||
{
|
||||
return get_C_add_icc(CC_DST, CC_SRC);
|
||||
return get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
}
|
||||
|
||||
static uint32_t compute_all_taddtv(void)
|
||||
|
@ -1054,20 +1038,24 @@ static uint32_t compute_all_taddtv(void)
|
|||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_add_icc(CC_DST, CC_SRC);
|
||||
ret |= get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_taddtv(void)
|
||||
{
|
||||
return get_C_add_icc(CC_DST, CC_SRC);
|
||||
return get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
}
|
||||
|
||||
static inline uint32_t get_C_sub_icc(target_ulong src1, target_ulong src2)
|
||||
/* carry = (~src1[31] & src2[31]) | ( dst[31] & (~src1[31] | src2[31])) */
|
||||
static inline uint32_t get_C_sub_icc(target_ulong dst, target_ulong src1,
|
||||
target_ulong src2)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
if ((src1 & 0xffffffffULL) < (src2 & 0xffffffffULL))
|
||||
if (((~(src1 & (1ULL << 31))) & (src2 & (1ULL << 31)))
|
||||
| ((dst & (1ULL << 31)) & (( ~(src1 & (1ULL << 31)))
|
||||
| (src2 & (1ULL << 31)))))
|
||||
ret |= PSR_CARRY;
|
||||
return ret;
|
||||
}
|
||||
|
@ -1082,20 +1070,6 @@ static inline uint32_t get_V_sub_icc(target_ulong dst, target_ulong src1,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_all_sub(void)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
|
||||
ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_sub(void)
|
||||
{
|
||||
return get_C_sub_icc(CC_SRC, CC_SRC2);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
|
||||
|
@ -1133,24 +1107,19 @@ static uint32_t compute_C_sub_xcc(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
static uint32_t compute_all_subx(void)
|
||||
static uint32_t compute_all_sub(void)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_sub_icc(CC_DST - CC_SRC2, CC_SRC);
|
||||
ret |= get_C_sub_icc(CC_DST, CC_SRC2);
|
||||
ret |= get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_subx(void)
|
||||
static uint32_t compute_C_sub(void)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = get_C_sub_icc(CC_DST - CC_SRC2, CC_SRC);
|
||||
ret |= get_C_sub_icc(CC_DST, CC_SRC2);
|
||||
return ret;
|
||||
return get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
|
@ -1180,7 +1149,7 @@ static uint32_t compute_all_tsub(void)
|
|||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_sub_icc(CC_DST, CC_SRC);
|
||||
ret |= get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
|
@ -1188,7 +1157,7 @@ static uint32_t compute_all_tsub(void)
|
|||
|
||||
static uint32_t compute_C_tsub(void)
|
||||
{
|
||||
return get_C_sub_icc(CC_DST, CC_SRC);
|
||||
return get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
}
|
||||
|
||||
static uint32_t compute_all_tsubtv(void)
|
||||
|
@ -1196,13 +1165,13 @@ static uint32_t compute_all_tsubtv(void)
|
|||
uint32_t ret;
|
||||
|
||||
ret = get_NZ_icc(CC_DST);
|
||||
ret |= get_C_sub_icc(CC_DST, CC_SRC);
|
||||
ret |= get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t compute_C_tsubtv(void)
|
||||
{
|
||||
return get_C_sub_icc(CC_DST, CC_SRC);
|
||||
return get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
|
||||
}
|
||||
|
||||
static uint32_t compute_all_logic(void)
|
||||
|
@ -1232,11 +1201,11 @@ static const CCTable icc_table[CC_OP_NB] = {
|
|||
[CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
|
||||
[CC_OP_DIV] = { compute_all_div, compute_C_div },
|
||||
[CC_OP_ADD] = { compute_all_add, compute_C_add },
|
||||
[CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
|
||||
[CC_OP_ADDX] = { compute_all_add, compute_C_add },
|
||||
[CC_OP_TADD] = { compute_all_tadd, compute_C_tadd },
|
||||
[CC_OP_TADDTV] = { compute_all_taddtv, compute_C_taddtv },
|
||||
[CC_OP_SUB] = { compute_all_sub, compute_C_sub },
|
||||
[CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
|
||||
[CC_OP_SUBX] = { compute_all_sub, compute_C_sub },
|
||||
[CC_OP_TSUB] = { compute_all_tsub, compute_C_tsub },
|
||||
[CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_tsubtv },
|
||||
[CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
|
||||
|
|
Loading…
Reference in New Issue