Commit 98daeaf68f8250e1ca38974ac05406a4620098a6

Authored by Filip Navara
1 parent 8f171993

Fix SRS/RFE instructions

The encoding of 'IA' and 'DB' conditions was swapped.
SRS instruction must store banked SPSR instead of CPSR at the specific address.
Missing 'return' statement at the end of RFE handling.
Fixed write-back code to reference correct registers.

From: Hyeonsung Jang <hsjang@ok-labs.com>
Signed-off-by: Filip Navara <filip.navara@gmail.com>
Showing 1 changed file with 16 additions and 15 deletions
target-arm/translate.c
... ... @@ -5753,7 +5753,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5753 5753 }
5754 5754 } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
5755 5755 /* srs */
5756   - uint32_t offset;
  5756 + int32_t offset;
5757 5757 if (IS_USER(s))
5758 5758 goto illegal_op;
5759 5759 ARCH(6);
... ... @@ -5767,8 +5767,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5767 5767 i = (insn >> 23) & 3;
5768 5768 switch (i) {
5769 5769 case 0: offset = -4; break; /* DA */
5770   - case 1: offset = -8; break; /* DB */
5771   - case 2: offset = 0; break; /* IA */
  5770 + case 1: offset = 0; break; /* IA */
  5771 + case 2: offset = -8; break; /* DB */
5772 5772 case 3: offset = 4; break; /* IB */
5773 5773 default: abort();
5774 5774 }
... ... @@ -5776,32 +5776,32 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5776 5776 tcg_gen_addi_i32(addr, addr, offset);
5777 5777 tmp = load_reg(s, 14);
5778 5778 gen_st32(tmp, addr, 0);
5779   - tmp = new_tmp();
5780   - gen_helper_cpsr_read(tmp);
  5779 + tmp = load_cpu_field(spsr);
5781 5780 tcg_gen_addi_i32(addr, addr, 4);
5782 5781 gen_st32(tmp, addr, 0);
5783 5782 if (insn & (1 << 21)) {
5784 5783 /* Base writeback. */
5785 5784 switch (i) {
5786 5785 case 0: offset = -8; break;
5787   - case 1: offset = -4; break;
5788   - case 2: offset = 4; break;
  5786 + case 1: offset = 4; break;
  5787 + case 2: offset = -4; break;
5789 5788 case 3: offset = 0; break;
5790 5789 default: abort();
5791 5790 }
5792 5791 if (offset)
5793   - tcg_gen_addi_i32(addr, tmp, offset);
  5792 + tcg_gen_addi_i32(addr, addr, offset);
5794 5793 if (op1 == (env->uncached_cpsr & CPSR_M)) {
5795   - gen_movl_reg_T1(s, 13);
  5794 + store_reg(s, 13, addr);
5796 5795 } else {
5797   - gen_helper_set_r13_banked(cpu_env, tcg_const_i32(op1), cpu_T[1]);
  5796 + gen_helper_set_r13_banked(cpu_env, tcg_const_i32(op1), addr);
  5797 + dead_tmp(addr);
5798 5798 }
5799 5799 } else {
5800 5800 dead_tmp(addr);
5801 5801 }
5802 5802 } else if ((insn & 0x0e5fffe0) == 0x081d0a00) {
5803 5803 /* rfe */
5804   - uint32_t offset;
  5804 + int32_t offset;
5805 5805 if (IS_USER(s))
5806 5806 goto illegal_op;
5807 5807 ARCH(6);
... ... @@ -5810,8 +5810,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5810 5810 i = (insn >> 23) & 3;
5811 5811 switch (i) {
5812 5812 case 0: offset = -4; break; /* DA */
5813   - case 1: offset = -8; break; /* DB */
5814   - case 2: offset = 0; break; /* IA */
  5813 + case 1: offset = 0; break; /* IA */
  5814 + case 2: offset = -8; break; /* DB */
5815 5815 case 3: offset = 4; break; /* IB */
5816 5816 default: abort();
5817 5817 }
... ... @@ -5825,8 +5825,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5825 5825 /* Base writeback. */
5826 5826 switch (i) {
5827 5827 case 0: offset = -8; break;
5828   - case 1: offset = -4; break;
5829   - case 2: offset = 4; break;
  5828 + case 1: offset = 4; break;
  5829 + case 2: offset = -4; break;
5830 5830 case 3: offset = 0; break;
5831 5831 default: abort();
5832 5832 }
... ... @@ -5837,6 +5837,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5837 5837 dead_tmp(addr);
5838 5838 }
5839 5839 gen_rfe(s, tmp, tmp2);
  5840 + return;
5840 5841 } else if ((insn & 0x0e000000) == 0x0a000000) {
5841 5842 /* branch link and change to thumb (blx <offset>) */
5842 5843 int32_t offset;
... ...