aboutsummaryrefslogtreecommitdiff
path: root/target-sparc/op_helper.c
diff options
context:
space:
mode:
authorArtyom Tarasenko <atar4qemu@gmail.com>2009-11-04 19:38:26 +0000
committerBlue Swirl <blauwirbel@gmail.com>2009-11-04 19:38:26 +0000
commit3e6ba503400c34cbe0f9ad6e289921688bf303a3 (patch)
tree0bfb80cad7b80cb90f1cf387c569b469e49f3f70 /target-sparc/op_helper.c
parent2d7adea4fe57a12f3b9f4b4761db2a90cb54173a (diff)
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>
Diffstat (limited to 'target-sparc/op_helper.c')
-rw-r--r--target-sparc/op_helper.c91
1 files changed, 30 insertions, 61 deletions
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index a1ada8bcd5..c3cc0a4030 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -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 },