Commit 5899f386ba9474d0bb0c055f9276d8923845cbd3
1 parent
6a0f9e82
ARM thumb fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1418 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
55 additions
and
34 deletions
target-arm/op.c
... | ... | @@ -824,12 +824,13 @@ void OPPROTO op_shrl_T0_im_thumb(void) |
824 | 824 | |
825 | 825 | shift = PARAM1; |
826 | 826 | if (shift == 0) { |
827 | - env->CF = 0; | |
827 | + env->CF = ((uint32_t)shift) >> 31; | |
828 | 828 | T0 = 0; |
829 | 829 | } else { |
830 | 830 | env->CF = (T0 >> (shift - 1)) & 1; |
831 | 831 | T0 = T0 >> shift; |
832 | 832 | } |
833 | + env->NZF = T0; | |
833 | 834 | FORCE_RET(); |
834 | 835 | } |
835 | 836 | ... | ... |
target-arm/translate.c
... | ... | @@ -38,6 +38,7 @@ typedef struct DisasContext { |
38 | 38 | int condlabel; |
39 | 39 | struct TranslationBlock *tb; |
40 | 40 | int singlestep_enabled; |
41 | + int thumb; | |
41 | 42 | } DisasContext; |
42 | 43 | |
43 | 44 | #define DISAS_JUMP_NEXT 4 |
... | ... | @@ -268,8 +269,11 @@ static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t) |
268 | 269 | int val; |
269 | 270 | |
270 | 271 | if (reg == 15) { |
271 | - /* normaly, since we updated PC, we need only to add 4 */ | |
272 | - val = (long)s->pc + 4; | |
272 | + /* normaly, since we updated PC, we need only to add one insn */ | |
273 | + if (s->thumb) | |
274 | + val = (long)s->pc + 2; | |
275 | + else | |
276 | + val = (long)s->pc + 4; | |
273 | 277 | gen_op_movl_TN_im[t](val); |
274 | 278 | } else { |
275 | 279 | gen_op_movl_TN_reg[t][reg](); |
... | ... | @@ -897,6 +901,8 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest) |
897 | 901 | { |
898 | 902 | if (__builtin_expect(s->singlestep_enabled, 0)) { |
899 | 903 | /* An indirect jump so that we still trigger the debug exception. */ |
904 | + if (s->thumb) | |
905 | + dest |= 1; | |
900 | 906 | gen_op_movl_T0_im(dest); |
901 | 907 | gen_bx(s); |
902 | 908 | } else { |
... | ... | @@ -1552,7 +1558,7 @@ static void disas_thumb_insn(DisasContext *s) |
1552 | 1558 | gen_movl_T1_reg(s, rm); |
1553 | 1559 | } |
1554 | 1560 | if (insn & (1 << 9)) |
1555 | - gen_op_addl_T0_T1_cc(); | |
1561 | + gen_op_subl_T0_T1_cc(); | |
1556 | 1562 | else |
1557 | 1563 | gen_op_addl_T0_T1_cc(); |
1558 | 1564 | gen_movl_reg_T0(s, rd); |
... | ... | @@ -1595,11 +1601,10 @@ static void disas_thumb_insn(DisasContext *s) |
1595 | 1601 | case 4: |
1596 | 1602 | if (insn & (1 << 11)) { |
1597 | 1603 | rd = (insn >> 8) & 7; |
1598 | - /* load pc-relative */ | |
1599 | - val = (insn & 0xff) * 4; | |
1604 | + /* load pc-relative. Bit 1 of PC is ignored. */ | |
1605 | + val = s->pc + 2 + ((insn & 0xff) * 4); | |
1606 | + val &= ~(uint32_t)2; | |
1600 | 1607 | gen_op_movl_T1_im(val); |
1601 | - gen_movl_T2_reg(s, 15); | |
1602 | - gen_op_addl_T1_T2(); | |
1603 | 1608 | gen_op_ldl_T0_T1(); |
1604 | 1609 | gen_movl_reg_T0(s, rd); |
1605 | 1610 | break; |
... | ... | @@ -1658,7 +1663,7 @@ static void disas_thumb_insn(DisasContext *s) |
1658 | 1663 | gen_movl_T0_reg(s, rd); |
1659 | 1664 | |
1660 | 1665 | gen_movl_T1_reg(s, rm); |
1661 | - switch (insn >> 6) { | |
1666 | + switch (op) { | |
1662 | 1667 | case 0x0: /* and */ |
1663 | 1668 | gen_op_andl_T0_T1(); |
1664 | 1669 | gen_op_logic_T0_cc(); |
... | ... | @@ -1689,8 +1694,9 @@ static void disas_thumb_insn(DisasContext *s) |
1689 | 1694 | gen_op_andl_T0_T1(); |
1690 | 1695 | gen_op_logic_T0_cc(); |
1691 | 1696 | rd = 16; |
1697 | + break; | |
1692 | 1698 | case 0x9: /* neg */ |
1693 | - gen_op_rsbl_T0_T1_cc(); | |
1699 | + gen_op_subl_T0_T1_cc(); | |
1694 | 1700 | break; |
1695 | 1701 | case 0xa: /* cmp */ |
1696 | 1702 | gen_op_subl_T0_T1_cc(); |
... | ... | @@ -1716,11 +1722,12 @@ static void disas_thumb_insn(DisasContext *s) |
1716 | 1722 | gen_op_notl_T1(); |
1717 | 1723 | gen_op_logic_T1_cc(); |
1718 | 1724 | val = 1; |
1725 | + rm = rd; | |
1719 | 1726 | break; |
1720 | 1727 | } |
1721 | 1728 | if (rd != 16) { |
1722 | 1729 | if (val) |
1723 | - gen_movl_reg_T1(s, rd); | |
1730 | + gen_movl_reg_T1(s, rm); | |
1724 | 1731 | else |
1725 | 1732 | gen_movl_reg_T0(s, rd); |
1726 | 1733 | } |
... | ... | @@ -1756,7 +1763,7 @@ static void disas_thumb_insn(DisasContext *s) |
1756 | 1763 | gen_op_ldl_T0_T1(); |
1757 | 1764 | break; |
1758 | 1765 | case 5: /* ldrh */ |
1759 | - gen_op_ldsw_T0_T1(); | |
1766 | + gen_op_lduw_T0_T1(); | |
1760 | 1767 | break; |
1761 | 1768 | case 6: /* ldrb */ |
1762 | 1769 | gen_op_ldub_T0_T1(); |
... | ... | @@ -1851,11 +1858,13 @@ static void disas_thumb_insn(DisasContext *s) |
1851 | 1858 | case 10: |
1852 | 1859 | /* add to high reg */ |
1853 | 1860 | rd = (insn >> 8) & 7; |
1854 | - if (insn & (1 << 11)) | |
1855 | - rm = 13; /* sp */ | |
1856 | - else | |
1857 | - rm = 15; /* pc */ | |
1858 | - gen_movl_T0_reg(s, rm); | |
1861 | + if (insn & (1 << 11)) { | |
1862 | + /* SP */ | |
1863 | + gen_movl_T0_reg(s, 13); | |
1864 | + } else { | |
1865 | + /* PC. bit 1 is ignored. */ | |
1866 | + gen_op_movl_T0_im((s->pc + 2) & ~(uint32_t)2); | |
1867 | + } | |
1859 | 1868 | val = (insn & 0xff) * 4; |
1860 | 1869 | gen_op_movl_T1_im(val); |
1861 | 1870 | gen_op_addl_T0_T1(); |
... | ... | @@ -1880,11 +1889,19 @@ static void disas_thumb_insn(DisasContext *s) |
1880 | 1889 | case 4: case 5: case 0xc: case 0xd: |
1881 | 1890 | /* push/pop */ |
1882 | 1891 | gen_movl_T1_reg(s, 13); |
1883 | - if (insn & (1 << 11)) | |
1884 | - val = 4; | |
1892 | + if (insn & (1 << 8)) | |
1893 | + offset = 4; | |
1885 | 1894 | else |
1886 | - val = -4; | |
1887 | - gen_op_movl_T2_im(val); | |
1895 | + offset = 0; | |
1896 | + for (i = 0; i < 8; i++) { | |
1897 | + if (insn & (1 << i)) | |
1898 | + offset += 4; | |
1899 | + } | |
1900 | + if ((insn & (1 << 11)) == 0) { | |
1901 | + gen_op_movl_T2_im(-offset); | |
1902 | + gen_op_addl_T1_T2(); | |
1903 | + } | |
1904 | + gen_op_movl_T2_im(4); | |
1888 | 1905 | for (i = 0; i < 8; i++) { |
1889 | 1906 | if (insn & (1 << i)) { |
1890 | 1907 | if (insn & (1 << 11)) { |
... | ... | @@ -1896,7 +1913,7 @@ static void disas_thumb_insn(DisasContext *s) |
1896 | 1913 | gen_movl_T0_reg(s, i); |
1897 | 1914 | gen_op_stl_T0_T1(); |
1898 | 1915 | } |
1899 | - /* move to the next address */ | |
1916 | + /* advance to the next address. */ | |
1900 | 1917 | gen_op_addl_T1_T2(); |
1901 | 1918 | } |
1902 | 1919 | } |
... | ... | @@ -1913,7 +1930,10 @@ static void disas_thumb_insn(DisasContext *s) |
1913 | 1930 | } |
1914 | 1931 | gen_op_addl_T1_T2(); |
1915 | 1932 | } |
1916 | - | |
1933 | + if ((insn & (1 << 11)) == 0) { | |
1934 | + gen_op_movl_T2_im(-offset); | |
1935 | + gen_op_addl_T1_T2(); | |
1936 | + } | |
1917 | 1937 | /* write back the new stack pointer */ |
1918 | 1938 | gen_movl_reg_T1(s, 13); |
1919 | 1939 | /* set the new PC value */ |
... | ... | @@ -1931,14 +1951,8 @@ static void disas_thumb_insn(DisasContext *s) |
1931 | 1951 | rn = (insn >> 8) & 0x7; |
1932 | 1952 | gen_movl_T1_reg(s, rn); |
1933 | 1953 | gen_op_movl_T2_im(4); |
1934 | - val = 0; | |
1935 | 1954 | for (i = 0; i < 8; i++) { |
1936 | 1955 | if (insn & (1 << i)) { |
1937 | - /* advance to the next address */ | |
1938 | - if (val) | |
1939 | - gen_op_addl_T1_T2(); | |
1940 | - else | |
1941 | - val = 1; | |
1942 | 1956 | if (insn & (1 << 11)) { |
1943 | 1957 | /* load */ |
1944 | 1958 | gen_op_ldl_T0_T1(); |
... | ... | @@ -1948,8 +1962,12 @@ static void disas_thumb_insn(DisasContext *s) |
1948 | 1962 | gen_movl_T0_reg(s, i); |
1949 | 1963 | gen_op_stl_T0_T1(); |
1950 | 1964 | } |
1965 | + /* advance to the next address */ | |
1966 | + gen_op_addl_T1_T2(); | |
1951 | 1967 | } |
1952 | 1968 | } |
1969 | + /* Base register writeback. */ | |
1970 | + gen_movl_reg_T1(s, rn); | |
1953 | 1971 | break; |
1954 | 1972 | |
1955 | 1973 | case 13: |
... | ... | @@ -1976,9 +1994,9 @@ static void disas_thumb_insn(DisasContext *s) |
1976 | 1994 | gen_movl_T1_reg(s, 15); |
1977 | 1995 | |
1978 | 1996 | /* jump to the offset */ |
1979 | - val = (uint32_t)s->pc; | |
1997 | + val = (uint32_t)s->pc + 2; | |
1980 | 1998 | offset = ((int32_t)insn << 24) >> 24; |
1981 | - val += (offset << 1) + 2; | |
1999 | + val += offset << 1; | |
1982 | 2000 | gen_jmp(s, val); |
1983 | 2001 | break; |
1984 | 2002 | |
... | ... | @@ -2002,19 +2020,20 @@ static void disas_thumb_insn(DisasContext *s) |
2002 | 2020 | gen_op_movl_T1_im(val | 1); |
2003 | 2021 | gen_movl_reg_T1(s, 14); |
2004 | 2022 | |
2005 | - val += offset; | |
2023 | + val += offset << 1; | |
2006 | 2024 | if (insn & (1 << 11)) { |
2007 | 2025 | /* bl */ |
2008 | 2026 | gen_jmp(s, val); |
2009 | 2027 | } else { |
2010 | 2028 | /* blx */ |
2029 | + val &= ~(uint32_t)2; | |
2011 | 2030 | gen_op_movl_T0_im(val); |
2012 | 2031 | gen_bx(s); |
2013 | 2032 | } |
2014 | 2033 | } |
2015 | 2034 | return; |
2016 | 2035 | undef: |
2017 | - gen_op_movl_T0_im((long)s->pc - 4); | |
2036 | + gen_op_movl_T0_im((long)s->pc - 2); | |
2018 | 2037 | gen_op_movl_reg_TN[0][15](); |
2019 | 2038 | gen_op_undef_insn(); |
2020 | 2039 | s->is_jmp = DISAS_JUMP; |
... | ... | @@ -2045,6 +2064,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
2045 | 2064 | dc->pc = pc_start; |
2046 | 2065 | dc->singlestep_enabled = env->singlestep_enabled; |
2047 | 2066 | dc->condjmp = 0; |
2067 | + dc->thumb = env->thumb; | |
2048 | 2068 | nb_gen_labels = 0; |
2049 | 2069 | lj = -1; |
2050 | 2070 | do { |
... | ... | @@ -2128,7 +2148,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
2128 | 2148 | if (loglevel & CPU_LOG_TB_IN_ASM) { |
2129 | 2149 | fprintf(logfile, "----------------\n"); |
2130 | 2150 | fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); |
2131 | - target_disas(logfile, pc_start, dc->pc - pc_start, 0); | |
2151 | + target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb); | |
2132 | 2152 | fprintf(logfile, "\n"); |
2133 | 2153 | if (loglevel & (CPU_LOG_TB_OP)) { |
2134 | 2154 | fprintf(logfile, "OP:\n"); | ... | ... |