This instruction always uses the input carry from bit 32,
but produces all 16 output carry bits.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/hppa/translate.c | 48 +++++++++++++++++++++++++++++++----------
1 file changed, 37 insertions(+), 11 deletions(-)
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index e6ab113a1c..fb7a295367 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -803,6 +803,12 @@ static bool cond_need_cb(int c)
return c == 4 || c == 5;
}
+/* Need extensions from TCGv_i32 to TCGv_reg. */
+static bool cond_need_ext(DisasContext *ctx, bool d)
+{
+ return TARGET_REGISTER_BITS == 64 && !d;
+}
+
/*
* Compute conditional for arithmetic. See Page 5-3, Table 5-1, of
* the Parisc 1.1 Architecture Reference Manual for details.
@@ -1040,6 +1046,22 @@ static DisasCond do_unit_cond(unsigned cf, TCGv_reg res,
return cond;
}
+static TCGv_reg get_carry(DisasContext *ctx, bool d,
+ TCGv_reg cb, TCGv_reg cb_msb)
+{
+ if (cond_need_ext(ctx, d)) {
+ TCGv_reg t = tcg_temp_new();
+ tcg_gen_extract_reg(t, cb, 32, 1);
+ return t;
+ }
+ return cb_msb;
+}
+
+static TCGv_reg get_psw_carry(DisasContext *ctx, bool d)
+{
+ return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
+}
+
/* Compute signed overflow for addition. */
static TCGv_reg do_add_sv(DisasContext *ctx, TCGv_reg res,
TCGv_reg in1, TCGv_reg in2)
@@ -2712,6 +2734,7 @@ static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf *a)
static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
{
TCGv_reg dest, add1, add2, addc, zero, in1, in2;
+ TCGv_reg cout;
nullify_over(ctx);
@@ -2726,18 +2749,20 @@ static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
/* Form R1 << 1 | PSW[CB]{8}. */
tcg_gen_add_reg(add1, in1, in1);
- tcg_gen_add_reg(add1, add1, cpu_psw_cb_msb);
+ tcg_gen_add_reg(add1, add1, get_psw_carry(ctx, false));
- /* Add or subtract R2, depending on PSW[V]. Proper computation of
- carry{8} requires that we subtract via + ~R2 + 1, as described in
- the manual. By extracting and masking V, we can produce the
- proper inputs to the addition without movcond. */
- tcg_gen_sari_reg(addc, cpu_psw_v, TARGET_REGISTER_BITS - 1);
+ /*
+ * Add or subtract R2, depending on PSW[V]. Proper computation of
+ * carry requires that we subtract via + ~R2 + 1, as described in
+ * the manual. By extracting and masking V, we can produce the
+ * proper inputs to the addition without movcond.
+ */
+ tcg_gen_sextract_reg(addc, cpu_psw_v, 31, 1);
tcg_gen_xor_reg(add2, in2, addc);
tcg_gen_andi_reg(addc, addc, 1);
- /* ??? This is only correct for 32-bit. */
- tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
- tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
+
+ tcg_gen_add2_reg(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
+ tcg_gen_add2_reg(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
/* Write back the result register. */
save_gpr(ctx, a->t, dest);
@@ -2747,7 +2772,8 @@ static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
tcg_gen_xor_reg(cpu_psw_cb, cpu_psw_cb, dest);
/* Write back PSW[V] for the division step. */
- tcg_gen_neg_reg(cpu_psw_v, cpu_psw_cb_msb);
+ cout = get_psw_carry(ctx, false);
+ tcg_gen_neg_reg(cpu_psw_v, cout);
tcg_gen_xor_reg(cpu_psw_v, cpu_psw_v, in2);
/* Install the new nullification. */
@@ -2757,7 +2783,7 @@ static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
/* ??? The lshift is supposed to contribute to overflow. */
sv = do_add_sv(ctx, dest, add1, add2);
}
- ctx->null_cond = do_cond(a->cf, dest, cpu_psw_cb_msb, sv);
+ ctx->null_cond = do_cond(a->cf, dest, cout, sv);
}
return nullify_end(ctx);
--
2.34.1