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 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 836 static inline TCGv gen_ld8s(TCGv addr, int index)
824 837 {
825 838 TCGv tmp = new_tmp();
... ... @@ -6131,14 +6144,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6131 6144 if (logic_cc) {
6132 6145 gen_logic_CC(tmp);
6133 6146 }
6134   - store_reg(s, rd, tmp);
  6147 + store_reg_bx(env, s, rd, tmp);
6135 6148 break;
6136 6149 case 0x01:
6137 6150 tcg_gen_xor_i32(tmp, tmp, tmp2);
6138 6151 if (logic_cc) {
6139 6152 gen_logic_CC(tmp);
6140 6153 }
6141   - store_reg(s, rd, tmp);
  6154 + store_reg_bx(env, s, rd, tmp);
6142 6155 break;
6143 6156 case 0x02:
6144 6157 if (set_cc && rd == 15) {
... ... @@ -6154,7 +6167,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6154 6167 } else {
6155 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 6172 break;
6160 6173 case 0x03:
... ... @@ -6163,7 +6176,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6163 6176 } else {
6164 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 6180 break;
6168 6181 case 0x04:
6169 6182 if (set_cc) {
... ... @@ -6171,7 +6184,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6171 6184 } else {
6172 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 6188 break;
6176 6189 case 0x05:
6177 6190 if (set_cc) {
... ... @@ -6179,7 +6192,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6179 6192 } else {
6180 6193 gen_add_carry(tmp, tmp, tmp2);
6181 6194 }
6182   - store_reg(s, rd, tmp);
  6195 + store_reg_bx(env, s, rd, tmp);
6183 6196 break;
6184 6197 case 0x06:
6185 6198 if (set_cc) {
... ... @@ -6187,7 +6200,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6187 6200 } else {
6188 6201 gen_sub_carry(tmp, tmp, tmp2);
6189 6202 }
6190   - store_reg(s, rd, tmp);
  6203 + store_reg_bx(env, s, rd, tmp);
6191 6204 break;
6192 6205 case 0x07:
6193 6206 if (set_cc) {
... ... @@ -6195,7 +6208,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6195 6208 } else {
6196 6209 gen_sub_carry(tmp, tmp2, tmp);
6197 6210 }
6198   - store_reg(s, rd, tmp);
  6211 + store_reg_bx(env, s, rd, tmp);
6199 6212 break;
6200 6213 case 0x08:
6201 6214 if (set_cc) {
... ... @@ -6228,7 +6241,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6228 6241 if (logic_cc) {
6229 6242 gen_logic_CC(tmp);
6230 6243 }
6231   - store_reg(s, rd, tmp);
  6244 + store_reg_bx(env, s, rd, tmp);
6232 6245 break;
6233 6246 case 0x0d:
6234 6247 if (logic_cc && rd == 15) {
... ... @@ -6241,7 +6254,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6241 6254 if (logic_cc) {
6242 6255 gen_logic_CC(tmp2);
6243 6256 }
6244   - store_reg(s, rd, tmp2);
  6257 + store_reg_bx(env, s, rd, tmp2);
6245 6258 }
6246 6259 break;
6247 6260 case 0x0e:
... ... @@ -6249,7 +6262,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6249 6262 if (logic_cc) {
6250 6263 gen_logic_CC(tmp);
6251 6264 }
6252   - store_reg(s, rd, tmp);
  6265 + store_reg_bx(env, s, rd, tmp);
6253 6266 break;
6254 6267 default:
6255 6268 case 0x0f:
... ... @@ -6257,7 +6270,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6257 6270 if (logic_cc) {
6258 6271 gen_logic_CC(tmp2);
6259 6272 }
6260   - store_reg(s, rd, tmp2);
  6273 + store_reg_bx(env, s, rd, tmp2);
6261 6274 break;
6262 6275 }
6263 6276 if (op1 != 0x0f && op1 != 0x0d) {
... ... @@ -7359,7 +7372,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
7359 7372 gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
7360 7373 if (logic_cc)
7361 7374 gen_logic_CC(tmp);
7362   - store_reg(s, rd, tmp);
  7375 + store_reg_bx(env, s, rd, tmp);
7363 7376 break;
7364 7377 case 1: /* Sign/zero extend. */
7365 7378 tmp = load_reg(s, rm);
... ...