]>
Commit | Line | Data |
---|---|---|
8289b279 BS |
1 | /* |
2 | * Tiny Code Generator for QEMU | |
3 | * | |
4 | * Copyright (c) 2008 Fabrice Bellard | |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | * of this software and associated documentation files (the "Software"), to deal | |
8 | * in the Software without restriction, including without limitation the rights | |
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | * copies of the Software, and to permit persons to whom the Software is | |
11 | * furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in | |
14 | * all copies or substantial portions of the Software. | |
15 | * | |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | * THE SOFTWARE. | |
23 | */ | |
24 | ||
25 | static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { | |
26 | "%g0", | |
27 | "%g1", | |
28 | "%g2", | |
29 | "%g3", | |
30 | "%g4", | |
31 | "%g5", | |
32 | "%g6", | |
33 | "%g7", | |
34 | "%o0", | |
35 | "%o1", | |
36 | "%o2", | |
37 | "%o3", | |
38 | "%o4", | |
39 | "%o5", | |
40 | "%o6", | |
41 | "%o7", | |
42 | "%l0", | |
43 | "%l1", | |
44 | "%l2", | |
45 | "%l3", | |
46 | "%l4", | |
47 | "%l5", | |
48 | "%l6", | |
49 | "%l7", | |
50 | "%i0", | |
51 | "%i1", | |
52 | "%i2", | |
53 | "%i3", | |
54 | "%i4", | |
55 | "%i5", | |
56 | "%i6", | |
57 | "%i7", | |
58 | }; | |
59 | ||
0954d0d9 | 60 | static const int tcg_target_reg_alloc_order[] = { |
8289b279 BS |
61 | TCG_REG_L0, |
62 | TCG_REG_L1, | |
63 | TCG_REG_L2, | |
64 | TCG_REG_L3, | |
65 | TCG_REG_L4, | |
66 | TCG_REG_L5, | |
67 | TCG_REG_L6, | |
68 | TCG_REG_L7, | |
69 | TCG_REG_I0, | |
70 | TCG_REG_I1, | |
71 | TCG_REG_I2, | |
72 | TCG_REG_I3, | |
73 | TCG_REG_I4, | |
8289b279 BS |
74 | }; |
75 | ||
76 | static const int tcg_target_call_iarg_regs[6] = { | |
77 | TCG_REG_O0, | |
78 | TCG_REG_O1, | |
79 | TCG_REG_O2, | |
80 | TCG_REG_O3, | |
81 | TCG_REG_O4, | |
82 | TCG_REG_O5, | |
83 | }; | |
84 | ||
85 | static const int tcg_target_call_oarg_regs[2] = { | |
86 | TCG_REG_O0, | |
87 | TCG_REG_O1, | |
88 | }; | |
89 | ||
57e49b40 | 90 | static inline int check_fit_tl(tcg_target_long val, unsigned int bits) |
f5ef6aac | 91 | { |
57e49b40 BS |
92 | return (val << ((sizeof(tcg_target_long) * 8 - bits)) |
93 | >> (sizeof(tcg_target_long) * 8 - bits)) == val; | |
94 | } | |
95 | ||
96 | static inline int check_fit_i32(uint32_t val, unsigned int bits) | |
97 | { | |
98 | return ((val << (32 - bits)) >> (32 - bits)) == val; | |
f5ef6aac BS |
99 | } |
100 | ||
8289b279 | 101 | static void patch_reloc(uint8_t *code_ptr, int type, |
f54b3f92 | 102 | tcg_target_long value, tcg_target_long addend) |
8289b279 | 103 | { |
f54b3f92 | 104 | value += addend; |
8289b279 BS |
105 | switch (type) { |
106 | case R_SPARC_32: | |
107 | if (value != (uint32_t)value) | |
108 | tcg_abort(); | |
109 | *(uint32_t *)code_ptr = value; | |
110 | break; | |
f5ef6aac BS |
111 | case R_SPARC_WDISP22: |
112 | value -= (long)code_ptr; | |
113 | value >>= 2; | |
57e49b40 | 114 | if (!check_fit_tl(value, 22)) |
f5ef6aac BS |
115 | tcg_abort(); |
116 | *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x3fffff) | value; | |
117 | break; | |
8289b279 BS |
118 | default: |
119 | tcg_abort(); | |
120 | } | |
121 | } | |
122 | ||
123 | /* maximum number of register used for input function arguments */ | |
124 | static inline int tcg_target_get_call_iarg_regs_count(int flags) | |
125 | { | |
126 | return 6; | |
127 | } | |
128 | ||
129 | /* parse target specific constraints */ | |
130 | static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) | |
131 | { | |
132 | const char *ct_str; | |
133 | ||
134 | ct_str = *pct_str; | |
135 | switch (ct_str[0]) { | |
136 | case 'r': | |
137 | case 'L': /* qemu_ld/st constraint */ | |
138 | ct->ct |= TCG_CT_REG; | |
139 | tcg_regset_set32(ct->u.regs, 0, 0xffffffff); | |
f5ef6aac BS |
140 | tcg_regset_reset_reg(ct->u.regs, TCG_REG_I0); |
141 | tcg_regset_reset_reg(ct->u.regs, TCG_REG_I1); | |
8289b279 BS |
142 | break; |
143 | case 'I': | |
144 | ct->ct |= TCG_CT_CONST_S11; | |
145 | break; | |
146 | case 'J': | |
147 | ct->ct |= TCG_CT_CONST_S13; | |
148 | break; | |
149 | default: | |
150 | return -1; | |
151 | } | |
152 | ct_str++; | |
153 | *pct_str = ct_str; | |
154 | return 0; | |
155 | } | |
156 | ||
8289b279 BS |
157 | /* test if a constant matches the constraint */ |
158 | static inline int tcg_target_const_match(tcg_target_long val, | |
159 | const TCGArgConstraint *arg_ct) | |
160 | { | |
161 | int ct; | |
162 | ||
163 | ct = arg_ct->ct; | |
164 | if (ct & TCG_CT_CONST) | |
165 | return 1; | |
57e49b40 | 166 | else if ((ct & TCG_CT_CONST_S11) && check_fit_tl(val, 11)) |
8289b279 | 167 | return 1; |
57e49b40 | 168 | else if ((ct & TCG_CT_CONST_S13) && check_fit_tl(val, 13)) |
8289b279 BS |
169 | return 1; |
170 | else | |
171 | return 0; | |
172 | } | |
173 | ||
174 | #define INSN_OP(x) ((x) << 30) | |
175 | #define INSN_OP2(x) ((x) << 22) | |
176 | #define INSN_OP3(x) ((x) << 19) | |
177 | #define INSN_OPF(x) ((x) << 5) | |
178 | #define INSN_RD(x) ((x) << 25) | |
179 | #define INSN_RS1(x) ((x) << 14) | |
180 | #define INSN_RS2(x) (x) | |
181 | ||
182 | #define INSN_IMM13(x) ((1 << 13) | ((x) & 0x1fff)) | |
b3db8758 | 183 | #define INSN_OFF22(x) (((x) >> 2) & 0x3fffff) |
8289b279 | 184 | |
b3db8758 | 185 | #define INSN_COND(x, a) (((x) << 25) | ((a) << 29)) |
cf7c2ca5 BS |
186 | #define COND_N 0x0 |
187 | #define COND_E 0x1 | |
188 | #define COND_LE 0x2 | |
189 | #define COND_L 0x3 | |
190 | #define COND_LEU 0x4 | |
191 | #define COND_CS 0x5 | |
192 | #define COND_NEG 0x6 | |
193 | #define COND_VS 0x7 | |
b3db8758 | 194 | #define COND_A 0x8 |
cf7c2ca5 BS |
195 | #define COND_NE 0x9 |
196 | #define COND_G 0xa | |
197 | #define COND_GE 0xb | |
198 | #define COND_GU 0xc | |
199 | #define COND_CC 0xd | |
200 | #define COND_POS 0xe | |
201 | #define COND_VC 0xf | |
b3db8758 | 202 | #define BA (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2)) |
8289b279 BS |
203 | |
204 | #define ARITH_ADD (INSN_OP(2) | INSN_OP3(0x00)) | |
205 | #define ARITH_AND (INSN_OP(2) | INSN_OP3(0x01)) | |
206 | #define ARITH_OR (INSN_OP(2) | INSN_OP3(0x02)) | |
9a7f3228 | 207 | #define ARITH_ORCC (INSN_OP(2) | INSN_OP3(0x12)) |
8289b279 | 208 | #define ARITH_XOR (INSN_OP(2) | INSN_OP3(0x03)) |
f5ef6aac BS |
209 | #define ARITH_SUB (INSN_OP(2) | INSN_OP3(0x04)) |
210 | #define ARITH_SUBCC (INSN_OP(2) | INSN_OP3(0x14)) | |
8289b279 BS |
211 | #define ARITH_ADDX (INSN_OP(2) | INSN_OP3(0x10)) |
212 | #define ARITH_SUBX (INSN_OP(2) | INSN_OP3(0x0c)) | |
213 | #define ARITH_UMUL (INSN_OP(2) | INSN_OP3(0x0a)) | |
214 | #define ARITH_UDIV (INSN_OP(2) | INSN_OP3(0x0e)) | |
215 | #define ARITH_SDIV (INSN_OP(2) | INSN_OP3(0x0f)) | |
216 | #define ARITH_MULX (INSN_OP(2) | INSN_OP3(0x09)) | |
217 | #define ARITH_UDIVX (INSN_OP(2) | INSN_OP3(0x0d)) | |
218 | #define ARITH_SDIVX (INSN_OP(2) | INSN_OP3(0x2d)) | |
219 | ||
220 | #define SHIFT_SLL (INSN_OP(2) | INSN_OP3(0x25)) | |
221 | #define SHIFT_SRL (INSN_OP(2) | INSN_OP3(0x26)) | |
222 | #define SHIFT_SRA (INSN_OP(2) | INSN_OP3(0x27)) | |
223 | ||
224 | #define SHIFT_SLLX (INSN_OP(2) | INSN_OP3(0x25) | (1 << 12)) | |
225 | #define SHIFT_SRLX (INSN_OP(2) | INSN_OP3(0x26) | (1 << 12)) | |
226 | #define SHIFT_SRAX (INSN_OP(2) | INSN_OP3(0x27) | (1 << 12)) | |
227 | ||
228 | #define WRY (INSN_OP(2) | INSN_OP3(0x30)) | |
229 | #define JMPL (INSN_OP(2) | INSN_OP3(0x38)) | |
230 | #define SAVE (INSN_OP(2) | INSN_OP3(0x3c)) | |
231 | #define RESTORE (INSN_OP(2) | INSN_OP3(0x3d)) | |
232 | #define SETHI (INSN_OP(0) | INSN_OP2(0x4)) | |
233 | #define CALL INSN_OP(1) | |
234 | #define LDUB (INSN_OP(3) | INSN_OP3(0x01)) | |
235 | #define LDSB (INSN_OP(3) | INSN_OP3(0x09)) | |
236 | #define LDUH (INSN_OP(3) | INSN_OP3(0x02)) | |
237 | #define LDSH (INSN_OP(3) | INSN_OP3(0x0a)) | |
238 | #define LDUW (INSN_OP(3) | INSN_OP3(0x00)) | |
239 | #define LDSW (INSN_OP(3) | INSN_OP3(0x08)) | |
240 | #define LDX (INSN_OP(3) | INSN_OP3(0x0b)) | |
241 | #define STB (INSN_OP(3) | INSN_OP3(0x05)) | |
242 | #define STH (INSN_OP(3) | INSN_OP3(0x06)) | |
243 | #define STW (INSN_OP(3) | INSN_OP3(0x04)) | |
244 | #define STX (INSN_OP(3) | INSN_OP3(0x0e)) | |
245 | ||
246 | static inline void tcg_out_mov(TCGContext *s, int ret, int arg) | |
247 | { | |
248 | tcg_out32(s, ARITH_OR | INSN_RD(ret) | INSN_RS1(arg) | | |
249 | INSN_RS2(TCG_REG_G0)); | |
250 | } | |
251 | ||
252 | static inline void tcg_out_movi(TCGContext *s, TCGType type, | |
253 | int ret, tcg_target_long arg) | |
254 | { | |
b3db8758 | 255 | #if defined(__sparc_v9__) && !defined(__sparc_v8plus__) |
57e49b40 | 256 | if (!check_fit_tl(arg, 32) && (arg & ~0xffffffff) != 0) |
b3db8758 BS |
257 | fprintf(stderr, "unimplemented %s with constant %ld\n", __func__, arg); |
258 | #endif | |
57e49b40 | 259 | if (check_fit_i32(arg, 13)) |
2f0a5008 | 260 | tcg_out32(s, ARITH_OR | INSN_RD(ret) | INSN_RS1(TCG_REG_G0) | |
8289b279 BS |
261 | INSN_IMM13(arg)); |
262 | else { | |
263 | tcg_out32(s, SETHI | INSN_RD(ret) | ((arg & 0xfffffc00) >> 10)); | |
264 | if (arg & 0x3ff) | |
265 | tcg_out32(s, ARITH_OR | INSN_RD(ret) | INSN_RS1(ret) | | |
266 | INSN_IMM13(arg & 0x3ff)); | |
267 | } | |
268 | } | |
269 | ||
270 | static inline void tcg_out_ld_raw(TCGContext *s, int ret, | |
271 | tcg_target_long arg) | |
272 | { | |
273 | tcg_out32(s, SETHI | INSN_RD(ret) | (((uint32_t)arg & 0xfffffc00) >> 10)); | |
274 | tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) | | |
275 | INSN_IMM13(arg & 0x3ff)); | |
276 | } | |
277 | ||
b3db8758 BS |
278 | static inline void tcg_out_ld_ptr(TCGContext *s, int ret, |
279 | tcg_target_long arg) | |
280 | { | |
281 | #if defined(__sparc_v9__) && !defined(__sparc_v8plus__) | |
57e49b40 | 282 | if (!check_fit_tl(arg, 32) && (arg & ~0xffffffff) != 0) |
b3db8758 | 283 | fprintf(stderr, "unimplemented %s with offset %ld\n", __func__, arg); |
57e49b40 | 284 | if (!check_fit_i32(arg, 13)) |
b3db8758 BS |
285 | tcg_out32(s, SETHI | INSN_RD(ret) | (((uint32_t)arg & 0xfffffc00) >> 10)); |
286 | tcg_out32(s, LDX | INSN_RD(ret) | INSN_RS1(ret) | | |
287 | INSN_IMM13(arg & 0x3ff)); | |
288 | #else | |
289 | tcg_out_ld_raw(s, ret, arg); | |
290 | #endif | |
291 | } | |
292 | ||
8289b279 BS |
293 | static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, int offset, int op) |
294 | { | |
57e49b40 | 295 | if (check_fit_tl(offset, 13)) |
8289b279 BS |
296 | tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(addr) | |
297 | INSN_IMM13(offset)); | |
cf7c2ca5 BS |
298 | else { |
299 | tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset); | |
300 | tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) | | |
301 | INSN_RS2(addr)); | |
302 | } | |
8289b279 BS |
303 | } |
304 | ||
e4d5434c | 305 | static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret, |
8289b279 BS |
306 | int arg1, tcg_target_long arg2) |
307 | { | |
7d551702 BS |
308 | if (type == TCG_TYPE_I32) |
309 | tcg_out_ldst(s, ret, arg1, arg2, LDUW); | |
310 | else | |
311 | tcg_out_ldst(s, ret, arg1, arg2, LDX); | |
8289b279 BS |
312 | } |
313 | ||
e4d5434c | 314 | static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, |
8289b279 BS |
315 | int arg1, tcg_target_long arg2) |
316 | { | |
7d551702 BS |
317 | if (type == TCG_TYPE_I32) |
318 | tcg_out_ldst(s, arg, arg1, arg2, STW); | |
319 | else | |
320 | tcg_out_ldst(s, arg, arg1, arg2, STX); | |
8289b279 BS |
321 | } |
322 | ||
323 | static inline void tcg_out_arith(TCGContext *s, int rd, int rs1, int rs2, | |
324 | int op) | |
325 | { | |
326 | tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) | | |
327 | INSN_RS2(rs2)); | |
328 | } | |
329 | ||
330 | static inline void tcg_out_arithi(TCGContext *s, int rd, int rs1, int offset, | |
331 | int op) | |
332 | { | |
333 | tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) | | |
334 | INSN_IMM13(offset)); | |
335 | } | |
336 | ||
337 | static inline void tcg_out_sety(TCGContext *s, tcg_target_long val) | |
338 | { | |
339 | if (val == 0 || val == -1) | |
340 | tcg_out32(s, WRY | INSN_IMM13(val)); | |
341 | else | |
342 | fprintf(stderr, "unimplemented sety %ld\n", (long)val); | |
343 | } | |
344 | ||
345 | static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) | |
346 | { | |
347 | if (val != 0) { | |
57e49b40 | 348 | if (check_fit_tl(val, 13)) |
8289b279 | 349 | tcg_out_arithi(s, reg, reg, val, ARITH_ADD); |
f5ef6aac BS |
350 | else { |
351 | tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, val); | |
352 | tcg_out_arith(s, reg, reg, TCG_REG_I5, ARITH_ADD); | |
353 | } | |
8289b279 BS |
354 | } |
355 | } | |
356 | ||
357 | static inline void tcg_out_nop(TCGContext *s) | |
358 | { | |
359 | tcg_out32(s, SETHI | INSN_RD(TCG_REG_G0) | 0); | |
360 | } | |
361 | ||
cf7c2ca5 BS |
362 | static void tcg_out_branch(TCGContext *s, int opc, int label_index) |
363 | { | |
364 | int32_t val; | |
365 | TCGLabel *l = &s->labels[label_index]; | |
366 | ||
367 | if (l->has_value) { | |
368 | val = l->u.value - (tcg_target_long)s->code_ptr; | |
f5ef6aac | 369 | tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) |
cf7c2ca5 | 370 | | INSN_OFF22(l->u.value - (unsigned long)s->code_ptr))); |
f5ef6aac BS |
371 | } else { |
372 | tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP22, label_index, 0); | |
373 | tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) | 0)); | |
374 | } | |
cf7c2ca5 BS |
375 | } |
376 | ||
377 | static const uint8_t tcg_cond_to_bcond[10] = { | |
378 | [TCG_COND_EQ] = COND_E, | |
379 | [TCG_COND_NE] = COND_NE, | |
380 | [TCG_COND_LT] = COND_L, | |
381 | [TCG_COND_GE] = COND_GE, | |
382 | [TCG_COND_LE] = COND_LE, | |
383 | [TCG_COND_GT] = COND_G, | |
384 | [TCG_COND_LTU] = COND_CS, | |
385 | [TCG_COND_GEU] = COND_CC, | |
386 | [TCG_COND_LEU] = COND_LEU, | |
387 | [TCG_COND_GTU] = COND_GU, | |
388 | }; | |
389 | ||
390 | static void tcg_out_brcond(TCGContext *s, int cond, | |
391 | TCGArg arg1, TCGArg arg2, int const_arg2, | |
392 | int label_index) | |
393 | { | |
394 | if (const_arg2 && arg2 == 0) | |
9a7f3228 BS |
395 | /* orcc r, r, %g0 */ |
396 | tcg_out_arith(s, TCG_REG_G0, TCG_REG_G0, arg1, ARITH_ORCC); | |
cf7c2ca5 BS |
397 | else |
398 | /* subcc r1, r2, %g0 */ | |
399 | tcg_out_arith(s, TCG_REG_G0, arg1, arg2, ARITH_SUBCC); | |
400 | tcg_out_branch(s, tcg_cond_to_bcond[cond], label_index); | |
401 | tcg_out_nop(s); | |
402 | } | |
403 | ||
7d551702 BS |
404 | /* Generate global QEMU prologue and epilogue code */ |
405 | void tcg_target_qemu_prologue(TCGContext *s) | |
b3db8758 BS |
406 | { |
407 | tcg_out32(s, SAVE | INSN_RD(TCG_REG_O6) | INSN_RS1(TCG_REG_O6) | | |
408 | INSN_IMM13(-TCG_TARGET_STACK_MINFRAME)); | |
cf7c2ca5 | 409 | tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I0) | |
7d551702 BS |
410 | INSN_RS2(TCG_REG_G0)); |
411 | tcg_out_nop(s); | |
b3db8758 BS |
412 | } |
413 | ||
f5ef6aac BS |
414 | #if defined(CONFIG_SOFTMMU) |
415 | extern void __ldb_mmu(void); | |
416 | extern void __ldw_mmu(void); | |
417 | extern void __ldl_mmu(void); | |
418 | extern void __ldq_mmu(void); | |
419 | ||
420 | extern void __stb_mmu(void); | |
421 | extern void __stw_mmu(void); | |
422 | extern void __stl_mmu(void); | |
423 | extern void __stq_mmu(void); | |
424 | ||
425 | ||
9a7f3228 | 426 | static const void * const qemu_ld_helpers[4] = { |
f5ef6aac BS |
427 | __ldb_mmu, |
428 | __ldw_mmu, | |
429 | __ldl_mmu, | |
430 | __ldq_mmu, | |
431 | }; | |
432 | ||
9a7f3228 | 433 | static const void * const qemu_st_helpers[4] = { |
f5ef6aac BS |
434 | __stb_mmu, |
435 | __stw_mmu, | |
436 | __stl_mmu, | |
437 | __stq_mmu, | |
438 | }; | |
439 | #endif | |
440 | ||
441 | static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, | |
442 | int opc) | |
443 | { | |
444 | int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, ld_op; | |
445 | #if defined(CONFIG_SOFTMMU) | |
446 | uint8_t *label1_ptr, *label2_ptr; | |
447 | #endif | |
448 | ||
449 | data_reg = *args++; | |
450 | addr_reg = *args++; | |
451 | mem_index = *args; | |
452 | s_bits = opc & 3; | |
453 | ||
454 | r0 = TCG_REG_I0; | |
455 | r1 = TCG_REG_I1; | |
456 | ||
457 | #if TARGET_LONG_BITS == 32 | |
458 | ld_op = LDUW; | |
459 | #else | |
460 | ld_op = LDX; | |
461 | #endif | |
462 | ||
463 | #if defined(CONFIG_SOFTMMU) | |
464 | /* srl addr_reg, x, r1 */ | |
465 | tcg_out_arithi(s, r1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS, | |
466 | SHIFT_SRL); | |
467 | /* and addr_reg, x, r0 */ | |
468 | tcg_out_arithi(s, r0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1), | |
469 | ARITH_AND); | |
470 | ||
471 | /* and r1, x, r1 */ | |
472 | tcg_out_arithi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, | |
473 | ARITH_AND); | |
474 | ||
475 | /* add r1, x, r1 */ | |
476 | tcg_out_arithi(s, r1, r1, offsetof(CPUState, tlb_table[mem_index][0].addr_read), | |
477 | ARITH_ADD); | |
478 | ||
479 | /* ld [env + r1], r1 */ | |
480 | tcg_out_ldst(s, r1, TCG_AREG0, r1, ld_op); | |
481 | ||
482 | /* subcc r0, r1, %g0 */ | |
483 | tcg_out_arith(s, TCG_REG_G0, r0, r1, ARITH_SUBCC); | |
484 | ||
485 | /* will become: | |
486 | be label1 */ | |
487 | label1_ptr = s->code_ptr; | |
488 | tcg_out32(s, 0); | |
489 | ||
490 | /* mov (delay slot)*/ | |
491 | tcg_out_mov(s, r0, addr_reg); | |
492 | ||
493 | /* XXX: move that code at the end of the TB */ | |
494 | tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_ld_helpers[s_bits] | |
495 | - (tcg_target_ulong)s->code_ptr) >> 2) | |
496 | & 0x3fffffff)); | |
497 | /* mov (delay slot)*/ | |
498 | tcg_out_movi(s, TCG_TYPE_I32, r1, mem_index); | |
499 | ||
500 | switch(opc) { | |
501 | case 0 | 4: | |
502 | /* sll i0, 24/56, i0 */ | |
503 | tcg_out_arithi(s, TCG_REG_I0, TCG_REG_I0, | |
504 | sizeof(tcg_target_long) * 8 - 8, SHIFT_SLL); | |
505 | /* sra i0, 24/56, data_reg */ | |
506 | tcg_out_arithi(s, data_reg, TCG_REG_I0, | |
507 | sizeof(tcg_target_long) * 8 - 8, SHIFT_SRA); | |
508 | break; | |
509 | case 1 | 4: | |
510 | /* sll i0, 16/48, i0 */ | |
511 | tcg_out_arithi(s, TCG_REG_I0, TCG_REG_I0, | |
512 | sizeof(tcg_target_long) * 8 - 16, SHIFT_SLL); | |
513 | /* sra i0, 16/48, data_reg */ | |
514 | tcg_out_arithi(s, data_reg, TCG_REG_I0, | |
515 | sizeof(tcg_target_long) * 8 - 16, SHIFT_SRA); | |
516 | break; | |
517 | case 2 | 4: | |
518 | /* sll i0, 32, i0 */ | |
519 | tcg_out_arithi(s, TCG_REG_I0, TCG_REG_I0, 32, SHIFT_SLL); | |
520 | /* sra i0, 32, data_reg */ | |
521 | tcg_out_arithi(s, data_reg, TCG_REG_I0, 32, SHIFT_SRA); | |
522 | break; | |
523 | case 0: | |
524 | case 1: | |
525 | case 2: | |
526 | case 3: | |
527 | default: | |
528 | /* mov */ | |
529 | tcg_out_mov(s, data_reg, TCG_REG_I0); | |
530 | break; | |
531 | } | |
532 | ||
533 | /* will become: | |
534 | ba label2 */ | |
535 | label2_ptr = s->code_ptr; | |
536 | tcg_out32(s, 0); | |
537 | ||
538 | /* label1: */ | |
9a7f3228 | 539 | *label1_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) | |
f5ef6aac BS |
540 | INSN_OFF22((unsigned long)label1_ptr - |
541 | (unsigned long)s->code_ptr)); | |
542 | ||
543 | /* ld [r1 + x], r1 */ | |
544 | tcg_out_ldst(s, r1, r1, offsetof(CPUTLBEntry, addend) - | |
545 | offsetof(CPUTLBEntry, addr_read), ld_op); | |
546 | /* add x(r1), r0 */ | |
547 | tcg_out_arith(s, r0, r1, r0, ARITH_ADD); | |
548 | #else | |
549 | r0 = addr_reg; | |
550 | #endif | |
551 | ||
552 | #ifdef TARGET_WORDS_BIGENDIAN | |
553 | bswap = 0; | |
554 | #else | |
555 | bswap = 1; | |
556 | #endif | |
557 | switch(opc) { | |
558 | case 0: | |
559 | /* ldub [r0], data_reg */ | |
560 | tcg_out_ldst(s, data_reg, r0, 0, LDUB); | |
561 | break; | |
562 | case 0 | 4: | |
563 | /* ldsb [r0], data_reg */ | |
564 | tcg_out_ldst(s, data_reg, r0, 0, LDSB); | |
565 | break; | |
566 | case 1: | |
567 | /* lduh [r0], data_reg */ | |
568 | tcg_out_ldst(s, data_reg, r0, 0, LDUH); | |
569 | if (bswap) { | |
570 | fprintf(stderr, "unimplemented %s with bswap\n", __func__); | |
571 | } | |
572 | break; | |
573 | case 1 | 4: | |
574 | /* ldsh [r0], data_reg */ | |
575 | tcg_out_ldst(s, data_reg, r0, 0, LDSH); | |
576 | if (bswap) { | |
577 | fprintf(stderr, "unimplemented %s with bswap\n", __func__); | |
578 | } | |
579 | break; | |
580 | case 2: | |
581 | /* lduw [r0], data_reg */ | |
582 | tcg_out_ldst(s, data_reg, r0, 0, LDUW); | |
583 | if (bswap) { | |
584 | fprintf(stderr, "unimplemented %s with bswap\n", __func__); | |
585 | } | |
586 | break; | |
587 | case 2 | 4: | |
588 | /* ldsw [r0], data_reg */ | |
589 | tcg_out_ldst(s, data_reg, r0, 0, LDSW); | |
590 | if (bswap) { | |
591 | fprintf(stderr, "unimplemented %s with bswap\n", __func__); | |
592 | } | |
593 | break; | |
594 | case 3: | |
595 | /* ldx [r0], data_reg */ | |
596 | tcg_out_ldst(s, data_reg, r0, 0, LDX); | |
597 | if (bswap) { | |
598 | fprintf(stderr, "unimplemented %s with bswap\n", __func__); | |
599 | } | |
600 | break; | |
601 | default: | |
602 | tcg_abort(); | |
603 | } | |
604 | ||
605 | #if defined(CONFIG_SOFTMMU) | |
606 | /* label2: */ | |
9a7f3228 | 607 | *label2_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) | |
f5ef6aac BS |
608 | INSN_OFF22((unsigned long)label2_ptr - |
609 | (unsigned long)s->code_ptr)); | |
610 | #endif | |
611 | } | |
612 | ||
613 | static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, | |
614 | int opc) | |
615 | { | |
616 | int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, ld_op; | |
617 | #if defined(CONFIG_SOFTMMU) | |
618 | uint8_t *label1_ptr, *label2_ptr; | |
619 | #endif | |
620 | ||
621 | data_reg = *args++; | |
622 | addr_reg = *args++; | |
623 | mem_index = *args; | |
624 | ||
625 | s_bits = opc; | |
626 | ||
627 | r0 = TCG_REG_I5; | |
628 | r1 = TCG_REG_I4; | |
629 | ||
630 | #if TARGET_LONG_BITS == 32 | |
631 | ld_op = LDUW; | |
632 | #else | |
633 | ld_op = LDX; | |
634 | #endif | |
635 | ||
636 | #if defined(CONFIG_SOFTMMU) | |
637 | /* srl addr_reg, x, r1 */ | |
638 | tcg_out_arithi(s, r1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS, | |
639 | SHIFT_SRL); | |
640 | /* and addr_reg, x, r0 */ | |
641 | tcg_out_arithi(s, r0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1), | |
642 | ARITH_AND); | |
643 | ||
644 | /* and r1, x, r1 */ | |
645 | tcg_out_arithi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, | |
646 | ARITH_AND); | |
647 | ||
648 | /* add r1, x, r1 */ | |
649 | tcg_out_arithi(s, r1, r1, | |
650 | offsetof(CPUState, tlb_table[mem_index][0].addr_write), | |
651 | ARITH_ADD); | |
652 | ||
653 | /* ld [env + r1], r1 */ | |
654 | tcg_out_ldst(s, r1, TCG_AREG0, r1, ld_op); | |
655 | ||
656 | /* subcc r0, r1, %g0 */ | |
657 | tcg_out_arith(s, TCG_REG_G0, r0, r1, ARITH_SUBCC); | |
658 | ||
659 | /* will become: | |
660 | be label1 */ | |
661 | label1_ptr = s->code_ptr; | |
662 | tcg_out32(s, 0); | |
663 | /* mov (delay slot)*/ | |
664 | tcg_out_mov(s, r0, addr_reg); | |
665 | ||
666 | switch(opc) { | |
667 | case 0 | 4: | |
668 | /* sll i0, 24/56, i0 */ | |
669 | tcg_out_arithi(s, TCG_REG_I0, TCG_REG_I0, | |
670 | sizeof(tcg_target_long) * 8 - 8, SHIFT_SLL); | |
671 | /* sra i0, 24/56, data_reg */ | |
672 | tcg_out_arithi(s, data_reg, TCG_REG_I0, | |
673 | sizeof(tcg_target_long) * 8 - 8, SHIFT_SRA); | |
674 | break; | |
675 | case 1 | 4: | |
676 | /* sll i0, 16/48, i0 */ | |
677 | tcg_out_arithi(s, TCG_REG_I0, TCG_REG_I0, | |
678 | sizeof(tcg_target_long) * 8 - 16, SHIFT_SLL); | |
679 | /* sra i0, 16/48, data_reg */ | |
680 | tcg_out_arithi(s, data_reg, TCG_REG_I0, | |
681 | sizeof(tcg_target_long) * 8 - 16, SHIFT_SRA); | |
682 | break; | |
683 | case 2 | 4: | |
684 | /* sll i0, 32, i0 */ | |
685 | tcg_out_arithi(s, TCG_REG_I0, TCG_REG_I0, 32, SHIFT_SLL); | |
686 | /* sra i0, 32, data_reg */ | |
687 | tcg_out_arithi(s, data_reg, TCG_REG_I0, 32, SHIFT_SRA); | |
688 | break; | |
689 | case 0: | |
690 | case 1: | |
691 | case 2: | |
692 | case 3: | |
693 | default: | |
694 | /* mov */ | |
695 | tcg_out_mov(s, data_reg, TCG_REG_I0); | |
696 | break; | |
697 | } | |
698 | ||
699 | tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_st_helpers[s_bits] | |
700 | - (tcg_target_ulong)s->code_ptr) >> 2) | |
701 | & 0x3fffffff)); | |
702 | /* mov (delay slot)*/ | |
703 | tcg_out_movi(s, TCG_TYPE_I32, r1, mem_index); | |
704 | ||
705 | /* will become: | |
706 | ba label2 */ | |
707 | label2_ptr = s->code_ptr; | |
708 | tcg_out32(s, 0); | |
709 | ||
710 | /* label1: */ | |
9a7f3228 | 711 | *label1_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) | |
f5ef6aac BS |
712 | INSN_OFF22((unsigned long)label1_ptr - |
713 | (unsigned long)s->code_ptr)); | |
714 | ||
715 | /* ld [r1 + x], r1 */ | |
716 | tcg_out_ldst(s, r1, r1, offsetof(CPUTLBEntry, addend) - | |
717 | offsetof(CPUTLBEntry, addr_write), ld_op); | |
718 | /* add x(r1), r0 */ | |
719 | tcg_out_arith(s, r0, r1, r0, ARITH_ADD); | |
720 | #else | |
721 | r0 = addr_reg; | |
722 | #endif | |
723 | ||
724 | #ifdef TARGET_WORDS_BIGENDIAN | |
725 | bswap = 0; | |
726 | #else | |
727 | bswap = 1; | |
728 | #endif | |
729 | switch(opc) { | |
730 | case 0: | |
731 | /* stb data_reg, [r0] */ | |
732 | tcg_out_ldst(s, data_reg, r0, 0, STB); | |
733 | break; | |
734 | case 1: | |
735 | if (bswap) { | |
736 | fprintf(stderr, "unimplemented %s with bswap\n", __func__); | |
737 | } | |
738 | /* sth data_reg, [r0] */ | |
739 | tcg_out_ldst(s, data_reg, r0, 0, STH); | |
740 | break; | |
741 | case 2: | |
742 | if (bswap) { | |
743 | fprintf(stderr, "unimplemented %s with bswap\n", __func__); | |
744 | } | |
745 | /* stw data_reg, [r0] */ | |
746 | tcg_out_ldst(s, data_reg, r0, 0, STW); | |
747 | break; | |
748 | case 3: | |
749 | if (bswap) { | |
750 | fprintf(stderr, "unimplemented %s with bswap\n", __func__); | |
751 | } | |
752 | /* stx data_reg, [r0] */ | |
753 | tcg_out_ldst(s, data_reg, r0, 0, STX); | |
754 | break; | |
755 | default: | |
756 | tcg_abort(); | |
757 | } | |
758 | ||
759 | #if defined(CONFIG_SOFTMMU) | |
760 | /* label2: */ | |
9a7f3228 | 761 | *label2_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) | |
f5ef6aac BS |
762 | INSN_OFF22((unsigned long)label2_ptr - |
763 | (unsigned long)s->code_ptr)); | |
764 | #endif | |
765 | } | |
766 | ||
8289b279 BS |
767 | static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, |
768 | const int *const_args) | |
769 | { | |
770 | int c; | |
771 | ||
772 | switch (opc) { | |
773 | case INDEX_op_exit_tb: | |
b3db8758 BS |
774 | tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I0, args[0]); |
775 | tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I7) | | |
8289b279 | 776 | INSN_IMM13(8)); |
b3db8758 BS |
777 | tcg_out32(s, RESTORE | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_G0) | |
778 | INSN_RS2(TCG_REG_G0)); | |
8289b279 BS |
779 | break; |
780 | case INDEX_op_goto_tb: | |
781 | if (s->tb_jmp_offset) { | |
782 | /* direct jump method */ | |
cf7c2ca5 BS |
783 | tcg_out32(s, SETHI | INSN_RD(TCG_REG_I5) | |
784 | ((args[0] & 0xffffe000) >> 10)); | |
785 | tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) | | |
786 | INSN_IMM13((args[0] & 0x1fff))); | |
8289b279 | 787 | s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; |
8289b279 BS |
788 | } else { |
789 | /* indirect jump method */ | |
b3db8758 BS |
790 | tcg_out_ld_ptr(s, TCG_REG_I5, (tcg_target_long)(s->tb_next + args[0])); |
791 | tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) | | |
792 | INSN_RS2(TCG_REG_G0)); | |
8289b279 | 793 | } |
53cd9273 | 794 | tcg_out_nop(s); |
8289b279 BS |
795 | s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; |
796 | break; | |
797 | case INDEX_op_call: | |
798 | if (const_args[0]) { | |
799 | tcg_out32(s, CALL | ((((tcg_target_ulong)args[0] | |
800 | - (tcg_target_ulong)s->code_ptr) >> 2) | |
801 | & 0x3fffffff)); | |
802 | tcg_out_nop(s); | |
803 | } else { | |
cf7c2ca5 BS |
804 | tcg_out_ld_ptr(s, TCG_REG_I5, (tcg_target_long)(s->tb_next + args[0])); |
805 | tcg_out32(s, JMPL | INSN_RD(TCG_REG_O7) | INSN_RS1(TCG_REG_I5) | | |
2f0a5008 | 806 | INSN_RS2(TCG_REG_G0)); |
8289b279 BS |
807 | tcg_out_nop(s); |
808 | } | |
809 | break; | |
810 | case INDEX_op_jmp: | |
8289b279 | 811 | case INDEX_op_br: |
f5ef6aac BS |
812 | tcg_out_branch(s, COND_A, args[0]); |
813 | tcg_out_nop(s); | |
8289b279 BS |
814 | break; |
815 | case INDEX_op_movi_i32: | |
816 | tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]); | |
817 | break; | |
818 | ||
819 | #if defined(__sparc_v9__) && !defined(__sparc_v8plus__) | |
820 | #define OP_32_64(x) \ | |
821 | glue(glue(case INDEX_op_, x), _i32:) \ | |
822 | glue(glue(case INDEX_op_, x), _i64:) | |
823 | #else | |
824 | #define OP_32_64(x) \ | |
825 | glue(glue(case INDEX_op_, x), _i32:) | |
826 | #endif | |
827 | OP_32_64(ld8u); | |
828 | tcg_out_ldst(s, args[0], args[1], args[2], LDUB); | |
829 | break; | |
830 | OP_32_64(ld8s); | |
831 | tcg_out_ldst(s, args[0], args[1], args[2], LDSB); | |
832 | break; | |
833 | OP_32_64(ld16u); | |
834 | tcg_out_ldst(s, args[0], args[1], args[2], LDUH); | |
835 | break; | |
836 | OP_32_64(ld16s); | |
837 | tcg_out_ldst(s, args[0], args[1], args[2], LDSH); | |
838 | break; | |
839 | case INDEX_op_ld_i32: | |
840 | #if defined(__sparc_v9__) && !defined(__sparc_v8plus__) | |
53cd9273 | 841 | case INDEX_op_ld32u_i64: |
8289b279 BS |
842 | #endif |
843 | tcg_out_ldst(s, args[0], args[1], args[2], LDUW); | |
844 | break; | |
845 | OP_32_64(st8); | |
846 | tcg_out_ldst(s, args[0], args[1], args[2], STB); | |
847 | break; | |
848 | OP_32_64(st16); | |
849 | tcg_out_ldst(s, args[0], args[1], args[2], STH); | |
850 | break; | |
851 | case INDEX_op_st_i32: | |
852 | #if defined(__sparc_v9__) && !defined(__sparc_v8plus__) | |
53cd9273 | 853 | case INDEX_op_st32_i64: |
8289b279 BS |
854 | #endif |
855 | tcg_out_ldst(s, args[0], args[1], args[2], STW); | |
856 | break; | |
53cd9273 BS |
857 | OP_32_64(add); |
858 | c = ARITH_ADD; | |
859 | goto gen_arith32; | |
8289b279 BS |
860 | OP_32_64(sub); |
861 | c = ARITH_SUB; | |
862 | goto gen_arith32; | |
863 | OP_32_64(and); | |
864 | c = ARITH_AND; | |
865 | goto gen_arith32; | |
866 | OP_32_64(or); | |
867 | c = ARITH_OR; | |
868 | goto gen_arith32; | |
869 | OP_32_64(xor); | |
870 | c = ARITH_XOR; | |
871 | goto gen_arith32; | |
872 | case INDEX_op_shl_i32: | |
873 | c = SHIFT_SLL; | |
874 | goto gen_arith32; | |
875 | case INDEX_op_shr_i32: | |
876 | c = SHIFT_SRL; | |
877 | goto gen_arith32; | |
878 | case INDEX_op_sar_i32: | |
879 | c = SHIFT_SRA; | |
880 | goto gen_arith32; | |
881 | case INDEX_op_mul_i32: | |
882 | c = ARITH_UMUL; | |
883 | goto gen_arith32; | |
8289b279 BS |
884 | case INDEX_op_div2_i32: |
885 | #if defined(__sparc_v9__) || defined(__sparc_v8plus__) | |
886 | c = ARITH_SDIVX; | |
887 | goto gen_arith32; | |
888 | #else | |
889 | tcg_out_sety(s, 0); | |
890 | c = ARITH_SDIV; | |
891 | goto gen_arith32; | |
892 | #endif | |
893 | case INDEX_op_divu2_i32: | |
894 | #if defined(__sparc_v9__) || defined(__sparc_v8plus__) | |
895 | c = ARITH_UDIVX; | |
896 | goto gen_arith32; | |
897 | #else | |
898 | tcg_out_sety(s, 0); | |
899 | c = ARITH_UDIV; | |
900 | goto gen_arith32; | |
901 | #endif | |
902 | ||
903 | case INDEX_op_brcond_i32: | |
cf7c2ca5 BS |
904 | tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], |
905 | args[3]); | |
8289b279 BS |
906 | break; |
907 | ||
908 | case INDEX_op_qemu_ld8u: | |
f5ef6aac | 909 | tcg_out_qemu_ld(s, args, 0); |
8289b279 BS |
910 | break; |
911 | case INDEX_op_qemu_ld8s: | |
f5ef6aac | 912 | tcg_out_qemu_ld(s, args, 0 | 4); |
8289b279 BS |
913 | break; |
914 | case INDEX_op_qemu_ld16u: | |
f5ef6aac | 915 | tcg_out_qemu_ld(s, args, 1); |
8289b279 BS |
916 | break; |
917 | case INDEX_op_qemu_ld16s: | |
f5ef6aac | 918 | tcg_out_qemu_ld(s, args, 1 | 4); |
8289b279 BS |
919 | break; |
920 | case INDEX_op_qemu_ld32u: | |
f5ef6aac | 921 | tcg_out_qemu_ld(s, args, 2); |
8289b279 BS |
922 | break; |
923 | case INDEX_op_qemu_ld32s: | |
f5ef6aac | 924 | tcg_out_qemu_ld(s, args, 2 | 4); |
8289b279 BS |
925 | break; |
926 | case INDEX_op_qemu_st8: | |
f5ef6aac | 927 | tcg_out_qemu_st(s, args, 0); |
8289b279 BS |
928 | break; |
929 | case INDEX_op_qemu_st16: | |
f5ef6aac | 930 | tcg_out_qemu_st(s, args, 1); |
8289b279 BS |
931 | break; |
932 | case INDEX_op_qemu_st32: | |
f5ef6aac | 933 | tcg_out_qemu_st(s, args, 2); |
8289b279 BS |
934 | break; |
935 | ||
936 | #if defined(__sparc_v9__) && !defined(__sparc_v8plus__) | |
937 | case INDEX_op_movi_i64: | |
938 | tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]); | |
939 | break; | |
53cd9273 BS |
940 | case INDEX_op_ld32s_i64: |
941 | tcg_out_ldst(s, args[0], args[1], args[2], LDSW); | |
942 | break; | |
8289b279 BS |
943 | case INDEX_op_ld_i64: |
944 | tcg_out_ldst(s, args[0], args[1], args[2], LDX); | |
945 | break; | |
946 | case INDEX_op_st_i64: | |
947 | tcg_out_ldst(s, args[0], args[1], args[2], STX); | |
948 | break; | |
949 | case INDEX_op_shl_i64: | |
950 | c = SHIFT_SLLX; | |
951 | goto gen_arith32; | |
952 | case INDEX_op_shr_i64: | |
953 | c = SHIFT_SRLX; | |
954 | goto gen_arith32; | |
955 | case INDEX_op_sar_i64: | |
956 | c = SHIFT_SRAX; | |
957 | goto gen_arith32; | |
958 | case INDEX_op_mul_i64: | |
959 | c = ARITH_MULX; | |
960 | goto gen_arith32; | |
961 | case INDEX_op_div2_i64: | |
53cd9273 | 962 | c = ARITH_SDIVX; |
8289b279 BS |
963 | goto gen_arith32; |
964 | case INDEX_op_divu2_i64: | |
965 | c = ARITH_UDIVX; | |
966 | goto gen_arith32; | |
967 | ||
968 | case INDEX_op_brcond_i64: | |
f5ef6aac BS |
969 | tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], |
970 | args[3]); | |
8289b279 BS |
971 | break; |
972 | case INDEX_op_qemu_ld64: | |
f5ef6aac | 973 | tcg_out_qemu_ld(s, args, 3); |
8289b279 BS |
974 | break; |
975 | case INDEX_op_qemu_st64: | |
f5ef6aac | 976 | tcg_out_qemu_st(s, args, 3); |
8289b279 BS |
977 | break; |
978 | ||
979 | #endif | |
53cd9273 BS |
980 | gen_arith32: |
981 | if (const_args[2]) { | |
982 | tcg_out_arithi(s, args[0], args[1], args[2], c); | |
983 | } else { | |
984 | tcg_out_arith(s, args[0], args[1], args[2], c); | |
985 | } | |
986 | break; | |
987 | ||
8289b279 BS |
988 | default: |
989 | fprintf(stderr, "unknown opcode 0x%x\n", opc); | |
990 | tcg_abort(); | |
991 | } | |
992 | } | |
993 | ||
994 | static const TCGTargetOpDef sparc_op_defs[] = { | |
995 | { INDEX_op_exit_tb, { } }, | |
b3db8758 | 996 | { INDEX_op_goto_tb, { } }, |
8289b279 BS |
997 | { INDEX_op_call, { "ri" } }, |
998 | { INDEX_op_jmp, { "ri" } }, | |
999 | { INDEX_op_br, { } }, | |
1000 | ||
1001 | { INDEX_op_mov_i32, { "r", "r" } }, | |
1002 | { INDEX_op_movi_i32, { "r" } }, | |
1003 | { INDEX_op_ld8u_i32, { "r", "r" } }, | |
1004 | { INDEX_op_ld8s_i32, { "r", "r" } }, | |
1005 | { INDEX_op_ld16u_i32, { "r", "r" } }, | |
1006 | { INDEX_op_ld16s_i32, { "r", "r" } }, | |
1007 | { INDEX_op_ld_i32, { "r", "r" } }, | |
1008 | { INDEX_op_st8_i32, { "r", "r" } }, | |
1009 | { INDEX_op_st16_i32, { "r", "r" } }, | |
1010 | { INDEX_op_st_i32, { "r", "r" } }, | |
1011 | ||
53cd9273 BS |
1012 | { INDEX_op_add_i32, { "r", "r", "rJ" } }, |
1013 | { INDEX_op_mul_i32, { "r", "r", "rJ" } }, | |
8289b279 BS |
1014 | { INDEX_op_div2_i32, { "r", "r", "0", "1", "r" } }, |
1015 | { INDEX_op_divu2_i32, { "r", "r", "0", "1", "r" } }, | |
53cd9273 BS |
1016 | { INDEX_op_sub_i32, { "r", "r", "rJ" } }, |
1017 | { INDEX_op_and_i32, { "r", "r", "rJ" } }, | |
1018 | { INDEX_op_or_i32, { "r", "r", "rJ" } }, | |
1019 | { INDEX_op_xor_i32, { "r", "r", "rJ" } }, | |
8289b279 | 1020 | |
53cd9273 BS |
1021 | { INDEX_op_shl_i32, { "r", "r", "rJ" } }, |
1022 | { INDEX_op_shr_i32, { "r", "r", "rJ" } }, | |
1023 | { INDEX_op_sar_i32, { "r", "r", "rJ" } }, | |
8289b279 BS |
1024 | |
1025 | { INDEX_op_brcond_i32, { "r", "ri" } }, | |
1026 | ||
1027 | { INDEX_op_qemu_ld8u, { "r", "L" } }, | |
1028 | { INDEX_op_qemu_ld8s, { "r", "L" } }, | |
1029 | { INDEX_op_qemu_ld16u, { "r", "L" } }, | |
1030 | { INDEX_op_qemu_ld16s, { "r", "L" } }, | |
1031 | { INDEX_op_qemu_ld32u, { "r", "L" } }, | |
1032 | { INDEX_op_qemu_ld32s, { "r", "L" } }, | |
1033 | ||
1034 | { INDEX_op_qemu_st8, { "L", "L" } }, | |
1035 | { INDEX_op_qemu_st16, { "L", "L" } }, | |
1036 | { INDEX_op_qemu_st32, { "L", "L" } }, | |
1037 | ||
1038 | #if defined(__sparc_v9__) && !defined(__sparc_v8plus__) | |
1039 | { INDEX_op_mov_i64, { "r", "r" } }, | |
1040 | { INDEX_op_movi_i64, { "r" } }, | |
1041 | { INDEX_op_ld8u_i64, { "r", "r" } }, | |
1042 | { INDEX_op_ld8s_i64, { "r", "r" } }, | |
1043 | { INDEX_op_ld16u_i64, { "r", "r" } }, | |
1044 | { INDEX_op_ld16s_i64, { "r", "r" } }, | |
1045 | { INDEX_op_ld32u_i64, { "r", "r" } }, | |
1046 | { INDEX_op_ld32s_i64, { "r", "r" } }, | |
1047 | { INDEX_op_ld_i64, { "r", "r" } }, | |
1048 | { INDEX_op_st8_i64, { "r", "r" } }, | |
1049 | { INDEX_op_st16_i64, { "r", "r" } }, | |
1050 | { INDEX_op_st32_i64, { "r", "r" } }, | |
1051 | { INDEX_op_st_i64, { "r", "r" } }, | |
1052 | ||
53cd9273 BS |
1053 | { INDEX_op_add_i64, { "r", "r", "rJ" } }, |
1054 | { INDEX_op_mul_i64, { "r", "r", "rJ" } }, | |
8289b279 BS |
1055 | { INDEX_op_div2_i64, { "r", "r", "0", "1", "r" } }, |
1056 | { INDEX_op_divu2_i64, { "r", "r", "0", "1", "r" } }, | |
53cd9273 BS |
1057 | { INDEX_op_sub_i64, { "r", "r", "rJ" } }, |
1058 | { INDEX_op_and_i64, { "r", "r", "rJ" } }, | |
1059 | { INDEX_op_or_i64, { "r", "r", "rJ" } }, | |
1060 | { INDEX_op_xor_i64, { "r", "r", "rJ" } }, | |
8289b279 | 1061 | |
53cd9273 BS |
1062 | { INDEX_op_shl_i64, { "r", "r", "rJ" } }, |
1063 | { INDEX_op_shr_i64, { "r", "r", "rJ" } }, | |
1064 | { INDEX_op_sar_i64, { "r", "r", "rJ" } }, | |
8289b279 BS |
1065 | |
1066 | { INDEX_op_brcond_i64, { "r", "ri" } }, | |
1067 | #endif | |
1068 | { -1 }, | |
1069 | }; | |
1070 | ||
1071 | void tcg_target_init(TCGContext *s) | |
1072 | { | |
1073 | tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); | |
1074 | #if defined(__sparc_v9__) && !defined(__sparc_v8plus__) | |
1075 | tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff); | |
1076 | #endif | |
1077 | tcg_regset_set32(tcg_target_call_clobber_regs, 0, | |
b3db8758 BS |
1078 | (1 << TCG_REG_G1) | |
1079 | (1 << TCG_REG_G2) | | |
1080 | (1 << TCG_REG_G3) | | |
1081 | (1 << TCG_REG_G4) | | |
1082 | (1 << TCG_REG_G5) | | |
1083 | (1 << TCG_REG_G6) | | |
1084 | (1 << TCG_REG_G7) | | |
8289b279 BS |
1085 | (1 << TCG_REG_O0) | |
1086 | (1 << TCG_REG_O1) | | |
1087 | (1 << TCG_REG_O2) | | |
1088 | (1 << TCG_REG_O3) | | |
1089 | (1 << TCG_REG_O4) | | |
1090 | (1 << TCG_REG_O5) | | |
8289b279 BS |
1091 | (1 << TCG_REG_O7)); |
1092 | ||
1093 | tcg_regset_clear(s->reserved_regs); | |
1094 | tcg_regset_set_reg(s->reserved_regs, TCG_REG_G0); | |
53cd9273 | 1095 | tcg_regset_set_reg(s->reserved_regs, TCG_REG_I5); // for internal use |
8289b279 BS |
1096 | tcg_regset_set_reg(s->reserved_regs, TCG_REG_I6); |
1097 | tcg_regset_set_reg(s->reserved_regs, TCG_REG_I7); | |
1098 | tcg_regset_set_reg(s->reserved_regs, TCG_REG_O6); | |
1099 | tcg_regset_set_reg(s->reserved_regs, TCG_REG_O7); | |
1100 | tcg_add_target_add_op_defs(sparc_op_defs); | |
1101 | } |