Commit 86753403b282cd1de867e19449c76a3b1c6e47ff
1 parent
f5a5cca3
Fix ARMv6t2 strex instructions.
Signed-off-by: Paul Brook <paul@codesourcery.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5517 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
45 additions
and
3 deletions
target-arm/translate.c
@@ -40,7 +40,7 @@ | @@ -40,7 +40,7 @@ | ||
40 | #define ENABLE_ARCH_6T2 arm_feature(env, ARM_FEATURE_THUMB2) | 40 | #define ENABLE_ARCH_6T2 arm_feature(env, ARM_FEATURE_THUMB2) |
41 | #define ENABLE_ARCH_7 arm_feature(env, ARM_FEATURE_V7) | 41 | #define ENABLE_ARCH_7 arm_feature(env, ARM_FEATURE_V7) |
42 | 42 | ||
43 | -#define ARCH(x) if (!ENABLE_ARCH_##x) goto illegal_op; | 43 | +#define ARCH(x) do { if (!ENABLE_ARCH_##x) goto illegal_op; } while(0) |
44 | 44 | ||
45 | /* internal defines */ | 45 | /* internal defines */ |
46 | typedef struct DisasContext { | 46 | typedef struct DisasContext { |
@@ -6225,11 +6225,35 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | @@ -6225,11 +6225,35 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | ||
6225 | rd = (insn >> 12) & 0xf; | 6225 | rd = (insn >> 12) & 0xf; |
6226 | if (insn & (1 << 23)) { | 6226 | if (insn & (1 << 23)) { |
6227 | /* load/store exclusive */ | 6227 | /* load/store exclusive */ |
6228 | + op1 = (insn >> 21) & 0x3; | ||
6229 | + if (op1) | ||
6230 | + ARCH(6T2); | ||
6231 | + else | ||
6232 | + ARCH(6); | ||
6228 | gen_movl_T1_reg(s, rn); | 6233 | gen_movl_T1_reg(s, rn); |
6229 | addr = cpu_T[1]; | 6234 | addr = cpu_T[1]; |
6230 | if (insn & (1 << 20)) { | 6235 | if (insn & (1 << 20)) { |
6231 | gen_helper_mark_exclusive(cpu_env, cpu_T[1]); | 6236 | gen_helper_mark_exclusive(cpu_env, cpu_T[1]); |
6232 | - tmp = gen_ld32(addr, IS_USER(s)); | 6237 | + switch (op1) { |
6238 | + case 0: /* ldrex */ | ||
6239 | + tmp = gen_ld32(addr, IS_USER(s)); | ||
6240 | + break; | ||
6241 | + case 1: /* ldrexd */ | ||
6242 | + tmp = gen_ld32(addr, IS_USER(s)); | ||
6243 | + store_reg(s, rd, tmp); | ||
6244 | + tcg_gen_addi_i32(addr, addr, 4); | ||
6245 | + tmp = gen_ld32(addr, IS_USER(s)); | ||
6246 | + rd++; | ||
6247 | + break; | ||
6248 | + case 2: /* ldrexb */ | ||
6249 | + tmp = gen_ld8u(addr, IS_USER(s)); | ||
6250 | + break; | ||
6251 | + case 3: /* ldrexh */ | ||
6252 | + tmp = gen_ld16u(addr, IS_USER(s)); | ||
6253 | + break; | ||
6254 | + default: | ||
6255 | + abort(); | ||
6256 | + } | ||
6233 | store_reg(s, rd, tmp); | 6257 | store_reg(s, rd, tmp); |
6234 | } else { | 6258 | } else { |
6235 | int label = gen_new_label(); | 6259 | int label = gen_new_label(); |
@@ -6238,7 +6262,25 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | @@ -6238,7 +6262,25 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | ||
6238 | tcg_gen_brcondi_i32(TCG_COND_NE, cpu_T[0], | 6262 | tcg_gen_brcondi_i32(TCG_COND_NE, cpu_T[0], |
6239 | 0, label); | 6263 | 0, label); |
6240 | tmp = load_reg(s,rm); | 6264 | tmp = load_reg(s,rm); |
6241 | - gen_st32(tmp, cpu_T[1], IS_USER(s)); | 6265 | + switch (op1) { |
6266 | + case 0: /* strex */ | ||
6267 | + gen_st32(tmp, addr, IS_USER(s)); | ||
6268 | + break; | ||
6269 | + case 1: /* strexd */ | ||
6270 | + gen_st32(tmp, addr, IS_USER(s)); | ||
6271 | + tcg_gen_addi_i32(addr, addr, 4); | ||
6272 | + tmp = load_reg(s, rm + 1); | ||
6273 | + gen_st32(tmp, addr, IS_USER(s)); | ||
6274 | + break; | ||
6275 | + case 2: /* strexb */ | ||
6276 | + gen_st8(tmp, addr, IS_USER(s)); | ||
6277 | + break; | ||
6278 | + case 3: /* strexh */ | ||
6279 | + gen_st16(tmp, addr, IS_USER(s)); | ||
6280 | + break; | ||
6281 | + default: | ||
6282 | + abort(); | ||
6283 | + } | ||
6242 | gen_set_label(label); | 6284 | gen_set_label(label); |
6243 | gen_movl_reg_T0(s, rd); | 6285 | gen_movl_reg_T0(s, rd); |
6244 | } | 6286 | } |