target-hppa: Implement floating-point insns

Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2016-12-15 15:04:19 -08:00
parent 98a9cb792c
commit ebe9383cae
3 changed files with 1177 additions and 0 deletions

View File

@ -9,3 +9,58 @@ DEF_HELPER_FLAGS_1(probe_r, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(probe_w, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(loaded_fr0, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_FLAGS_2(fsqrt_s, TCG_CALL_NO_RWG, f32, env, f32)
DEF_HELPER_FLAGS_2(frnd_s, TCG_CALL_NO_RWG, f32, env, f32)
DEF_HELPER_FLAGS_3(fadd_s, TCG_CALL_NO_RWG, f32, env, f32, f32)
DEF_HELPER_FLAGS_3(fsub_s, TCG_CALL_NO_RWG, f32, env, f32, f32)
DEF_HELPER_FLAGS_3(fmpy_s, TCG_CALL_NO_RWG, f32, env, f32, f32)
DEF_HELPER_FLAGS_3(fdiv_s, TCG_CALL_NO_RWG, f32, env, f32, f32)
DEF_HELPER_FLAGS_2(fsqrt_d, TCG_CALL_NO_RWG, f64, env, f64)
DEF_HELPER_FLAGS_2(frnd_d, TCG_CALL_NO_RWG, f64, env, f64)
DEF_HELPER_FLAGS_3(fadd_d, TCG_CALL_NO_RWG, f64, env, f64, f64)
DEF_HELPER_FLAGS_3(fsub_d, TCG_CALL_NO_RWG, f64, env, f64, f64)
DEF_HELPER_FLAGS_3(fmpy_d, TCG_CALL_NO_RWG, f64, env, f64, f64)
DEF_HELPER_FLAGS_3(fdiv_d, TCG_CALL_NO_RWG, f64, env, f64, f64)
DEF_HELPER_FLAGS_2(fcnv_s_d, TCG_CALL_NO_RWG, f64, env, f32)
DEF_HELPER_FLAGS_2(fcnv_d_s, TCG_CALL_NO_RWG, f32, env, f64)
DEF_HELPER_FLAGS_2(fcnv_w_s, TCG_CALL_NO_RWG, f32, env, s32)
DEF_HELPER_FLAGS_2(fcnv_dw_s, TCG_CALL_NO_RWG, f32, env, s64)
DEF_HELPER_FLAGS_2(fcnv_w_d, TCG_CALL_NO_RWG, f64, env, s32)
DEF_HELPER_FLAGS_2(fcnv_dw_d, TCG_CALL_NO_RWG, f64, env, s64)
DEF_HELPER_FLAGS_2(fcnv_s_w, TCG_CALL_NO_RWG, s32, env, f32)
DEF_HELPER_FLAGS_2(fcnv_d_w, TCG_CALL_NO_RWG, s32, env, f64)
DEF_HELPER_FLAGS_2(fcnv_s_dw, TCG_CALL_NO_RWG, s64, env, f32)
DEF_HELPER_FLAGS_2(fcnv_d_dw, TCG_CALL_NO_RWG, s64, env, f64)
DEF_HELPER_FLAGS_2(fcnv_t_s_w, TCG_CALL_NO_RWG, s32, env, f32)
DEF_HELPER_FLAGS_2(fcnv_t_d_w, TCG_CALL_NO_RWG, s32, env, f64)
DEF_HELPER_FLAGS_2(fcnv_t_s_dw, TCG_CALL_NO_RWG, s64, env, f32)
DEF_HELPER_FLAGS_2(fcnv_t_d_dw, TCG_CALL_NO_RWG, s64, env, f64)
DEF_HELPER_FLAGS_2(fcnv_uw_s, TCG_CALL_NO_RWG, f32, env, i32)
DEF_HELPER_FLAGS_2(fcnv_udw_s, TCG_CALL_NO_RWG, f32, env, i64)
DEF_HELPER_FLAGS_2(fcnv_uw_d, TCG_CALL_NO_RWG, f64, env, i32)
DEF_HELPER_FLAGS_2(fcnv_udw_d, TCG_CALL_NO_RWG, f64, env, i64)
DEF_HELPER_FLAGS_2(fcnv_s_uw, TCG_CALL_NO_RWG, i32, env, f32)
DEF_HELPER_FLAGS_2(fcnv_d_uw, TCG_CALL_NO_RWG, i32, env, f64)
DEF_HELPER_FLAGS_2(fcnv_s_udw, TCG_CALL_NO_RWG, i64, env, f32)
DEF_HELPER_FLAGS_2(fcnv_d_udw, TCG_CALL_NO_RWG, i64, env, f64)
DEF_HELPER_FLAGS_2(fcnv_t_s_uw, TCG_CALL_NO_RWG, i32, env, f32)
DEF_HELPER_FLAGS_2(fcnv_t_d_uw, TCG_CALL_NO_RWG, i32, env, f64)
DEF_HELPER_FLAGS_2(fcnv_t_s_udw, TCG_CALL_NO_RWG, i64, env, f32)
DEF_HELPER_FLAGS_2(fcnv_t_d_udw, TCG_CALL_NO_RWG, i64, env, f64)
DEF_HELPER_FLAGS_5(fcmp_s, TCG_CALL_NO_RWG, void, env, f32, f32, i32, i32)
DEF_HELPER_FLAGS_5(fcmp_d, TCG_CALL_NO_RWG, void, env, f64, f64, i32, i32)
DEF_HELPER_FLAGS_4(fmpyfadd_s, TCG_CALL_NO_RWG, i32, env, i32, i32, i32)
DEF_HELPER_FLAGS_4(fmpynfadd_s, TCG_CALL_NO_RWG, i32, env, i32, i32, i32)
DEF_HELPER_FLAGS_4(fmpyfadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(fmpynfadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)

View File

@ -174,3 +174,397 @@ void cpu_hppa_loaded_fr0(CPUHPPAState *env)
{
helper_loaded_fr0(env);
}
#define CONVERT_BIT(X, SRC, DST) \
((SRC) > (DST) \
? (X) / ((SRC) / (DST)) & (DST) \
: ((X) & (SRC)) * ((DST) / (SRC)))
static void update_fr0_op(CPUHPPAState *env, uintptr_t ra)
{
uint32_t soft_exp = get_float_exception_flags(&env->fp_status);
uint32_t hard_exp = 0;
uint32_t shadow = env->fr0_shadow;
if (likely(soft_exp == 0)) {
env->fr[0] = (uint64_t)shadow << 32;
return;
}
set_float_exception_flags(0, &env->fp_status);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_inexact, 1u << 0);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_underflow, 1u << 1);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_overflow, 1u << 2);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_divbyzero, 1u << 3);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_invalid, 1u << 4);
shadow |= hard_exp << (32 - 5);
env->fr0_shadow = shadow;
env->fr[0] = (uint64_t)shadow << 32;
if (hard_exp & shadow) {
dynexcp(env, EXCP_SIGFPE, ra);
}
}
float32 HELPER(fsqrt_s)(CPUHPPAState *env, float32 arg)
{
float32 ret = float32_sqrt(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float32 HELPER(frnd_s)(CPUHPPAState *env, float32 arg)
{
float32 ret = float32_round_to_int(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float32 HELPER(fadd_s)(CPUHPPAState *env, float32 a, float32 b)
{
float32 ret = float32_add(a, b, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float32 HELPER(fsub_s)(CPUHPPAState *env, float32 a, float32 b)
{
float32 ret = float32_sub(a, b, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float32 HELPER(fmpy_s)(CPUHPPAState *env, float32 a, float32 b)
{
float32 ret = float32_mul(a, b, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float32 HELPER(fdiv_s)(CPUHPPAState *env, float32 a, float32 b)
{
float32 ret = float32_div(a, b, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float64 HELPER(fsqrt_d)(CPUHPPAState *env, float64 arg)
{
float64 ret = float64_sqrt(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float64 HELPER(frnd_d)(CPUHPPAState *env, float64 arg)
{
float64 ret = float64_round_to_int(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float64 HELPER(fadd_d)(CPUHPPAState *env, float64 a, float64 b)
{
float64 ret = float64_add(a, b, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float64 HELPER(fsub_d)(CPUHPPAState *env, float64 a, float64 b)
{
float64 ret = float64_sub(a, b, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float64 HELPER(fmpy_d)(CPUHPPAState *env, float64 a, float64 b)
{
float64 ret = float64_mul(a, b, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float64 HELPER(fdiv_d)(CPUHPPAState *env, float64 a, float64 b)
{
float64 ret = float64_div(a, b, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float64 HELPER(fcnv_s_d)(CPUHPPAState *env, float32 arg)
{
float64 ret = float32_to_float64(arg, &env->fp_status);
ret = float64_maybe_silence_nan(ret, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float32 HELPER(fcnv_d_s)(CPUHPPAState *env, float64 arg)
{
float32 ret = float64_to_float32(arg, &env->fp_status);
ret = float32_maybe_silence_nan(ret, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float32 HELPER(fcnv_w_s)(CPUHPPAState *env, int32_t arg)
{
float32 ret = int32_to_float32(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float32 HELPER(fcnv_dw_s)(CPUHPPAState *env, int64_t arg)
{
float32 ret = int64_to_float32(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float64 HELPER(fcnv_w_d)(CPUHPPAState *env, int32_t arg)
{
float64 ret = int32_to_float64(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float64 HELPER(fcnv_dw_d)(CPUHPPAState *env, int64_t arg)
{
float64 ret = int64_to_float64(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
int32_t HELPER(fcnv_s_w)(CPUHPPAState *env, float32 arg)
{
int32_t ret = float32_to_int32(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
int32_t HELPER(fcnv_d_w)(CPUHPPAState *env, float64 arg)
{
int32_t ret = float64_to_int32(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
int64_t HELPER(fcnv_s_dw)(CPUHPPAState *env, float32 arg)
{
int64_t ret = float32_to_int64(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
int64_t HELPER(fcnv_d_dw)(CPUHPPAState *env, float64 arg)
{
int64_t ret = float64_to_int64(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
int32_t HELPER(fcnv_t_s_w)(CPUHPPAState *env, float32 arg)
{
int32_t ret = float32_to_int32_round_to_zero(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
int32_t HELPER(fcnv_t_d_w)(CPUHPPAState *env, float64 arg)
{
int32_t ret = float64_to_int32_round_to_zero(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
int64_t HELPER(fcnv_t_s_dw)(CPUHPPAState *env, float32 arg)
{
int64_t ret = float32_to_int64_round_to_zero(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
int64_t HELPER(fcnv_t_d_dw)(CPUHPPAState *env, float64 arg)
{
int64_t ret = float64_to_int64_round_to_zero(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float32 HELPER(fcnv_uw_s)(CPUHPPAState *env, uint32_t arg)
{
float32 ret = uint32_to_float32(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float32 HELPER(fcnv_udw_s)(CPUHPPAState *env, uint64_t arg)
{
float32 ret = uint64_to_float32(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float64 HELPER(fcnv_uw_d)(CPUHPPAState *env, uint32_t arg)
{
float64 ret = uint32_to_float64(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float64 HELPER(fcnv_udw_d)(CPUHPPAState *env, uint64_t arg)
{
float64 ret = uint64_to_float64(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
uint32_t HELPER(fcnv_s_uw)(CPUHPPAState *env, float32 arg)
{
uint32_t ret = float32_to_uint32(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
uint32_t HELPER(fcnv_d_uw)(CPUHPPAState *env, float64 arg)
{
uint32_t ret = float64_to_uint32(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
uint64_t HELPER(fcnv_s_udw)(CPUHPPAState *env, float32 arg)
{
uint64_t ret = float32_to_uint64(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
uint64_t HELPER(fcnv_d_udw)(CPUHPPAState *env, float64 arg)
{
uint64_t ret = float64_to_uint64(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
uint32_t HELPER(fcnv_t_s_uw)(CPUHPPAState *env, float32 arg)
{
uint32_t ret = float32_to_uint32_round_to_zero(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
uint32_t HELPER(fcnv_t_d_uw)(CPUHPPAState *env, float64 arg)
{
uint32_t ret = float64_to_uint32_round_to_zero(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
uint64_t HELPER(fcnv_t_s_udw)(CPUHPPAState *env, float32 arg)
{
uint64_t ret = float32_to_uint64_round_to_zero(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
uint64_t HELPER(fcnv_t_d_udw)(CPUHPPAState *env, float64 arg)
{
uint64_t ret = float64_to_uint64_round_to_zero(arg, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
static void update_fr0_cmp(CPUHPPAState *env, uint32_t y, uint32_t c, int r)
{
uint32_t shadow = env->fr0_shadow;
switch (r) {
case float_relation_greater:
c = extract32(c, 4, 1);
break;
case float_relation_less:
c = extract32(c, 3, 1);
break;
case float_relation_equal:
c = extract32(c, 2, 1);
break;
case float_relation_unordered:
c = extract32(c, 1, 1);
break;
default:
g_assert_not_reached();
}
if (y) {
/* targeted comparison */
/* set fpsr[ca[y - 1]] to current compare */
shadow = deposit32(shadow, 21 - (y - 1), 1, c);
} else {
/* queued comparison */
/* shift cq right by one place */
shadow = deposit32(shadow, 11, 10, extract32(shadow, 12, 10));
/* move fpsr[c] to fpsr[cq[0]] */
shadow = deposit32(shadow, 21, 1, extract32(shadow, 26, 1));
/* set fpsr[c] to current compare */
shadow = deposit32(shadow, 26, 1, c);
}
env->fr0_shadow = shadow;
env->fr[0] = (uint64_t)shadow << 32;
}
void HELPER(fcmp_s)(CPUHPPAState *env, float32 a, float32 b,
uint32_t y, uint32_t c)
{
int r;
if (c & 1) {
r = float32_compare(a, b, &env->fp_status);
} else {
r = float32_compare_quiet(a, b, &env->fp_status);
}
update_fr0_op(env, GETPC());
update_fr0_cmp(env, y, c, r);
}
void HELPER(fcmp_d)(CPUHPPAState *env, float64 a, float64 b,
uint32_t y, uint32_t c)
{
int r;
if (c & 1) {
r = float64_compare(a, b, &env->fp_status);
} else {
r = float64_compare_quiet(a, b, &env->fp_status);
}
update_fr0_op(env, GETPC());
update_fr0_cmp(env, y, c, r);
}
float32 HELPER(fmpyfadd_s)(CPUHPPAState *env, float32 a, float32 b, float32 c)
{
float32 ret = float32_muladd(a, b, c, 0, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float32 HELPER(fmpynfadd_s)(CPUHPPAState *env, float32 a, float32 b, float32 c)
{
float32 ret = float32_muladd(a, b, c, float_muladd_negate_product,
&env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float64 HELPER(fmpyfadd_d)(CPUHPPAState *env, float64 a, float64 b, float64 c)
{
float64 ret = float64_muladd(a, b, c, 0, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
float64 HELPER(fmpynfadd_d)(CPUHPPAState *env, float64 a, float64 b, float64 c)
{
float64 ret = float64_muladd(a, b, c, float_muladd_negate_product,
&env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}

View File

@ -85,6 +85,12 @@ typedef struct DisasInsn {
const struct DisasInsn *f);
union {
void (*f_ttt)(TCGv, TCGv, TCGv);
void (*f_weww)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32);
void (*f_dedd)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64);
void (*f_wew)(TCGv_i32, TCGv_env, TCGv_i32);
void (*f_ded)(TCGv_i64, TCGv_env, TCGv_i64);
void (*f_wed)(TCGv_i32, TCGv_env, TCGv_i64);
void (*f_dew)(TCGv_i64, TCGv_env, TCGv_i32);
};
} DisasInsn;
@ -295,6 +301,28 @@ static TCGv_i32 load_frw_i32(unsigned rt)
return ret;
}
static TCGv_i32 load_frw0_i32(unsigned rt)
{
if (rt == 0) {
return tcg_const_i32(0);
} else {
return load_frw_i32(rt);
}
}
static TCGv_i64 load_frw0_i64(unsigned rt)
{
if (rt == 0) {
return tcg_const_i64(0);
} else {
TCGv_i64 ret = tcg_temp_new_i64();
tcg_gen_ld32u_i64(ret, cpu_env,
offsetof(CPUHPPAState, fr[rt & 31])
+ (rt & 32 ? LO_OFS : HI_OFS));
return ret;
}
}
static void save_frw_i32(unsigned rt, TCGv_i32 val)
{
tcg_gen_st_i32(val, cpu_env,
@ -312,6 +340,15 @@ static TCGv_i64 load_frd(unsigned rt)
return ret;
}
static TCGv_i64 load_frd0(unsigned rt)
{
if (rt == 0) {
return tcg_const_i64(0);
} else {
return load_frd(rt);
}
}
static void save_frd(unsigned rt, TCGv_i64 val)
{
tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt]));
@ -494,6 +531,35 @@ static target_long low_sextract(uint32_t val, int pos, int len)
return x;
}
static unsigned assemble_rt64(uint32_t insn)
{
unsigned r1 = extract32(insn, 6, 1);
unsigned r0 = extract32(insn, 0, 5);
return r1 * 32 + r0;
}
static unsigned assemble_ra64(uint32_t insn)
{
unsigned r1 = extract32(insn, 7, 1);
unsigned r0 = extract32(insn, 21, 5);
return r1 * 32 + r0;
}
static unsigned assemble_rb64(uint32_t insn)
{
unsigned r1 = extract32(insn, 12, 1);
unsigned r0 = extract32(insn, 16, 5);
return r1 * 32 + r0;
}
static unsigned assemble_rc64(uint32_t insn)
{
unsigned r2 = extract32(insn, 8, 1);
unsigned r1 = extract32(insn, 13, 3);
unsigned r0 = extract32(insn, 9, 2);
return r2 * 32 + r1 * 4 + r0;
}
static target_long assemble_12(uint32_t insn)
{
target_ulong x = -(target_ulong)(insn & 1);
@ -1218,6 +1284,110 @@ static ExitStatus do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
return nullify_end(ctx, NO_EXIT);
}
static ExitStatus do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
{
TCGv_i32 tmp;
nullify_over(ctx);
tmp = load_frw0_i32(ra);
func(tmp, cpu_env, tmp);
save_frw_i32(rt, tmp);
tcg_temp_free_i32(tmp);
return nullify_end(ctx, NO_EXIT);
}
static ExitStatus do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
{
TCGv_i32 dst;
TCGv_i64 src;
nullify_over(ctx);
src = load_frd(ra);
dst = tcg_temp_new_i32();
func(dst, cpu_env, src);
tcg_temp_free_i64(src);
save_frw_i32(rt, dst);
tcg_temp_free_i32(dst);
return nullify_end(ctx, NO_EXIT);
}
static ExitStatus do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
{
TCGv_i64 tmp;
nullify_over(ctx);
tmp = load_frd0(ra);
func(tmp, cpu_env, tmp);
save_frd(rt, tmp);
tcg_temp_free_i64(tmp);
return nullify_end(ctx, NO_EXIT);
}
static ExitStatus do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
{
TCGv_i32 src;
TCGv_i64 dst;
nullify_over(ctx);
src = load_frw0_i32(ra);
dst = tcg_temp_new_i64();
func(dst, cpu_env, src);
tcg_temp_free_i32(src);
save_frd(rt, dst);
tcg_temp_free_i64(dst);
return nullify_end(ctx, NO_EXIT);
}
static ExitStatus do_fop_weww(DisasContext *ctx, unsigned rt,
unsigned ra, unsigned rb,
void (*func)(TCGv_i32, TCGv_env,
TCGv_i32, TCGv_i32))
{
TCGv_i32 a, b;
nullify_over(ctx);
a = load_frw0_i32(ra);
b = load_frw0_i32(rb);
func(a, cpu_env, a, b);
tcg_temp_free_i32(b);
save_frw_i32(rt, a);
tcg_temp_free_i32(a);
return nullify_end(ctx, NO_EXIT);
}
static ExitStatus do_fop_dedd(DisasContext *ctx, unsigned rt,
unsigned ra, unsigned rb,
void (*func)(TCGv_i64, TCGv_env,
TCGv_i64, TCGv_i64))
{
TCGv_i64 a, b;
nullify_over(ctx);
a = load_frd0(ra);
b = load_frd0(rb);
func(a, cpu_env, a, b);
tcg_temp_free_i64(b);
save_frd(rt, a);
tcg_temp_free_i64(a);
return nullify_end(ctx, NO_EXIT);
}
/* Emit an unconditional branch to a direct target, which may or may not
have already had nullification handled. */
static ExitStatus do_dbranch(DisasContext *ctx, target_ulong dest,
@ -2893,6 +3063,554 @@ static const DisasInsn table_branch[] = {
{ 0xe800d000u, 0xfc00dffcu, trans_bve },
};
static ExitStatus trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned rt = extract32(insn, 0, 5);
unsigned ra = extract32(insn, 21, 5);
return do_fop_wew(ctx, rt, ra, di->f_wew);
}
static ExitStatus trans_fop_wew_0e(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned rt = assemble_rt64(insn);
unsigned ra = assemble_ra64(insn);
return do_fop_wew(ctx, rt, ra, di->f_wew);
}
static ExitStatus trans_fop_ded(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned rt = extract32(insn, 0, 5);
unsigned ra = extract32(insn, 21, 5);
return do_fop_ded(ctx, rt, ra, di->f_ded);
}
static ExitStatus trans_fop_wed_0c(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned rt = extract32(insn, 0, 5);
unsigned ra = extract32(insn, 21, 5);
return do_fop_wed(ctx, rt, ra, di->f_wed);
}
static ExitStatus trans_fop_wed_0e(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned rt = assemble_rt64(insn);
unsigned ra = extract32(insn, 21, 5);
return do_fop_wed(ctx, rt, ra, di->f_wed);
}
static ExitStatus trans_fop_dew_0c(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned rt = extract32(insn, 0, 5);
unsigned ra = extract32(insn, 21, 5);
return do_fop_dew(ctx, rt, ra, di->f_dew);
}
static ExitStatus trans_fop_dew_0e(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned rt = extract32(insn, 0, 5);
unsigned ra = assemble_ra64(insn);
return do_fop_dew(ctx, rt, ra, di->f_dew);
}
static ExitStatus trans_fop_weww_0c(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned rt = extract32(insn, 0, 5);
unsigned rb = extract32(insn, 16, 5);
unsigned ra = extract32(insn, 21, 5);
return do_fop_weww(ctx, rt, ra, rb, di->f_weww);
}
static ExitStatus trans_fop_weww_0e(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned rt = assemble_rt64(insn);
unsigned rb = assemble_rb64(insn);
unsigned ra = assemble_ra64(insn);
return do_fop_weww(ctx, rt, ra, rb, di->f_weww);
}
static ExitStatus trans_fop_dedd(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned rt = extract32(insn, 0, 5);
unsigned rb = extract32(insn, 16, 5);
unsigned ra = extract32(insn, 21, 5);
return do_fop_dedd(ctx, rt, ra, rb, di->f_dedd);
}
static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
{
tcg_gen_mov_i32(dst, src);
}
static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
{
tcg_gen_mov_i64(dst, src);
}
static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
{
tcg_gen_andi_i32(dst, src, INT32_MAX);
}
static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
{
tcg_gen_andi_i64(dst, src, INT64_MAX);
}
static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
{
tcg_gen_xori_i32(dst, src, INT32_MIN);
}
static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
{
tcg_gen_xori_i64(dst, src, INT64_MIN);
}
static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
{
tcg_gen_ori_i32(dst, src, INT32_MIN);
}
static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
{
tcg_gen_ori_i64(dst, src, INT64_MIN);
}
static ExitStatus do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb,
unsigned y, unsigned c)
{
TCGv_i32 ta, tb, tc, ty;
nullify_over(ctx);
ta = load_frw0_i32(ra);
tb = load_frw0_i32(rb);
ty = tcg_const_i32(y);
tc = tcg_const_i32(c);
gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc);
tcg_temp_free_i32(ta);
tcg_temp_free_i32(tb);
tcg_temp_free_i32(ty);
tcg_temp_free_i32(tc);
return nullify_end(ctx, NO_EXIT);
}
static ExitStatus trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned c = extract32(insn, 0, 5);
unsigned y = extract32(insn, 13, 3);
unsigned rb = extract32(insn, 16, 5);
unsigned ra = extract32(insn, 21, 5);
return do_fcmp_s(ctx, ra, rb, y, c);
}
static ExitStatus trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned c = extract32(insn, 0, 5);
unsigned y = extract32(insn, 13, 3);
unsigned rb = assemble_rb64(insn);
unsigned ra = assemble_ra64(insn);
return do_fcmp_s(ctx, ra, rb, y, c);
}
static ExitStatus trans_fcmp_d(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned c = extract32(insn, 0, 5);
unsigned y = extract32(insn, 13, 3);
unsigned rb = extract32(insn, 16, 5);
unsigned ra = extract32(insn, 21, 5);
TCGv_i64 ta, tb;
TCGv_i32 tc, ty;
nullify_over(ctx);
ta = load_frd0(ra);
tb = load_frd0(rb);
ty = tcg_const_i32(y);
tc = tcg_const_i32(c);
gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc);
tcg_temp_free_i64(ta);
tcg_temp_free_i64(tb);
tcg_temp_free_i32(ty);
tcg_temp_free_i32(tc);
return nullify_end(ctx, NO_EXIT);
}
static ExitStatus trans_ftest_t(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned y = extract32(insn, 13, 3);
unsigned cbit = (y ^ 1) - 1;
TCGv t;
nullify_over(ctx);
t = tcg_temp_new();
tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
tcg_gen_extract_tl(t, t, 21 - cbit, 1);
ctx->null_cond = cond_make_0(TCG_COND_NE, t);
tcg_temp_free(t);
return nullify_end(ctx, NO_EXIT);
}
static ExitStatus trans_ftest_q(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned c = extract32(insn, 0, 5);
int mask;
bool inv = false;
TCGv t;
nullify_over(ctx);
t = tcg_temp_new();
tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
switch (c) {
case 0: /* simple */
tcg_gen_andi_tl(t, t, 0x4000000);
ctx->null_cond = cond_make_0(TCG_COND_NE, t);
goto done;
case 2: /* rej */
inv = true;
/* fallthru */
case 1: /* acc */
mask = 0x43ff800;
break;
case 6: /* rej8 */
inv = true;
/* fallthru */
case 5: /* acc8 */
mask = 0x43f8000;
break;
case 9: /* acc6 */
mask = 0x43e0000;
break;
case 13: /* acc4 */
mask = 0x4380000;
break;
case 17: /* acc2 */
mask = 0x4200000;
break;
default:
return gen_illegal(ctx);
}
if (inv) {
TCGv c = load_const(ctx, mask);
tcg_gen_or_tl(t, t, c);
ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
} else {
tcg_gen_andi_tl(t, t, mask);
ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
}
done:
return nullify_end(ctx, NO_EXIT);
}
static ExitStatus trans_xmpyu(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned rt = extract32(insn, 0, 5);
unsigned rb = assemble_rb64(insn);
unsigned ra = assemble_ra64(insn);
TCGv_i64 a, b;
nullify_over(ctx);
a = load_frw0_i64(ra);
b = load_frw0_i64(rb);
tcg_gen_mul_i64(a, a, b);
save_frd(rt, a);
tcg_temp_free_i64(a);
tcg_temp_free_i64(b);
return nullify_end(ctx, NO_EXIT);
}
#define FOP_DED trans_fop_ded, .f_ded
#define FOP_DEDD trans_fop_dedd, .f_dedd
#define FOP_WEW trans_fop_wew_0c, .f_wew
#define FOP_DEW trans_fop_dew_0c, .f_dew
#define FOP_WED trans_fop_wed_0c, .f_wed
#define FOP_WEWW trans_fop_weww_0c, .f_weww
static const DisasInsn table_float_0c[] = {
/* floating point class zero */
{ 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s },
{ 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s },
{ 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s },
{ 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s },
{ 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s },
{ 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s },
{ 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
{ 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
{ 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
{ 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
{ 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
{ 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
/* floating point class three */
{ 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s },
{ 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s },
{ 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s },
{ 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s },
{ 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
{ 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
{ 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
{ 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
/* floating point class one */
/* float/float */
{ 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s },
{ 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d },
/* int/float */
{ 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s },
{ 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s },
{ 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d },
{ 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
/* float/int */
{ 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w },
{ 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w },
{ 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw },
{ 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
/* float/int truncate */
{ 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w },
{ 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w },
{ 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw },
{ 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
/* uint/float */
{ 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s },
{ 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s },
{ 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d },
{ 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
/* float/uint */
{ 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw },
{ 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw },
{ 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw },
{ 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
/* float/uint truncate */
{ 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw },
{ 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw },
{ 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw },
{ 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
/* floating point class two */
{ 0x30000400, 0xfc001fe0, trans_fcmp_s_0c },
{ 0x30000c00, 0xfc001fe0, trans_fcmp_d },
{ 0x30002420, 0xffffffe0, trans_ftest_q },
{ 0x30000420, 0xffff1fff, trans_ftest_t },
/* FID. Note that ra == rt == 0, which via fcpy puts 0 into fr0.
This is machine/revision == 0, which is reserved for simulator. */
{ 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s },
};
#undef FOP_WEW
#undef FOP_DEW
#undef FOP_WED
#undef FOP_WEWW
#define FOP_WEW trans_fop_wew_0e, .f_wew
#define FOP_DEW trans_fop_dew_0e, .f_dew
#define FOP_WED trans_fop_wed_0e, .f_wed
#define FOP_WEWW trans_fop_weww_0e, .f_weww
static const DisasInsn table_float_0e[] = {
/* floating point class zero */
{ 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s },
{ 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s },
{ 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s },
{ 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s },
{ 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s },
{ 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s },
{ 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
{ 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
{ 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
{ 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
{ 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
{ 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
/* floating point class three */
{ 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s },
{ 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s },
{ 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s },
{ 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s },
{ 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
{ 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
{ 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
{ 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
{ 0x38004700, 0xfc00ef60, trans_xmpyu },
/* floating point class one */
/* float/float */
{ 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s },
{ 0x38002200, 0xfc1fffc0, FOP_DEW = gen_helper_fcnv_s_d },
/* int/float */
{ 0x38008200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_w_s },
{ 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s },
{ 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d },
{ 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
/* float/int */
{ 0x38010200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_w },
{ 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w },
{ 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw },
{ 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
/* float/int truncate */
{ 0x38018200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_w },
{ 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w },
{ 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw },
{ 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
/* uint/float */
{ 0x38028200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_uw_s },
{ 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s },
{ 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d },
{ 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
/* float/uint */
{ 0x38030200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_uw },
{ 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw },
{ 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw },
{ 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
/* float/uint truncate */
{ 0x38038200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_uw },
{ 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw },
{ 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw },
{ 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
/* floating point class two */
{ 0x38000400, 0xfc000f60, trans_fcmp_s_0e },
{ 0x38000c00, 0xfc001fe0, trans_fcmp_d },
};
#undef FOP_WEW
#undef FOP_DEW
#undef FOP_WED
#undef FOP_WEWW
#undef FOP_DED
#undef FOP_DEDD
/* Convert the fmpyadd single-precision register encodings to standard. */
static inline int fmpyadd_s_reg(unsigned r)
{
return (r & 16) * 2 + 16 + (r & 15);
}
static ExitStatus trans_fmpyadd(DisasContext *ctx, uint32_t insn, bool is_sub)
{
unsigned tm = extract32(insn, 0, 5);
unsigned f = extract32(insn, 5, 1);
unsigned ra = extract32(insn, 6, 5);
unsigned ta = extract32(insn, 11, 5);
unsigned rm2 = extract32(insn, 16, 5);
unsigned rm1 = extract32(insn, 21, 5);
nullify_over(ctx);
/* Independent multiply & add/sub, with undefined behaviour
if outputs overlap inputs. */
if (f == 0) {
tm = fmpyadd_s_reg(tm);
ra = fmpyadd_s_reg(ra);
ta = fmpyadd_s_reg(ta);
rm2 = fmpyadd_s_reg(rm2);
rm1 = fmpyadd_s_reg(rm1);
do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
do_fop_weww(ctx, ta, ta, ra,
is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
} else {
do_fop_dedd(ctx, tm, rm1, rm2, gen_helper_fmpy_d);
do_fop_dedd(ctx, ta, ta, ra,
is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
}
return nullify_end(ctx, NO_EXIT);
}
static ExitStatus trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned rt = assemble_rt64(insn);
unsigned neg = extract32(insn, 5, 1);
unsigned rm1 = assemble_ra64(insn);
unsigned rm2 = assemble_rb64(insn);
unsigned ra3 = assemble_rc64(insn);
TCGv_i32 a, b, c;
nullify_over(ctx);
a = load_frw0_i32(rm1);
b = load_frw0_i32(rm2);
c = load_frw0_i32(ra3);
if (neg) {
gen_helper_fmpynfadd_s(a, cpu_env, a, b, c);
} else {
gen_helper_fmpyfadd_s(a, cpu_env, a, b, c);
}
tcg_temp_free_i32(b);
tcg_temp_free_i32(c);
save_frw_i32(rt, a);
tcg_temp_free_i32(a);
return nullify_end(ctx, NO_EXIT);
}
static ExitStatus trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned rt = extract32(insn, 0, 5);
unsigned neg = extract32(insn, 5, 1);
unsigned rm1 = extract32(insn, 21, 5);
unsigned rm2 = extract32(insn, 16, 5);
unsigned ra3 = assemble_rc64(insn);
TCGv_i64 a, b, c;
nullify_over(ctx);
a = load_frd0(rm1);
b = load_frd0(rm2);
c = load_frd0(ra3);
if (neg) {
gen_helper_fmpynfadd_d(a, cpu_env, a, b, c);
} else {
gen_helper_fmpyfadd_d(a, cpu_env, a, b, c);
}
tcg_temp_free_i64(b);
tcg_temp_free_i64(c);
save_frd(rt, a);
tcg_temp_free_i64(a);
return nullify_end(ctx, NO_EXIT);
}
static const DisasInsn table_fp_fused[] = {
{ 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s },
{ 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d }
};
static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn,
const DisasInsn table[], size_t n)
{
@ -2921,6 +3639,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
return translate_table(ctx, insn, table_arith_log);
case 0x03:
return translate_table(ctx, insn, table_index_mem);
case 0x06:
return trans_fmpyadd(ctx, insn, false);
case 0x08:
return trans_ldil(ctx, insn);
case 0x09:
@ -2929,8 +3649,12 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
return trans_addil(ctx, insn);
case 0x0B:
return trans_copr_dw(ctx, insn);
case 0x0C:
return translate_table(ctx, insn, table_float_0c);
case 0x0D:
return trans_ldo(ctx, insn);
case 0x0E:
return translate_table(ctx, insn, table_float_0e);
case 0x10:
return trans_load(ctx, insn, false, MO_UB);
@ -2969,6 +3693,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
return trans_cmpiclr(ctx, insn);
case 0x25:
return trans_subi(ctx, insn);
case 0x26:
return trans_fmpyadd(ctx, insn, true);
case 0x27:
return trans_cmpb(ctx, insn, true, false, true);
case 0x28:
@ -2982,6 +3708,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
case 0x2C:
case 0x2D:
return trans_addi(ctx, insn);
case 0x2E:
return translate_table(ctx, insn, table_fp_fused);
case 0x2F:
return trans_cmpb(ctx, insn, false, false, true);