diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-05-15 14:38:53 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-05-15 14:38:53 +0100 |
commit | 06e33c1c3c193074574eb3813eded91bff0fc86f (patch) | |
tree | a965f03c8be3c95ca315a3489e4eefdd6cd29732 | |
parent | 7d983531c6a17f38ad66908216b1d51923a9664c (diff) | |
parent | dc1823ce26f0539eab098e0209400d793ef66279 (diff) |
Merge remote-tracking branch 'remotes/rth/tags/pull-tgt-i386-20140512' into staging
Fix BT zero flag for new Intel manuals
# gpg: Signature made Mon 12 May 2014 22:26:01 BST using RSA key ID 4DD0279B
# gpg: Can't check signature: public key not found
* remotes/rth/tags/pull-tgt-i386-20140512:
target-i386: Preserve the Z bit for bt/bts/btr/btc
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | target-i386/translate.c | 40 |
1 files changed, 31 insertions, 9 deletions
diff --git a/target-i386/translate.c b/target-i386/translate.c index 02625e31c2..032b0fdffc 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -6708,41 +6708,63 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } bt_op: tcg_gen_andi_tl(cpu_T[1], cpu_T[1], (1 << (3 + ot)) - 1); + tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]); switch(op) { case 0: - tcg_gen_shr_tl(cpu_cc_src, cpu_T[0], cpu_T[1]); - tcg_gen_movi_tl(cpu_cc_dst, 0); break; case 1: - tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]); tcg_gen_movi_tl(cpu_tmp0, 1); tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]); tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0); break; case 2: - tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]); tcg_gen_movi_tl(cpu_tmp0, 1); tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]); - tcg_gen_not_tl(cpu_tmp0, cpu_tmp0); - tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_tmp0); + tcg_gen_andc_tl(cpu_T[0], cpu_T[0], cpu_tmp0); break; default: case 3: - tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]); tcg_gen_movi_tl(cpu_tmp0, 1); tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]); tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0); break; } - set_cc_op(s, CC_OP_SARB + ot); if (op != 0) { if (mod != 3) { gen_op_st_v(s, ot, cpu_T[0], cpu_A0); } else { gen_op_mov_reg_v(ot, rm, cpu_T[0]); } + } + + /* Delay all CC updates until after the store above. Note that + C is the result of the test, Z is unchanged, and the others + are all undefined. */ + switch (s->cc_op) { + case CC_OP_MULB ... CC_OP_MULQ: + case CC_OP_ADDB ... CC_OP_ADDQ: + case CC_OP_ADCB ... CC_OP_ADCQ: + case CC_OP_SUBB ... CC_OP_SUBQ: + case CC_OP_SBBB ... CC_OP_SBBQ: + case CC_OP_LOGICB ... CC_OP_LOGICQ: + case CC_OP_INCB ... CC_OP_INCQ: + case CC_OP_DECB ... CC_OP_DECQ: + case CC_OP_SHLB ... CC_OP_SHLQ: + case CC_OP_SARB ... CC_OP_SARQ: + case CC_OP_BMILGB ... CC_OP_BMILGQ: + /* Z was going to be computed from the non-zero status of CC_DST. + We can get that same Z value (and the new C value) by leaving + CC_DST alone, setting CC_SRC, and using a CC_OP_SAR of the + same width. */ tcg_gen_mov_tl(cpu_cc_src, cpu_tmp4); - tcg_gen_movi_tl(cpu_cc_dst, 0); + set_cc_op(s, ((s->cc_op - CC_OP_MULB) & 3) + CC_OP_SARB); + break; + default: + /* Otherwise, generate EFLAGS and replace the C bit. */ + gen_compute_eflags(s); + tcg_gen_deposit_tl(cpu_cc_src, cpu_cc_src, cpu_tmp4, + ctz32(CC_C), 1); + break; } break; case 0x1bc: /* bsf / tzcnt */ |