aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastian Koppelmann <kbastian@mail.uni-paderborn.de>2015-01-19 14:28:59 +0000
committerBastian Koppelmann <kbastian@mail.uni-paderborn.de>2015-01-26 19:56:46 +0000
commit85d604af5f96c32734af9974ec6ddb625b6716a2 (patch)
tree63b12215c9d770e7129ede77387c56caf5931972
parent40a1f64b468ee247fca3b237f0b89f066e59626c (diff)
target-tricore: split up suov32 into suov32_pos and suov32_neg
suov checks unsigned for an overflow and an underflow, after some arithmetic operations and saturates the result to either max_uint32 or 0. So far we handled this by expanding to the next bigger data type and compare whether the result is > max_uint32 or < 0. However this approach can fail for an 32 bit multiplication, if both operands of the multiplication are 0x80000000. This sets the sign bit of the 64 bit integer and would result in a false saturation to 0. Since unsigned operations, e.g add, sub, mul always result in either a positive or negative overflow, we split the functions for suov32 up into two functions (suov32_pos, suov32_neg) for each case. Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
-rw-r--r--target-tricore/op_helper.c41
1 files changed, 26 insertions, 15 deletions
diff --git a/target-tricore/op_helper.c b/target-tricore/op_helper.c
index dcc65b1385..254135ed9e 100644
--- a/target-tricore/op_helper.c
+++ b/target-tricore/op_helper.c
@@ -80,29 +80,40 @@ static uint32_t ssov32(CPUTriCoreState *env, int64_t arg)
return ret;
}
-static uint32_t suov32(CPUTriCoreState *env, int64_t arg)
+static uint32_t suov32_pos(CPUTriCoreState *env, uint64_t arg)
{
uint32_t ret;
- int64_t max_pos = UINT32_MAX;
+ uint64_t max_pos = UINT32_MAX;
if (arg > max_pos) {
env->PSW_USB_V = (1 << 31);
env->PSW_USB_SV = (1 << 31);
ret = (target_ulong)max_pos;
} else {
- if (arg < 0) {
- env->PSW_USB_V = (1 << 31);
- env->PSW_USB_SV = (1 << 31);
- ret = 0;
- } else {
- env->PSW_USB_V = 0;
- ret = (target_ulong)arg;
- }
+ env->PSW_USB_V = 0;
+ ret = (target_ulong)arg;
}
env->PSW_USB_AV = arg ^ arg * 2u;
env->PSW_USB_SAV |= env->PSW_USB_AV;
return ret;
}
+static uint32_t suov32_neg(CPUTriCoreState *env, int64_t arg)
+{
+ uint32_t ret;
+
+ if (arg < 0) {
+ env->PSW_USB_V = (1 << 31);
+ env->PSW_USB_SV = (1 << 31);
+ ret = 0;
+ } else {
+ env->PSW_USB_V = 0;
+ ret = (target_ulong)arg;
+ }
+ env->PSW_USB_AV = arg ^ arg * 2u;
+ env->PSW_USB_SAV |= env->PSW_USB_AV;
+ return ret;
+}
+
static uint32_t ssov16(CPUTriCoreState *env, int32_t hw0, int32_t hw1)
{
int32_t max_pos = INT16_MAX;
@@ -189,7 +200,7 @@ target_ulong helper_add_suov(CPUTriCoreState *env, target_ulong r1,
int64_t t1 = extract64(r1, 0, 32);
int64_t t2 = extract64(r2, 0, 32);
int64_t result = t1 + t2;
- return suov32(env, result);
+ return suov32_pos(env, result);
}
target_ulong helper_add_h_suov(CPUTriCoreState *env, target_ulong r1,
@@ -227,7 +238,7 @@ target_ulong helper_sub_suov(CPUTriCoreState *env, target_ulong r1,
int64_t t1 = extract64(r1, 0, 32);
int64_t t2 = extract64(r2, 0, 32);
int64_t result = t1 - t2;
- return suov32(env, result);
+ return suov32_neg(env, result);
}
target_ulong helper_sub_h_suov(CPUTriCoreState *env, target_ulong r1,
@@ -256,7 +267,7 @@ target_ulong helper_mul_suov(CPUTriCoreState *env, target_ulong r1,
int64_t t2 = extract64(r2, 0, 32);
int64_t result = t1 * t2;
- return suov32(env, result);
+ return suov32_pos(env, result);
}
target_ulong helper_sha_ssov(CPUTriCoreState *env, target_ulong r1,
@@ -356,7 +367,7 @@ target_ulong helper_madd32_suov(CPUTriCoreState *env, target_ulong r1,
int64_t result;
result = t2 + (t1 * t3);
- return suov32(env, result);
+ return suov32_pos(env, result);
}
uint64_t helper_madd64_ssov(CPUTriCoreState *env, target_ulong r1,
@@ -438,7 +449,7 @@ target_ulong helper_msub32_suov(CPUTriCoreState *env, target_ulong r1,
int64_t result;
result = t2 - (t1 * t3);
- return suov32(env, result);
+ return suov32_neg(env, result);
}
uint64_t helper_msub64_ssov(CPUTriCoreState *env, target_ulong r1,