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>
1697 lines
46 KiB
C
1697 lines
46 KiB
C
/*
|
||
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
|
||
*
|
||
* This library is free software; you can redistribute it and/or
|
||
* modify it under the terms of the GNU Lesser General Public
|
||
* License as published by the Free Software Foundation; either
|
||
* version 2 of the License, or (at your option) any later version.
|
||
*
|
||
* This library is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
* Lesser General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU Lesser General Public
|
||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
#include <stdlib.h>
|
||
#include "cpu.h"
|
||
#include "qemu/host-utils.h"
|
||
#include "exec/helper-proto.h"
|
||
#include "exec/cpu_ldst.h"
|
||
|
||
/* Addressing mode helper */
|
||
|
||
static uint16_t reverse16(uint16_t val)
|
||
{
|
||
uint8_t high = (uint8_t)(val >> 8);
|
||
uint8_t low = (uint8_t)(val & 0xff);
|
||
|
||
uint16_t rh, rl;
|
||
|
||
rl = (uint16_t)((high * 0x0202020202ULL & 0x010884422010ULL) % 1023);
|
||
rh = (uint16_t)((low * 0x0202020202ULL & 0x010884422010ULL) % 1023);
|
||
|
||
return (rh << 8) | rl;
|
||
}
|
||
|
||
uint32_t helper_br_update(uint32_t reg)
|
||
{
|
||
uint32_t index = reg & 0xffff;
|
||
uint32_t incr = reg >> 16;
|
||
uint32_t new_index = reverse16(reverse16(index) + reverse16(incr));
|
||
return reg - index + new_index;
|
||
}
|
||
|
||
uint32_t helper_circ_update(uint32_t reg, uint32_t off)
|
||
{
|
||
uint32_t index = reg & 0xffff;
|
||
uint32_t length = reg >> 16;
|
||
int32_t new_index = index + off;
|
||
if (new_index < 0) {
|
||
new_index += length;
|
||
} else {
|
||
new_index %= length;
|
||
}
|
||
return reg - index + new_index;
|
||
}
|
||
|
||
static uint32_t ssov32(CPUTriCoreState *env, int64_t arg)
|
||
{
|
||
uint32_t ret;
|
||
int64_t max_pos = INT32_MAX;
|
||
int64_t max_neg = INT32_MIN;
|
||
if (arg > max_pos) {
|
||
env->PSW_USB_V = (1 << 31);
|
||
env->PSW_USB_SV = (1 << 31);
|
||
ret = (target_ulong)max_pos;
|
||
} else {
|
||
if (arg < max_neg) {
|
||
env->PSW_USB_V = (1 << 31);
|
||
env->PSW_USB_SV = (1 << 31);
|
||
ret = (target_ulong)max_neg;
|
||
} 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 suov32_pos(CPUTriCoreState *env, uint64_t arg)
|
||
{
|
||
uint32_t ret;
|
||
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 {
|
||
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;
|
||
int32_t max_neg = INT16_MIN;
|
||
int32_t av0, av1;
|
||
|
||
env->PSW_USB_V = 0;
|
||
av0 = hw0 ^ hw0 * 2u;
|
||
if (hw0 > max_pos) {
|
||
env->PSW_USB_V = (1 << 31);
|
||
hw0 = max_pos;
|
||
} else if (hw0 < max_neg) {
|
||
env->PSW_USB_V = (1 << 31);
|
||
hw0 = max_neg;
|
||
}
|
||
|
||
av1 = hw1 ^ hw1 * 2u;
|
||
if (hw1 > max_pos) {
|
||
env->PSW_USB_V = (1 << 31);
|
||
hw1 = max_pos;
|
||
} else if (hw1 < max_neg) {
|
||
env->PSW_USB_V = (1 << 31);
|
||
hw1 = max_neg;
|
||
}
|
||
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
env->PSW_USB_AV = (av0 | av1) << 16;
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
return (hw0 & 0xffff) | (hw1 << 16);
|
||
}
|
||
|
||
static uint32_t suov16(CPUTriCoreState *env, int32_t hw0, int32_t hw1)
|
||
{
|
||
int32_t max_pos = UINT16_MAX;
|
||
int32_t av0, av1;
|
||
|
||
env->PSW_USB_V = 0;
|
||
av0 = hw0 ^ hw0 * 2u;
|
||
if (hw0 > max_pos) {
|
||
env->PSW_USB_V = (1 << 31);
|
||
hw0 = max_pos;
|
||
} else if (hw0 < 0) {
|
||
env->PSW_USB_V = (1 << 31);
|
||
hw0 = 0;
|
||
}
|
||
|
||
av1 = hw1 ^ hw1 * 2u;
|
||
if (hw1 > max_pos) {
|
||
env->PSW_USB_V = (1 << 31);
|
||
hw1 = max_pos;
|
||
} else if (hw1 < 0) {
|
||
env->PSW_USB_V = (1 << 31);
|
||
hw1 = 0;
|
||
}
|
||
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
env->PSW_USB_AV = (av0 | av1) << 16;
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
return (hw0 & 0xffff) | (hw1 << 16);
|
||
}
|
||
|
||
target_ulong helper_add_ssov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2)
|
||
{
|
||
int64_t t1 = sextract64(r1, 0, 32);
|
||
int64_t t2 = sextract64(r2, 0, 32);
|
||
int64_t result = t1 + t2;
|
||
return ssov32(env, result);
|
||
}
|
||
|
||
target_ulong helper_add_h_ssov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2)
|
||
{
|
||
int32_t ret_hw0, ret_hw1;
|
||
|
||
ret_hw0 = sextract32(r1, 0, 16) + sextract32(r2, 0, 16);
|
||
ret_hw1 = sextract32(r1, 16, 16) + sextract32(r2, 16, 16);
|
||
return ssov16(env, ret_hw0, ret_hw1);
|
||
}
|
||
|
||
target_ulong helper_add_suov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2)
|
||
{
|
||
int64_t t1 = extract64(r1, 0, 32);
|
||
int64_t t2 = extract64(r2, 0, 32);
|
||
int64_t result = t1 + t2;
|
||
return suov32_pos(env, result);
|
||
}
|
||
|
||
target_ulong helper_add_h_suov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2)
|
||
{
|
||
int32_t ret_hw0, ret_hw1;
|
||
|
||
ret_hw0 = extract32(r1, 0, 16) + extract32(r2, 0, 16);
|
||
ret_hw1 = extract32(r1, 16, 16) + extract32(r2, 16, 16);
|
||
return suov16(env, ret_hw0, ret_hw1);
|
||
}
|
||
|
||
target_ulong helper_sub_ssov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2)
|
||
{
|
||
int64_t t1 = sextract64(r1, 0, 32);
|
||
int64_t t2 = sextract64(r2, 0, 32);
|
||
int64_t result = t1 - t2;
|
||
return ssov32(env, result);
|
||
}
|
||
|
||
target_ulong helper_sub_h_ssov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2)
|
||
{
|
||
int32_t ret_hw0, ret_hw1;
|
||
|
||
ret_hw0 = sextract32(r1, 0, 16) - sextract32(r2, 0, 16);
|
||
ret_hw1 = sextract32(r1, 16, 16) - sextract32(r2, 16, 16);
|
||
return ssov16(env, ret_hw0, ret_hw1);
|
||
}
|
||
|
||
target_ulong helper_sub_suov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2)
|
||
{
|
||
int64_t t1 = extract64(r1, 0, 32);
|
||
int64_t t2 = extract64(r2, 0, 32);
|
||
int64_t result = t1 - t2;
|
||
return suov32_neg(env, result);
|
||
}
|
||
|
||
target_ulong helper_sub_h_suov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2)
|
||
{
|
||
int32_t ret_hw0, ret_hw1;
|
||
|
||
ret_hw0 = extract32(r1, 0, 16) - extract32(r2, 0, 16);
|
||
ret_hw1 = extract32(r1, 16, 16) - extract32(r2, 16, 16);
|
||
return suov16(env, ret_hw0, ret_hw1);
|
||
}
|
||
|
||
target_ulong helper_mul_ssov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2)
|
||
{
|
||
int64_t t1 = sextract64(r1, 0, 32);
|
||
int64_t t2 = sextract64(r2, 0, 32);
|
||
int64_t result = t1 * t2;
|
||
return ssov32(env, result);
|
||
}
|
||
|
||
target_ulong helper_mul_suov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2)
|
||
{
|
||
int64_t t1 = extract64(r1, 0, 32);
|
||
int64_t t2 = extract64(r2, 0, 32);
|
||
int64_t result = t1 * t2;
|
||
|
||
return suov32_pos(env, result);
|
||
}
|
||
|
||
target_ulong helper_sha_ssov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2)
|
||
{
|
||
int64_t t1 = sextract64(r1, 0, 32);
|
||
int32_t t2 = sextract64(r2, 0, 6);
|
||
int64_t result;
|
||
if (t2 == 0) {
|
||
result = t1;
|
||
} else if (t2 > 0) {
|
||
result = t1 << t2;
|
||
} else {
|
||
result = t1 >> -t2;
|
||
}
|
||
return ssov32(env, result);
|
||
}
|
||
|
||
uint32_t helper_abs_ssov(CPUTriCoreState *env, target_ulong r1)
|
||
{
|
||
target_ulong result;
|
||
result = ((int32_t)r1 >= 0) ? r1 : (0 - r1);
|
||
return ssov32(env, result);
|
||
}
|
||
|
||
uint32_t helper_abs_h_ssov(CPUTriCoreState *env, target_ulong r1)
|
||
{
|
||
int32_t ret_h0, ret_h1;
|
||
|
||
ret_h0 = sextract32(r1, 0, 16);
|
||
ret_h0 = (ret_h0 >= 0) ? ret_h0 : (0 - ret_h0);
|
||
|
||
ret_h1 = sextract32(r1, 16, 16);
|
||
ret_h1 = (ret_h1 >= 0) ? ret_h1 : (0 - ret_h1);
|
||
|
||
return ssov16(env, ret_h0, ret_h1);
|
||
}
|
||
|
||
target_ulong helper_absdif_ssov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2)
|
||
{
|
||
int64_t t1 = sextract64(r1, 0, 32);
|
||
int64_t t2 = sextract64(r2, 0, 32);
|
||
int64_t result;
|
||
|
||
if (t1 > t2) {
|
||
result = t1 - t2;
|
||
} else {
|
||
result = t2 - t1;
|
||
}
|
||
return ssov32(env, result);
|
||
}
|
||
|
||
uint32_t helper_absdif_h_ssov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2)
|
||
{
|
||
int32_t t1, t2;
|
||
int32_t ret_h0, ret_h1;
|
||
|
||
t1 = sextract32(r1, 0, 16);
|
||
t2 = sextract32(r2, 0, 16);
|
||
if (t1 > t2) {
|
||
ret_h0 = t1 - t2;
|
||
} else {
|
||
ret_h0 = t2 - t1;
|
||
}
|
||
|
||
t1 = sextract32(r1, 16, 16);
|
||
t2 = sextract32(r2, 16, 16);
|
||
if (t1 > t2) {
|
||
ret_h1 = t1 - t2;
|
||
} else {
|
||
ret_h1 = t2 - t1;
|
||
}
|
||
|
||
return ssov16(env, ret_h0, ret_h1);
|
||
}
|
||
|
||
target_ulong helper_madd32_ssov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2, target_ulong r3)
|
||
{
|
||
int64_t t1 = sextract64(r1, 0, 32);
|
||
int64_t t2 = sextract64(r2, 0, 32);
|
||
int64_t t3 = sextract64(r3, 0, 32);
|
||
int64_t result;
|
||
|
||
result = t2 + (t1 * t3);
|
||
return ssov32(env, result);
|
||
}
|
||
|
||
target_ulong helper_madd32_suov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2, target_ulong r3)
|
||
{
|
||
uint64_t t1 = extract64(r1, 0, 32);
|
||
uint64_t t2 = extract64(r2, 0, 32);
|
||
uint64_t t3 = extract64(r3, 0, 32);
|
||
int64_t result;
|
||
|
||
result = t2 + (t1 * t3);
|
||
return suov32_pos(env, result);
|
||
}
|
||
|
||
uint64_t helper_madd64_ssov(CPUTriCoreState *env, target_ulong r1,
|
||
uint64_t r2, target_ulong r3)
|
||
{
|
||
uint64_t ret, ovf;
|
||
int64_t t1 = sextract64(r1, 0, 32);
|
||
int64_t t3 = sextract64(r3, 0, 32);
|
||
int64_t mul;
|
||
|
||
mul = t1 * t3;
|
||
ret = mul + r2;
|
||
ovf = (ret ^ mul) & ~(mul ^ r2);
|
||
|
||
t1 = ret >> 32;
|
||
env->PSW_USB_AV = t1 ^ t1 * 2u;
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
|
||
if ((int64_t)ovf < 0) {
|
||
env->PSW_USB_V = (1 << 31);
|
||
env->PSW_USB_SV = (1 << 31);
|
||
/* ext_ret > MAX_INT */
|
||
if (mul >= 0) {
|
||
ret = INT64_MAX;
|
||
/* ext_ret < MIN_INT */
|
||
} else {
|
||
ret = INT64_MIN;
|
||
}
|
||
} else {
|
||
env->PSW_USB_V = 0;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint64_t helper_madd64_suov(CPUTriCoreState *env, target_ulong r1,
|
||
uint64_t r2, target_ulong r3)
|
||
{
|
||
uint64_t ret, mul;
|
||
uint64_t t1 = extract64(r1, 0, 32);
|
||
uint64_t t3 = extract64(r3, 0, 32);
|
||
|
||
mul = t1 * t3;
|
||
ret = mul + r2;
|
||
|
||
t1 = ret >> 32;
|
||
env->PSW_USB_AV = t1 ^ t1 * 2u;
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
|
||
if (ret < r2) {
|
||
env->PSW_USB_V = (1 << 31);
|
||
env->PSW_USB_SV = (1 << 31);
|
||
/* saturate */
|
||
ret = UINT64_MAX;
|
||
} else {
|
||
env->PSW_USB_V = 0;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
target_ulong helper_msub32_ssov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2, target_ulong r3)
|
||
{
|
||
int64_t t1 = sextract64(r1, 0, 32);
|
||
int64_t t2 = sextract64(r2, 0, 32);
|
||
int64_t t3 = sextract64(r3, 0, 32);
|
||
int64_t result;
|
||
|
||
result = t2 - (t1 * t3);
|
||
return ssov32(env, result);
|
||
}
|
||
|
||
target_ulong helper_msub32_suov(CPUTriCoreState *env, target_ulong r1,
|
||
target_ulong r2, target_ulong r3)
|
||
{
|
||
int64_t t1 = extract64(r1, 0, 32);
|
||
int64_t t2 = extract64(r2, 0, 32);
|
||
int64_t t3 = extract64(r3, 0, 32);
|
||
int64_t result;
|
||
|
||
result = t2 - (t1 * t3);
|
||
return suov32_neg(env, result);
|
||
}
|
||
|
||
uint64_t helper_msub64_ssov(CPUTriCoreState *env, target_ulong r1,
|
||
uint64_t r2, target_ulong r3)
|
||
{
|
||
uint64_t ret, ovf;
|
||
int64_t t1 = sextract64(r1, 0, 32);
|
||
int64_t t3 = sextract64(r3, 0, 32);
|
||
int64_t mul;
|
||
|
||
mul = t1 * t3;
|
||
ret = r2 - mul;
|
||
ovf = (ret ^ r2) & (mul ^ r2);
|
||
|
||
t1 = ret >> 32;
|
||
env->PSW_USB_AV = t1 ^ t1 * 2u;
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
|
||
if ((int64_t)ovf < 0) {
|
||
env->PSW_USB_V = (1 << 31);
|
||
env->PSW_USB_SV = (1 << 31);
|
||
/* ext_ret > MAX_INT */
|
||
if (mul < 0) {
|
||
ret = INT64_MAX;
|
||
/* ext_ret < MIN_INT */
|
||
} else {
|
||
ret = INT64_MIN;
|
||
}
|
||
} else {
|
||
env->PSW_USB_V = 0;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
uint64_t helper_msub64_suov(CPUTriCoreState *env, target_ulong r1,
|
||
uint64_t r2, target_ulong r3)
|
||
{
|
||
uint64_t ret, mul;
|
||
uint64_t t1 = extract64(r1, 0, 32);
|
||
uint64_t t3 = extract64(r3, 0, 32);
|
||
|
||
mul = t1 * t3;
|
||
ret = r2 - mul;
|
||
|
||
t1 = ret >> 32;
|
||
env->PSW_USB_AV = t1 ^ t1 * 2u;
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
|
||
if (ret > r2) {
|
||
env->PSW_USB_V = (1 << 31);
|
||
env->PSW_USB_SV = (1 << 31);
|
||
/* saturate */
|
||
ret = 0;
|
||
} else {
|
||
env->PSW_USB_V = 0;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_abs_b(CPUTriCoreState *env, target_ulong arg)
|
||
{
|
||
int32_t b, i;
|
||
int32_t ovf = 0;
|
||
int32_t avf = 0;
|
||
int32_t ret = 0;
|
||
|
||
for (i = 0; i < 4; i++) {
|
||
b = sextract32(arg, i * 8, 8);
|
||
b = (b >= 0) ? b : (0 - b);
|
||
ovf |= (b > 0x7F) || (b < -0x80);
|
||
avf |= b ^ b * 2u;
|
||
ret |= (b & 0xff) << (i * 8);
|
||
}
|
||
|
||
env->PSW_USB_V = ovf << 31;
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
env->PSW_USB_AV = avf << 24;
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_abs_h(CPUTriCoreState *env, target_ulong arg)
|
||
{
|
||
int32_t h, i;
|
||
int32_t ovf = 0;
|
||
int32_t avf = 0;
|
||
int32_t ret = 0;
|
||
|
||
for (i = 0; i < 2; i++) {
|
||
h = sextract32(arg, i * 16, 16);
|
||
h = (h >= 0) ? h : (0 - h);
|
||
ovf |= (h > 0x7FFF) || (h < -0x8000);
|
||
avf |= h ^ h * 2u;
|
||
ret |= (h & 0xffff) << (i * 16);
|
||
}
|
||
|
||
env->PSW_USB_V = ovf << 31;
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
env->PSW_USB_AV = avf << 16;
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_absdif_b(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t b, i;
|
||
int32_t extr_r2;
|
||
int32_t ovf = 0;
|
||
int32_t avf = 0;
|
||
int32_t ret = 0;
|
||
|
||
for (i = 0; i < 4; i++) {
|
||
extr_r2 = sextract32(r2, i * 8, 8);
|
||
b = sextract32(r1, i * 8, 8);
|
||
b = (b > extr_r2) ? (b - extr_r2) : (extr_r2 - b);
|
||
ovf |= (b > 0x7F) || (b < -0x80);
|
||
avf |= b ^ b * 2u;
|
||
ret |= (b & 0xff) << (i * 8);
|
||
}
|
||
|
||
env->PSW_USB_V = ovf << 31;
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
env->PSW_USB_AV = avf << 24;
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_absdif_h(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t h, i;
|
||
int32_t extr_r2;
|
||
int32_t ovf = 0;
|
||
int32_t avf = 0;
|
||
int32_t ret = 0;
|
||
|
||
for (i = 0; i < 2; i++) {
|
||
extr_r2 = sextract32(r2, i * 16, 16);
|
||
h = sextract32(r1, i * 16, 16);
|
||
h = (h > extr_r2) ? (h - extr_r2) : (extr_r2 - h);
|
||
ovf |= (h > 0x7FFF) || (h < -0x8000);
|
||
avf |= h ^ h * 2u;
|
||
ret |= (h & 0xffff) << (i * 16);
|
||
}
|
||
|
||
env->PSW_USB_V = ovf << 31;
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
env->PSW_USB_AV = avf << 16;
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_add_b(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t b, i;
|
||
int32_t extr_r1, extr_r2;
|
||
int32_t ovf = 0;
|
||
int32_t avf = 0;
|
||
uint32_t ret = 0;
|
||
|
||
for (i = 0; i < 4; i++) {
|
||
extr_r1 = sextract32(r1, i * 8, 8);
|
||
extr_r2 = sextract32(r2, i * 8, 8);
|
||
|
||
b = extr_r1 + extr_r2;
|
||
ovf |= ((b > 0x7f) || (b < -0x80));
|
||
avf |= b ^ b * 2u;
|
||
ret |= ((b & 0xff) << (i*8));
|
||
}
|
||
|
||
env->PSW_USB_V = (ovf << 31);
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
env->PSW_USB_AV = avf << 24;
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_add_h(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t h, i;
|
||
int32_t extr_r1, extr_r2;
|
||
int32_t ovf = 0;
|
||
int32_t avf = 0;
|
||
int32_t ret = 0;
|
||
|
||
for (i = 0; i < 2; i++) {
|
||
extr_r1 = sextract32(r1, i * 16, 16);
|
||
extr_r2 = sextract32(r2, i * 16, 16);
|
||
h = extr_r1 + extr_r2;
|
||
ovf |= ((h > 0x7fff) || (h < -0x8000));
|
||
avf |= h ^ h * 2u;
|
||
ret |= (h & 0xffff) << (i * 16);
|
||
}
|
||
|
||
env->PSW_USB_V = (ovf << 31);
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
env->PSW_USB_AV = (avf << 16);
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_sub_b(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t b, i;
|
||
int32_t extr_r1, extr_r2;
|
||
int32_t ovf = 0;
|
||
int32_t avf = 0;
|
||
uint32_t ret = 0;
|
||
|
||
for (i = 0; i < 4; i++) {
|
||
extr_r1 = sextract32(r1, i * 8, 8);
|
||
extr_r2 = sextract32(r2, i * 8, 8);
|
||
|
||
b = extr_r1 - extr_r2;
|
||
ovf |= ((b > 0x7f) || (b < -0x80));
|
||
avf |= b ^ b * 2u;
|
||
ret |= ((b & 0xff) << (i*8));
|
||
}
|
||
|
||
env->PSW_USB_V = (ovf << 31);
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
env->PSW_USB_AV = avf << 24;
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_sub_h(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t h, i;
|
||
int32_t extr_r1, extr_r2;
|
||
int32_t ovf = 0;
|
||
int32_t avf = 0;
|
||
int32_t ret = 0;
|
||
|
||
for (i = 0; i < 2; i++) {
|
||
extr_r1 = sextract32(r1, i * 16, 16);
|
||
extr_r2 = sextract32(r2, i * 16, 16);
|
||
h = extr_r1 - extr_r2;
|
||
ovf |= ((h > 0x7fff) || (h < -0x8000));
|
||
avf |= h ^ h * 2u;
|
||
ret |= (h & 0xffff) << (i * 16);
|
||
}
|
||
|
||
env->PSW_USB_V = (ovf << 31);
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
env->PSW_USB_AV = avf << 16;
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_eq_b(target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t ret;
|
||
int32_t i, msk;
|
||
|
||
ret = 0;
|
||
msk = 0xff;
|
||
for (i = 0; i < 4; i++) {
|
||
if ((r1 & msk) == (r2 & msk)) {
|
||
ret |= msk;
|
||
}
|
||
msk = msk << 8;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_eq_h(target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t ret = 0;
|
||
|
||
if ((r1 & 0xffff) == (r2 & 0xffff)) {
|
||
ret = 0xffff;
|
||
}
|
||
|
||
if ((r1 & 0xffff0000) == (r2 & 0xffff0000)) {
|
||
ret |= 0xffff0000;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_eqany_b(target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t i;
|
||
uint32_t ret = 0;
|
||
|
||
for (i = 0; i < 4; i++) {
|
||
ret |= (sextract32(r1, i * 8, 8) == sextract32(r2, i * 8, 8));
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_eqany_h(target_ulong r1, target_ulong r2)
|
||
{
|
||
uint32_t ret;
|
||
|
||
ret = (sextract32(r1, 0, 16) == sextract32(r2, 0, 16));
|
||
ret |= (sextract32(r1, 16, 16) == sextract32(r2, 16, 16));
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_lt_b(target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t i;
|
||
uint32_t ret = 0;
|
||
|
||
for (i = 0; i < 4; i++) {
|
||
if (sextract32(r1, i * 8, 8) < sextract32(r2, i * 8, 8)) {
|
||
ret |= (0xff << (i * 8));
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_lt_bu(target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t i;
|
||
uint32_t ret = 0;
|
||
|
||
for (i = 0; i < 4; i++) {
|
||
if (extract32(r1, i * 8, 8) < extract32(r2, i * 8, 8)) {
|
||
ret |= (0xff << (i * 8));
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_lt_h(target_ulong r1, target_ulong r2)
|
||
{
|
||
uint32_t ret = 0;
|
||
|
||
if (sextract32(r1, 0, 16) < sextract32(r2, 0, 16)) {
|
||
ret |= 0xffff;
|
||
}
|
||
|
||
if (sextract32(r1, 16, 16) < sextract32(r2, 16, 16)) {
|
||
ret |= 0xffff0000;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_lt_hu(target_ulong r1, target_ulong r2)
|
||
{
|
||
uint32_t ret = 0;
|
||
|
||
if (extract32(r1, 0, 16) < extract32(r2, 0, 16)) {
|
||
ret |= 0xffff;
|
||
}
|
||
|
||
if (extract32(r1, 16, 16) < extract32(r2, 16, 16)) {
|
||
ret |= 0xffff0000;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
#define EXTREMA_H_B(name, op) \
|
||
uint32_t helper_##name ##_b(target_ulong r1, target_ulong r2) \
|
||
{ \
|
||
int32_t i, extr_r1, extr_r2; \
|
||
uint32_t ret = 0; \
|
||
\
|
||
for (i = 0; i < 4; i++) { \
|
||
extr_r1 = sextract32(r1, i * 8, 8); \
|
||
extr_r2 = sextract32(r2, i * 8, 8); \
|
||
extr_r1 = (extr_r1 op extr_r2) ? extr_r1 : extr_r2; \
|
||
ret |= (extr_r1 & 0xff) << (i * 8); \
|
||
} \
|
||
return ret; \
|
||
} \
|
||
\
|
||
uint32_t helper_##name ##_bu(target_ulong r1, target_ulong r2)\
|
||
{ \
|
||
int32_t i; \
|
||
uint32_t extr_r1, extr_r2; \
|
||
uint32_t ret = 0; \
|
||
\
|
||
for (i = 0; i < 4; i++) { \
|
||
extr_r1 = extract32(r1, i * 8, 8); \
|
||
extr_r2 = extract32(r2, i * 8, 8); \
|
||
extr_r1 = (extr_r1 op extr_r2) ? extr_r1 : extr_r2; \
|
||
ret |= (extr_r1 & 0xff) << (i * 8); \
|
||
} \
|
||
return ret; \
|
||
} \
|
||
\
|
||
uint32_t helper_##name ##_h(target_ulong r1, target_ulong r2) \
|
||
{ \
|
||
int32_t extr_r1, extr_r2; \
|
||
uint32_t ret = 0; \
|
||
\
|
||
extr_r1 = sextract32(r1, 0, 16); \
|
||
extr_r2 = sextract32(r2, 0, 16); \
|
||
ret = (extr_r1 op extr_r2) ? extr_r1 : extr_r2; \
|
||
ret = ret & 0xffff; \
|
||
\
|
||
extr_r1 = sextract32(r1, 16, 16); \
|
||
extr_r2 = sextract32(r2, 16, 16); \
|
||
extr_r1 = (extr_r1 op extr_r2) ? extr_r1 : extr_r2; \
|
||
ret |= extr_r1 << 16; \
|
||
\
|
||
return ret; \
|
||
} \
|
||
\
|
||
uint32_t helper_##name ##_hu(target_ulong r1, target_ulong r2)\
|
||
{ \
|
||
uint32_t extr_r1, extr_r2; \
|
||
uint32_t ret = 0; \
|
||
\
|
||
extr_r1 = extract32(r1, 0, 16); \
|
||
extr_r2 = extract32(r2, 0, 16); \
|
||
ret = (extr_r1 op extr_r2) ? extr_r1 : extr_r2; \
|
||
ret = ret & 0xffff; \
|
||
\
|
||
extr_r1 = extract32(r1, 16, 16); \
|
||
extr_r2 = extract32(r2, 16, 16); \
|
||
extr_r1 = (extr_r1 op extr_r2) ? extr_r1 : extr_r2; \
|
||
ret |= extr_r1 << (16); \
|
||
\
|
||
return ret; \
|
||
} \
|
||
|
||
EXTREMA_H_B(max, >)
|
||
EXTREMA_H_B(min, <)
|
||
|
||
#undef EXTREMA_H_B
|
||
|
||
uint32_t helper_clo(target_ulong r1)
|
||
{
|
||
return clo32(r1);
|
||
}
|
||
|
||
uint32_t helper_clo_h(target_ulong r1)
|
||
{
|
||
uint32_t ret_hw0 = extract32(r1, 0, 16);
|
||
uint32_t ret_hw1 = extract32(r1, 16, 16);
|
||
|
||
ret_hw0 = clo32(ret_hw0 << 16);
|
||
ret_hw1 = clo32(ret_hw1 << 16);
|
||
|
||
if (ret_hw0 > 16) {
|
||
ret_hw0 = 16;
|
||
}
|
||
if (ret_hw1 > 16) {
|
||
ret_hw1 = 16;
|
||
}
|
||
|
||
return ret_hw0 | (ret_hw1 << 16);
|
||
}
|
||
|
||
uint32_t helper_clz(target_ulong r1)
|
||
{
|
||
return clz32(r1);
|
||
}
|
||
|
||
uint32_t helper_clz_h(target_ulong r1)
|
||
{
|
||
uint32_t ret_hw0 = extract32(r1, 0, 16);
|
||
uint32_t ret_hw1 = extract32(r1, 16, 16);
|
||
|
||
ret_hw0 = clz32(ret_hw0 << 16);
|
||
ret_hw1 = clz32(ret_hw1 << 16);
|
||
|
||
if (ret_hw0 > 16) {
|
||
ret_hw0 = 16;
|
||
}
|
||
if (ret_hw1 > 16) {
|
||
ret_hw1 = 16;
|
||
}
|
||
|
||
return ret_hw0 | (ret_hw1 << 16);
|
||
}
|
||
|
||
uint32_t helper_cls(target_ulong r1)
|
||
{
|
||
return clrsb32(r1);
|
||
}
|
||
|
||
uint32_t helper_cls_h(target_ulong r1)
|
||
{
|
||
uint32_t ret_hw0 = extract32(r1, 0, 16);
|
||
uint32_t ret_hw1 = extract32(r1, 16, 16);
|
||
|
||
ret_hw0 = clrsb32(ret_hw0 << 16);
|
||
ret_hw1 = clrsb32(ret_hw1 << 16);
|
||
|
||
if (ret_hw0 > 15) {
|
||
ret_hw0 = 15;
|
||
}
|
||
if (ret_hw1 > 15) {
|
||
ret_hw1 = 15;
|
||
}
|
||
|
||
return ret_hw0 | (ret_hw1 << 16);
|
||
}
|
||
|
||
uint32_t helper_sh(target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t shift_count = sextract32(r2, 0, 6);
|
||
|
||
if (shift_count == -32) {
|
||
return 0;
|
||
} else if (shift_count < 0) {
|
||
return r1 >> -shift_count;
|
||
} else {
|
||
return r1 << shift_count;
|
||
}
|
||
}
|
||
|
||
uint32_t helper_sh_h(target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t ret_hw0, ret_hw1;
|
||
int32_t shift_count;
|
||
|
||
shift_count = sextract32(r2, 0, 5);
|
||
|
||
if (shift_count == -16) {
|
||
return 0;
|
||
} else if (shift_count < 0) {
|
||
ret_hw0 = extract32(r1, 0, 16) >> -shift_count;
|
||
ret_hw1 = extract32(r1, 16, 16) >> -shift_count;
|
||
return (ret_hw0 & 0xffff) | (ret_hw1 << 16);
|
||
} else {
|
||
ret_hw0 = extract32(r1, 0, 16) << shift_count;
|
||
ret_hw1 = extract32(r1, 16, 16) << shift_count;
|
||
return (ret_hw0 & 0xffff) | (ret_hw1 << 16);
|
||
}
|
||
}
|
||
|
||
uint32_t helper_sha(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t shift_count;
|
||
int64_t result, t1;
|
||
uint32_t ret;
|
||
|
||
shift_count = sextract32(r2, 0, 6);
|
||
t1 = sextract32(r1, 0, 32);
|
||
|
||
if (shift_count == 0) {
|
||
env->PSW_USB_C = env->PSW_USB_V = 0;
|
||
ret = r1;
|
||
} else if (shift_count == -32) {
|
||
env->PSW_USB_C = r1;
|
||
env->PSW_USB_V = 0;
|
||
ret = t1 >> 31;
|
||
} else if (shift_count > 0) {
|
||
result = t1 << shift_count;
|
||
/* calc carry */
|
||
env->PSW_USB_C = ((result & 0xffffffff00000000ULL) != 0);
|
||
/* calc v */
|
||
env->PSW_USB_V = (((result > 0x7fffffffLL) ||
|
||
(result < -0x80000000LL)) << 31);
|
||
/* calc sv */
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
ret = (uint32_t)result;
|
||
} else {
|
||
env->PSW_USB_V = 0;
|
||
env->PSW_USB_C = (r1 & ((1 << -shift_count) - 1));
|
||
ret = t1 >> -shift_count;
|
||
}
|
||
|
||
env->PSW_USB_AV = ret ^ ret * 2u;
|
||
env->PSW_USB_SAV |= env->PSW_USB_AV;
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_sha_h(target_ulong r1, target_ulong r2)
|
||
{
|
||
int32_t shift_count;
|
||
int32_t ret_hw0, ret_hw1;
|
||
|
||
shift_count = sextract32(r2, 0, 5);
|
||
|
||
if (shift_count == 0) {
|
||
return r1;
|
||
} else if (shift_count < 0) {
|
||
ret_hw0 = sextract32(r1, 0, 16) >> -shift_count;
|
||
ret_hw1 = sextract32(r1, 16, 16) >> -shift_count;
|
||
return (ret_hw0 & 0xffff) | (ret_hw1 << 16);
|
||
} else {
|
||
ret_hw0 = sextract32(r1, 0, 16) << shift_count;
|
||
ret_hw1 = sextract32(r1, 16, 16) << shift_count;
|
||
return (ret_hw0 & 0xffff) | (ret_hw1 << 16);
|
||
}
|
||
}
|
||
|
||
uint32_t helper_bmerge(target_ulong r1, target_ulong r2)
|
||
{
|
||
uint32_t i, ret;
|
||
|
||
ret = 0;
|
||
for (i = 0; i < 16; i++) {
|
||
ret |= (r1 & 1) << (2 * i + 1);
|
||
ret |= (r2 & 1) << (2 * i);
|
||
r1 = r1 >> 1;
|
||
r2 = r2 >> 1;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
uint64_t helper_bsplit(uint32_t r1)
|
||
{
|
||
int32_t i;
|
||
uint64_t ret;
|
||
|
||
ret = 0;
|
||
for (i = 0; i < 32; i = i + 2) {
|
||
/* even */
|
||
ret |= (r1 & 1) << (i/2);
|
||
r1 = r1 >> 1;
|
||
/* odd */
|
||
ret |= (uint64_t)(r1 & 1) << (i/2 + 32);
|
||
r1 = r1 >> 1;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
uint32_t helper_parity(target_ulong r1)
|
||
{
|
||
uint32_t ret;
|
||
uint32_t nOnes, i;
|
||
|
||
ret = 0;
|
||
nOnes = 0;
|
||
for (i = 0; i < 8; i++) {
|
||
ret ^= (r1 & 1);
|
||
r1 = r1 >> 1;
|
||
}
|
||
/* second byte */
|
||
nOnes = 0;
|
||
for (i = 0; i < 8; i++) {
|
||
nOnes ^= (r1 & 1);
|
||
r1 = r1 >> 1;
|
||
}
|
||
ret |= nOnes << 8;
|
||
/* third byte */
|
||
nOnes = 0;
|
||
for (i = 0; i < 8; i++) {
|
||
nOnes ^= (r1 & 1);
|
||
r1 = r1 >> 1;
|
||
}
|
||
ret |= nOnes << 16;
|
||
/* fourth byte */
|
||
nOnes = 0;
|
||
for (i = 0; i < 8; i++) {
|
||
nOnes ^= (r1 & 1);
|
||
r1 = r1 >> 1;
|
||
}
|
||
ret |= nOnes << 24;
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint64_t helper_unpack(target_ulong arg1)
|
||
{
|
||
int32_t fp_exp = extract32(arg1, 23, 8);
|
||
int32_t fp_frac = extract32(arg1, 0, 23);
|
||
uint64_t ret;
|
||
int32_t int_exp, int_mant;
|
||
|
||
if (fp_exp == 255) {
|
||
int_exp = 255;
|
||
int_mant = (fp_frac << 7);
|
||
} else if ((fp_exp == 0) && (fp_frac == 0)) {
|
||
int_exp = -127;
|
||
int_mant = 0;
|
||
} else if ((fp_exp == 0) && (fp_frac != 0)) {
|
||
int_exp = -126;
|
||
int_mant = (fp_frac << 7);
|
||
} else {
|
||
int_exp = fp_exp - 127;
|
||
int_mant = (fp_frac << 7);
|
||
int_mant |= (1 << 30);
|
||
}
|
||
ret = int_exp;
|
||
ret = ret << 32;
|
||
ret |= int_mant;
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint64_t helper_dvinit_b_13(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
|
||
{
|
||
uint64_t ret;
|
||
int32_t abs_sig_dividend, abs_base_dividend, abs_divisor;
|
||
int32_t quotient_sign;
|
||
|
||
ret = sextract32(r1, 0, 32);
|
||
ret = ret << 24;
|
||
quotient_sign = 0;
|
||
if (!((r1 & 0x80000000) == (r2 & 0x80000000))) {
|
||
ret |= 0xffffff;
|
||
quotient_sign = 1;
|
||
}
|
||
|
||
abs_sig_dividend = abs(r1) >> 7;
|
||
abs_base_dividend = abs(r1) & 0x7f;
|
||
abs_divisor = abs(r1);
|
||
/* calc overflow */
|
||
env->PSW_USB_V = 0;
|
||
if ((quotient_sign) && (abs_divisor)) {
|
||
env->PSW_USB_V = (((abs_sig_dividend == abs_divisor) &&
|
||
(abs_base_dividend >= abs_divisor)) ||
|
||
(abs_sig_dividend > abs_divisor));
|
||
} else {
|
||
env->PSW_USB_V = (abs_sig_dividend >= abs_divisor);
|
||
}
|
||
env->PSW_USB_V = env->PSW_USB_V << 31;
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
env->PSW_USB_AV = 0;
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint64_t helper_dvinit_b_131(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
|
||
{
|
||
uint64_t ret = sextract32(r1, 0, 32);
|
||
|
||
ret = ret << 24;
|
||
if (!((r1 & 0x80000000) == (r2 & 0x80000000))) {
|
||
ret |= 0xffffff;
|
||
}
|
||
/* calc overflow */
|
||
env->PSW_USB_V = ((r2 == 0) || ((r2 == 0xffffffff) && (r1 == 0xffffff80)));
|
||
env->PSW_USB_V = env->PSW_USB_V << 31;
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
env->PSW_USB_AV = 0;
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint64_t helper_dvinit_h_13(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
|
||
{
|
||
uint64_t ret;
|
||
int32_t abs_sig_dividend, abs_base_dividend, abs_divisor;
|
||
int32_t quotient_sign;
|
||
|
||
ret = sextract32(r1, 0, 32);
|
||
ret = ret << 16;
|
||
quotient_sign = 0;
|
||
if (!((r1 & 0x80000000) == (r2 & 0x80000000))) {
|
||
ret |= 0xffff;
|
||
quotient_sign = 1;
|
||
}
|
||
|
||
abs_sig_dividend = abs(r1) >> 7;
|
||
abs_base_dividend = abs(r1) & 0x7f;
|
||
abs_divisor = abs(r1);
|
||
/* calc overflow */
|
||
env->PSW_USB_V = 0;
|
||
if ((quotient_sign) && (abs_divisor)) {
|
||
env->PSW_USB_V = (((abs_sig_dividend == abs_divisor) &&
|
||
(abs_base_dividend >= abs_divisor)) ||
|
||
(abs_sig_dividend > abs_divisor));
|
||
} else {
|
||
env->PSW_USB_V = (abs_sig_dividend >= abs_divisor);
|
||
}
|
||
env->PSW_USB_V = env->PSW_USB_V << 31;
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
env->PSW_USB_AV = 0;
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint64_t helper_dvinit_h_131(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
|
||
{
|
||
uint64_t ret = sextract32(r1, 0, 32);
|
||
|
||
ret = ret << 16;
|
||
if (!((r1 & 0x80000000) == (r2 & 0x80000000))) {
|
||
ret |= 0xffff;
|
||
}
|
||
/* calc overflow */
|
||
env->PSW_USB_V = ((r2 == 0) || ((r2 == 0xffffffff) && (r1 == 0xffff8000)));
|
||
env->PSW_USB_V = env->PSW_USB_V << 31;
|
||
env->PSW_USB_SV |= env->PSW_USB_V;
|
||
env->PSW_USB_AV = 0;
|
||
|
||
return ret;
|
||
}
|
||
|
||
uint64_t helper_mul_h(uint32_t arg00, uint32_t arg01,
|
||
uint32_t arg10, uint32_t arg11, uint32_t n)
|
||
{
|
||
uint64_t ret;
|
||
uint32_t result0, result1;
|
||
|
||
int32_t sc1 = ((arg00 & 0xffff) == 0x8000) &&
|
||
((arg10 & 0xffff) == 0x8000) && (n == 1);
|
||
int32_t sc0 = ((arg01 & 0xffff) == 0x8000) &&
|
||
((arg11 & 0xffff) == 0x8000) && (n == 1);
|
||
if (sc1) {
|
||
result1 = 0x7fffffff;
|
||
} else {
|
||
result1 = (((uint32_t)(arg00 * arg10)) << n);
|
||
}
|
||
if (sc0) {
|
||
result0 = 0x7fffffff;
|
||
} else {
|
||
result0 = (((uint32_t)(arg01 * arg11)) << n);
|
||
}
|
||
ret = (((uint64_t)result1 << 32)) | result0;
|
||
return ret;
|
||
}
|
||
|
||
uint64_t helper_mulm_h(uint32_t arg00, uint32_t arg01,
|
||
uint32_t arg10, uint32_t arg11, uint32_t n)
|
||
{
|
||
uint64_t ret;
|
||
int64_t result0, result1;
|
||
|
||
int32_t sc1 = ((arg00 & 0xffff) == 0x8000) &&
|
||
((arg10 & 0xffff) == 0x8000) && (n == 1);
|
||
int32_t sc0 = ((arg01 & 0xffff) == 0x8000) &&
|
||
((arg11 & 0xffff) == 0x8000) && (n == 1);
|
||
|
||
if (sc1) {
|
||
result1 = 0x7fffffff;
|
||
} else {
|
||
result1 = (((int32_t)arg00 * (int32_t)arg10) << n);
|
||
}
|
||
if (sc0) {
|
||
result0 = 0x7fffffff;
|
||
} else {
|
||
result0 = (((int32_t)arg01 * (int32_t)arg11) << n);
|
||
}
|
||
ret = (result1 + result0);
|
||
ret = ret << 16;
|
||
return ret;
|
||
}
|
||
uint32_t helper_mulr_h(uint32_t arg00, uint32_t arg01,
|
||
uint32_t arg10, uint32_t arg11, uint32_t n)
|
||
{
|
||
uint32_t result0, result1;
|
||
|
||
int32_t sc1 = ((arg00 & 0xffff) == 0x8000) &&
|
||
((arg10 & 0xffff) == 0x8000) && (n == 1);
|
||
int32_t sc0 = ((arg01 & 0xffff) == 0x8000) &&
|
||
((arg11 & 0xffff) == 0x8000) && (n == 1);
|
||
|
||
if (sc1) {
|
||
result1 = 0x7fffffff;
|
||
} else {
|
||
result1 = ((arg00 * arg10) << n) + 0x8000;
|
||
}
|
||
if (sc0) {
|
||
result0 = 0x7fffffff;
|
||
} else {
|
||
result0 = ((arg01 * arg11) << n) + 0x8000;
|
||
}
|
||
return (result1 & 0xffff0000) | (result0 >> 16);
|
||
}
|
||
|
||
/* context save area (CSA) related helpers */
|
||
|
||
static int cdc_increment(target_ulong *psw)
|
||
{
|
||
if ((*psw & MASK_PSW_CDC) == 0x7f) {
|
||
return 0;
|
||
}
|
||
|
||
(*psw)++;
|
||
/* check for overflow */
|
||
int lo = clo32((*psw & MASK_PSW_CDC) << (32 - 7));
|
||
int mask = (1u << (7 - lo)) - 1;
|
||
int count = *psw & mask;
|
||
if (count == 0) {
|
||
(*psw)--;
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static int cdc_decrement(target_ulong *psw)
|
||
{
|
||
if ((*psw & MASK_PSW_CDC) == 0x7f) {
|
||
return 0;
|
||
}
|
||
/* check for underflow */
|
||
int lo = clo32((*psw & MASK_PSW_CDC) << (32 - 7));
|
||
int mask = (1u << (7 - lo)) - 1;
|
||
int count = *psw & mask;
|
||
if (count == 0) {
|
||
return 1;
|
||
}
|
||
(*psw)--;
|
||
return 0;
|
||
}
|
||
|
||
static bool cdc_zero(target_ulong *psw)
|
||
{
|
||
int cdc = *psw & MASK_PSW_CDC;
|
||
/* Returns TRUE if PSW.CDC.COUNT == 0 or if PSW.CDC ==
|
||
7'b1111111, otherwise returns FALSE. */
|
||
if (cdc == 0x7f) {
|
||
return true;
|
||
}
|
||
/* find CDC.COUNT */
|
||
int lo = clo32((*psw & MASK_PSW_CDC) << (32 - 7));
|
||
int mask = (1u << (7 - lo)) - 1;
|
||
int count = *psw & mask;
|
||
return count == 0;
|
||
}
|
||
|
||
static void save_context_upper(CPUTriCoreState *env, int ea)
|
||
{
|
||
cpu_stl_data(env, ea, env->PCXI);
|
||
cpu_stl_data(env, ea+4, env->PSW);
|
||
cpu_stl_data(env, ea+8, env->gpr_a[10]);
|
||
cpu_stl_data(env, ea+12, env->gpr_a[11]);
|
||
cpu_stl_data(env, ea+16, env->gpr_d[8]);
|
||
cpu_stl_data(env, ea+20, env->gpr_d[9]);
|
||
cpu_stl_data(env, ea+24, env->gpr_d[10]);
|
||
cpu_stl_data(env, ea+28, env->gpr_d[11]);
|
||
cpu_stl_data(env, ea+32, env->gpr_a[12]);
|
||
cpu_stl_data(env, ea+36, env->gpr_a[13]);
|
||
cpu_stl_data(env, ea+40, env->gpr_a[14]);
|
||
cpu_stl_data(env, ea+44, env->gpr_a[15]);
|
||
cpu_stl_data(env, ea+48, env->gpr_d[12]);
|
||
cpu_stl_data(env, ea+52, env->gpr_d[13]);
|
||
cpu_stl_data(env, ea+56, env->gpr_d[14]);
|
||
cpu_stl_data(env, ea+60, env->gpr_d[15]);
|
||
}
|
||
|
||
static void save_context_lower(CPUTriCoreState *env, int ea)
|
||
{
|
||
cpu_stl_data(env, ea, env->PCXI);
|
||
cpu_stl_data(env, ea+4, env->gpr_a[11]);
|
||
cpu_stl_data(env, ea+8, env->gpr_a[2]);
|
||
cpu_stl_data(env, ea+12, env->gpr_a[3]);
|
||
cpu_stl_data(env, ea+16, env->gpr_d[0]);
|
||
cpu_stl_data(env, ea+20, env->gpr_d[1]);
|
||
cpu_stl_data(env, ea+24, env->gpr_d[2]);
|
||
cpu_stl_data(env, ea+28, env->gpr_d[3]);
|
||
cpu_stl_data(env, ea+32, env->gpr_a[4]);
|
||
cpu_stl_data(env, ea+36, env->gpr_a[5]);
|
||
cpu_stl_data(env, ea+40, env->gpr_a[6]);
|
||
cpu_stl_data(env, ea+44, env->gpr_a[7]);
|
||
cpu_stl_data(env, ea+48, env->gpr_d[4]);
|
||
cpu_stl_data(env, ea+52, env->gpr_d[5]);
|
||
cpu_stl_data(env, ea+56, env->gpr_d[6]);
|
||
cpu_stl_data(env, ea+60, env->gpr_d[7]);
|
||
}
|
||
|
||
static void restore_context_upper(CPUTriCoreState *env, int ea,
|
||
target_ulong *new_PCXI, target_ulong *new_PSW)
|
||
{
|
||
*new_PCXI = cpu_ldl_data(env, ea);
|
||
*new_PSW = cpu_ldl_data(env, ea+4);
|
||
env->gpr_a[10] = cpu_ldl_data(env, ea+8);
|
||
env->gpr_a[11] = cpu_ldl_data(env, ea+12);
|
||
env->gpr_d[8] = cpu_ldl_data(env, ea+16);
|
||
env->gpr_d[9] = cpu_ldl_data(env, ea+20);
|
||
env->gpr_d[10] = cpu_ldl_data(env, ea+24);
|
||
env->gpr_d[11] = cpu_ldl_data(env, ea+28);
|
||
env->gpr_a[12] = cpu_ldl_data(env, ea+32);
|
||
env->gpr_a[13] = cpu_ldl_data(env, ea+36);
|
||
env->gpr_a[14] = cpu_ldl_data(env, ea+40);
|
||
env->gpr_a[15] = cpu_ldl_data(env, ea+44);
|
||
env->gpr_d[12] = cpu_ldl_data(env, ea+48);
|
||
env->gpr_d[13] = cpu_ldl_data(env, ea+52);
|
||
env->gpr_d[14] = cpu_ldl_data(env, ea+56);
|
||
env->gpr_d[15] = cpu_ldl_data(env, ea+60);
|
||
}
|
||
|
||
static void restore_context_lower(CPUTriCoreState *env, int ea,
|
||
target_ulong *ra, target_ulong *pcxi)
|
||
{
|
||
*pcxi = cpu_ldl_data(env, ea);
|
||
*ra = cpu_ldl_data(env, ea+4);
|
||
env->gpr_a[2] = cpu_ldl_data(env, ea+8);
|
||
env->gpr_a[3] = cpu_ldl_data(env, ea+12);
|
||
env->gpr_d[0] = cpu_ldl_data(env, ea+16);
|
||
env->gpr_d[1] = cpu_ldl_data(env, ea+20);
|
||
env->gpr_d[2] = cpu_ldl_data(env, ea+24);
|
||
env->gpr_d[3] = cpu_ldl_data(env, ea+28);
|
||
env->gpr_a[4] = cpu_ldl_data(env, ea+32);
|
||
env->gpr_a[5] = cpu_ldl_data(env, ea+36);
|
||
env->gpr_a[6] = cpu_ldl_data(env, ea+40);
|
||
env->gpr_a[7] = cpu_ldl_data(env, ea+44);
|
||
env->gpr_d[4] = cpu_ldl_data(env, ea+48);
|
||
env->gpr_d[5] = cpu_ldl_data(env, ea+52);
|
||
env->gpr_d[6] = cpu_ldl_data(env, ea+56);
|
||
env->gpr_d[7] = cpu_ldl_data(env, ea+60);
|
||
}
|
||
|
||
void helper_call(CPUTriCoreState *env, uint32_t next_pc)
|
||
{
|
||
target_ulong tmp_FCX;
|
||
target_ulong ea;
|
||
target_ulong new_FCX;
|
||
target_ulong psw;
|
||
|
||
psw = psw_read(env);
|
||
/* if (FCX == 0) trap(FCU); */
|
||
if (env->FCX == 0) {
|
||
/* FCU trap */
|
||
}
|
||
/* if (PSW.CDE) then if (cdc_increment()) then trap(CDO); */
|
||
if (psw & MASK_PSW_CDE) {
|
||
if (cdc_increment(&psw)) {
|
||
/* CDO trap */
|
||
}
|
||
}
|
||
/* PSW.CDE = 1;*/
|
||
psw |= MASK_PSW_CDE;
|
||
/* tmp_FCX = FCX; */
|
||
tmp_FCX = env->FCX;
|
||
/* EA = {FCX.FCXS, 6'b0, FCX.FCXO, 6'b0}; */
|
||
ea = ((env->FCX & MASK_FCX_FCXS) << 12) +
|
||
((env->FCX & MASK_FCX_FCXO) << 6);
|
||
/* new_FCX = M(EA, word); */
|
||
new_FCX = cpu_ldl_data(env, ea);
|
||
/* M(EA, 16 * word) = {PCXI, PSW, A[10], A[11], D[8], D[9], D[10], D[11],
|
||
A[12], A[13], A[14], A[15], D[12], D[13], D[14],
|
||
D[15]}; */
|
||
save_context_upper(env, ea);
|
||
|
||
/* PCXI.PCPN = ICR.CCPN; */
|
||
env->PCXI = (env->PCXI & 0xffffff) +
|
||
((env->ICR & MASK_ICR_CCPN) << 24);
|
||
/* PCXI.PIE = ICR.IE; */
|
||
env->PCXI = ((env->PCXI & ~MASK_PCXI_PIE) +
|
||
((env->ICR & MASK_ICR_IE) << 15));
|
||
/* PCXI.UL = 1; */
|
||
env->PCXI |= MASK_PCXI_UL;
|
||
|
||
/* PCXI[19: 0] = FCX[19: 0]; */
|
||
env->PCXI = (env->PCXI & 0xfff00000) + (env->FCX & 0xfffff);
|
||
/* FCX[19: 0] = new_FCX[19: 0]; */
|
||
env->FCX = (env->FCX & 0xfff00000) + (new_FCX & 0xfffff);
|
||
/* A[11] = next_pc[31: 0]; */
|
||
env->gpr_a[11] = next_pc;
|
||
|
||
/* if (tmp_FCX == LCX) trap(FCD);*/
|
||
if (tmp_FCX == env->LCX) {
|
||
/* FCD trap */
|
||
}
|
||
psw_write(env, psw);
|
||
}
|
||
|
||
void helper_ret(CPUTriCoreState *env)
|
||
{
|
||
target_ulong ea;
|
||
target_ulong new_PCXI;
|
||
target_ulong new_PSW, psw;
|
||
|
||
psw = psw_read(env);
|
||
/* if (PSW.CDE) then if (cdc_decrement()) then trap(CDU);*/
|
||
if (env->PSW & MASK_PSW_CDE) {
|
||
if (cdc_decrement(&(env->PSW))) {
|
||
/* CDU trap */
|
||
}
|
||
}
|
||
/* if (PCXI[19: 0] == 0) then trap(CSU); */
|
||
if ((env->PCXI & 0xfffff) == 0) {
|
||
/* CSU trap */
|
||
}
|
||
/* if (PCXI.UL == 0) then trap(CTYP); */
|
||
if ((env->PCXI & MASK_PCXI_UL) == 0) {
|
||
/* CTYP trap */
|
||
}
|
||
/* PC = {A11 [31: 1], 1’b0}; */
|
||
env->PC = env->gpr_a[11] & 0xfffffffe;
|
||
|
||
/* EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0}; */
|
||
ea = ((env->PCXI & MASK_PCXI_PCXS) << 12) +
|
||
((env->PCXI & MASK_PCXI_PCXO) << 6);
|
||
/* {new_PCXI, new_PSW, A[10], A[11], D[8], D[9], D[10], D[11], A[12],
|
||
A[13], A[14], A[15], D[12], D[13], D[14], D[15]} = M(EA, 16 * word); */
|
||
restore_context_upper(env, ea, &new_PCXI, &new_PSW);
|
||
/* M(EA, word) = FCX; */
|
||
cpu_stl_data(env, ea, env->FCX);
|
||
/* FCX[19: 0] = PCXI[19: 0]; */
|
||
env->FCX = (env->FCX & 0xfff00000) + (env->PCXI & 0x000fffff);
|
||
/* PCXI = new_PCXI; */
|
||
env->PCXI = new_PCXI;
|
||
|
||
if (tricore_feature(env, TRICORE_FEATURE_13)) {
|
||
/* PSW = new_PSW */
|
||
psw_write(env, new_PSW);
|
||
} else {
|
||
/* PSW = {new_PSW[31:26], PSW[25:24], new_PSW[23:0]}; */
|
||
psw_write(env, (new_PSW & ~(0x3000000)) + (psw & (0x3000000)));
|
||
}
|
||
}
|
||
|
||
void helper_bisr(CPUTriCoreState *env, uint32_t const9)
|
||
{
|
||
target_ulong tmp_FCX;
|
||
target_ulong ea;
|
||
target_ulong new_FCX;
|
||
|
||
if (env->FCX == 0) {
|
||
/* FCU trap */
|
||
}
|
||
|
||
tmp_FCX = env->FCX;
|
||
ea = ((env->FCX & 0xf0000) << 12) + ((env->FCX & 0xffff) << 6);
|
||
|
||
/* new_FCX = M(EA, word); */
|
||
new_FCX = cpu_ldl_data(env, ea);
|
||
/* M(EA, 16 * word) = {PCXI, A[11], A[2], A[3], D[0], D[1], D[2], D[3], A[4]
|
||
, A[5], A[6], A[7], D[4], D[5], D[6], D[7]}; */
|
||
save_context_lower(env, ea);
|
||
|
||
|
||
/* PCXI.PCPN = ICR.CCPN */
|
||
env->PCXI = (env->PCXI & 0xffffff) +
|
||
((env->ICR & MASK_ICR_CCPN) << 24);
|
||
/* PCXI.PIE = ICR.IE */
|
||
env->PCXI = ((env->PCXI & ~MASK_PCXI_PIE) +
|
||
((env->ICR & MASK_ICR_IE) << 15));
|
||
/* PCXI.UL = 0 */
|
||
env->PCXI &= ~(MASK_PCXI_UL);
|
||
/* PCXI[19: 0] = FCX[19: 0] */
|
||
env->PCXI = (env->PCXI & 0xfff00000) + (env->FCX & 0xfffff);
|
||
/* FXC[19: 0] = new_FCX[19: 0] */
|
||
env->FCX = (env->FCX & 0xfff00000) + (new_FCX & 0xfffff);
|
||
/* ICR.IE = 1 */
|
||
env->ICR |= MASK_ICR_IE;
|
||
|
||
env->ICR |= const9; /* ICR.CCPN = const9[7: 0];*/
|
||
|
||
if (tmp_FCX == env->LCX) {
|
||
/* FCD trap */
|
||
}
|
||
}
|
||
|
||
void helper_rfe(CPUTriCoreState *env)
|
||
{
|
||
target_ulong ea;
|
||
target_ulong new_PCXI;
|
||
target_ulong new_PSW;
|
||
/* if (PCXI[19: 0] == 0) then trap(CSU); */
|
||
if ((env->PCXI & 0xfffff) == 0) {
|
||
/* raise csu trap */
|
||
}
|
||
/* if (PCXI.UL == 0) then trap(CTYP); */
|
||
if ((env->PCXI & MASK_PCXI_UL) == 0) {
|
||
/* raise CTYP trap */
|
||
}
|
||
/* if (!cdc_zero() AND PSW.CDE) then trap(NEST); */
|
||
if (!cdc_zero(&(env->PSW)) && (env->PSW & MASK_PSW_CDE)) {
|
||
/* raise MNG trap */
|
||
}
|
||
/* ICR.IE = PCXI.PIE; */
|
||
env->ICR = (env->ICR & ~MASK_ICR_IE) + ((env->PCXI & MASK_PCXI_PIE) >> 15);
|
||
/* ICR.CCPN = PCXI.PCPN; */
|
||
env->ICR = (env->ICR & ~MASK_ICR_CCPN) +
|
||
((env->PCXI & MASK_PCXI_PCPN) >> 24);
|
||
/*EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0};*/
|
||
ea = ((env->PCXI & MASK_PCXI_PCXS) << 12) +
|
||
((env->PCXI & MASK_PCXI_PCXO) << 6);
|
||
/*{new_PCXI, PSW, A[10], A[11], D[8], D[9], D[10], D[11], A[12],
|
||
A[13], A[14], A[15], D[12], D[13], D[14], D[15]} = M(EA, 16 * word); */
|
||
restore_context_upper(env, ea, &new_PCXI, &new_PSW);
|
||
/* M(EA, word) = FCX;*/
|
||
cpu_stl_data(env, ea, env->FCX);
|
||
/* FCX[19: 0] = PCXI[19: 0]; */
|
||
env->FCX = (env->FCX & 0xfff00000) + (env->PCXI & 0x000fffff);
|
||
/* PCXI = new_PCXI; */
|
||
env->PCXI = new_PCXI;
|
||
/* write psw */
|
||
psw_write(env, new_PSW);
|
||
}
|
||
|
||
void helper_ldlcx(CPUTriCoreState *env, uint32_t ea)
|
||
{
|
||
uint32_t dummy;
|
||
/* insn doesn't load PCXI and RA */
|
||
restore_context_lower(env, ea, &dummy, &dummy);
|
||
}
|
||
|
||
void helper_lducx(CPUTriCoreState *env, uint32_t ea)
|
||
{
|
||
uint32_t dummy;
|
||
/* insn doesn't load PCXI and PSW */
|
||
restore_context_upper(env, ea, &dummy, &dummy);
|
||
}
|
||
|
||
void helper_stlcx(CPUTriCoreState *env, uint32_t ea)
|
||
{
|
||
save_context_lower(env, ea);
|
||
}
|
||
|
||
void helper_stucx(CPUTriCoreState *env, uint32_t ea)
|
||
{
|
||
save_context_upper(env, ea);
|
||
}
|
||
|
||
void helper_psw_write(CPUTriCoreState *env, uint32_t arg)
|
||
{
|
||
psw_write(env, arg);
|
||
}
|
||
|
||
uint32_t helper_psw_read(CPUTriCoreState *env)
|
||
{
|
||
return psw_read(env);
|
||
}
|
||
|
||
|
||
static inline void QEMU_NORETURN do_raise_exception_err(CPUTriCoreState *env,
|
||
uint32_t exception,
|
||
int error_code,
|
||
uintptr_t pc)
|
||
{
|
||
CPUState *cs = CPU(tricore_env_get_cpu(env));
|
||
cs->exception_index = exception;
|
||
env->error_code = error_code;
|
||
|
||
if (pc) {
|
||
/* now we have a real cpu fault */
|
||
cpu_restore_state(cs, pc);
|
||
}
|
||
|
||
cpu_loop_exit(cs);
|
||
}
|
||
|
||
void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
|
||
uintptr_t retaddr)
|
||
{
|
||
int ret;
|
||
ret = cpu_tricore_handle_mmu_fault(cs, addr, is_write, mmu_idx);
|
||
if (ret) {
|
||
TriCoreCPU *cpu = TRICORE_CPU(cs);
|
||
CPUTriCoreState *env = &cpu->env;
|
||
do_raise_exception_err(env, cs->exception_index,
|
||
env->error_code, retaddr);
|
||
}
|
||
}
|