Revision 9ee6e8bb target-arm/translate.c
b/target-arm/translate.c | ||
---|---|---|
2 | 2 |
* ARM translation |
3 | 3 |
* |
4 | 4 |
* Copyright (c) 2003 Fabrice Bellard |
5 |
* Copyright (c) 2005 CodeSourcery, LLC
|
|
5 |
* Copyright (c) 2005-2007 CodeSourcery
|
|
6 | 6 |
* Copyright (c) 2007 OpenedHand, Ltd. |
7 | 7 |
* |
8 | 8 |
* This library is free software; you can redistribute it and/or |
... | ... | |
29 | 29 |
#include "exec-all.h" |
30 | 30 |
#include "disas.h" |
31 | 31 |
|
32 |
#define ENABLE_ARCH_5J 0 |
|
33 |
#define ENABLE_ARCH_6 1 |
|
34 |
#define ENABLE_ARCH_6T2 1 |
|
32 |
#define ENABLE_ARCH_5J 0 |
|
33 |
#define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6) |
|
34 |
#define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K) |
|
35 |
#define ENABLE_ARCH_6T2 arm_feature(env, ARM_FEATURE_THUMB2) |
|
36 |
#define ENABLE_ARCH_7 arm_feature(env, ARM_FEATURE_V7) |
|
35 | 37 |
|
36 | 38 |
#define ARCH(x) if (!ENABLE_ARCH_##x) goto illegal_op; |
37 | 39 |
|
... | ... | |
43 | 45 |
int condjmp; |
44 | 46 |
/* The label that will be jumped to when the instruction is skipped. */ |
45 | 47 |
int condlabel; |
48 |
/* Thumb-2 condtional execution bits. */ |
|
49 |
int condexec_mask; |
|
50 |
int condexec_cond; |
|
46 | 51 |
struct TranslationBlock *tb; |
47 | 52 |
int singlestep_enabled; |
48 | 53 |
int thumb; |
... | ... | |
58 | 63 |
#define IS_USER(s) (s->user) |
59 | 64 |
#endif |
60 | 65 |
|
61 |
#define DISAS_JUMP_NEXT 4 |
|
66 |
/* These instructions trap after executing, so defer them until after the |
|
67 |
conditional executions state has been updated. */ |
|
68 |
#define DISAS_WFI 4 |
|
69 |
#define DISAS_SWI 5 |
|
62 | 70 |
|
63 | 71 |
#ifdef USE_DIRECT_JUMP |
64 | 72 |
#define TBPARAM(x) |
... | ... | |
81 | 89 |
|
82 | 90 |
#include "gen-op.h" |
83 | 91 |
|
92 |
#define PAS_OP(pfx) { \ |
|
93 |
gen_op_ ## pfx ## add16_T0_T1, \ |
|
94 |
gen_op_ ## pfx ## addsubx_T0_T1, \ |
|
95 |
gen_op_ ## pfx ## subaddx_T0_T1, \ |
|
96 |
gen_op_ ## pfx ## sub16_T0_T1, \ |
|
97 |
gen_op_ ## pfx ## add8_T0_T1, \ |
|
98 |
NULL, \ |
|
99 |
NULL, \ |
|
100 |
gen_op_ ## pfx ## sub8_T0_T1 } |
|
101 |
|
|
102 |
static GenOpFunc *gen_arm_parallel_addsub[8][8] = { |
|
103 |
{}, |
|
104 |
PAS_OP(s), |
|
105 |
PAS_OP(q), |
|
106 |
PAS_OP(sh), |
|
107 |
{}, |
|
108 |
PAS_OP(u), |
|
109 |
PAS_OP(uq), |
|
110 |
PAS_OP(uh), |
|
111 |
}; |
|
112 |
#undef PAS_OP |
|
113 |
|
|
114 |
/* For unknown reasons Arm and Thumb-2 use arbitrarily diffenet encodings. */ |
|
115 |
#define PAS_OP(pfx) { \ |
|
116 |
gen_op_ ## pfx ## add8_T0_T1, \ |
|
117 |
gen_op_ ## pfx ## add16_T0_T1, \ |
|
118 |
gen_op_ ## pfx ## addsubx_T0_T1, \ |
|
119 |
NULL, \ |
|
120 |
gen_op_ ## pfx ## sub8_T0_T1, \ |
|
121 |
gen_op_ ## pfx ## sub16_T0_T1, \ |
|
122 |
gen_op_ ## pfx ## subaddx_T0_T1, \ |
|
123 |
NULL } |
|
124 |
|
|
125 |
static GenOpFunc *gen_thumb2_parallel_addsub[8][8] = { |
|
126 |
PAS_OP(s), |
|
127 |
PAS_OP(q), |
|
128 |
PAS_OP(sh), |
|
129 |
{}, |
|
130 |
PAS_OP(u), |
|
131 |
PAS_OP(uq), |
|
132 |
PAS_OP(uh), |
|
133 |
{} |
|
134 |
}; |
|
135 |
#undef PAS_OP |
|
136 |
|
|
84 | 137 |
static GenOpFunc1 *gen_test_cc[14] = { |
85 | 138 |
gen_op_test_eq, |
86 | 139 |
gen_op_test_ne, |
... | ... | |
275 | 328 |
gen_op_movl_T2_im, |
276 | 329 |
}; |
277 | 330 |
|
331 |
static GenOpFunc1 *gen_shift_T0_im_thumb_cc[3] = { |
|
332 |
gen_op_shll_T0_im_thumb_cc, |
|
333 |
gen_op_shrl_T0_im_thumb_cc, |
|
334 |
gen_op_sarl_T0_im_thumb_cc, |
|
335 |
}; |
|
336 |
|
|
278 | 337 |
static GenOpFunc1 *gen_shift_T0_im_thumb[3] = { |
279 | 338 |
gen_op_shll_T0_im_thumb, |
280 | 339 |
gen_op_shrl_T0_im_thumb, |
... | ... | |
421 | 480 |
gen_op_vfp_##name##s(); \ |
422 | 481 |
} |
423 | 482 |
|
483 |
#define VFP_OP1(name) \ |
|
484 |
static inline void gen_vfp_##name(int dp, int arg) \ |
|
485 |
{ \ |
|
486 |
if (dp) \ |
|
487 |
gen_op_vfp_##name##d(arg); \ |
|
488 |
else \ |
|
489 |
gen_op_vfp_##name##s(arg); \ |
|
490 |
} |
|
491 |
|
|
424 | 492 |
VFP_OP(add) |
425 | 493 |
VFP_OP(sub) |
426 | 494 |
VFP_OP(mul) |
... | ... | |
437 | 505 |
VFP_OP(touiz) |
438 | 506 |
VFP_OP(tosi) |
439 | 507 |
VFP_OP(tosiz) |
508 |
VFP_OP1(tosh) |
|
509 |
VFP_OP1(tosl) |
|
510 |
VFP_OP1(touh) |
|
511 |
VFP_OP1(toul) |
|
512 |
VFP_OP1(shto) |
|
513 |
VFP_OP1(slto) |
|
514 |
VFP_OP1(uhto) |
|
515 |
VFP_OP1(ulto) |
|
440 | 516 |
|
441 | 517 |
#undef VFP_OP |
442 | 518 |
|
519 |
static inline void gen_vfp_fconst(int dp, uint32_t val) |
|
520 |
{ |
|
521 |
if (dp) |
|
522 |
gen_op_vfp_fconstd(val); |
|
523 |
else |
|
524 |
gen_op_vfp_fconsts(val); |
|
525 |
} |
|
526 |
|
|
443 | 527 |
static inline void gen_vfp_ld(DisasContext *s, int dp) |
444 | 528 |
{ |
445 | 529 |
if (dp) |
... | ... | |
469 | 553 |
+ offsetof(CPU_DoubleU, l.lower); |
470 | 554 |
} |
471 | 555 |
} |
556 |
|
|
557 |
/* Return the offset of a 32-bit piece of a NEON register. |
|
558 |
zero is the least significant end of the register. */ |
|
559 |
static inline long |
|
560 |
neon_reg_offset (int reg, int n) |
|
561 |
{ |
|
562 |
int sreg; |
|
563 |
sreg = reg * 2 + n; |
|
564 |
return vfp_reg_offset(0, sreg); |
|
565 |
} |
|
566 |
|
|
567 |
#define NEON_GET_REG(T, reg, n) gen_op_neon_getreg_##T(neon_reg_offset(reg, n)) |
|
568 |
#define NEON_SET_REG(T, reg, n) gen_op_neon_setreg_##T(neon_reg_offset(reg, n)) |
|
569 |
|
|
472 | 570 |
static inline void gen_mov_F0_vreg(int dp, int reg) |
473 | 571 |
{ |
474 | 572 |
if (dp) |
... | ... | |
1582 | 1680 |
return 0; |
1583 | 1681 |
} |
1584 | 1682 |
|
1683 |
static int cp15_user_ok(uint32_t insn) |
|
1684 |
{ |
|
1685 |
int cpn = (insn >> 16) & 0xf; |
|
1686 |
int cpm = insn & 0xf; |
|
1687 |
int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38); |
|
1688 |
|
|
1689 |
if (cpn == 13 && cpm == 0) { |
|
1690 |
/* TLS register. */ |
|
1691 |
if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT))) |
|
1692 |
return 1; |
|
1693 |
} |
|
1694 |
if (cpn == 7) { |
|
1695 |
/* ISB, DSB, DMB. */ |
|
1696 |
if ((cpm == 5 && op == 4) |
|
1697 |
|| (cpm == 10 && (op == 4 || op == 5))) |
|
1698 |
return 1; |
|
1699 |
} |
|
1700 |
return 0; |
|
1701 |
} |
|
1702 |
|
|
1585 | 1703 |
/* Disassemble system coprocessor (cp15) instruction. Return nonzero if |
1586 | 1704 |
instruction is not defined. */ |
1587 | 1705 |
static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn) |
1588 | 1706 |
{ |
1589 | 1707 |
uint32_t rd; |
1590 | 1708 |
|
1591 |
/* ??? Some cp15 registers are accessible from userspace. */ |
|
1592 |
if (IS_USER(s)) { |
|
1709 |
/* M profile cores use memory mapped registers instead of cp15. */ |
|
1710 |
if (arm_feature(env, ARM_FEATURE_M)) |
|
1711 |
return 1; |
|
1712 |
|
|
1713 |
if ((insn & (1 << 25)) == 0) { |
|
1714 |
if (insn & (1 << 20)) { |
|
1715 |
/* mrrc */ |
|
1716 |
return 1; |
|
1717 |
} |
|
1718 |
/* mcrr. Used for block cache operations, so implement as no-op. */ |
|
1719 |
return 0; |
|
1720 |
} |
|
1721 |
if ((insn & (1 << 4)) == 0) { |
|
1722 |
/* cdp */ |
|
1723 |
return 1; |
|
1724 |
} |
|
1725 |
if (IS_USER(s) && !cp15_user_ok(insn)) { |
|
1593 | 1726 |
return 1; |
1594 | 1727 |
} |
1595 | 1728 |
if ((insn & 0x0fff0fff) == 0x0e070f90 |
... | ... | |
1597 | 1730 |
/* Wait for interrupt. */ |
1598 | 1731 |
gen_op_movl_T0_im((long)s->pc); |
1599 | 1732 |
gen_op_movl_reg_TN[0][15](); |
1600 |
gen_op_wfi(); |
|
1601 |
s->is_jmp = DISAS_JUMP; |
|
1733 |
s->is_jmp = DISAS_WFI; |
|
1602 | 1734 |
return 0; |
1603 | 1735 |
} |
1604 | 1736 |
rd = (insn >> 12) & 0xf; |
... | ... | |
1620 | 1752 |
return 0; |
1621 | 1753 |
} |
1622 | 1754 |
|
1755 |
#define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n)) |
|
1756 |
#define VFP_SREG(insn, bigbit, smallbit) \ |
|
1757 |
((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1)) |
|
1758 |
#define VFP_DREG(reg, insn, bigbit, smallbit) do { \ |
|
1759 |
if (arm_feature(env, ARM_FEATURE_VFP3)) { \ |
|
1760 |
reg = (((insn) >> (bigbit)) & 0x0f) \ |
|
1761 |
| (((insn) >> ((smallbit) - 4)) & 0x10); \ |
|
1762 |
} else { \ |
|
1763 |
if (insn & (1 << (smallbit))) \ |
|
1764 |
return 1; \ |
|
1765 |
reg = ((insn) >> (bigbit)) & 0x0f; \ |
|
1766 |
}} while (0) |
|
1767 |
|
|
1768 |
#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22) |
|
1769 |
#define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22) |
|
1770 |
#define VFP_SREG_N(insn) VFP_SREG(insn, 16, 7) |
|
1771 |
#define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16, 7) |
|
1772 |
#define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5) |
|
1773 |
#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5) |
|
1774 |
|
|
1775 |
static inline int |
|
1776 |
vfp_enabled(CPUState * env) |
|
1777 |
{ |
|
1778 |
return ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) != 0); |
|
1779 |
} |
|
1780 |
|
|
1623 | 1781 |
/* Disassemble a VFP instruction. Returns nonzero if an error occured |
1624 | 1782 |
(ie. an undefined instruction). */ |
1625 | 1783 |
static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) |
... | ... | |
1630 | 1788 |
if (!arm_feature(env, ARM_FEATURE_VFP)) |
1631 | 1789 |
return 1; |
1632 | 1790 |
|
1633 |
if ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) == 0) {
|
|
1634 |
/* VFP disabled. Only allow fmxr/fmrx to/from fpexc and fpsid. */
|
|
1791 |
if (!vfp_enabled(env)) {
|
|
1792 |
/* VFP disabled. Only allow fmxr/fmrx to/from some control regs. */
|
|
1635 | 1793 |
if ((insn & 0x0fe00fff) != 0x0ee00a10) |
1636 | 1794 |
return 1; |
1637 | 1795 |
rn = (insn >> 16) & 0xf; |
1638 |
if (rn != 0 && rn != 8) |
|
1796 |
if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC |
|
1797 |
&& rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0) |
|
1639 | 1798 |
return 1; |
1640 | 1799 |
} |
1641 | 1800 |
dp = ((insn & 0xf00) == 0xb00); |
... | ... | |
1643 | 1802 |
case 0xe: |
1644 | 1803 |
if (insn & (1 << 4)) { |
1645 | 1804 |
/* single register transfer */ |
1646 |
if ((insn & 0x6f) != 0x00) |
|
1647 |
return 1; |
|
1648 | 1805 |
rd = (insn >> 12) & 0xf; |
1649 | 1806 |
if (dp) { |
1650 |
if (insn & 0x80) |
|
1807 |
int size; |
|
1808 |
int pass; |
|
1809 |
|
|
1810 |
VFP_DREG_N(rn, insn); |
|
1811 |
if (insn & 0xf) |
|
1651 | 1812 |
return 1; |
1652 |
rn = (insn >> 16) & 0xf; |
|
1653 |
/* Get the existing value even for arm->vfp moves because |
|
1654 |
we only set half the register. */ |
|
1655 |
gen_mov_F0_vreg(1, rn); |
|
1656 |
gen_op_vfp_mrrd(); |
|
1813 |
if (insn & 0x00c00060 |
|
1814 |
&& !arm_feature(env, ARM_FEATURE_NEON)) |
|
1815 |
return 1; |
|
1816 |
|
|
1817 |
pass = (insn >> 21) & 1; |
|
1818 |
if (insn & (1 << 22)) { |
|
1819 |
size = 0; |
|
1820 |
offset = ((insn >> 5) & 3) * 8; |
|
1821 |
} else if (insn & (1 << 5)) { |
|
1822 |
size = 1; |
|
1823 |
offset = (insn & (1 << 6)) ? 16 : 0; |
|
1824 |
} else { |
|
1825 |
size = 2; |
|
1826 |
offset = 0; |
|
1827 |
} |
|
1657 | 1828 |
if (insn & ARM_CP_RW_BIT) { |
1658 | 1829 |
/* vfp->arm */ |
1659 |
if (insn & (1 << 21)) |
|
1660 |
gen_movl_reg_T1(s, rd); |
|
1661 |
else |
|
1662 |
gen_movl_reg_T0(s, rd); |
|
1830 |
switch (size) { |
|
1831 |
case 0: |
|
1832 |
NEON_GET_REG(T1, rn, pass); |
|
1833 |
if (offset) |
|
1834 |
gen_op_shrl_T1_im(offset); |
|
1835 |
if (insn & (1 << 23)) |
|
1836 |
gen_op_uxtb_T1(); |
|
1837 |
else |
|
1838 |
gen_op_sxtb_T1(); |
|
1839 |
break; |
|
1840 |
case 1: |
|
1841 |
NEON_GET_REG(T1, rn, pass); |
|
1842 |
if (insn & (1 << 23)) { |
|
1843 |
if (offset) { |
|
1844 |
gen_op_shrl_T1_im(16); |
|
1845 |
} else { |
|
1846 |
gen_op_uxth_T1(); |
|
1847 |
} |
|
1848 |
} else { |
|
1849 |
if (offset) { |
|
1850 |
gen_op_sarl_T1_im(16); |
|
1851 |
} else { |
|
1852 |
gen_op_sxth_T1(); |
|
1853 |
} |
|
1854 |
} |
|
1855 |
break; |
|
1856 |
case 2: |
|
1857 |
NEON_GET_REG(T1, rn, pass); |
|
1858 |
break; |
|
1859 |
} |
|
1860 |
gen_movl_reg_T1(s, rd); |
|
1663 | 1861 |
} else { |
1664 | 1862 |
/* arm->vfp */ |
1665 |
if (insn & (1 << 21)) |
|
1666 |
gen_movl_T1_reg(s, rd); |
|
1667 |
else |
|
1668 |
gen_movl_T0_reg(s, rd); |
|
1669 |
gen_op_vfp_mdrr(); |
|
1670 |
gen_mov_vreg_F0(dp, rn); |
|
1863 |
gen_movl_T0_reg(s, rd); |
|
1864 |
if (insn & (1 << 23)) { |
|
1865 |
/* VDUP */ |
|
1866 |
if (size == 0) { |
|
1867 |
gen_op_neon_dup_u8(0); |
|
1868 |
} else if (size == 1) { |
|
1869 |
gen_op_neon_dup_low16(); |
|
1870 |
} |
|
1871 |
NEON_SET_REG(T0, rn, 0); |
|
1872 |
NEON_SET_REG(T0, rn, 1); |
|
1873 |
} else { |
|
1874 |
/* VMOV */ |
|
1875 |
switch (size) { |
|
1876 |
case 0: |
|
1877 |
NEON_GET_REG(T2, rn, pass); |
|
1878 |
gen_op_movl_T1_im(0xff); |
|
1879 |
gen_op_andl_T0_T1(); |
|
1880 |
gen_op_neon_insert_elt(offset, ~(0xff << offset)); |
|
1881 |
NEON_SET_REG(T2, rn, pass); |
|
1882 |
break; |
|
1883 |
case 1: |
|
1884 |
NEON_GET_REG(T2, rn, pass); |
|
1885 |
gen_op_movl_T1_im(0xffff); |
|
1886 |
gen_op_andl_T0_T1(); |
|
1887 |
bank_mask = offset ? 0xffff : 0xffff0000; |
|
1888 |
gen_op_neon_insert_elt(offset, bank_mask); |
|
1889 |
NEON_SET_REG(T2, rn, pass); |
|
1890 |
break; |
|
1891 |
case 2: |
|
1892 |
NEON_SET_REG(T0, rn, pass); |
|
1893 |
break; |
|
1894 |
} |
|
1895 |
} |
|
1671 | 1896 |
} |
1672 |
} else { |
|
1673 |
rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1); |
|
1897 |
} else { /* !dp */ |
|
1898 |
if ((insn & 0x6f) != 0x00) |
|
1899 |
return 1; |
|
1900 |
rn = VFP_SREG_N(insn); |
|
1674 | 1901 |
if (insn & ARM_CP_RW_BIT) { |
1675 | 1902 |
/* vfp->arm */ |
1676 | 1903 |
if (insn & (1 << 21)) { |
1677 | 1904 |
/* system register */ |
1678 | 1905 |
rn >>= 1; |
1906 |
|
|
1679 | 1907 |
switch (rn) { |
1680 | 1908 |
case ARM_VFP_FPSID: |
1909 |
/* VFP2 allows access for FSID from userspace. |
|
1910 |
VFP3 restricts all id registers to privileged |
|
1911 |
accesses. */ |
|
1912 |
if (IS_USER(s) |
|
1913 |
&& arm_feature(env, ARM_FEATURE_VFP3)) |
|
1914 |
return 1; |
|
1915 |
gen_op_vfp_movl_T0_xreg(rn); |
|
1916 |
break; |
|
1681 | 1917 |
case ARM_VFP_FPEXC: |
1918 |
if (IS_USER(s)) |
|
1919 |
return 1; |
|
1920 |
gen_op_vfp_movl_T0_xreg(rn); |
|
1921 |
break; |
|
1682 | 1922 |
case ARM_VFP_FPINST: |
1683 | 1923 |
case ARM_VFP_FPINST2: |
1924 |
/* Not present in VFP3. */ |
|
1925 |
if (IS_USER(s) |
|
1926 |
|| arm_feature(env, ARM_FEATURE_VFP3)) |
|
1927 |
return 1; |
|
1684 | 1928 |
gen_op_vfp_movl_T0_xreg(rn); |
1685 | 1929 |
break; |
1686 | 1930 |
case ARM_VFP_FPSCR: |
... | ... | |
1689 | 1933 |
else |
1690 | 1934 |
gen_op_vfp_movl_T0_fpscr(); |
1691 | 1935 |
break; |
1936 |
case ARM_VFP_MVFR0: |
|
1937 |
case ARM_VFP_MVFR1: |
|
1938 |
if (IS_USER(s) |
|
1939 |
|| !arm_feature(env, ARM_FEATURE_VFP3)) |
|
1940 |
return 1; |
|
1941 |
gen_op_vfp_movl_T0_xreg(rn); |
|
1942 |
break; |
|
1692 | 1943 |
default: |
1693 | 1944 |
return 1; |
1694 | 1945 |
} |
... | ... | |
1709 | 1960 |
/* system register */ |
1710 | 1961 |
switch (rn) { |
1711 | 1962 |
case ARM_VFP_FPSID: |
1963 |
case ARM_VFP_MVFR0: |
|
1964 |
case ARM_VFP_MVFR1: |
|
1712 | 1965 |
/* Writes are ignored. */ |
1713 | 1966 |
break; |
1714 | 1967 |
case ARM_VFP_FPSCR: |
... | ... | |
1716 | 1969 |
gen_lookup_tb(s); |
1717 | 1970 |
break; |
1718 | 1971 |
case ARM_VFP_FPEXC: |
1972 |
if (IS_USER(s)) |
|
1973 |
return 1; |
|
1719 | 1974 |
gen_op_vfp_movl_xreg_T0(rn); |
1720 | 1975 |
gen_lookup_tb(s); |
1721 | 1976 |
break; |
... | ... | |
1742 | 1997 |
rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1); |
1743 | 1998 |
} else { |
1744 | 1999 |
/* rn is register number */ |
1745 |
if (insn & (1 << 7)) |
|
1746 |
return 1; |
|
1747 |
rn = (insn >> 16) & 0xf; |
|
2000 |
VFP_DREG_N(rn, insn); |
|
1748 | 2001 |
} |
1749 | 2002 |
|
1750 | 2003 |
if (op == 15 && (rn == 15 || rn > 17)) { |
1751 | 2004 |
/* Integer or single precision destination. */ |
1752 |
rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
|
|
2005 |
rd = VFP_SREG_D(insn);
|
|
1753 | 2006 |
} else { |
1754 |
if (insn & (1 << 22)) |
|
1755 |
return 1; |
|
1756 |
rd = (insn >> 12) & 0xf; |
|
2007 |
VFP_DREG_D(rd, insn); |
|
1757 | 2008 |
} |
1758 | 2009 |
|
1759 | 2010 |
if (op == 15 && (rn == 16 || rn == 17)) { |
1760 | 2011 |
/* Integer source. */ |
1761 | 2012 |
rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1); |
1762 | 2013 |
} else { |
1763 |
if (insn & (1 << 5)) |
|
1764 |
return 1; |
|
1765 |
rm = insn & 0xf; |
|
2014 |
VFP_DREG_M(rm, insn); |
|
1766 | 2015 |
} |
1767 | 2016 |
} else { |
1768 |
rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
|
|
2017 |
rn = VFP_SREG_N(insn);
|
|
1769 | 2018 |
if (op == 15 && rn == 15) { |
1770 | 2019 |
/* Double precision destination. */ |
1771 |
if (insn & (1 << 22)) |
|
1772 |
return 1; |
|
1773 |
rd = (insn >> 12) & 0xf; |
|
1774 |
} else |
|
1775 |
rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1); |
|
1776 |
rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1); |
|
2020 |
VFP_DREG_D(rd, insn); |
|
2021 |
} else { |
|
2022 |
rd = VFP_SREG_D(insn); |
|
2023 |
} |
|
2024 |
rm = VFP_SREG_M(insn); |
|
1777 | 2025 |
} |
1778 | 2026 |
|
1779 | 2027 |
veclen = env->vfp.vec_len; |
... | ... | |
1831 | 2079 |
gen_mov_F0_vreg(dp, rd); |
1832 | 2080 |
gen_vfp_F1_ld0(dp); |
1833 | 2081 |
break; |
2082 |
case 20: |
|
2083 |
case 21: |
|
2084 |
case 22: |
|
2085 |
case 23: |
|
2086 |
/* Source and destination the same. */ |
|
2087 |
gen_mov_F0_vreg(dp, rd); |
|
2088 |
break; |
|
1834 | 2089 |
default: |
1835 | 2090 |
/* One source operand. */ |
1836 | 2091 |
gen_mov_F0_vreg(dp, rm); |
2092 |
break; |
|
1837 | 2093 |
} |
1838 | 2094 |
} else { |
1839 | 2095 |
/* Two source operands. */ |
... | ... | |
1882 | 2138 |
case 8: /* div: fn / fm */ |
1883 | 2139 |
gen_vfp_div(dp); |
1884 | 2140 |
break; |
2141 |
case 14: /* fconst */ |
|
2142 |
if (!arm_feature(env, ARM_FEATURE_VFP3)) |
|
2143 |
return 1; |
|
2144 |
|
|
2145 |
n = (insn << 12) & 0x80000000; |
|
2146 |
i = ((insn >> 12) & 0x70) | (insn & 0xf); |
|
2147 |
if (dp) { |
|
2148 |
if (i & 0x40) |
|
2149 |
i |= 0x3f80; |
|
2150 |
else |
|
2151 |
i |= 0x4000; |
|
2152 |
n |= i << 16; |
|
2153 |
} else { |
|
2154 |
if (i & 0x40) |
|
2155 |
i |= 0x780; |
|
2156 |
else |
|
2157 |
i |= 0x800; |
|
2158 |
n |= i << 19; |
|
2159 |
} |
|
2160 |
gen_vfp_fconst(dp, n); |
|
2161 |
break; |
|
1885 | 2162 |
case 15: /* extension space */ |
1886 | 2163 |
switch (rn) { |
1887 | 2164 |
case 0: /* cpy */ |
... | ... | |
1921 | 2198 |
case 17: /* fsito */ |
1922 | 2199 |
gen_vfp_sito(dp); |
1923 | 2200 |
break; |
2201 |
case 20: /* fshto */ |
|
2202 |
if (!arm_feature(env, ARM_FEATURE_VFP3)) |
|
2203 |
return 1; |
|
2204 |
gen_vfp_shto(dp, rm); |
|
2205 |
break; |
|
2206 |
case 21: /* fslto */ |
|
2207 |
if (!arm_feature(env, ARM_FEATURE_VFP3)) |
|
2208 |
return 1; |
|
2209 |
gen_vfp_slto(dp, rm); |
|
2210 |
break; |
|
2211 |
case 22: /* fuhto */ |
|
2212 |
if (!arm_feature(env, ARM_FEATURE_VFP3)) |
|
2213 |
return 1; |
|
2214 |
gen_vfp_uhto(dp, rm); |
|
2215 |
break; |
|
2216 |
case 23: /* fulto */ |
|
2217 |
if (!arm_feature(env, ARM_FEATURE_VFP3)) |
|
2218 |
return 1; |
|
2219 |
gen_vfp_ulto(dp, rm); |
|
2220 |
break; |
|
1924 | 2221 |
case 24: /* ftoui */ |
1925 | 2222 |
gen_vfp_toui(dp); |
1926 | 2223 |
break; |
... | ... | |
1933 | 2230 |
case 27: /* ftosiz */ |
1934 | 2231 |
gen_vfp_tosiz(dp); |
1935 | 2232 |
break; |
2233 |
case 28: /* ftosh */ |
|
2234 |
if (!arm_feature(env, ARM_FEATURE_VFP3)) |
|
2235 |
return 1; |
|
2236 |
gen_vfp_tosh(dp, rm); |
|
2237 |
break; |
|
2238 |
case 29: /* ftosl */ |
|
2239 |
if (!arm_feature(env, ARM_FEATURE_VFP3)) |
|
2240 |
return 1; |
|
2241 |
gen_vfp_tosl(dp, rm); |
|
2242 |
break; |
|
2243 |
case 30: /* ftouh */ |
|
2244 |
if (!arm_feature(env, ARM_FEATURE_VFP3)) |
|
2245 |
return 1; |
|
2246 |
gen_vfp_touh(dp, rm); |
|
2247 |
break; |
|
2248 |
case 31: /* ftoul */ |
|
2249 |
if (!arm_feature(env, ARM_FEATURE_VFP3)) |
|
2250 |
return 1; |
|
2251 |
gen_vfp_toul(dp, rm); |
|
2252 |
break; |
|
1936 | 2253 |
default: /* undefined */ |
1937 | 2254 |
printf ("rn:%d\n", rn); |
1938 | 2255 |
return 1; |
... | ... | |
1994 | 2311 |
break; |
1995 | 2312 |
case 0xc: |
1996 | 2313 |
case 0xd: |
1997 |
if (dp && (insn & (1 << 22))) {
|
|
2314 |
if (dp && (insn & 0x03e00000) == 0x00400000) {
|
|
1998 | 2315 |
/* two-register transfer */ |
1999 | 2316 |
rn = (insn >> 16) & 0xf; |
2000 | 2317 |
rd = (insn >> 12) & 0xf; |
2001 | 2318 |
if (dp) { |
2002 |
if (insn & (1 << 5)) |
|
2003 |
return 1; |
|
2004 |
rm = insn & 0xf; |
|
2005 |
} else |
|
2006 |
rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1); |
|
2319 |
VFP_DREG_M(rm, insn); |
|
2320 |
} else { |
|
2321 |
rm = VFP_SREG_M(insn); |
|
2322 |
} |
|
2007 | 2323 |
|
2008 | 2324 |
if (insn & ARM_CP_RW_BIT) { |
2009 | 2325 |
/* vfp->arm */ |
... | ... | |
2040 | 2356 |
/* Load/store */ |
2041 | 2357 |
rn = (insn >> 16) & 0xf; |
2042 | 2358 |
if (dp) |
2043 |
rd = (insn >> 12) & 0xf;
|
|
2359 |
VFP_DREG_D(rd, insn);
|
|
2044 | 2360 |
else |
2045 |
rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1); |
|
2046 |
gen_movl_T1_reg(s, rn); |
|
2361 |
rd = VFP_SREG_D(insn); |
|
2362 |
if (s->thumb && rn == 15) { |
|
2363 |
gen_op_movl_T1_im(s->pc & ~2); |
|
2364 |
} else { |
|
2365 |
gen_movl_T1_reg(s, rn); |
|
2366 |
} |
|
2047 | 2367 |
if ((insn & 0x01200000) == 0x01000000) { |
2048 | 2368 |
/* Single load/store */ |
2049 | 2369 |
offset = (insn & 0xff) << 2; |
... | ... | |
2156 | 2476 |
} |
2157 | 2477 |
|
2158 | 2478 |
/* Return the mask of PSR bits set by a MSR instruction. */ |
2159 |
static uint32_t msr_mask(DisasContext *s, int flags, int spsr) { |
|
2479 |
static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) {
|
|
2160 | 2480 |
uint32_t mask; |
2481 |
uint32_t reserved; |
|
2161 | 2482 |
|
2162 | 2483 |
mask = 0; |
2163 | 2484 |
if (flags & (1 << 0)) |
... | ... | |
2168 | 2489 |
mask |= 0xff0000; |
2169 | 2490 |
if (flags & (1 << 3)) |
2170 | 2491 |
mask |= 0xff000000; |
2492 |
|
|
2171 | 2493 |
/* Mask out undefined bits. */ |
2172 |
mask &= 0xf90f03ff; |
|
2173 |
/* Mask out state bits. */ |
|
2494 |
mask &= ~CPSR_RESERVED; |
|
2495 |
if (!arm_feature(env, ARM_FEATURE_V6)) |
|
2496 |
reserved &= ~(CPSR_E | CPSR_GE); |
|
2497 |
if (!arm_feature(env, ARM_FEATURE_THUMB2)) |
|
2498 |
reserved &= ~CPSR_IT; |
|
2499 |
/* Mask out execution state bits. */ |
|
2174 | 2500 |
if (!spsr) |
2175 |
mask &= ~0x01000020;
|
|
2501 |
reserved &= ~CPSR_EXEC;
|
|
2176 | 2502 |
/* Mask out privileged bits. */ |
2177 | 2503 |
if (IS_USER(s)) |
2178 |
mask &= 0xf80f0200;
|
|
2504 |
mask &= CPSR_USER;
|
|
2179 | 2505 |
return mask; |
2180 | 2506 |
} |
2181 | 2507 |
|
... | ... | |
2194 | 2520 |
return 0; |
2195 | 2521 |
} |
2196 | 2522 |
|
2523 |
/* Generate an old-style exception return. */ |
|
2197 | 2524 |
static void gen_exception_return(DisasContext *s) |
2198 | 2525 |
{ |
2199 | 2526 |
gen_op_movl_reg_TN[0][15](); |
... | ... | |
2202 | 2529 |
s->is_jmp = DISAS_UPDATE; |
2203 | 2530 |
} |
2204 | 2531 |
|
2205 |
static void disas_arm_insn(CPUState * env, DisasContext *s) |
|
2532 |
/* Generate a v6 exception return. */ |
|
2533 |
static void gen_rfe(DisasContext *s) |
|
2206 | 2534 |
{ |
2207 |
unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; |
|
2535 |
gen_op_movl_cpsr_T0(0xffffffff); |
|
2536 |
gen_op_movl_T0_T2(); |
|
2537 |
gen_op_movl_reg_TN[0][15](); |
|
2538 |
s->is_jmp = DISAS_UPDATE; |
|
2539 |
} |
|
2208 | 2540 |
|
2209 |
insn = ldl_code(s->pc); |
|
2210 |
s->pc += 4; |
|
2541 |
static inline void |
|
2542 |
gen_set_condexec (DisasContext *s) |
|
2543 |
{ |
|
2544 |
if (s->condexec_mask) { |
|
2545 |
gen_op_set_condexec((s->condexec_cond << 4) | (s->condexec_mask >> 1)); |
|
2546 |
} |
|
2547 |
} |
|
2211 | 2548 |
|
2212 |
cond = insn >> 28; |
|
2213 |
if (cond == 0xf){ |
|
2214 |
/* Unconditional instructions. */ |
|
2215 |
if ((insn & 0x0d70f000) == 0x0550f000) |
|
2216 |
return; /* PLD */ |
|
2217 |
else if ((insn & 0x0e000000) == 0x0a000000) { |
|
2218 |
/* branch link and change to thumb (blx <offset>) */ |
|
2219 |
int32_t offset; |
|
2549 |
static void gen_nop_hint(DisasContext *s, int val) |
|
2550 |
{ |
|
2551 |
switch (val) { |
|
2552 |
case 3: /* wfi */ |
|
2553 |
gen_op_movl_T0_im((long)s->pc); |
|
2554 |
gen_op_movl_reg_TN[0][15](); |
|
2555 |
s->is_jmp = DISAS_WFI; |
|
2556 |
break; |
|
2557 |
case 2: /* wfe */ |
|
2558 |
case 4: /* sev */ |
|
2559 |
/* TODO: Implement SEV and WFE. May help SMP performance. */ |
|
2560 |
default: /* nop */ |
|
2561 |
break; |
|
2562 |
} |
|
2563 |
} |
|
2220 | 2564 |
|
2221 |
val = (uint32_t)s->pc; |
|
2222 |
gen_op_movl_T0_im(val); |
|
2223 |
gen_movl_reg_T0(s, 14); |
|
2224 |
/* Sign-extend the 24-bit offset */ |
|
2225 |
offset = (((int32_t)insn) << 8) >> 8; |
|
2226 |
/* offset * 4 + bit24 * 2 + (thumb bit) */ |
|
2227 |
val += (offset << 2) | ((insn >> 23) & 2) | 1; |
|
2228 |
/* pipeline offset */ |
|
2229 |
val += 4; |
|
2230 |
gen_op_movl_T0_im(val); |
|
2231 |
gen_bx(s); |
|
2232 |
return; |
|
2233 |
} else if ((insn & 0x0e000f00) == 0x0c000100) { |
|
2234 |
if (arm_feature(env, ARM_FEATURE_IWMMXT)) { |
|
2235 |
/* iWMMXt register transfer. */ |
|
2236 |
if (env->cp15.c15_cpar & (1 << 1)) |
|
2237 |
if (!disas_iwmmxt_insn(env, s, insn)) |
|
2238 |
return; |
|
2239 |
} |
|
2240 |
} else if ((insn & 0x0fe00000) == 0x0c400000) { |
|
2241 |
/* Coprocessor double register transfer. */ |
|
2242 |
} else if ((insn & 0x0f000010) == 0x0e000010) { |
|
2243 |
/* Additional coprocessor register transfer. */ |
|
2244 |
} else if ((insn & 0x0ff10010) == 0x01000000) { |
|
2245 |
/* cps (privileged) */ |
|
2246 |
} else if ((insn & 0x0ffffdff) == 0x01010000) { |
|
2247 |
/* setend */ |
|
2248 |
if (insn & (1 << 9)) { |
|
2249 |
/* BE8 mode not implemented. */ |
|
2250 |
goto illegal_op; |
|
2251 |
} |
|
2252 |
return; |
|
2253 |
} |
|
2254 |
goto illegal_op; |
|
2565 |
/* Neon shift by constant. The actual ops are the same as used for variable |
|
2566 |
shifts. [OP][U][SIZE] */ |
|
2567 |
static GenOpFunc *gen_neon_shift_im[8][2][4] = { |
|
2568 |
{ /* 0 */ /* VSHR */ |
|
2569 |
{ |
|
2570 |
gen_op_neon_shl_u8, |
|
2571 |
gen_op_neon_shl_u16, |
|
2572 |
gen_op_neon_shl_u32, |
|
2573 |
gen_op_neon_shl_u64 |
|
2574 |
}, { |
|
2575 |
gen_op_neon_shl_s8, |
|
2576 |
gen_op_neon_shl_s16, |
|
2577 |
gen_op_neon_shl_s32, |
|
2578 |
gen_op_neon_shl_s64 |
|
2579 |
} |
|
2580 |
}, { /* 1 */ /* VSRA */ |
|
2581 |
{ |
|
2582 |
gen_op_neon_shl_u8, |
|
2583 |
gen_op_neon_shl_u16, |
|
2584 |
gen_op_neon_shl_u32, |
|
2585 |
gen_op_neon_shl_u64 |
|
2586 |
}, { |
|
2587 |
gen_op_neon_shl_s8, |
|
2588 |
gen_op_neon_shl_s16, |
|
2589 |
gen_op_neon_shl_s32, |
|
2590 |
gen_op_neon_shl_s64 |
|
2591 |
} |
|
2592 |
}, { /* 2 */ /* VRSHR */ |
|
2593 |
{ |
|
2594 |
gen_op_neon_rshl_u8, |
|
2595 |
gen_op_neon_rshl_u16, |
|
2596 |
gen_op_neon_rshl_u32, |
|
2597 |
gen_op_neon_rshl_u64 |
|
2598 |
}, { |
|
2599 |
gen_op_neon_rshl_s8, |
|
2600 |
gen_op_neon_rshl_s16, |
|
2601 |
gen_op_neon_rshl_s32, |
|
2602 |
gen_op_neon_rshl_s64 |
|
2603 |
} |
|
2604 |
}, { /* 3 */ /* VRSRA */ |
|
2605 |
{ |
|
2606 |
gen_op_neon_rshl_u8, |
|
2607 |
gen_op_neon_rshl_u16, |
|
2608 |
gen_op_neon_rshl_u32, |
|
2609 |
gen_op_neon_rshl_u64 |
|
2610 |
}, { |
|
2611 |
gen_op_neon_rshl_s8, |
|
2612 |
gen_op_neon_rshl_s16, |
|
2613 |
gen_op_neon_rshl_s32, |
|
2614 |
gen_op_neon_rshl_s64 |
|
2615 |
} |
|
2616 |
}, { /* 4 */ |
|
2617 |
{ |
|
2618 |
NULL, NULL, NULL, NULL |
|
2619 |
}, { /* VSRI */ |
|
2620 |
gen_op_neon_shl_u8, |
|
2621 |
gen_op_neon_shl_u16, |
|
2622 |
gen_op_neon_shl_u32, |
|
2623 |
gen_op_neon_shl_u64, |
|
2624 |
} |
|
2625 |
}, { /* 5 */ |
|
2626 |
{ /* VSHL */ |
|
2627 |
gen_op_neon_shl_u8, |
|
2628 |
gen_op_neon_shl_u16, |
|
2629 |
gen_op_neon_shl_u32, |
|
2630 |
gen_op_neon_shl_u64, |
|
2631 |
}, { /* VSLI */ |
|
2632 |
gen_op_neon_shl_u8, |
|
2633 |
gen_op_neon_shl_u16, |
|
2634 |
gen_op_neon_shl_u32, |
|
2635 |
gen_op_neon_shl_u64, |
|
2636 |
} |
|
2637 |
}, { /* 6 */ /* VQSHL */ |
|
2638 |
{ |
|
2639 |
gen_op_neon_qshl_u8, |
|
2640 |
gen_op_neon_qshl_u16, |
|
2641 |
gen_op_neon_qshl_u32, |
|
2642 |
gen_op_neon_qshl_u64 |
|
2643 |
}, { |
|
2644 |
gen_op_neon_qshl_s8, |
|
2645 |
gen_op_neon_qshl_s16, |
|
2646 |
gen_op_neon_qshl_s32, |
|
2647 |
gen_op_neon_qshl_s64 |
|
2648 |
} |
|
2649 |
}, { /* 7 */ /* VQSHLU */ |
|
2650 |
{ |
|
2651 |
gen_op_neon_qshl_u8, |
|
2652 |
gen_op_neon_qshl_u16, |
|
2653 |
gen_op_neon_qshl_u32, |
|
2654 |
gen_op_neon_qshl_u64 |
|
2655 |
}, { |
|
2656 |
gen_op_neon_qshl_u8, |
|
2657 |
gen_op_neon_qshl_u16, |
|
2658 |
gen_op_neon_qshl_u32, |
|
2659 |
gen_op_neon_qshl_u64 |
|
2660 |
} |
|
2255 | 2661 |
} |
2256 |
if (cond != 0xe) { |
|
2257 |
/* if not always execute, we generate a conditional jump to |
|
2258 |
next instruction */ |
|
2259 |
s->condlabel = gen_new_label(); |
|
2260 |
gen_test_cc[cond ^ 1](s->condlabel); |
|
2261 |
s->condjmp = 1; |
|
2262 |
//gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); |
|
2263 |
//s->is_jmp = DISAS_JUMP_NEXT; |
|
2662 |
}; |
|
2663 |
|
|
2664 |
/* [R][U][size - 1] */ |
|
2665 |
static GenOpFunc *gen_neon_shift_im_narrow[2][2][3] = { |
|
2666 |
{ |
|
2667 |
{ |
|
2668 |
gen_op_neon_shl_u16, |
|
2669 |
gen_op_neon_shl_u32, |
|
2670 |
gen_op_neon_shl_u64 |
|
2671 |
}, { |
|
2672 |
gen_op_neon_shl_s16, |
|
2673 |
gen_op_neon_shl_s32, |
|
2674 |
gen_op_neon_shl_s64 |
|
2675 |
} |
|
2676 |
}, { |
|
2677 |
{ |
|
2678 |
gen_op_neon_rshl_u16, |
|
2679 |
gen_op_neon_rshl_u32, |
|
2680 |
gen_op_neon_rshl_u64 |
|
2681 |
}, { |
|
2682 |
gen_op_neon_rshl_s16, |
|
2683 |
gen_op_neon_rshl_s32, |
|
2684 |
gen_op_neon_rshl_s64 |
|
2685 |
} |
|
2264 | 2686 |
} |
2265 |
if ((insn & 0x0f900000) == 0x03000000) { |
|
2266 |
if ((insn & 0x0fb0f000) != 0x0320f000) |
|
2267 |
goto illegal_op; |
|
2268 |
/* CPSR = immediate */ |
|
2269 |
val = insn & 0xff; |
|
2270 |
shift = ((insn >> 8) & 0xf) * 2; |
|
2271 |
if (shift) |
|
2272 |
val = (val >> shift) | (val << (32 - shift)); |
|
2273 |
gen_op_movl_T0_im(val); |
|
2274 |
i = ((insn & (1 << 22)) != 0); |
|
2275 |
if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i)) |
|
2276 |
goto illegal_op; |
|
2277 |
} else if ((insn & 0x0f900000) == 0x01000000 |
|
2278 |
&& (insn & 0x00000090) != 0x00000090) { |
|
2279 |
/* miscellaneous instructions */ |
|
2280 |
op1 = (insn >> 21) & 3; |
|
2281 |
sh = (insn >> 4) & 0xf; |
|
2282 |
rm = insn & 0xf; |
|
2283 |
switch (sh) { |
|
2284 |
case 0x0: /* move program status register */ |
|
2285 |
if (op1 & 1) { |
|
2286 |
/* PSR = reg */ |
|
2287 |
gen_movl_T0_reg(s, rm); |
|
2288 |
i = ((op1 & 2) != 0); |
|
2289 |
if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i)) |
|
2290 |
goto illegal_op; |
|
2291 |
} else { |
|
2292 |
/* reg = PSR */ |
|
2293 |
rd = (insn >> 12) & 0xf; |
|
2294 |
if (op1 & 2) { |
|
2295 |
if (IS_USER(s)) |
|
2296 |
goto illegal_op; |
|
2297 |
gen_op_movl_T0_spsr(); |
|
2298 |
} else { |
|
2299 |
gen_op_movl_T0_cpsr(); |
|
2300 |
} |
|
2301 |
gen_movl_reg_T0(s, rd); |
|
2302 |
} |
|
2303 |
break; |
|
2304 |
case 0x1: |
|
2305 |
if (op1 == 1) { |
|
2306 |
/* branch/exchange thumb (bx). */ |
|
2307 |
gen_movl_T0_reg(s, rm); |
|
2308 |
gen_bx(s); |
|
2309 |
} else if (op1 == 3) { |
|
2310 |
/* clz */ |
|
2311 |
rd = (insn >> 12) & 0xf; |
|
2312 |
gen_movl_T0_reg(s, rm); |
|
2313 |
gen_op_clz_T0(); |
|
2314 |
gen_movl_reg_T0(s, rd); |
|
2315 |
} else { |
|
2316 |
goto illegal_op; |
|
2317 |
} |
|
2318 |
break; |
|
2319 |
case 0x2: |
|
2320 |
if (op1 == 1) { |
|
2321 |
ARCH(5J); /* bxj */ |
|
2322 |
/* Trivial implementation equivalent to bx. */ |
|
2323 |
gen_movl_T0_reg(s, rm); |
|
2324 |
gen_bx(s); |
|
2325 |
} else { |
|
2326 |
goto illegal_op; |
|
2327 |
} |
|
2328 |
break; |
|
2329 |
case 0x3: |
|
2330 |
if (op1 != 1) |
|
2331 |
goto illegal_op; |
|
2687 |
}; |
|
2332 | 2688 |
|
2333 |
/* branch link/exchange thumb (blx) */ |
|
2334 |
val = (uint32_t)s->pc; |
|
2335 |
gen_op_movl_T1_im(val); |
|
2336 |
gen_movl_T0_reg(s, rm); |
|
2337 |
gen_movl_reg_T1(s, 14); |
|
2338 |
gen_bx(s); |
|
2339 |
break; |
|
2340 |
case 0x5: /* saturating add/subtract */ |
|
2341 |
rd = (insn >> 12) & 0xf; |
|
2342 |
rn = (insn >> 16) & 0xf; |
|
2343 |
gen_movl_T0_reg(s, rm); |
|
2689 |
static inline void |
|
2690 |
gen_op_neon_narrow_u32 () |
|
2691 |
{ |
|
2692 |
/* No-op. */ |
|
2693 |
} |
|
2694 |
|
|
2695 |
static GenOpFunc *gen_neon_narrow[3] = { |
|
2696 |
gen_op_neon_narrow_u8, |
|
2697 |
gen_op_neon_narrow_u16, |
|
2698 |
gen_op_neon_narrow_u32 |
|
2699 |
}; |
|
2700 |
|
|
2701 |
static GenOpFunc *gen_neon_narrow_satu[3] = { |
|
2702 |
gen_op_neon_narrow_sat_u8, |
|
2703 |
gen_op_neon_narrow_sat_u16, |
|
2704 |
gen_op_neon_narrow_sat_u32 |
|
2705 |
}; |
|
2706 |
|
|
2707 |
static GenOpFunc *gen_neon_narrow_sats[3] = { |
|
2708 |
gen_op_neon_narrow_sat_s8, |
|
2709 |
gen_op_neon_narrow_sat_s16, |
|
2710 |
gen_op_neon_narrow_sat_s32 |
|
2711 |
}; |
|
2712 |
|
|
2713 |
static inline int gen_neon_add(int size) |
|
2714 |
{ |
|
2715 |
switch (size) { |
|
2716 |
case 0: gen_op_neon_add_u8(); break; |
|
2717 |
case 1: gen_op_neon_add_u16(); break; |
|
2718 |
case 2: gen_op_addl_T0_T1(); break; |
|
2719 |
default: return 1; |
|
2720 |
} |
|
2721 |
return 0; |
|
2722 |
} |
|
2723 |
|
|
2724 |
/* 32-bit pairwise ops end up the same as the elementsise versions. */ |
|
2725 |
#define gen_op_neon_pmax_s32 gen_op_neon_max_s32 |
|
2726 |
#define gen_op_neon_pmax_u32 gen_op_neon_max_u32 |
|
2727 |
#define gen_op_neon_pmin_s32 gen_op_neon_min_s32 |
|
2728 |
#define gen_op_neon_pmin_u32 gen_op_neon_min_u32 |
|
2729 |
|
|
2730 |
#define GEN_NEON_INTEGER_OP(name) do { \ |
|
2731 |
switch ((size << 1) | u) { \ |
|
2732 |
case 0: gen_op_neon_##name##_s8(); break; \ |
|
2733 |
case 1: gen_op_neon_##name##_u8(); break; \ |
|
2734 |
case 2: gen_op_neon_##name##_s16(); break; \ |
|
2735 |
case 3: gen_op_neon_##name##_u16(); break; \ |
|
2736 |
case 4: gen_op_neon_##name##_s32(); break; \ |
|
2737 |
case 5: gen_op_neon_##name##_u32(); break; \ |
|
2738 |
default: return 1; \ |
|
2739 |
}} while (0) |
|
2740 |
|
|
2741 |
static inline void |
|
2742 |
gen_neon_movl_scratch_T0(int scratch) |
|
2743 |
{ |
|
2744 |
uint32_t offset; |
|
2745 |
|
|
2746 |
offset = offsetof(CPUARMState, vfp.scratch[scratch]); |
|
2747 |
gen_op_neon_setreg_T0(offset); |
|
2748 |
} |
|
2749 |
|
|
2750 |
static inline void |
|
2751 |
gen_neon_movl_scratch_T1(int scratch) |
|
2752 |
{ |
|
2753 |
uint32_t offset; |
|
2754 |
|
|
2755 |
offset = offsetof(CPUARMState, vfp.scratch[scratch]); |
|
2756 |
gen_op_neon_setreg_T1(offset); |
|
2757 |
} |
|
2758 |
|
|
2759 |
static inline void |
|
2760 |
gen_neon_movl_T0_scratch(int scratch) |
|
2761 |
{ |
|
2762 |
uint32_t offset; |
|
2763 |
|
|
2764 |
offset = offsetof(CPUARMState, vfp.scratch[scratch]); |
|
2765 |
gen_op_neon_getreg_T0(offset); |
|
2766 |
} |
|
2767 |
|
|
2768 |
static inline void |
|
2769 |
gen_neon_movl_T1_scratch(int scratch) |
|
2770 |
{ |
|
2771 |
uint32_t offset; |
|
2772 |
|
|
2773 |
offset = offsetof(CPUARMState, vfp.scratch[scratch]); |
|
2774 |
gen_op_neon_getreg_T1(offset); |
|
2775 |
} |
|
2776 |
|
|
2777 |
static inline void gen_op_neon_widen_u32(void) |
|
2778 |
{ |
|
2779 |
gen_op_movl_T1_im(0); |
|
2780 |
} |
|
2781 |
|
|
2782 |
static inline void gen_neon_get_scalar(int size, int reg) |
|
2783 |
{ |
|
2784 |
if (size == 1) { |
|
2785 |
NEON_GET_REG(T0, reg >> 1, reg & 1); |
|
2786 |
} else { |
|
2787 |
NEON_GET_REG(T0, reg >> 2, (reg >> 1) & 1); |
|
2788 |
if (reg & 1) |
|
2789 |
gen_op_neon_dup_low16(); |
|
2790 |
else |
|
2791 |
gen_op_neon_dup_high16(); |
|
2792 |
} |
|
2793 |
} |
|
2794 |
|
|
2795 |
static void gen_neon_unzip(int reg, int q, int tmp, int size) |
|
2796 |
{ |
|
2797 |
int n; |
|
2798 |
|
|
2799 |
for (n = 0; n < q + 1; n += 2) { |
|
2800 |
NEON_GET_REG(T0, reg, n); |
|
2801 |
NEON_GET_REG(T0, reg, n + n); |
|
2802 |
switch (size) { |
|
2803 |
case 0: gen_op_neon_unzip_u8(); break; |
|
2804 |
case 1: gen_op_neon_zip_u16(); break; /* zip and unzip are the same. */ |
|
2805 |
case 2: /* no-op */; break; |
|
2806 |
default: abort(); |
|
2807 |
} |
|
2808 |
gen_neon_movl_scratch_T0(tmp + n); |
|
2809 |
gen_neon_movl_scratch_T1(tmp + n + 1); |
|
2810 |
} |
|
2811 |
} |
|
2812 |
|
|
2813 |
static struct { |
|
2814 |
int nregs; |
|
2815 |
int interleave; |
|
2816 |
int spacing; |
|
2817 |
} neon_ls_element_type[11] = { |
|
2818 |
{4, 4, 1}, |
|
2819 |
{4, 4, 2}, |
|
2820 |
{4, 1, 1}, |
|
2821 |
{4, 2, 1}, |
|
2822 |
{3, 3, 1}, |
|
2823 |
{3, 3, 2}, |
|
2824 |
{3, 1, 1}, |
|
2825 |
{1, 1, 1}, |
|
2826 |
{2, 2, 1}, |
|
2827 |
{2, 2, 2}, |
|
2828 |
{2, 1, 1} |
|
2829 |
}; |
|
2830 |
|
|
2831 |
/* Translate a NEON load/store element instruction. Return nonzero if the |
|
2832 |
instruction is invalid. */ |
|
2833 |
static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) |
|
2834 |
{ |
|
2835 |
int rd, rn, rm; |
|
2836 |
int op; |
|
2837 |
int nregs; |
|
2838 |
int interleave; |
|
2839 |
int stride; |
|
2840 |
int size; |
|
2841 |
int reg; |
|
2842 |
int pass; |
|
2843 |
int load; |
|
2844 |
int shift; |
|
2845 |
uint32_t mask; |
|
2846 |
int n; |
|
2847 |
|
|
2848 |
if (!vfp_enabled(env)) |
|
2849 |
return 1; |
|
2850 |
VFP_DREG_D(rd, insn); |
|
2851 |
rn = (insn >> 16) & 0xf; |
|
2852 |
rm = insn & 0xf; |
|
2853 |
load = (insn & (1 << 21)) != 0; |
|
2854 |
if ((insn & (1 << 23)) == 0) { |
|
2855 |
/* Load store all elements. */ |
|
2856 |
op = (insn >> 8) & 0xf; |
|
2857 |
size = (insn >> 6) & 3; |
|
2858 |
if (op > 10 || size == 3) |
|
2859 |
return 1; |
|
2860 |
nregs = neon_ls_element_type[op].nregs; |
|
2861 |
interleave = neon_ls_element_type[op].interleave; |
|
2862 |
gen_movl_T1_reg(s, rn); |
|
2863 |
stride = (1 << size) * interleave; |
|
2864 |
for (reg = 0; reg < nregs; reg++) { |
|
2865 |
if (interleave > 2 || (interleave == 2 && nregs == 2)) { |
|
2866 |
gen_movl_T1_reg(s, rn); |
|
2867 |
gen_op_addl_T1_im((1 << size) * reg); |
|
2868 |
} else if (interleave == 2 && nregs == 4 && reg == 2) { |
|
2869 |
gen_movl_T1_reg(s, rn); |
|
2870 |
gen_op_addl_T1_im(1 << size); |
|
2871 |
} |
|
2872 |
for (pass = 0; pass < 2; pass++) { |
|
2873 |
if (size == 2) { |
|
2874 |
if (load) { |
|
2875 |
gen_ldst(ldl, s); |
|
2876 |
NEON_SET_REG(T0, rd, pass); |
|
2877 |
} else { |
|
2878 |
NEON_GET_REG(T0, rd, pass); |
|
2879 |
gen_ldst(stl, s); |
|
2880 |
} |
|
2881 |
gen_op_addl_T1_im(stride); |
|
2882 |
} else if (size == 1) { |
|
2883 |
if (load) { |
|
2884 |
gen_ldst(lduw, s); |
|
2885 |
gen_op_addl_T1_im(stride); |
|
2886 |
gen_op_movl_T2_T0(); |
|
2887 |
gen_ldst(lduw, s); |
|
2888 |
gen_op_addl_T1_im(stride); |
|
2889 |
gen_op_neon_insert_elt(16, 0xffff); |
|
2890 |
NEON_SET_REG(T2, rd, pass); |
|
2891 |
} else { |
|
2892 |
NEON_GET_REG(T2, rd, pass); |
|
2893 |
gen_op_movl_T0_T2(); |
|
2894 |
gen_ldst(stw, s); |
|
2895 |
gen_op_addl_T1_im(stride); |
|
2896 |
gen_op_neon_extract_elt(16, 0xffff0000); |
|
2897 |
gen_ldst(stw, s); |
|
2898 |
gen_op_addl_T1_im(stride); |
|
2899 |
} |
|
2900 |
} else /* size == 0 */ { |
|
2901 |
if (load) { |
|
2902 |
mask = 0xff; |
|
2903 |
for (n = 0; n < 4; n++) { |
|
2904 |
gen_ldst(ldub, s); |
|
2905 |
gen_op_addl_T1_im(stride); |
|
2906 |
if (n == 0) { |
|
2907 |
gen_op_movl_T2_T0(); |
|
2908 |
} else { |
|
2909 |
gen_op_neon_insert_elt(n * 8, ~mask); |
|
2910 |
} |
|
2911 |
mask <<= 8; |
|
2912 |
} |
|
2913 |
NEON_SET_REG(T2, rd, pass); |
|
2914 |
} else { |
|
2915 |
NEON_GET_REG(T2, rd, pass); |
|
2916 |
mask = 0xff; |
|
2917 |
for (n = 0; n < 4; n++) { |
|
2918 |
if (n == 0) { |
|
2919 |
gen_op_movl_T0_T2(); |
|
2920 |
} else { |
|
2921 |
gen_op_neon_extract_elt(n * 8, mask); |
|
2922 |
} |
|
2923 |
gen_ldst(stb, s); |
|
2924 |
gen_op_addl_T1_im(stride); |
|
2925 |
mask <<= 8; |
|
2926 |
} |
|
2927 |
} |
|
2928 |
} |
|
2929 |
} |
|
2930 |
rd += neon_ls_element_type[op].spacing; |
|
2931 |
} |
|
2932 |
stride = nregs * 8; |
|
2933 |
} else { |
|
2934 |
size = (insn >> 10) & 3; |
|
2935 |
if (size == 3) { |
|
2936 |
/* Load single element to all lanes. */ |
|
2937 |
if (!load) |
|
2938 |
return 1; |
|
2939 |
size = (insn >> 6) & 3; |
|
2940 |
nregs = ((insn >> 8) & 3) + 1; |
|
2941 |
stride = (insn & (1 << 5)) ? 2 : 1; |
|
2344 | 2942 |
gen_movl_T1_reg(s, rn); |
2345 |
if (op1 & 2) |
|
2346 |
gen_op_double_T1_saturate(); |
|
2347 |
if (op1 & 1) |
|
2348 |
gen_op_subl_T0_T1_saturate(); |
|
2349 |
else |
|
2350 |
gen_op_addl_T0_T1_saturate(); |
|
2351 |
gen_movl_reg_T0(s, rd); |
|
2352 |
break; |
|
2353 |
case 7: /* bkpt */ |
|
2354 |
gen_op_movl_T0_im((long)s->pc - 4); |
|
2355 |
gen_op_movl_reg_TN[0][15](); |
|
2356 |
gen_op_bkpt(); |
|
2357 |
s->is_jmp = DISAS_JUMP; |
|
2358 |
break; |
|
2359 |
case 0x8: /* signed multiply */ |
|
2360 |
case 0xa: |
|
2361 |
case 0xc: |
|
2362 |
case 0xe: |
|
2363 |
rs = (insn >> 8) & 0xf; |
|
2364 |
rn = (insn >> 12) & 0xf; |
|
2365 |
rd = (insn >> 16) & 0xf; |
|
2366 |
if (op1 == 1) { |
|
2367 |
/* (32 * 16) >> 16 */ |
|
2368 |
gen_movl_T0_reg(s, rm); |
|
2369 |
gen_movl_T1_reg(s, rs); |
|
2370 |
if (sh & 4) |
|
2371 |
gen_op_sarl_T1_im(16); |
|
2372 |
else |
|
2373 |
gen_op_sxth_T1(); |
|
2374 |
gen_op_imulw_T0_T1(); |
|
2375 |
if ((sh & 2) == 0) { |
|
2376 |
gen_movl_T1_reg(s, rn); |
|
2377 |
gen_op_addl_T0_T1_setq(); |
|
2943 |
for (reg = 0; reg < nregs; reg++) { |
|
2944 |
switch (size) { |
|
2945 |
case 0: |
|
2946 |
gen_ldst(ldub, s); |
|
2947 |
gen_op_neon_dup_u8(0); |
|
2948 |
break; |
|
2949 |
case 1: |
|
2950 |
gen_ldst(lduw, s); |
|
2951 |
gen_op_neon_dup_low16(); |
|
2952 |
break; |
|
2953 |
case 2: |
|
2954 |
gen_ldst(ldl, s); |
|
2955 |
break; |
|
2956 |
case 3: |
|
2957 |
return 1; |
|
2378 | 2958 |
} |
2379 |
gen_movl_reg_T0(s, rd); |
|
2380 |
} else { |
|
2381 |
/* 16 * 16 */ |
|
2382 |
gen_movl_T0_reg(s, rm); |
|
2383 |
gen_movl_T1_reg(s, rs); |
|
2384 |
gen_mulxy(sh & 2, sh & 4); |
|
2385 |
if (op1 == 2) { |
|
2386 |
gen_op_signbit_T1_T0(); |
|
2387 |
gen_op_addq_T0_T1(rn, rd); |
|
2388 |
gen_movl_reg_T0(s, rn); |
|
2389 |
gen_movl_reg_T1(s, rd); |
|
2390 |
} else { |
|
2391 |
if (op1 == 0) { |
|
2392 |
gen_movl_T1_reg(s, rn); |
|
2393 |
gen_op_addl_T0_T1_setq(); |
|
2959 |
gen_op_addl_T1_im(1 << size); |
|
2960 |
NEON_SET_REG(T0, rd, 0); |
|
2961 |
NEON_SET_REG(T0, rd, 1); |
|
2962 |
rd += stride; |
|
2963 |
} |
|
2964 |
stride = (1 << size) * nregs; |
|
2965 |
} else { |
|
2966 |
/* Single element. */ |
|
2967 |
pass = (insn >> 7) & 1; |
|
2968 |
switch (size) { |
|
2969 |
case 0: |
|
2970 |
shift = ((insn >> 5) & 3) * 8; |
|
2971 |
mask = 0xff << shift; |
|
2972 |
stride = 1; |
|
2973 |
break; |
|
2974 |
case 1: |
|
2975 |
shift = ((insn >> 6) & 1) * 16; |
|
2976 |
mask = shift ? 0xffff0000 : 0xffff; |
|
2977 |
stride = (insn & (1 << 5)) ? 2 : 1; |
|
2978 |
break; |
|
2979 |
case 2: |
|
2980 |
shift = 0; |
|
2981 |
mask = 0xffffffff; |
|
2982 |
stride = (insn & (1 << 6)) ? 2 : 1; |
|
2983 |
break; |
|
2984 |
default: |
|
2985 |
abort(); |
|
2986 |
} |
|
2987 |
nregs = ((insn >> 8) & 3) + 1; |
|
2988 |
gen_movl_T1_reg(s, rn); |
|
2989 |
for (reg = 0; reg < nregs; reg++) { |
|
2990 |
if (load) { |
|
2991 |
if (size != 2) { |
|
2992 |
NEON_GET_REG(T2, rd, pass); |
|
2993 |
} |
|
2994 |
switch (size) { |
|
2995 |
case 0: |
|
2996 |
gen_ldst(ldub, s); |
|
2997 |
break; |
|
2998 |
case 1: |
|
2999 |
gen_ldst(lduw, s); |
|
3000 |
break; |
|
3001 |
case 2: |
|
3002 |
gen_ldst(ldl, s); |
|
3003 |
NEON_SET_REG(T0, rd, pass); |
|
3004 |
break; |
|
3005 |
} |
|
3006 |
if (size != 2) { |
|
3007 |
gen_op_neon_insert_elt(shift, ~mask); |
|
3008 |
NEON_SET_REG(T0, rd, pass); |
|
3009 |
} |
|
3010 |
} else { /* Store */ |
|
3011 |
if (size == 2) { |
|
3012 |
NEON_GET_REG(T0, rd, pass); |
|
3013 |
} else { |
|
3014 |
NEON_GET_REG(T2, rd, pass); |
|
3015 |
gen_op_neon_extract_elt(shift, mask); |
|
3016 |
} |
|
3017 |
switch (size) { |
|
3018 |
case 0: |
|
3019 |
gen_ldst(stb, s); |
|
3020 |
break; |
|
3021 |
case 1: |
|
3022 |
gen_ldst(stw, s); |
|
3023 |
break; |
|
3024 |
case 2: |
|
3025 |
gen_ldst(stl, s); |
|
3026 |
break; |
|
2394 | 3027 |
} |
2395 |
gen_movl_reg_T0(s, rd); |
|
2396 | 3028 |
} |
3029 |
rd += stride; |
|
3030 |
gen_op_addl_T1_im(1 << size); |
|
2397 | 3031 |
} |
2398 |
break; |
|
2399 |
default: |
|
2400 |
goto illegal_op; |
|
3032 |
stride = nregs * (1 << size); |
|
2401 | 3033 |
} |
2402 |
} else if (((insn & 0x0e000000) == 0 && |
|
2403 |
(insn & 0x00000090) != 0x90) || |
|
2404 |
((insn & 0x0e000000) == (1 << 25))) { |
|
2405 |
int set_cc, logic_cc, shiftop; |
|
3034 |
} |
|
3035 |
if (rm != 15) { |
|
3036 |
gen_movl_T1_reg(s, rn); |
|
3037 |
if (rm == 13) { |
|
3038 |
gen_op_addl_T1_im(stride); |
|
3039 |
} else { |
|
3040 |
gen_movl_T2_reg(s, rm); |
|
3041 |
gen_op_addl_T1_T2(); |
|
3042 |
} |
|
3043 |
gen_movl_reg_T1(s, rn); |
|
3044 |
} |
|
3045 |
return 0; |
|
3046 |
} |
|
2406 | 3047 |
|
2407 |
op1 = (insn >> 21) & 0xf; |
|
2408 |
set_cc = (insn >> 20) & 1; |
|
2409 |
logic_cc = table_logic_cc[op1] & set_cc; |
|
3048 |
/* Translate a NEON data processing instruction. Return nonzero if the |
|
3049 |
instruction is invalid. |
|
3050 |
In general we process vectors in 32-bit chunks. This means we can reuse |
|
3051 |
some of the scalar ops, and hopefully the code generated for 32-bit |
|
3052 |
hosts won't be too awful. The downside is that the few 64-bit operations |
|
3053 |
(mainly shifts) get complicated. */ |
|
2410 | 3054 |
|
2411 |
/* data processing instruction */ |
|
2412 |
if (insn & (1 << 25)) { |
|
2413 |
/* immediate operand */ |
|
2414 |
val = insn & 0xff; |
|
2415 |
shift = ((insn >> 8) & 0xf) * 2; |
|
2416 |
if (shift) |
|
2417 |
val = (val >> shift) | (val << (32 - shift)); |
|
2418 |
gen_op_movl_T1_im(val); |
|
2419 |
if (logic_cc && shift) |
|
2420 |
gen_op_mov_CF_T1(); |
|
2421 |
} else { |
|
2422 |
/* register */ |
|
2423 |
rm = (insn) & 0xf; |
|
2424 |
gen_movl_T1_reg(s, rm); |
|
2425 |
shiftop = (insn >> 5) & 3; |
|
2426 |
if (!(insn & (1 << 4))) { |
|
2427 |
shift = (insn >> 7) & 0x1f; |
|
2428 |
if (shift != 0) { |
|
2429 |
if (logic_cc) { |
|
2430 |
gen_shift_T1_im_cc[shiftop](shift); |
|
3055 |
static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) |
|
3056 |
{ |
|
3057 |
int op; |
|
3058 |
int q; |
|
3059 |
int rd, rn, rm; |
|
3060 |
int size; |
|
3061 |
int shift; |
|
3062 |
int pass; |
|
3063 |
int count; |
|
3064 |
int pairwise; |
|
3065 |
int u; |
|
3066 |
int n; |
|
3067 |
uint32_t imm; |
|
3068 |
|
|
3069 |
if (!vfp_enabled(env)) |
|
3070 |
return 1; |
|
3071 |
q = (insn & (1 << 6)) != 0; |
|
3072 |
u = (insn >> 24) & 1; |
|
3073 |
VFP_DREG_D(rd, insn); |
|
3074 |
VFP_DREG_N(rn, insn); |
|
3075 |
VFP_DREG_M(rm, insn); |
|
3076 |
size = (insn >> 20) & 3; |
|
3077 |
if ((insn & (1 << 23)) == 0) { |
|
3078 |
/* Three register same length. */ |
|
3079 |
op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1); |
|
3080 |
if (size == 3 && (op == 1 || op == 5 || op == 16)) { |
|
3081 |
for (pass = 0; pass < (q ? 2 : 1); pass++) { |
|
3082 |
NEON_GET_REG(T0, rm, pass * 2); |
|
3083 |
NEON_GET_REG(T1, rm, pass * 2 + 1); |
|
3084 |
gen_neon_movl_scratch_T0(0); |
|
3085 |
gen_neon_movl_scratch_T1(1); |
|
3086 |
NEON_GET_REG(T0, rn, pass * 2); |
|
3087 |
NEON_GET_REG(T1, rn, pass * 2 + 1); |
|
3088 |
switch (op) { |
|
3089 |
case 1: /* VQADD */ |
|
3090 |
if (u) { |
|
3091 |
gen_op_neon_addl_saturate_u64(); |
|
2431 | 3092 |
} else { |
2432 |
gen_shift_T1_im[shiftop](shift);
|
|
3093 |
gen_op_neon_addl_saturate_s64();
|
|
2433 | 3094 |
} |
2434 |
} else if (shiftop != 0) { |
|
2435 |
if (logic_cc) { |
|
2436 |
gen_shift_T1_0_cc[shiftop](); |
|
3095 |
break; |
|
3096 |
case 5: /* VQSUB */ |
|
3097 |
if (u) { |
|
3098 |
gen_op_neon_subl_saturate_u64(); |
|
2437 | 3099 |
} else { |
2438 |
gen_shift_T1_0[shiftop](); |
Also available in: Unified diff