1 | /* |
2 | * AArch64 translation, common definitions. |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | #ifndef TARGET_ARM_TRANSLATE_A64_H |
19 | #define TARGET_ARM_TRANSLATE_A64_H |
20 | |
21 | void unallocated_encoding(DisasContext *s); |
22 | |
23 | #define unsupported_encoding(s, insn) \ |
24 | do { \ |
25 | qemu_log_mask(LOG_UNIMP, \ |
26 | "%s:%d: unsupported instruction encoding 0x%08x " \ |
27 | "at pc=%016" PRIx64 "\n", \ |
28 | __FILE__, __LINE__, insn, s->pc_curr); \ |
29 | unallocated_encoding(s); \ |
30 | } while (0) |
31 | |
32 | TCGv_i64 new_tmp_a64(DisasContext *s); |
33 | TCGv_i64 new_tmp_a64_zero(DisasContext *s); |
34 | TCGv_i64 cpu_reg(DisasContext *s, int reg); |
35 | TCGv_i64 cpu_reg_sp(DisasContext *s, int reg); |
36 | TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf); |
37 | TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf); |
38 | void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v); |
39 | TCGv_ptr get_fpstatus_ptr(bool); |
40 | bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn, |
41 | unsigned int imms, unsigned int immr); |
42 | bool sve_access_check(DisasContext *s); |
43 | |
44 | /* We should have at some point before trying to access an FP register |
45 | * done the necessary access check, so assert that |
46 | * (a) we did the check and |
47 | * (b) we didn't then just plough ahead anyway if it failed. |
48 | * Print the instruction pattern in the abort message so we can figure |
49 | * out what we need to fix if a user encounters this problem in the wild. |
50 | */ |
51 | static inline void assert_fp_access_checked(DisasContext *s) |
52 | { |
53 | #ifdef CONFIG_DEBUG_TCG |
54 | if (unlikely(!s->fp_access_checked || s->fp_excp_el)) { |
55 | fprintf(stderr, "target-arm: FP access check missing for " |
56 | "instruction 0x%08x\n" , s->insn); |
57 | abort(); |
58 | } |
59 | #endif |
60 | } |
61 | |
62 | /* Return the offset into CPUARMState of an element of specified |
63 | * size, 'element' places in from the least significant end of |
64 | * the FP/vector register Qn. |
65 | */ |
66 | static inline int vec_reg_offset(DisasContext *s, int regno, |
67 | int element, MemOp size) |
68 | { |
69 | int element_size = 1 << size; |
70 | int offs = element * element_size; |
71 | #ifdef HOST_WORDS_BIGENDIAN |
72 | /* This is complicated slightly because vfp.zregs[n].d[0] is |
73 | * still the lowest and vfp.zregs[n].d[15] the highest of the |
74 | * 256 byte vector, even on big endian systems. |
75 | * |
76 | * Calculate the offset assuming fully little-endian, |
77 | * then XOR to account for the order of the 8-byte units. |
78 | * |
79 | * For 16 byte elements, the two 8 byte halves will not form a |
80 | * host int128 if the host is bigendian, since they're in the |
81 | * wrong order. However the only 16 byte operation we have is |
82 | * a move, so we can ignore this for the moment. More complicated |
83 | * operations will have to special case loading and storing from |
84 | * the zregs array. |
85 | */ |
86 | if (element_size < 8) { |
87 | offs ^= 8 - element_size; |
88 | } |
89 | #endif |
90 | offs += offsetof(CPUARMState, vfp.zregs[regno]); |
91 | assert_fp_access_checked(s); |
92 | return offs; |
93 | } |
94 | |
95 | /* Return the offset info CPUARMState of the "whole" vector register Qn. */ |
96 | static inline int vec_full_reg_offset(DisasContext *s, int regno) |
97 | { |
98 | assert_fp_access_checked(s); |
99 | return offsetof(CPUARMState, vfp.zregs[regno]); |
100 | } |
101 | |
102 | /* Return a newly allocated pointer to the vector register. */ |
103 | static inline TCGv_ptr vec_full_reg_ptr(DisasContext *s, int regno) |
104 | { |
105 | TCGv_ptr ret = tcg_temp_new_ptr(); |
106 | tcg_gen_addi_ptr(ret, cpu_env, vec_full_reg_offset(s, regno)); |
107 | return ret; |
108 | } |
109 | |
110 | /* Return the byte size of the "whole" vector register, VL / 8. */ |
111 | static inline int vec_full_reg_size(DisasContext *s) |
112 | { |
113 | return s->sve_len; |
114 | } |
115 | |
116 | bool disas_sve(DisasContext *, uint32_t); |
117 | |
118 | /* Note that the gvec expanders operate on offsets + sizes. */ |
119 | typedef void GVecGen2Fn(unsigned, uint32_t, uint32_t, uint32_t, uint32_t); |
120 | typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t, |
121 | uint32_t, uint32_t); |
122 | typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t, |
123 | uint32_t, uint32_t, uint32_t); |
124 | typedef void GVecGen4Fn(unsigned, uint32_t, uint32_t, uint32_t, |
125 | uint32_t, uint32_t, uint32_t); |
126 | |
127 | #endif /* TARGET_ARM_TRANSLATE_A64_H */ |
128 | |