Commit 98daeaf68f8250e1ca38974ac05406a4620098a6
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; | ... | ... |