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