Skip to content

Commit

Permalink
target-tricore: Add instructions of RRR1 opcode format, which have 0x…
Browse files Browse the repository at this point in the history
…43 as first opcode

Add helpers:
    * madd64_q_ssov: multiply two 32 bit q-format number, add them with a
                     64 bit q-format number and saturate.
    * madd32_q_add_ssov: add two 64 bit q-format numbers and return a 32 bit
                         result.
    * maddr_q_ssov: multiplay two 32 bit q-format numbers, add a 32 bit
                    q-format number and saturate.
    * maddr_q: multiplay two 32 bit q-format numbers and add a 32 bit
               q-format number.

Note: madd instructions in the q format can behave strange, e.g.
0x1 + (0x80000000 * 0x80000000) << 1 for 32 bit signed values does not cause an
overflow on the guest, because all intermediate results should be handled as if
they are indefinitely precise. We handle this by inverting the overflow bit for
all cases: a + (0x80000000 * 0x80000000) << 1.

Signed-off-by: Bastian Koppelmann <[email protected]>
Reviewed-by: Richard Henderson <[email protected]>
  • Loading branch information
bkoppelmann committed Mar 3, 2015
1 parent 2e430e1 commit b00aa8e
Show file tree
Hide file tree
Showing 4 changed files with 588 additions and 4 deletions.
4 changes: 4 additions & 0 deletions target-tricore/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ DEF_HELPER_3(absdif_ssov, i32, env, i32, i32)
DEF_HELPER_4(madd32_ssov, i32, env, i32, i32, i32)
DEF_HELPER_4(madd32_suov, i32, env, i32, i32, i32)
DEF_HELPER_4(madd64_ssov, i64, env, i32, i64, i32)
DEF_HELPER_5(madd64_q_ssov, i64, env, i64, i32, i32, i32)
DEF_HELPER_3(madd32_q_add_ssov, i32, env, i64, i64)
DEF_HELPER_5(maddr_q_ssov, i32, env, i32, i32, i32, i32)
DEF_HELPER_4(madd64_suov, i64, env, i32, i64, i32)
DEF_HELPER_4(msub32_ssov, i32, env, i32, i32, i32)
DEF_HELPER_4(msub32_suov, i32, env, i32, i32, i32)
Expand All @@ -47,6 +50,7 @@ DEF_HELPER_2(abs_h, i32, env, i32)
DEF_HELPER_3(absdif_b, i32, env, i32, i32)
DEF_HELPER_3(absdif_h, i32, env, i32, i32)
DEF_HELPER_4(addr_h, i32, env, i64, i32, i32)
DEF_HELPER_5(maddr_q, i32, env, i32, i32, i32, i32)
DEF_HELPER_3(add_b, i32, env, i32, i32)
DEF_HELPER_3(add_h, i32, env, i32, i32)
DEF_HELPER_3(sub_b, i32, env, i32, i32)
Expand Down
153 changes: 153 additions & 0 deletions target-tricore/op_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,131 @@ uint64_t helper_madd64_ssov(CPUTriCoreState *env, target_ulong r1,
return ret;
}

uint32_t
helper_madd32_q_add_ssov(CPUTriCoreState *env, uint64_t r1, uint64_t r2)
{
int64_t result;

result = (r1 + r2);

env->PSW_USB_AV = (result ^ result * 2u);
env->PSW_USB_SAV |= env->PSW_USB_AV;

/* we do the saturation by hand, since we produce an overflow on the host
if the mul before was (0x80000000 * 0x80000000) << 1). If this is the
case, we flip the saturated value. */
if (r2 == 0x8000000000000000LL) {
if (result > 0x7fffffffLL) {
env->PSW_USB_V = (1 << 31);
env->PSW_USB_SV = (1 << 31);
result = INT32_MIN;
} else if (result < -0x80000000LL) {
env->PSW_USB_V = (1 << 31);
env->PSW_USB_SV = (1 << 31);
result = INT32_MAX;
} else {
env->PSW_USB_V = 0;
}
} else {
if (result > 0x7fffffffLL) {
env->PSW_USB_V = (1 << 31);
env->PSW_USB_SV = (1 << 31);
result = INT32_MAX;
} else if (result < -0x80000000LL) {
env->PSW_USB_V = (1 << 31);
env->PSW_USB_SV = (1 << 31);
result = INT32_MIN;
} else {
env->PSW_USB_V = 0;
}
}
return (uint32_t)result;
}

uint64_t helper_madd64_q_ssov(CPUTriCoreState *env, uint64_t r1, uint32_t r2,
uint32_t r3, uint32_t n)
{
int64_t t1 = (int64_t)r1;
int64_t t2 = sextract64(r2, 0, 32);
int64_t t3 = sextract64(r3, 0, 32);
int64_t result, mul;
int64_t ovf;

mul = (t2 * t3) << n;
result = mul + t1;

env->PSW_USB_AV = (result ^ result * 2u) >> 32;
env->PSW_USB_SAV |= env->PSW_USB_AV;

ovf = (result ^ mul) & ~(mul ^ t1);
/* we do the saturation by hand, since we produce an overflow on the host
if the mul was (0x80000000 * 0x80000000) << 1). If this is the
case, we flip the saturated value. */
if ((r2 == 0x80000000) && (r3 == 0x80000000) && (n == 1)) {
if (ovf >= 0) {
env->PSW_USB_V = (1 << 31);
env->PSW_USB_SV = (1 << 31);
/* ext_ret > MAX_INT */
if (mul < 0) {
result = INT64_MAX;
/* ext_ret < MIN_INT */
} else {
result = INT64_MIN;
}
} else {
env->PSW_USB_V = 0;
}
} else {
if (ovf < 0) {
env->PSW_USB_V = (1 << 31);
env->PSW_USB_SV = (1 << 31);
/* ext_ret > MAX_INT */
if (mul >= 0) {
result = INT64_MAX;
/* ext_ret < MIN_INT */
} else {
result = INT64_MIN;
}
} else {
env->PSW_USB_V = 0;
}
}
return (uint64_t)result;
}

uint32_t helper_maddr_q_ssov(CPUTriCoreState *env, uint32_t r1, uint32_t r2,
uint32_t r3, uint32_t n)
{
int64_t t1 = sextract64(r1, 0, 32);
int64_t t2 = sextract64(r2, 0, 32);
int64_t t3 = sextract64(r3, 0, 32);
int64_t mul, ret;

if ((t2 == -0x8000ll) && (t3 == -0x8000ll) && (n == 1)) {
mul = 0x7fffffff;
} else {
mul = (t2 * t3) << n;
}

ret = t1 + mul + 0x8000;

env->PSW_USB_AV = ret ^ ret * 2u;
env->PSW_USB_SAV |= env->PSW_USB_AV;

if (ret > 0x7fffffffll) {
env->PSW_USB_V = (1 << 31);
env->PSW_USB_SV |= env->PSW_USB_V;
ret = INT32_MAX;
} else if (ret < -0x80000000ll) {
env->PSW_USB_V = (1 << 31);
env->PSW_USB_SV |= env->PSW_USB_V;
ret = INT32_MIN;
} else {
env->PSW_USB_V = 0;
}
return ret & 0xffff0000ll;
}

uint64_t helper_madd64_suov(CPUTriCoreState *env, target_ulong r1,
uint64_t r2, target_ulong r3)
{
Expand Down Expand Up @@ -729,6 +854,34 @@ uint32_t helper_addr_h(CPUTriCoreState *env, uint64_t r1, uint32_t r2_l,
return (result1 & 0xffff0000ULL) | ((result0 >> 16) & 0xffffULL);
}

uint32_t helper_maddr_q(CPUTriCoreState *env, uint32_t r1, uint32_t r2,
uint32_t r3, uint32_t n)
{
int64_t t1 = sextract64(r1, 0, 32);
int64_t t2 = sextract64(r2, 0, 32);
int64_t t3 = sextract64(r3, 0, 32);
int64_t mul, ret;

if ((t2 == -0x8000ll) && (t3 == -0x8000ll) && (n == 1)) {
mul = 0x7fffffff;
} else {
mul = (t2 * t3) << n;
}

ret = t1 + mul + 0x8000;

if ((ret > 0x7fffffffll) || (ret < -0x80000000ll)) {
env->PSW_USB_V = (1 << 31);
env->PSW_USB_SV |= env->PSW_USB_V;
} else {
env->PSW_USB_V = 0;
}
env->PSW_USB_AV = ret ^ ret * 2u;
env->PSW_USB_SAV |= env->PSW_USB_AV;

return ret & 0xffff0000ll;
}

uint32_t helper_add_b(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
{
int32_t b, i;
Expand Down
Loading

0 comments on commit b00aa8e

Please sign in to comment.