mirror of https://gitee.com/openkylin/qemu.git
fix ARMv7 data processing instructions
ARMv7 defines a new behavior for ARM data processing instructions compared to earlier architecture revisions; when the destination register is R15, a Branch and Exchange operation is executed rather than a simple Branch to the target address. This patch corrects the behavior of the emulation for the aforementioned operations. To be applied after applying the previous patch in this patch set. Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com> Signed-off-by: Paul Brook <paul@codesourcery.com>
This commit is contained in:
parent
e9bb4aa977
commit
21aeb3430c
|
@ -820,6 +820,19 @@ static inline void gen_bx_T0(DisasContext *s)
|
||||||
gen_bx(s, tmp);
|
gen_bx(s, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Variant of store_reg which uses branch&exchange logic when storing
|
||||||
|
to r15 in ARM architecture v7 and above. The source must be a temporary
|
||||||
|
and will be marked as dead. */
|
||||||
|
static inline void store_reg_bx(CPUState *env, DisasContext *s,
|
||||||
|
int reg, TCGv var)
|
||||||
|
{
|
||||||
|
if (reg == 15 && ENABLE_ARCH_7) {
|
||||||
|
gen_bx(s, var);
|
||||||
|
} else {
|
||||||
|
store_reg(s, reg, var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline TCGv gen_ld8s(TCGv addr, int index)
|
static inline TCGv gen_ld8s(TCGv addr, int index)
|
||||||
{
|
{
|
||||||
TCGv tmp = new_tmp();
|
TCGv tmp = new_tmp();
|
||||||
|
@ -6131,14 +6144,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
||||||
if (logic_cc) {
|
if (logic_cc) {
|
||||||
gen_logic_CC(tmp);
|
gen_logic_CC(tmp);
|
||||||
}
|
}
|
||||||
store_reg(s, rd, tmp);
|
store_reg_bx(env, s, rd, tmp);
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
tcg_gen_xor_i32(tmp, tmp, tmp2);
|
tcg_gen_xor_i32(tmp, tmp, tmp2);
|
||||||
if (logic_cc) {
|
if (logic_cc) {
|
||||||
gen_logic_CC(tmp);
|
gen_logic_CC(tmp);
|
||||||
}
|
}
|
||||||
store_reg(s, rd, tmp);
|
store_reg_bx(env, s, rd, tmp);
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
if (set_cc && rd == 15) {
|
if (set_cc && rd == 15) {
|
||||||
|
@ -6154,7 +6167,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_sub_i32(tmp, tmp, tmp2);
|
tcg_gen_sub_i32(tmp, tmp, tmp2);
|
||||||
}
|
}
|
||||||
store_reg(s, rd, tmp);
|
store_reg_bx(env, s, rd, tmp);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x03:
|
case 0x03:
|
||||||
|
@ -6163,7 +6176,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_sub_i32(tmp, tmp2, tmp);
|
tcg_gen_sub_i32(tmp, tmp2, tmp);
|
||||||
}
|
}
|
||||||
store_reg(s, rd, tmp);
|
store_reg_bx(env, s, rd, tmp);
|
||||||
break;
|
break;
|
||||||
case 0x04:
|
case 0x04:
|
||||||
if (set_cc) {
|
if (set_cc) {
|
||||||
|
@ -6171,7 +6184,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_add_i32(tmp, tmp, tmp2);
|
tcg_gen_add_i32(tmp, tmp, tmp2);
|
||||||
}
|
}
|
||||||
store_reg(s, rd, tmp);
|
store_reg_bx(env, s, rd, tmp);
|
||||||
break;
|
break;
|
||||||
case 0x05:
|
case 0x05:
|
||||||
if (set_cc) {
|
if (set_cc) {
|
||||||
|
@ -6179,7 +6192,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
||||||
} else {
|
} else {
|
||||||
gen_add_carry(tmp, tmp, tmp2);
|
gen_add_carry(tmp, tmp, tmp2);
|
||||||
}
|
}
|
||||||
store_reg(s, rd, tmp);
|
store_reg_bx(env, s, rd, tmp);
|
||||||
break;
|
break;
|
||||||
case 0x06:
|
case 0x06:
|
||||||
if (set_cc) {
|
if (set_cc) {
|
||||||
|
@ -6187,7 +6200,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
||||||
} else {
|
} else {
|
||||||
gen_sub_carry(tmp, tmp, tmp2);
|
gen_sub_carry(tmp, tmp, tmp2);
|
||||||
}
|
}
|
||||||
store_reg(s, rd, tmp);
|
store_reg_bx(env, s, rd, tmp);
|
||||||
break;
|
break;
|
||||||
case 0x07:
|
case 0x07:
|
||||||
if (set_cc) {
|
if (set_cc) {
|
||||||
|
@ -6195,7 +6208,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
||||||
} else {
|
} else {
|
||||||
gen_sub_carry(tmp, tmp2, tmp);
|
gen_sub_carry(tmp, tmp2, tmp);
|
||||||
}
|
}
|
||||||
store_reg(s, rd, tmp);
|
store_reg_bx(env, s, rd, tmp);
|
||||||
break;
|
break;
|
||||||
case 0x08:
|
case 0x08:
|
||||||
if (set_cc) {
|
if (set_cc) {
|
||||||
|
@ -6228,7 +6241,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
||||||
if (logic_cc) {
|
if (logic_cc) {
|
||||||
gen_logic_CC(tmp);
|
gen_logic_CC(tmp);
|
||||||
}
|
}
|
||||||
store_reg(s, rd, tmp);
|
store_reg_bx(env, s, rd, tmp);
|
||||||
break;
|
break;
|
||||||
case 0x0d:
|
case 0x0d:
|
||||||
if (logic_cc && rd == 15) {
|
if (logic_cc && rd == 15) {
|
||||||
|
@ -6241,7 +6254,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
||||||
if (logic_cc) {
|
if (logic_cc) {
|
||||||
gen_logic_CC(tmp2);
|
gen_logic_CC(tmp2);
|
||||||
}
|
}
|
||||||
store_reg(s, rd, tmp2);
|
store_reg_bx(env, s, rd, tmp2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x0e:
|
case 0x0e:
|
||||||
|
@ -6249,7 +6262,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
||||||
if (logic_cc) {
|
if (logic_cc) {
|
||||||
gen_logic_CC(tmp);
|
gen_logic_CC(tmp);
|
||||||
}
|
}
|
||||||
store_reg(s, rd, tmp);
|
store_reg_bx(env, s, rd, tmp);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case 0x0f:
|
case 0x0f:
|
||||||
|
@ -6257,7 +6270,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
||||||
if (logic_cc) {
|
if (logic_cc) {
|
||||||
gen_logic_CC(tmp2);
|
gen_logic_CC(tmp2);
|
||||||
}
|
}
|
||||||
store_reg(s, rd, tmp2);
|
store_reg_bx(env, s, rd, tmp2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (op1 != 0x0f && op1 != 0x0d) {
|
if (op1 != 0x0f && op1 != 0x0d) {
|
||||||
|
@ -7359,7 +7372,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
|
||||||
gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
|
gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
|
||||||
if (logic_cc)
|
if (logic_cc)
|
||||||
gen_logic_CC(tmp);
|
gen_logic_CC(tmp);
|
||||||
store_reg(s, rd, tmp);
|
store_reg_bx(env, s, rd, tmp);
|
||||||
break;
|
break;
|
||||||
case 1: /* Sign/zero extend. */
|
case 1: /* Sign/zero extend. */
|
||||||
tmp = load_reg(s, rm);
|
tmp = load_reg(s, rm);
|
||||||
|
|
Loading…
Reference in New Issue