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,7 +5753,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5753 } 5753 }
5754 } else if ((insn & 0x0e5fffe0) == 0x084d0500) { 5754 } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
5755 /* srs */ 5755 /* srs */
5756 - uint32_t offset; 5756 + int32_t offset;
5757 if (IS_USER(s)) 5757 if (IS_USER(s))
5758 goto illegal_op; 5758 goto illegal_op;
5759 ARCH(6); 5759 ARCH(6);
@@ -5767,8 +5767,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -5767,8 +5767,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5767 i = (insn >> 23) & 3; 5767 i = (insn >> 23) & 3;
5768 switch (i) { 5768 switch (i) {
5769 case 0: offset = -4; break; /* DA */ 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 case 3: offset = 4; break; /* IB */ 5772 case 3: offset = 4; break; /* IB */
5773 default: abort(); 5773 default: abort();
5774 } 5774 }
@@ -5776,32 +5776,32 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -5776,32 +5776,32 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5776 tcg_gen_addi_i32(addr, addr, offset); 5776 tcg_gen_addi_i32(addr, addr, offset);
5777 tmp = load_reg(s, 14); 5777 tmp = load_reg(s, 14);
5778 gen_st32(tmp, addr, 0); 5778 gen_st32(tmp, addr, 0);
5779 - tmp = new_tmp();  
5780 - gen_helper_cpsr_read(tmp); 5779 + tmp = load_cpu_field(spsr);
5781 tcg_gen_addi_i32(addr, addr, 4); 5780 tcg_gen_addi_i32(addr, addr, 4);
5782 gen_st32(tmp, addr, 0); 5781 gen_st32(tmp, addr, 0);
5783 if (insn & (1 << 21)) { 5782 if (insn & (1 << 21)) {
5784 /* Base writeback. */ 5783 /* Base writeback. */
5785 switch (i) { 5784 switch (i) {
5786 case 0: offset = -8; break; 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 case 3: offset = 0; break; 5788 case 3: offset = 0; break;
5790 default: abort(); 5789 default: abort();
5791 } 5790 }
5792 if (offset) 5791 if (offset)
5793 - tcg_gen_addi_i32(addr, tmp, offset); 5792 + tcg_gen_addi_i32(addr, addr, offset);
5794 if (op1 == (env->uncached_cpsr & CPSR_M)) { 5793 if (op1 == (env->uncached_cpsr & CPSR_M)) {
5795 - gen_movl_reg_T1(s, 13); 5794 + store_reg(s, 13, addr);
5796 } else { 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 } else { 5799 } else {
5800 dead_tmp(addr); 5800 dead_tmp(addr);
5801 } 5801 }
5802 } else if ((insn & 0x0e5fffe0) == 0x081d0a00) { 5802 } else if ((insn & 0x0e5fffe0) == 0x081d0a00) {
5803 /* rfe */ 5803 /* rfe */
5804 - uint32_t offset; 5804 + int32_t offset;
5805 if (IS_USER(s)) 5805 if (IS_USER(s))
5806 goto illegal_op; 5806 goto illegal_op;
5807 ARCH(6); 5807 ARCH(6);
@@ -5810,8 +5810,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -5810,8 +5810,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5810 i = (insn >> 23) & 3; 5810 i = (insn >> 23) & 3;
5811 switch (i) { 5811 switch (i) {
5812 case 0: offset = -4; break; /* DA */ 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 case 3: offset = 4; break; /* IB */ 5815 case 3: offset = 4; break; /* IB */
5816 default: abort(); 5816 default: abort();
5817 } 5817 }
@@ -5825,8 +5825,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -5825,8 +5825,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5825 /* Base writeback. */ 5825 /* Base writeback. */
5826 switch (i) { 5826 switch (i) {
5827 case 0: offset = -8; break; 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 case 3: offset = 0; break; 5830 case 3: offset = 0; break;
5831 default: abort(); 5831 default: abort();
5832 } 5832 }
@@ -5837,6 +5837,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) @@ -5837,6 +5837,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5837 dead_tmp(addr); 5837 dead_tmp(addr);
5838 } 5838 }
5839 gen_rfe(s, tmp, tmp2); 5839 gen_rfe(s, tmp, tmp2);
  5840 + return;
5840 } else if ((insn & 0x0e000000) == 0x0a000000) { 5841 } else if ((insn & 0x0e000000) == 0x0a000000) {
5841 /* branch link and change to thumb (blx <offset>) */ 5842 /* branch link and change to thumb (blx <offset>) */
5842 int32_t offset; 5843 int32_t offset;