Commit 21aeb3430ce7ba066f394c2029c2ddf130662455

Authored by Juha Riihimäki
Committed by Paul Brook
1 parent e9bb4aa9

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>
Showing 1 changed file with 26 additions and 13 deletions
target-arm/translate.c
@@ -820,6 +820,19 @@ static inline void gen_bx_T0(DisasContext *s) @@ -820,6 +820,19 @@ static inline void gen_bx_T0(DisasContext *s)
820 gen_bx(s, tmp); 820 gen_bx(s, tmp);
821 } 821 }
822 822
  823 +/* Variant of store_reg which uses branch&exchange logic when storing
  824 + to r15 in ARM architecture v7 and above. The source must be a temporary
  825 + and will be marked as dead. */
  826 +static inline void store_reg_bx(CPUState *env, DisasContext *s,
  827 + int reg, TCGv var)
  828 +{
  829 + if (reg == 15 && ENABLE_ARCH_7) {
  830 + gen_bx(s, var);
  831 + } else {
  832 + store_reg(s, reg, var);
  833 + }
  834 +}
  835 +
823 static inline TCGv gen_ld8s(TCGv addr, int index) 836 static inline TCGv gen_ld8s(TCGv addr, int index)
824 { 837 {
825 TCGv tmp = new_tmp(); 838 TCGv tmp = new_tmp();
@@ -6131,14 +6144,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -6131,14 +6144,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6131 if (logic_cc) { 6144 if (logic_cc) {
6132 gen_logic_CC(tmp); 6145 gen_logic_CC(tmp);
6133 } 6146 }
6134 - store_reg(s, rd, tmp); 6147 + store_reg_bx(env, s, rd, tmp);
6135 break; 6148 break;
6136 case 0x01: 6149 case 0x01:
6137 tcg_gen_xor_i32(tmp, tmp, tmp2); 6150 tcg_gen_xor_i32(tmp, tmp, tmp2);
6138 if (logic_cc) { 6151 if (logic_cc) {
6139 gen_logic_CC(tmp); 6152 gen_logic_CC(tmp);
6140 } 6153 }
6141 - store_reg(s, rd, tmp); 6154 + store_reg_bx(env, s, rd, tmp);
6142 break; 6155 break;
6143 case 0x02: 6156 case 0x02:
6144 if (set_cc && rd == 15) { 6157 if (set_cc && rd == 15) {
@@ -6154,7 +6167,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -6154,7 +6167,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6154 } else { 6167 } else {
6155 tcg_gen_sub_i32(tmp, tmp, tmp2); 6168 tcg_gen_sub_i32(tmp, tmp, tmp2);
6156 } 6169 }
6157 - store_reg(s, rd, tmp); 6170 + store_reg_bx(env, s, rd, tmp);
6158 } 6171 }
6159 break; 6172 break;
6160 case 0x03: 6173 case 0x03:
@@ -6163,7 +6176,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -6163,7 +6176,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6163 } else { 6176 } else {
6164 tcg_gen_sub_i32(tmp, tmp2, tmp); 6177 tcg_gen_sub_i32(tmp, tmp2, tmp);
6165 } 6178 }
6166 - store_reg(s, rd, tmp); 6179 + store_reg_bx(env, s, rd, tmp);
6167 break; 6180 break;
6168 case 0x04: 6181 case 0x04:
6169 if (set_cc) { 6182 if (set_cc) {
@@ -6171,7 +6184,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -6171,7 +6184,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6171 } else { 6184 } else {
6172 tcg_gen_add_i32(tmp, tmp, tmp2); 6185 tcg_gen_add_i32(tmp, tmp, tmp2);
6173 } 6186 }
6174 - store_reg(s, rd, tmp); 6187 + store_reg_bx(env, s, rd, tmp);
6175 break; 6188 break;
6176 case 0x05: 6189 case 0x05:
6177 if (set_cc) { 6190 if (set_cc) {
@@ -6179,7 +6192,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -6179,7 +6192,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6179 } else { 6192 } else {
6180 gen_add_carry(tmp, tmp, tmp2); 6193 gen_add_carry(tmp, tmp, tmp2);
6181 } 6194 }
6182 - store_reg(s, rd, tmp); 6195 + store_reg_bx(env, s, rd, tmp);
6183 break; 6196 break;
6184 case 0x06: 6197 case 0x06:
6185 if (set_cc) { 6198 if (set_cc) {
@@ -6187,7 +6200,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -6187,7 +6200,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6187 } else { 6200 } else {
6188 gen_sub_carry(tmp, tmp, tmp2); 6201 gen_sub_carry(tmp, tmp, tmp2);
6189 } 6202 }
6190 - store_reg(s, rd, tmp); 6203 + store_reg_bx(env, s, rd, tmp);
6191 break; 6204 break;
6192 case 0x07: 6205 case 0x07:
6193 if (set_cc) { 6206 if (set_cc) {
@@ -6195,7 +6208,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -6195,7 +6208,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6195 } else { 6208 } else {
6196 gen_sub_carry(tmp, tmp2, tmp); 6209 gen_sub_carry(tmp, tmp2, tmp);
6197 } 6210 }
6198 - store_reg(s, rd, tmp); 6211 + store_reg_bx(env, s, rd, tmp);
6199 break; 6212 break;
6200 case 0x08: 6213 case 0x08:
6201 if (set_cc) { 6214 if (set_cc) {
@@ -6228,7 +6241,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -6228,7 +6241,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6228 if (logic_cc) { 6241 if (logic_cc) {
6229 gen_logic_CC(tmp); 6242 gen_logic_CC(tmp);
6230 } 6243 }
6231 - store_reg(s, rd, tmp); 6244 + store_reg_bx(env, s, rd, tmp);
6232 break; 6245 break;
6233 case 0x0d: 6246 case 0x0d:
6234 if (logic_cc && rd == 15) { 6247 if (logic_cc && rd == 15) {
@@ -6241,7 +6254,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -6241,7 +6254,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6241 if (logic_cc) { 6254 if (logic_cc) {
6242 gen_logic_CC(tmp2); 6255 gen_logic_CC(tmp2);
6243 } 6256 }
6244 - store_reg(s, rd, tmp2); 6257 + store_reg_bx(env, s, rd, tmp2);
6245 } 6258 }
6246 break; 6259 break;
6247 case 0x0e: 6260 case 0x0e:
@@ -6249,7 +6262,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -6249,7 +6262,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6249 if (logic_cc) { 6262 if (logic_cc) {
6250 gen_logic_CC(tmp); 6263 gen_logic_CC(tmp);
6251 } 6264 }
6252 - store_reg(s, rd, tmp); 6265 + store_reg_bx(env, s, rd, tmp);
6253 break; 6266 break;
6254 default: 6267 default:
6255 case 0x0f: 6268 case 0x0f:
@@ -6257,7 +6270,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -6257,7 +6270,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6257 if (logic_cc) { 6270 if (logic_cc) {
6258 gen_logic_CC(tmp2); 6271 gen_logic_CC(tmp2);
6259 } 6272 }
6260 - store_reg(s, rd, tmp2); 6273 + store_reg_bx(env, s, rd, tmp2);
6261 break; 6274 break;
6262 } 6275 }
6263 if (op1 != 0x0f && op1 != 0x0d) { 6276 if (op1 != 0x0f && op1 != 0x0d) {
@@ -7359,7 +7372,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) @@ -7359,7 +7372,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
7359 gen_arm_shift_reg(tmp, op, tmp2, logic_cc); 7372 gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
7360 if (logic_cc) 7373 if (logic_cc)
7361 gen_logic_CC(tmp); 7374 gen_logic_CC(tmp);
7362 - store_reg(s, rd, tmp); 7375 + store_reg_bx(env, s, rd, tmp);
7363 break; 7376 break;
7364 case 1: /* Sign/zero extend. */ 7377 case 1: /* Sign/zero extend. */
7365 tmp = load_reg(s, rm); 7378 tmp = load_reg(s, rm);