]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * OpenRISC translation | |
3 | * | |
4 | * Copyright (c) 2011-2012 Jia Liu <[email protected]> | |
5 | * Feng Gao <[email protected]> | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
19 | */ | |
20 | ||
21 | #include "qemu/osdep.h" | |
22 | #include "cpu.h" | |
23 | #include "exec/exec-all.h" | |
24 | #include "disas/disas.h" | |
25 | #include "tcg/tcg-op.h" | |
26 | #include "qemu/log.h" | |
27 | #include "qemu/bitops.h" | |
28 | #include "qemu/qemu-print.h" | |
29 | #include "exec/cpu_ldst.h" | |
30 | #include "exec/translator.h" | |
31 | ||
32 | #include "exec/helper-proto.h" | |
33 | #include "exec/helper-gen.h" | |
34 | #include "exec/gen-icount.h" | |
35 | ||
36 | #include "exec/log.h" | |
37 | ||
38 | /* is_jmp field values */ | |
39 | #define DISAS_EXIT DISAS_TARGET_0 /* force exit to main loop */ | |
40 | #define DISAS_JUMP DISAS_TARGET_1 /* exit via jmp_pc/jmp_pc_imm */ | |
41 | ||
42 | typedef struct DisasContext { | |
43 | DisasContextBase base; | |
44 | uint32_t mem_idx; | |
45 | uint32_t tb_flags; | |
46 | uint32_t delayed_branch; | |
47 | uint32_t cpucfgr; | |
48 | uint32_t avr; | |
49 | ||
50 | /* If not -1, jmp_pc contains this value and so is a direct jump. */ | |
51 | target_ulong jmp_pc_imm; | |
52 | ||
53 | /* The temporary corresponding to register 0 for this compilation. */ | |
54 | TCGv R0; | |
55 | /* The constant zero. */ | |
56 | TCGv zero; | |
57 | } DisasContext; | |
58 | ||
59 | static inline bool is_user(DisasContext *dc) | |
60 | { | |
61 | #ifdef CONFIG_USER_ONLY | |
62 | return true; | |
63 | #else | |
64 | return !(dc->tb_flags & TB_FLAGS_SM); | |
65 | #endif | |
66 | } | |
67 | ||
68 | /* Include the auto-generated decoder. */ | |
69 | #include "decode-insns.c.inc" | |
70 | ||
71 | static TCGv cpu_sr; | |
72 | static TCGv cpu_regs[32]; | |
73 | static TCGv cpu_pc; | |
74 | static TCGv jmp_pc; /* l.jr/l.jalr temp pc */ | |
75 | static TCGv cpu_ppc; | |
76 | static TCGv cpu_sr_f; /* bf/bnf, F flag taken */ | |
77 | static TCGv cpu_sr_cy; /* carry (unsigned overflow) */ | |
78 | static TCGv cpu_sr_ov; /* signed overflow */ | |
79 | static TCGv cpu_lock_addr; | |
80 | static TCGv cpu_lock_value; | |
81 | static TCGv_i32 fpcsr; | |
82 | static TCGv_i64 cpu_mac; /* MACHI:MACLO */ | |
83 | static TCGv_i32 cpu_dflag; | |
84 | ||
85 | void openrisc_translate_init(void) | |
86 | { | |
87 | static const char * const regnames[] = { | |
88 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | |
89 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", | |
90 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", | |
91 | "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", | |
92 | }; | |
93 | int i; | |
94 | ||
95 | cpu_sr = tcg_global_mem_new(cpu_env, | |
96 | offsetof(CPUOpenRISCState, sr), "sr"); | |
97 | cpu_dflag = tcg_global_mem_new_i32(cpu_env, | |
98 | offsetof(CPUOpenRISCState, dflag), | |
99 | "dflag"); | |
100 | cpu_pc = tcg_global_mem_new(cpu_env, | |
101 | offsetof(CPUOpenRISCState, pc), "pc"); | |
102 | cpu_ppc = tcg_global_mem_new(cpu_env, | |
103 | offsetof(CPUOpenRISCState, ppc), "ppc"); | |
104 | jmp_pc = tcg_global_mem_new(cpu_env, | |
105 | offsetof(CPUOpenRISCState, jmp_pc), "jmp_pc"); | |
106 | cpu_sr_f = tcg_global_mem_new(cpu_env, | |
107 | offsetof(CPUOpenRISCState, sr_f), "sr_f"); | |
108 | cpu_sr_cy = tcg_global_mem_new(cpu_env, | |
109 | offsetof(CPUOpenRISCState, sr_cy), "sr_cy"); | |
110 | cpu_sr_ov = tcg_global_mem_new(cpu_env, | |
111 | offsetof(CPUOpenRISCState, sr_ov), "sr_ov"); | |
112 | cpu_lock_addr = tcg_global_mem_new(cpu_env, | |
113 | offsetof(CPUOpenRISCState, lock_addr), | |
114 | "lock_addr"); | |
115 | cpu_lock_value = tcg_global_mem_new(cpu_env, | |
116 | offsetof(CPUOpenRISCState, lock_value), | |
117 | "lock_value"); | |
118 | fpcsr = tcg_global_mem_new_i32(cpu_env, | |
119 | offsetof(CPUOpenRISCState, fpcsr), | |
120 | "fpcsr"); | |
121 | cpu_mac = tcg_global_mem_new_i64(cpu_env, | |
122 | offsetof(CPUOpenRISCState, mac), | |
123 | "mac"); | |
124 | for (i = 0; i < 32; i++) { | |
125 | cpu_regs[i] = tcg_global_mem_new(cpu_env, | |
126 | offsetof(CPUOpenRISCState, | |
127 | shadow_gpr[0][i]), | |
128 | regnames[i]); | |
129 | } | |
130 | } | |
131 | ||
132 | static void gen_exception(DisasContext *dc, unsigned int excp) | |
133 | { | |
134 | gen_helper_exception(cpu_env, tcg_constant_i32(excp)); | |
135 | } | |
136 | ||
137 | static void gen_illegal_exception(DisasContext *dc) | |
138 | { | |
139 | tcg_gen_movi_tl(cpu_pc, dc->base.pc_next); | |
140 | gen_exception(dc, EXCP_ILLEGAL); | |
141 | dc->base.is_jmp = DISAS_NORETURN; | |
142 | } | |
143 | ||
144 | static bool check_v1_3(DisasContext *dc) | |
145 | { | |
146 | return dc->avr >= 0x01030000; | |
147 | } | |
148 | ||
149 | static bool check_of32s(DisasContext *dc) | |
150 | { | |
151 | return dc->cpucfgr & CPUCFGR_OF32S; | |
152 | } | |
153 | ||
154 | static bool check_of64a32s(DisasContext *dc) | |
155 | { | |
156 | return dc->cpucfgr & CPUCFGR_OF64A32S; | |
157 | } | |
158 | ||
159 | static TCGv cpu_R(DisasContext *dc, int reg) | |
160 | { | |
161 | if (reg == 0) { | |
162 | return dc->R0; | |
163 | } else { | |
164 | return cpu_regs[reg]; | |
165 | } | |
166 | } | |
167 | ||
168 | /* | |
169 | * We're about to write to REG. On the off-chance that the user is | |
170 | * writing to R0, re-instate the architectural register. | |
171 | */ | |
172 | static void check_r0_write(DisasContext *dc, int reg) | |
173 | { | |
174 | if (unlikely(reg == 0)) { | |
175 | dc->R0 = cpu_regs[0]; | |
176 | } | |
177 | } | |
178 | ||
179 | static void gen_ove_cy(DisasContext *dc) | |
180 | { | |
181 | if (dc->tb_flags & SR_OVE) { | |
182 | gen_helper_ove_cy(cpu_env); | |
183 | } | |
184 | } | |
185 | ||
186 | static void gen_ove_ov(DisasContext *dc) | |
187 | { | |
188 | if (dc->tb_flags & SR_OVE) { | |
189 | gen_helper_ove_ov(cpu_env); | |
190 | } | |
191 | } | |
192 | ||
193 | static void gen_ove_cyov(DisasContext *dc) | |
194 | { | |
195 | if (dc->tb_flags & SR_OVE) { | |
196 | gen_helper_ove_cyov(cpu_env); | |
197 | } | |
198 | } | |
199 | ||
200 | static void gen_add(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) | |
201 | { | |
202 | TCGv t0 = tcg_temp_new(); | |
203 | TCGv res = tcg_temp_new(); | |
204 | ||
205 | tcg_gen_add2_tl(res, cpu_sr_cy, srca, dc->zero, srcb, dc->zero); | |
206 | tcg_gen_xor_tl(cpu_sr_ov, srca, srcb); | |
207 | tcg_gen_xor_tl(t0, res, srcb); | |
208 | tcg_gen_andc_tl(cpu_sr_ov, t0, cpu_sr_ov); | |
209 | tcg_temp_free(t0); | |
210 | ||
211 | tcg_gen_mov_tl(dest, res); | |
212 | tcg_temp_free(res); | |
213 | ||
214 | gen_ove_cyov(dc); | |
215 | } | |
216 | ||
217 | static void gen_addc(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) | |
218 | { | |
219 | TCGv t0 = tcg_temp_new(); | |
220 | TCGv res = tcg_temp_new(); | |
221 | ||
222 | tcg_gen_add2_tl(res, cpu_sr_cy, srca, dc->zero, cpu_sr_cy, dc->zero); | |
223 | tcg_gen_add2_tl(res, cpu_sr_cy, res, cpu_sr_cy, srcb, dc->zero); | |
224 | tcg_gen_xor_tl(cpu_sr_ov, srca, srcb); | |
225 | tcg_gen_xor_tl(t0, res, srcb); | |
226 | tcg_gen_andc_tl(cpu_sr_ov, t0, cpu_sr_ov); | |
227 | tcg_temp_free(t0); | |
228 | ||
229 | tcg_gen_mov_tl(dest, res); | |
230 | tcg_temp_free(res); | |
231 | ||
232 | gen_ove_cyov(dc); | |
233 | } | |
234 | ||
235 | static void gen_sub(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) | |
236 | { | |
237 | TCGv res = tcg_temp_new(); | |
238 | ||
239 | tcg_gen_sub_tl(res, srca, srcb); | |
240 | tcg_gen_xor_tl(cpu_sr_cy, srca, srcb); | |
241 | tcg_gen_xor_tl(cpu_sr_ov, res, srcb); | |
242 | tcg_gen_and_tl(cpu_sr_ov, cpu_sr_ov, cpu_sr_cy); | |
243 | tcg_gen_setcond_tl(TCG_COND_LTU, cpu_sr_cy, srca, srcb); | |
244 | ||
245 | tcg_gen_mov_tl(dest, res); | |
246 | tcg_temp_free(res); | |
247 | ||
248 | gen_ove_cyov(dc); | |
249 | } | |
250 | ||
251 | static void gen_mul(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) | |
252 | { | |
253 | TCGv t0 = tcg_temp_new(); | |
254 | ||
255 | tcg_gen_muls2_tl(dest, cpu_sr_ov, srca, srcb); | |
256 | tcg_gen_sari_tl(t0, dest, TARGET_LONG_BITS - 1); | |
257 | tcg_gen_setcond_tl(TCG_COND_NE, cpu_sr_ov, cpu_sr_ov, t0); | |
258 | tcg_temp_free(t0); | |
259 | ||
260 | tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov); | |
261 | gen_ove_ov(dc); | |
262 | } | |
263 | ||
264 | static void gen_mulu(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) | |
265 | { | |
266 | tcg_gen_muls2_tl(dest, cpu_sr_cy, srca, srcb); | |
267 | tcg_gen_setcondi_tl(TCG_COND_NE, cpu_sr_cy, cpu_sr_cy, 0); | |
268 | ||
269 | gen_ove_cy(dc); | |
270 | } | |
271 | ||
272 | static void gen_div(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) | |
273 | { | |
274 | TCGv t0 = tcg_temp_new(); | |
275 | ||
276 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_ov, srcb, 0); | |
277 | /* The result of divide-by-zero is undefined. | |
278 | Supress the host-side exception by dividing by 1. */ | |
279 | tcg_gen_or_tl(t0, srcb, cpu_sr_ov); | |
280 | tcg_gen_div_tl(dest, srca, t0); | |
281 | tcg_temp_free(t0); | |
282 | ||
283 | tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov); | |
284 | gen_ove_ov(dc); | |
285 | } | |
286 | ||
287 | static void gen_divu(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) | |
288 | { | |
289 | TCGv t0 = tcg_temp_new(); | |
290 | ||
291 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_cy, srcb, 0); | |
292 | /* The result of divide-by-zero is undefined. | |
293 | Supress the host-side exception by dividing by 1. */ | |
294 | tcg_gen_or_tl(t0, srcb, cpu_sr_cy); | |
295 | tcg_gen_divu_tl(dest, srca, t0); | |
296 | tcg_temp_free(t0); | |
297 | ||
298 | gen_ove_cy(dc); | |
299 | } | |
300 | ||
301 | static void gen_muld(DisasContext *dc, TCGv srca, TCGv srcb) | |
302 | { | |
303 | TCGv_i64 t1 = tcg_temp_new_i64(); | |
304 | TCGv_i64 t2 = tcg_temp_new_i64(); | |
305 | ||
306 | tcg_gen_ext_tl_i64(t1, srca); | |
307 | tcg_gen_ext_tl_i64(t2, srcb); | |
308 | if (TARGET_LONG_BITS == 32) { | |
309 | tcg_gen_mul_i64(cpu_mac, t1, t2); | |
310 | tcg_gen_movi_tl(cpu_sr_ov, 0); | |
311 | } else { | |
312 | TCGv_i64 high = tcg_temp_new_i64(); | |
313 | ||
314 | tcg_gen_muls2_i64(cpu_mac, high, t1, t2); | |
315 | tcg_gen_sari_i64(t1, cpu_mac, 63); | |
316 | tcg_gen_setcond_i64(TCG_COND_NE, t1, t1, high); | |
317 | tcg_temp_free_i64(high); | |
318 | tcg_gen_trunc_i64_tl(cpu_sr_ov, t1); | |
319 | tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov); | |
320 | ||
321 | gen_ove_ov(dc); | |
322 | } | |
323 | tcg_temp_free_i64(t1); | |
324 | tcg_temp_free_i64(t2); | |
325 | } | |
326 | ||
327 | static void gen_muldu(DisasContext *dc, TCGv srca, TCGv srcb) | |
328 | { | |
329 | TCGv_i64 t1 = tcg_temp_new_i64(); | |
330 | TCGv_i64 t2 = tcg_temp_new_i64(); | |
331 | ||
332 | tcg_gen_extu_tl_i64(t1, srca); | |
333 | tcg_gen_extu_tl_i64(t2, srcb); | |
334 | if (TARGET_LONG_BITS == 32) { | |
335 | tcg_gen_mul_i64(cpu_mac, t1, t2); | |
336 | tcg_gen_movi_tl(cpu_sr_cy, 0); | |
337 | } else { | |
338 | TCGv_i64 high = tcg_temp_new_i64(); | |
339 | ||
340 | tcg_gen_mulu2_i64(cpu_mac, high, t1, t2); | |
341 | tcg_gen_setcondi_i64(TCG_COND_NE, high, high, 0); | |
342 | tcg_gen_trunc_i64_tl(cpu_sr_cy, high); | |
343 | tcg_temp_free_i64(high); | |
344 | ||
345 | gen_ove_cy(dc); | |
346 | } | |
347 | tcg_temp_free_i64(t1); | |
348 | tcg_temp_free_i64(t2); | |
349 | } | |
350 | ||
351 | static void gen_mac(DisasContext *dc, TCGv srca, TCGv srcb) | |
352 | { | |
353 | TCGv_i64 t1 = tcg_temp_new_i64(); | |
354 | TCGv_i64 t2 = tcg_temp_new_i64(); | |
355 | ||
356 | tcg_gen_ext_tl_i64(t1, srca); | |
357 | tcg_gen_ext_tl_i64(t2, srcb); | |
358 | tcg_gen_mul_i64(t1, t1, t2); | |
359 | ||
360 | /* Note that overflow is only computed during addition stage. */ | |
361 | tcg_gen_xor_i64(t2, cpu_mac, t1); | |
362 | tcg_gen_add_i64(cpu_mac, cpu_mac, t1); | |
363 | tcg_gen_xor_i64(t1, t1, cpu_mac); | |
364 | tcg_gen_andc_i64(t1, t1, t2); | |
365 | tcg_temp_free_i64(t2); | |
366 | ||
367 | #if TARGET_LONG_BITS == 32 | |
368 | tcg_gen_extrh_i64_i32(cpu_sr_ov, t1); | |
369 | #else | |
370 | tcg_gen_mov_i64(cpu_sr_ov, t1); | |
371 | #endif | |
372 | tcg_temp_free_i64(t1); | |
373 | ||
374 | gen_ove_ov(dc); | |
375 | } | |
376 | ||
377 | static void gen_macu(DisasContext *dc, TCGv srca, TCGv srcb) | |
378 | { | |
379 | TCGv_i64 t1 = tcg_temp_new_i64(); | |
380 | TCGv_i64 t2 = tcg_temp_new_i64(); | |
381 | ||
382 | tcg_gen_extu_tl_i64(t1, srca); | |
383 | tcg_gen_extu_tl_i64(t2, srcb); | |
384 | tcg_gen_mul_i64(t1, t1, t2); | |
385 | tcg_temp_free_i64(t2); | |
386 | ||
387 | /* Note that overflow is only computed during addition stage. */ | |
388 | tcg_gen_add_i64(cpu_mac, cpu_mac, t1); | |
389 | tcg_gen_setcond_i64(TCG_COND_LTU, t1, cpu_mac, t1); | |
390 | tcg_gen_trunc_i64_tl(cpu_sr_cy, t1); | |
391 | tcg_temp_free_i64(t1); | |
392 | ||
393 | gen_ove_cy(dc); | |
394 | } | |
395 | ||
396 | static void gen_msb(DisasContext *dc, TCGv srca, TCGv srcb) | |
397 | { | |
398 | TCGv_i64 t1 = tcg_temp_new_i64(); | |
399 | TCGv_i64 t2 = tcg_temp_new_i64(); | |
400 | ||
401 | tcg_gen_ext_tl_i64(t1, srca); | |
402 | tcg_gen_ext_tl_i64(t2, srcb); | |
403 | tcg_gen_mul_i64(t1, t1, t2); | |
404 | ||
405 | /* Note that overflow is only computed during subtraction stage. */ | |
406 | tcg_gen_xor_i64(t2, cpu_mac, t1); | |
407 | tcg_gen_sub_i64(cpu_mac, cpu_mac, t1); | |
408 | tcg_gen_xor_i64(t1, t1, cpu_mac); | |
409 | tcg_gen_and_i64(t1, t1, t2); | |
410 | tcg_temp_free_i64(t2); | |
411 | ||
412 | #if TARGET_LONG_BITS == 32 | |
413 | tcg_gen_extrh_i64_i32(cpu_sr_ov, t1); | |
414 | #else | |
415 | tcg_gen_mov_i64(cpu_sr_ov, t1); | |
416 | #endif | |
417 | tcg_temp_free_i64(t1); | |
418 | ||
419 | gen_ove_ov(dc); | |
420 | } | |
421 | ||
422 | static void gen_msbu(DisasContext *dc, TCGv srca, TCGv srcb) | |
423 | { | |
424 | TCGv_i64 t1 = tcg_temp_new_i64(); | |
425 | TCGv_i64 t2 = tcg_temp_new_i64(); | |
426 | ||
427 | tcg_gen_extu_tl_i64(t1, srca); | |
428 | tcg_gen_extu_tl_i64(t2, srcb); | |
429 | tcg_gen_mul_i64(t1, t1, t2); | |
430 | ||
431 | /* Note that overflow is only computed during subtraction stage. */ | |
432 | tcg_gen_setcond_i64(TCG_COND_LTU, t2, cpu_mac, t1); | |
433 | tcg_gen_sub_i64(cpu_mac, cpu_mac, t1); | |
434 | tcg_gen_trunc_i64_tl(cpu_sr_cy, t2); | |
435 | tcg_temp_free_i64(t2); | |
436 | tcg_temp_free_i64(t1); | |
437 | ||
438 | gen_ove_cy(dc); | |
439 | } | |
440 | ||
441 | static bool trans_l_add(DisasContext *dc, arg_dab *a) | |
442 | { | |
443 | check_r0_write(dc, a->d); | |
444 | gen_add(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
445 | return true; | |
446 | } | |
447 | ||
448 | static bool trans_l_addc(DisasContext *dc, arg_dab *a) | |
449 | { | |
450 | check_r0_write(dc, a->d); | |
451 | gen_addc(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
452 | return true; | |
453 | } | |
454 | ||
455 | static bool trans_l_sub(DisasContext *dc, arg_dab *a) | |
456 | { | |
457 | check_r0_write(dc, a->d); | |
458 | gen_sub(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
459 | return true; | |
460 | } | |
461 | ||
462 | static bool trans_l_and(DisasContext *dc, arg_dab *a) | |
463 | { | |
464 | check_r0_write(dc, a->d); | |
465 | tcg_gen_and_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
466 | return true; | |
467 | } | |
468 | ||
469 | static bool trans_l_or(DisasContext *dc, arg_dab *a) | |
470 | { | |
471 | check_r0_write(dc, a->d); | |
472 | tcg_gen_or_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
473 | return true; | |
474 | } | |
475 | ||
476 | static bool trans_l_xor(DisasContext *dc, arg_dab *a) | |
477 | { | |
478 | check_r0_write(dc, a->d); | |
479 | tcg_gen_xor_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
480 | return true; | |
481 | } | |
482 | ||
483 | static bool trans_l_sll(DisasContext *dc, arg_dab *a) | |
484 | { | |
485 | check_r0_write(dc, a->d); | |
486 | tcg_gen_shl_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
487 | return true; | |
488 | } | |
489 | ||
490 | static bool trans_l_srl(DisasContext *dc, arg_dab *a) | |
491 | { | |
492 | check_r0_write(dc, a->d); | |
493 | tcg_gen_shr_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
494 | return true; | |
495 | } | |
496 | ||
497 | static bool trans_l_sra(DisasContext *dc, arg_dab *a) | |
498 | { | |
499 | check_r0_write(dc, a->d); | |
500 | tcg_gen_sar_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
501 | return true; | |
502 | } | |
503 | ||
504 | static bool trans_l_ror(DisasContext *dc, arg_dab *a) | |
505 | { | |
506 | check_r0_write(dc, a->d); | |
507 | tcg_gen_rotr_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
508 | return true; | |
509 | } | |
510 | ||
511 | static bool trans_l_exths(DisasContext *dc, arg_da *a) | |
512 | { | |
513 | check_r0_write(dc, a->d); | |
514 | tcg_gen_ext16s_tl(cpu_R(dc, a->d), cpu_R(dc, a->a)); | |
515 | return true; | |
516 | } | |
517 | ||
518 | static bool trans_l_extbs(DisasContext *dc, arg_da *a) | |
519 | { | |
520 | check_r0_write(dc, a->d); | |
521 | tcg_gen_ext8s_tl(cpu_R(dc, a->d), cpu_R(dc, a->a)); | |
522 | return true; | |
523 | } | |
524 | ||
525 | static bool trans_l_exthz(DisasContext *dc, arg_da *a) | |
526 | { | |
527 | check_r0_write(dc, a->d); | |
528 | tcg_gen_ext16u_tl(cpu_R(dc, a->d), cpu_R(dc, a->a)); | |
529 | return true; | |
530 | } | |
531 | ||
532 | static bool trans_l_extbz(DisasContext *dc, arg_da *a) | |
533 | { | |
534 | check_r0_write(dc, a->d); | |
535 | tcg_gen_ext8u_tl(cpu_R(dc, a->d), cpu_R(dc, a->a)); | |
536 | return true; | |
537 | } | |
538 | ||
539 | static bool trans_l_cmov(DisasContext *dc, arg_dab *a) | |
540 | { | |
541 | check_r0_write(dc, a->d); | |
542 | tcg_gen_movcond_tl(TCG_COND_NE, cpu_R(dc, a->d), cpu_sr_f, dc->zero, | |
543 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
544 | return true; | |
545 | } | |
546 | ||
547 | static bool trans_l_ff1(DisasContext *dc, arg_da *a) | |
548 | { | |
549 | check_r0_write(dc, a->d); | |
550 | tcg_gen_ctzi_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), -1); | |
551 | tcg_gen_addi_tl(cpu_R(dc, a->d), cpu_R(dc, a->d), 1); | |
552 | return true; | |
553 | } | |
554 | ||
555 | static bool trans_l_fl1(DisasContext *dc, arg_da *a) | |
556 | { | |
557 | check_r0_write(dc, a->d); | |
558 | tcg_gen_clzi_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), TARGET_LONG_BITS); | |
559 | tcg_gen_subfi_tl(cpu_R(dc, a->d), TARGET_LONG_BITS, cpu_R(dc, a->d)); | |
560 | return true; | |
561 | } | |
562 | ||
563 | static bool trans_l_mul(DisasContext *dc, arg_dab *a) | |
564 | { | |
565 | check_r0_write(dc, a->d); | |
566 | gen_mul(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
567 | return true; | |
568 | } | |
569 | ||
570 | static bool trans_l_mulu(DisasContext *dc, arg_dab *a) | |
571 | { | |
572 | check_r0_write(dc, a->d); | |
573 | gen_mulu(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
574 | return true; | |
575 | } | |
576 | ||
577 | static bool trans_l_div(DisasContext *dc, arg_dab *a) | |
578 | { | |
579 | check_r0_write(dc, a->d); | |
580 | gen_div(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
581 | return true; | |
582 | } | |
583 | ||
584 | static bool trans_l_divu(DisasContext *dc, arg_dab *a) | |
585 | { | |
586 | check_r0_write(dc, a->d); | |
587 | gen_divu(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
588 | return true; | |
589 | } | |
590 | ||
591 | static bool trans_l_muld(DisasContext *dc, arg_ab *a) | |
592 | { | |
593 | gen_muld(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
594 | return true; | |
595 | } | |
596 | ||
597 | static bool trans_l_muldu(DisasContext *dc, arg_ab *a) | |
598 | { | |
599 | gen_muldu(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
600 | return true; | |
601 | } | |
602 | ||
603 | static bool trans_l_j(DisasContext *dc, arg_l_j *a) | |
604 | { | |
605 | target_ulong tmp_pc = dc->base.pc_next + a->n * 4; | |
606 | ||
607 | tcg_gen_movi_tl(jmp_pc, tmp_pc); | |
608 | dc->jmp_pc_imm = tmp_pc; | |
609 | dc->delayed_branch = 2; | |
610 | return true; | |
611 | } | |
612 | ||
613 | static bool trans_l_jal(DisasContext *dc, arg_l_jal *a) | |
614 | { | |
615 | target_ulong tmp_pc = dc->base.pc_next + a->n * 4; | |
616 | target_ulong ret_pc = dc->base.pc_next + 8; | |
617 | ||
618 | tcg_gen_movi_tl(cpu_regs[9], ret_pc); | |
619 | /* Optimize jal being used to load the PC for PIC. */ | |
620 | if (tmp_pc != ret_pc) { | |
621 | tcg_gen_movi_tl(jmp_pc, tmp_pc); | |
622 | dc->jmp_pc_imm = tmp_pc; | |
623 | dc->delayed_branch = 2; | |
624 | } | |
625 | return true; | |
626 | } | |
627 | ||
628 | static void do_bf(DisasContext *dc, arg_l_bf *a, TCGCond cond) | |
629 | { | |
630 | target_ulong tmp_pc = dc->base.pc_next + a->n * 4; | |
631 | TCGv t_next = tcg_constant_tl(dc->base.pc_next + 8); | |
632 | TCGv t_true = tcg_constant_tl(tmp_pc); | |
633 | ||
634 | tcg_gen_movcond_tl(cond, jmp_pc, cpu_sr_f, dc->zero, t_true, t_next); | |
635 | dc->delayed_branch = 2; | |
636 | } | |
637 | ||
638 | static bool trans_l_bf(DisasContext *dc, arg_l_bf *a) | |
639 | { | |
640 | do_bf(dc, a, TCG_COND_NE); | |
641 | return true; | |
642 | } | |
643 | ||
644 | static bool trans_l_bnf(DisasContext *dc, arg_l_bf *a) | |
645 | { | |
646 | do_bf(dc, a, TCG_COND_EQ); | |
647 | return true; | |
648 | } | |
649 | ||
650 | static bool trans_l_jr(DisasContext *dc, arg_l_jr *a) | |
651 | { | |
652 | tcg_gen_mov_tl(jmp_pc, cpu_R(dc, a->b)); | |
653 | dc->delayed_branch = 2; | |
654 | return true; | |
655 | } | |
656 | ||
657 | static bool trans_l_jalr(DisasContext *dc, arg_l_jalr *a) | |
658 | { | |
659 | tcg_gen_mov_tl(jmp_pc, cpu_R(dc, a->b)); | |
660 | tcg_gen_movi_tl(cpu_regs[9], dc->base.pc_next + 8); | |
661 | dc->delayed_branch = 2; | |
662 | return true; | |
663 | } | |
664 | ||
665 | static bool trans_l_lwa(DisasContext *dc, arg_load *a) | |
666 | { | |
667 | TCGv ea; | |
668 | ||
669 | check_r0_write(dc, a->d); | |
670 | ea = tcg_temp_new(); | |
671 | tcg_gen_addi_tl(ea, cpu_R(dc, a->a), a->i); | |
672 | tcg_gen_qemu_ld_tl(cpu_R(dc, a->d), ea, dc->mem_idx, MO_TEUL); | |
673 | tcg_gen_mov_tl(cpu_lock_addr, ea); | |
674 | tcg_gen_mov_tl(cpu_lock_value, cpu_R(dc, a->d)); | |
675 | tcg_temp_free(ea); | |
676 | return true; | |
677 | } | |
678 | ||
679 | static void do_load(DisasContext *dc, arg_load *a, MemOp mop) | |
680 | { | |
681 | TCGv ea; | |
682 | ||
683 | check_r0_write(dc, a->d); | |
684 | ea = tcg_temp_new(); | |
685 | tcg_gen_addi_tl(ea, cpu_R(dc, a->a), a->i); | |
686 | tcg_gen_qemu_ld_tl(cpu_R(dc, a->d), ea, dc->mem_idx, mop); | |
687 | tcg_temp_free(ea); | |
688 | } | |
689 | ||
690 | static bool trans_l_lwz(DisasContext *dc, arg_load *a) | |
691 | { | |
692 | do_load(dc, a, MO_TEUL); | |
693 | return true; | |
694 | } | |
695 | ||
696 | static bool trans_l_lws(DisasContext *dc, arg_load *a) | |
697 | { | |
698 | do_load(dc, a, MO_TESL); | |
699 | return true; | |
700 | } | |
701 | ||
702 | static bool trans_l_lbz(DisasContext *dc, arg_load *a) | |
703 | { | |
704 | do_load(dc, a, MO_UB); | |
705 | return true; | |
706 | } | |
707 | ||
708 | static bool trans_l_lbs(DisasContext *dc, arg_load *a) | |
709 | { | |
710 | do_load(dc, a, MO_SB); | |
711 | return true; | |
712 | } | |
713 | ||
714 | static bool trans_l_lhz(DisasContext *dc, arg_load *a) | |
715 | { | |
716 | do_load(dc, a, MO_TEUW); | |
717 | return true; | |
718 | } | |
719 | ||
720 | static bool trans_l_lhs(DisasContext *dc, arg_load *a) | |
721 | { | |
722 | do_load(dc, a, MO_TESW); | |
723 | return true; | |
724 | } | |
725 | ||
726 | static bool trans_l_swa(DisasContext *dc, arg_store *a) | |
727 | { | |
728 | TCGv ea, val; | |
729 | TCGLabel *lab_fail, *lab_done; | |
730 | ||
731 | ea = tcg_temp_new(); | |
732 | tcg_gen_addi_tl(ea, cpu_R(dc, a->a), a->i); | |
733 | ||
734 | lab_fail = gen_new_label(); | |
735 | lab_done = gen_new_label(); | |
736 | tcg_gen_brcond_tl(TCG_COND_NE, ea, cpu_lock_addr, lab_fail); | |
737 | tcg_temp_free(ea); | |
738 | ||
739 | val = tcg_temp_new(); | |
740 | tcg_gen_atomic_cmpxchg_tl(val, cpu_lock_addr, cpu_lock_value, | |
741 | cpu_R(dc, a->b), dc->mem_idx, MO_TEUL); | |
742 | tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, val, cpu_lock_value); | |
743 | tcg_temp_free(val); | |
744 | ||
745 | tcg_gen_br(lab_done); | |
746 | ||
747 | gen_set_label(lab_fail); | |
748 | tcg_gen_movi_tl(cpu_sr_f, 0); | |
749 | ||
750 | gen_set_label(lab_done); | |
751 | tcg_gen_movi_tl(cpu_lock_addr, -1); | |
752 | return true; | |
753 | } | |
754 | ||
755 | static void do_store(DisasContext *dc, arg_store *a, MemOp mop) | |
756 | { | |
757 | TCGv t0 = tcg_temp_new(); | |
758 | tcg_gen_addi_tl(t0, cpu_R(dc, a->a), a->i); | |
759 | tcg_gen_qemu_st_tl(cpu_R(dc, a->b), t0, dc->mem_idx, mop); | |
760 | tcg_temp_free(t0); | |
761 | } | |
762 | ||
763 | static bool trans_l_sw(DisasContext *dc, arg_store *a) | |
764 | { | |
765 | do_store(dc, a, MO_TEUL); | |
766 | return true; | |
767 | } | |
768 | ||
769 | static bool trans_l_sb(DisasContext *dc, arg_store *a) | |
770 | { | |
771 | do_store(dc, a, MO_UB); | |
772 | return true; | |
773 | } | |
774 | ||
775 | static bool trans_l_sh(DisasContext *dc, arg_store *a) | |
776 | { | |
777 | do_store(dc, a, MO_TEUW); | |
778 | return true; | |
779 | } | |
780 | ||
781 | static bool trans_l_nop(DisasContext *dc, arg_l_nop *a) | |
782 | { | |
783 | return true; | |
784 | } | |
785 | ||
786 | static bool trans_l_adrp(DisasContext *dc, arg_l_adrp *a) | |
787 | { | |
788 | if (!check_v1_3(dc)) { | |
789 | return false; | |
790 | } | |
791 | check_r0_write(dc, a->d); | |
792 | ||
793 | tcg_gen_movi_i32(cpu_R(dc, a->d), | |
794 | (dc->base.pc_next & TARGET_PAGE_MASK) + | |
795 | ((target_long)a->i << TARGET_PAGE_BITS)); | |
796 | return true; | |
797 | } | |
798 | ||
799 | static bool trans_l_addi(DisasContext *dc, arg_rri *a) | |
800 | { | |
801 | check_r0_write(dc, a->d); | |
802 | gen_add(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), tcg_constant_tl(a->i)); | |
803 | return true; | |
804 | } | |
805 | ||
806 | static bool trans_l_addic(DisasContext *dc, arg_rri *a) | |
807 | { | |
808 | check_r0_write(dc, a->d); | |
809 | gen_addc(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), tcg_constant_tl(a->i)); | |
810 | return true; | |
811 | } | |
812 | ||
813 | static bool trans_l_muli(DisasContext *dc, arg_rri *a) | |
814 | { | |
815 | check_r0_write(dc, a->d); | |
816 | gen_mul(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), tcg_constant_tl(a->i)); | |
817 | return true; | |
818 | } | |
819 | ||
820 | static bool trans_l_maci(DisasContext *dc, arg_l_maci *a) | |
821 | { | |
822 | gen_mac(dc, cpu_R(dc, a->a), tcg_constant_tl(a->i)); | |
823 | return true; | |
824 | } | |
825 | ||
826 | static bool trans_l_andi(DisasContext *dc, arg_rrk *a) | |
827 | { | |
828 | check_r0_write(dc, a->d); | |
829 | tcg_gen_andi_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), a->k); | |
830 | return true; | |
831 | } | |
832 | ||
833 | static bool trans_l_ori(DisasContext *dc, arg_rrk *a) | |
834 | { | |
835 | check_r0_write(dc, a->d); | |
836 | tcg_gen_ori_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), a->k); | |
837 | return true; | |
838 | } | |
839 | ||
840 | static bool trans_l_xori(DisasContext *dc, arg_rri *a) | |
841 | { | |
842 | check_r0_write(dc, a->d); | |
843 | tcg_gen_xori_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), a->i); | |
844 | return true; | |
845 | } | |
846 | ||
847 | static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) | |
848 | { | |
849 | check_r0_write(dc, a->d); | |
850 | ||
851 | if (is_user(dc)) { | |
852 | gen_illegal_exception(dc); | |
853 | } else { | |
854 | TCGv spr = tcg_temp_new(); | |
855 | ||
856 | if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { | |
857 | gen_io_start(); | |
858 | if (dc->delayed_branch) { | |
859 | tcg_gen_mov_tl(cpu_pc, jmp_pc); | |
860 | tcg_gen_discard_tl(jmp_pc); | |
861 | } else { | |
862 | tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); | |
863 | } | |
864 | dc->base.is_jmp = DISAS_EXIT; | |
865 | } | |
866 | ||
867 | tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); | |
868 | gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); | |
869 | tcg_temp_free(spr); | |
870 | } | |
871 | return true; | |
872 | } | |
873 | ||
874 | static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) | |
875 | { | |
876 | if (is_user(dc)) { | |
877 | gen_illegal_exception(dc); | |
878 | } else { | |
879 | TCGv spr; | |
880 | ||
881 | if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { | |
882 | gen_io_start(); | |
883 | } | |
884 | /* For SR, we will need to exit the TB to recognize the new | |
885 | * exception state. For NPC, in theory this counts as a branch | |
886 | * (although the SPR only exists for use by an ICE). Save all | |
887 | * of the cpu state first, allowing it to be overwritten. | |
888 | */ | |
889 | if (dc->delayed_branch) { | |
890 | tcg_gen_mov_tl(cpu_pc, jmp_pc); | |
891 | tcg_gen_discard_tl(jmp_pc); | |
892 | } else { | |
893 | tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); | |
894 | } | |
895 | dc->base.is_jmp = DISAS_EXIT; | |
896 | ||
897 | spr = tcg_temp_new(); | |
898 | tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); | |
899 | gen_helper_mtspr(cpu_env, spr, cpu_R(dc, a->b)); | |
900 | tcg_temp_free(spr); | |
901 | } | |
902 | return true; | |
903 | } | |
904 | ||
905 | static bool trans_l_mac(DisasContext *dc, arg_ab *a) | |
906 | { | |
907 | gen_mac(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
908 | return true; | |
909 | } | |
910 | ||
911 | static bool trans_l_msb(DisasContext *dc, arg_ab *a) | |
912 | { | |
913 | gen_msb(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
914 | return true; | |
915 | } | |
916 | ||
917 | static bool trans_l_macu(DisasContext *dc, arg_ab *a) | |
918 | { | |
919 | gen_macu(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
920 | return true; | |
921 | } | |
922 | ||
923 | static bool trans_l_msbu(DisasContext *dc, arg_ab *a) | |
924 | { | |
925 | gen_msbu(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
926 | return true; | |
927 | } | |
928 | ||
929 | static bool trans_l_slli(DisasContext *dc, arg_dal *a) | |
930 | { | |
931 | check_r0_write(dc, a->d); | |
932 | tcg_gen_shli_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), | |
933 | a->l & (TARGET_LONG_BITS - 1)); | |
934 | return true; | |
935 | } | |
936 | ||
937 | static bool trans_l_srli(DisasContext *dc, arg_dal *a) | |
938 | { | |
939 | check_r0_write(dc, a->d); | |
940 | tcg_gen_shri_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), | |
941 | a->l & (TARGET_LONG_BITS - 1)); | |
942 | return true; | |
943 | } | |
944 | ||
945 | static bool trans_l_srai(DisasContext *dc, arg_dal *a) | |
946 | { | |
947 | check_r0_write(dc, a->d); | |
948 | tcg_gen_sari_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), | |
949 | a->l & (TARGET_LONG_BITS - 1)); | |
950 | return true; | |
951 | } | |
952 | ||
953 | static bool trans_l_rori(DisasContext *dc, arg_dal *a) | |
954 | { | |
955 | check_r0_write(dc, a->d); | |
956 | tcg_gen_rotri_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), | |
957 | a->l & (TARGET_LONG_BITS - 1)); | |
958 | return true; | |
959 | } | |
960 | ||
961 | static bool trans_l_movhi(DisasContext *dc, arg_l_movhi *a) | |
962 | { | |
963 | check_r0_write(dc, a->d); | |
964 | tcg_gen_movi_tl(cpu_R(dc, a->d), a->k << 16); | |
965 | return true; | |
966 | } | |
967 | ||
968 | static bool trans_l_macrc(DisasContext *dc, arg_l_macrc *a) | |
969 | { | |
970 | check_r0_write(dc, a->d); | |
971 | tcg_gen_trunc_i64_tl(cpu_R(dc, a->d), cpu_mac); | |
972 | tcg_gen_movi_i64(cpu_mac, 0); | |
973 | return true; | |
974 | } | |
975 | ||
976 | static bool trans_l_sfeq(DisasContext *dc, arg_ab *a) | |
977 | { | |
978 | tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, | |
979 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
980 | return true; | |
981 | } | |
982 | ||
983 | static bool trans_l_sfne(DisasContext *dc, arg_ab *a) | |
984 | { | |
985 | tcg_gen_setcond_tl(TCG_COND_NE, cpu_sr_f, | |
986 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
987 | return true; | |
988 | } | |
989 | ||
990 | static bool trans_l_sfgtu(DisasContext *dc, arg_ab *a) | |
991 | { | |
992 | tcg_gen_setcond_tl(TCG_COND_GTU, cpu_sr_f, | |
993 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
994 | return true; | |
995 | } | |
996 | ||
997 | static bool trans_l_sfgeu(DisasContext *dc, arg_ab *a) | |
998 | { | |
999 | tcg_gen_setcond_tl(TCG_COND_GEU, cpu_sr_f, | |
1000 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
1001 | return true; | |
1002 | } | |
1003 | ||
1004 | static bool trans_l_sfltu(DisasContext *dc, arg_ab *a) | |
1005 | { | |
1006 | tcg_gen_setcond_tl(TCG_COND_LTU, cpu_sr_f, | |
1007 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
1008 | return true; | |
1009 | } | |
1010 | ||
1011 | static bool trans_l_sfleu(DisasContext *dc, arg_ab *a) | |
1012 | { | |
1013 | tcg_gen_setcond_tl(TCG_COND_LEU, cpu_sr_f, | |
1014 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
1015 | return true; | |
1016 | } | |
1017 | ||
1018 | static bool trans_l_sfgts(DisasContext *dc, arg_ab *a) | |
1019 | { | |
1020 | tcg_gen_setcond_tl(TCG_COND_GT, cpu_sr_f, | |
1021 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
1022 | return true; | |
1023 | } | |
1024 | ||
1025 | static bool trans_l_sfges(DisasContext *dc, arg_ab *a) | |
1026 | { | |
1027 | tcg_gen_setcond_tl(TCG_COND_GE, cpu_sr_f, | |
1028 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
1029 | return true; | |
1030 | } | |
1031 | ||
1032 | static bool trans_l_sflts(DisasContext *dc, arg_ab *a) | |
1033 | { | |
1034 | tcg_gen_setcond_tl(TCG_COND_LT, cpu_sr_f, | |
1035 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
1036 | return true; | |
1037 | } | |
1038 | ||
1039 | static bool trans_l_sfles(DisasContext *dc, arg_ab *a) | |
1040 | { | |
1041 | tcg_gen_setcond_tl(TCG_COND_LE, | |
1042 | cpu_sr_f, cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
1043 | return true; | |
1044 | } | |
1045 | ||
1046 | static bool trans_l_sfeqi(DisasContext *dc, arg_ai *a) | |
1047 | { | |
1048 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_f, cpu_R(dc, a->a), a->i); | |
1049 | return true; | |
1050 | } | |
1051 | ||
1052 | static bool trans_l_sfnei(DisasContext *dc, arg_ai *a) | |
1053 | { | |
1054 | tcg_gen_setcondi_tl(TCG_COND_NE, cpu_sr_f, cpu_R(dc, a->a), a->i); | |
1055 | return true; | |
1056 | } | |
1057 | ||
1058 | static bool trans_l_sfgtui(DisasContext *dc, arg_ai *a) | |
1059 | { | |
1060 | tcg_gen_setcondi_tl(TCG_COND_GTU, cpu_sr_f, cpu_R(dc, a->a), a->i); | |
1061 | return true; | |
1062 | } | |
1063 | ||
1064 | static bool trans_l_sfgeui(DisasContext *dc, arg_ai *a) | |
1065 | { | |
1066 | tcg_gen_setcondi_tl(TCG_COND_GEU, cpu_sr_f, cpu_R(dc, a->a), a->i); | |
1067 | return true; | |
1068 | } | |
1069 | ||
1070 | static bool trans_l_sfltui(DisasContext *dc, arg_ai *a) | |
1071 | { | |
1072 | tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_sr_f, cpu_R(dc, a->a), a->i); | |
1073 | return true; | |
1074 | } | |
1075 | ||
1076 | static bool trans_l_sfleui(DisasContext *dc, arg_ai *a) | |
1077 | { | |
1078 | tcg_gen_setcondi_tl(TCG_COND_LEU, cpu_sr_f, cpu_R(dc, a->a), a->i); | |
1079 | return true; | |
1080 | } | |
1081 | ||
1082 | static bool trans_l_sfgtsi(DisasContext *dc, arg_ai *a) | |
1083 | { | |
1084 | tcg_gen_setcondi_tl(TCG_COND_GT, cpu_sr_f, cpu_R(dc, a->a), a->i); | |
1085 | return true; | |
1086 | } | |
1087 | ||
1088 | static bool trans_l_sfgesi(DisasContext *dc, arg_ai *a) | |
1089 | { | |
1090 | tcg_gen_setcondi_tl(TCG_COND_GE, cpu_sr_f, cpu_R(dc, a->a), a->i); | |
1091 | return true; | |
1092 | } | |
1093 | ||
1094 | static bool trans_l_sfltsi(DisasContext *dc, arg_ai *a) | |
1095 | { | |
1096 | tcg_gen_setcondi_tl(TCG_COND_LT, cpu_sr_f, cpu_R(dc, a->a), a->i); | |
1097 | return true; | |
1098 | } | |
1099 | ||
1100 | static bool trans_l_sflesi(DisasContext *dc, arg_ai *a) | |
1101 | { | |
1102 | tcg_gen_setcondi_tl(TCG_COND_LE, cpu_sr_f, cpu_R(dc, a->a), a->i); | |
1103 | return true; | |
1104 | } | |
1105 | ||
1106 | static bool trans_l_sys(DisasContext *dc, arg_l_sys *a) | |
1107 | { | |
1108 | tcg_gen_movi_tl(cpu_pc, dc->base.pc_next); | |
1109 | gen_exception(dc, EXCP_SYSCALL); | |
1110 | dc->base.is_jmp = DISAS_NORETURN; | |
1111 | return true; | |
1112 | } | |
1113 | ||
1114 | static bool trans_l_trap(DisasContext *dc, arg_l_trap *a) | |
1115 | { | |
1116 | tcg_gen_movi_tl(cpu_pc, dc->base.pc_next); | |
1117 | gen_exception(dc, EXCP_TRAP); | |
1118 | dc->base.is_jmp = DISAS_NORETURN; | |
1119 | return true; | |
1120 | } | |
1121 | ||
1122 | static bool trans_l_msync(DisasContext *dc, arg_l_msync *a) | |
1123 | { | |
1124 | tcg_gen_mb(TCG_MO_ALL); | |
1125 | return true; | |
1126 | } | |
1127 | ||
1128 | static bool trans_l_psync(DisasContext *dc, arg_l_psync *a) | |
1129 | { | |
1130 | return true; | |
1131 | } | |
1132 | ||
1133 | static bool trans_l_csync(DisasContext *dc, arg_l_csync *a) | |
1134 | { | |
1135 | return true; | |
1136 | } | |
1137 | ||
1138 | static bool trans_l_rfe(DisasContext *dc, arg_l_rfe *a) | |
1139 | { | |
1140 | if (is_user(dc)) { | |
1141 | gen_illegal_exception(dc); | |
1142 | } else { | |
1143 | gen_helper_rfe(cpu_env); | |
1144 | dc->base.is_jmp = DISAS_EXIT; | |
1145 | } | |
1146 | return true; | |
1147 | } | |
1148 | ||
1149 | static bool do_fp2(DisasContext *dc, arg_da *a, | |
1150 | void (*fn)(TCGv, TCGv_env, TCGv)) | |
1151 | { | |
1152 | if (!check_of32s(dc)) { | |
1153 | return false; | |
1154 | } | |
1155 | check_r0_write(dc, a->d); | |
1156 | fn(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->a)); | |
1157 | gen_helper_update_fpcsr(cpu_env); | |
1158 | return true; | |
1159 | } | |
1160 | ||
1161 | static bool do_fp3(DisasContext *dc, arg_dab *a, | |
1162 | void (*fn)(TCGv, TCGv_env, TCGv, TCGv)) | |
1163 | { | |
1164 | if (!check_of32s(dc)) { | |
1165 | return false; | |
1166 | } | |
1167 | check_r0_write(dc, a->d); | |
1168 | fn(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
1169 | gen_helper_update_fpcsr(cpu_env); | |
1170 | return true; | |
1171 | } | |
1172 | ||
1173 | static bool do_fpcmp(DisasContext *dc, arg_ab *a, | |
1174 | void (*fn)(TCGv, TCGv_env, TCGv, TCGv), | |
1175 | bool inv, bool swap) | |
1176 | { | |
1177 | if (!check_of32s(dc)) { | |
1178 | return false; | |
1179 | } | |
1180 | if (swap) { | |
1181 | fn(cpu_sr_f, cpu_env, cpu_R(dc, a->b), cpu_R(dc, a->a)); | |
1182 | } else { | |
1183 | fn(cpu_sr_f, cpu_env, cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
1184 | } | |
1185 | if (inv) { | |
1186 | tcg_gen_xori_tl(cpu_sr_f, cpu_sr_f, 1); | |
1187 | } | |
1188 | gen_helper_update_fpcsr(cpu_env); | |
1189 | return true; | |
1190 | } | |
1191 | ||
1192 | static bool trans_lf_add_s(DisasContext *dc, arg_dab *a) | |
1193 | { | |
1194 | return do_fp3(dc, a, gen_helper_float_add_s); | |
1195 | } | |
1196 | ||
1197 | static bool trans_lf_sub_s(DisasContext *dc, arg_dab *a) | |
1198 | { | |
1199 | return do_fp3(dc, a, gen_helper_float_sub_s); | |
1200 | } | |
1201 | ||
1202 | static bool trans_lf_mul_s(DisasContext *dc, arg_dab *a) | |
1203 | { | |
1204 | return do_fp3(dc, a, gen_helper_float_mul_s); | |
1205 | } | |
1206 | ||
1207 | static bool trans_lf_div_s(DisasContext *dc, arg_dab *a) | |
1208 | { | |
1209 | return do_fp3(dc, a, gen_helper_float_div_s); | |
1210 | } | |
1211 | ||
1212 | static bool trans_lf_rem_s(DisasContext *dc, arg_dab *a) | |
1213 | { | |
1214 | return do_fp3(dc, a, gen_helper_float_rem_s); | |
1215 | return true; | |
1216 | } | |
1217 | ||
1218 | static bool trans_lf_itof_s(DisasContext *dc, arg_da *a) | |
1219 | { | |
1220 | return do_fp2(dc, a, gen_helper_itofs); | |
1221 | } | |
1222 | ||
1223 | static bool trans_lf_ftoi_s(DisasContext *dc, arg_da *a) | |
1224 | { | |
1225 | return do_fp2(dc, a, gen_helper_ftois); | |
1226 | } | |
1227 | ||
1228 | static bool trans_lf_madd_s(DisasContext *dc, arg_dab *a) | |
1229 | { | |
1230 | if (!check_of32s(dc)) { | |
1231 | return false; | |
1232 | } | |
1233 | check_r0_write(dc, a->d); | |
1234 | gen_helper_float_madd_s(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), | |
1235 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
1236 | gen_helper_update_fpcsr(cpu_env); | |
1237 | return true; | |
1238 | } | |
1239 | ||
1240 | static bool trans_lf_sfeq_s(DisasContext *dc, arg_ab *a) | |
1241 | { | |
1242 | return do_fpcmp(dc, a, gen_helper_float_eq_s, false, false); | |
1243 | } | |
1244 | ||
1245 | static bool trans_lf_sfne_s(DisasContext *dc, arg_ab *a) | |
1246 | { | |
1247 | return do_fpcmp(dc, a, gen_helper_float_eq_s, true, false); | |
1248 | } | |
1249 | ||
1250 | static bool trans_lf_sfgt_s(DisasContext *dc, arg_ab *a) | |
1251 | { | |
1252 | return do_fpcmp(dc, a, gen_helper_float_lt_s, false, true); | |
1253 | } | |
1254 | ||
1255 | static bool trans_lf_sfge_s(DisasContext *dc, arg_ab *a) | |
1256 | { | |
1257 | return do_fpcmp(dc, a, gen_helper_float_le_s, false, true); | |
1258 | } | |
1259 | ||
1260 | static bool trans_lf_sflt_s(DisasContext *dc, arg_ab *a) | |
1261 | { | |
1262 | return do_fpcmp(dc, a, gen_helper_float_lt_s, false, false); | |
1263 | } | |
1264 | ||
1265 | static bool trans_lf_sfle_s(DisasContext *dc, arg_ab *a) | |
1266 | { | |
1267 | return do_fpcmp(dc, a, gen_helper_float_le_s, false, false); | |
1268 | } | |
1269 | ||
1270 | static bool trans_lf_sfueq_s(DisasContext *dc, arg_ab *a) | |
1271 | { | |
1272 | if (!check_v1_3(dc)) { | |
1273 | return false; | |
1274 | } | |
1275 | return do_fpcmp(dc, a, gen_helper_float_ueq_s, false, false); | |
1276 | } | |
1277 | ||
1278 | static bool trans_lf_sfult_s(DisasContext *dc, arg_ab *a) | |
1279 | { | |
1280 | if (!check_v1_3(dc)) { | |
1281 | return false; | |
1282 | } | |
1283 | return do_fpcmp(dc, a, gen_helper_float_ult_s, false, false); | |
1284 | } | |
1285 | ||
1286 | static bool trans_lf_sfugt_s(DisasContext *dc, arg_ab *a) | |
1287 | { | |
1288 | if (!check_v1_3(dc)) { | |
1289 | return false; | |
1290 | } | |
1291 | return do_fpcmp(dc, a, gen_helper_float_ult_s, false, true); | |
1292 | } | |
1293 | ||
1294 | static bool trans_lf_sfule_s(DisasContext *dc, arg_ab *a) | |
1295 | { | |
1296 | if (!check_v1_3(dc)) { | |
1297 | return false; | |
1298 | } | |
1299 | return do_fpcmp(dc, a, gen_helper_float_ule_s, false, false); | |
1300 | } | |
1301 | ||
1302 | static bool trans_lf_sfuge_s(DisasContext *dc, arg_ab *a) | |
1303 | { | |
1304 | if (!check_v1_3(dc)) { | |
1305 | return false; | |
1306 | } | |
1307 | return do_fpcmp(dc, a, gen_helper_float_ule_s, false, true); | |
1308 | } | |
1309 | ||
1310 | static bool trans_lf_sfun_s(DisasContext *dc, arg_ab *a) | |
1311 | { | |
1312 | if (!check_v1_3(dc)) { | |
1313 | return false; | |
1314 | } | |
1315 | return do_fpcmp(dc, a, gen_helper_float_un_s, false, false); | |
1316 | } | |
1317 | ||
1318 | static bool check_pair(DisasContext *dc, int r, int p) | |
1319 | { | |
1320 | return r + 1 + p < 32; | |
1321 | } | |
1322 | ||
1323 | static void load_pair(DisasContext *dc, TCGv_i64 t, int r, int p) | |
1324 | { | |
1325 | tcg_gen_concat_i32_i64(t, cpu_R(dc, r + 1 + p), cpu_R(dc, r)); | |
1326 | } | |
1327 | ||
1328 | static void save_pair(DisasContext *dc, TCGv_i64 t, int r, int p) | |
1329 | { | |
1330 | tcg_gen_extr_i64_i32(cpu_R(dc, r + 1 + p), cpu_R(dc, r), t); | |
1331 | } | |
1332 | ||
1333 | static bool do_dp3(DisasContext *dc, arg_dab_pair *a, | |
1334 | void (*fn)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) | |
1335 | { | |
1336 | TCGv_i64 t0, t1; | |
1337 | ||
1338 | if (!check_of64a32s(dc) || | |
1339 | !check_pair(dc, a->a, a->ap) || | |
1340 | !check_pair(dc, a->b, a->bp) || | |
1341 | !check_pair(dc, a->d, a->dp)) { | |
1342 | return false; | |
1343 | } | |
1344 | check_r0_write(dc, a->d); | |
1345 | ||
1346 | t0 = tcg_temp_new_i64(); | |
1347 | t1 = tcg_temp_new_i64(); | |
1348 | load_pair(dc, t0, a->a, a->ap); | |
1349 | load_pair(dc, t1, a->b, a->bp); | |
1350 | fn(t0, cpu_env, t0, t1); | |
1351 | save_pair(dc, t0, a->d, a->dp); | |
1352 | tcg_temp_free_i64(t0); | |
1353 | tcg_temp_free_i64(t1); | |
1354 | ||
1355 | gen_helper_update_fpcsr(cpu_env); | |
1356 | return true; | |
1357 | } | |
1358 | ||
1359 | static bool do_dp2(DisasContext *dc, arg_da_pair *a, | |
1360 | void (*fn)(TCGv_i64, TCGv_env, TCGv_i64)) | |
1361 | { | |
1362 | TCGv_i64 t0; | |
1363 | ||
1364 | if (!check_of64a32s(dc) || | |
1365 | !check_pair(dc, a->a, a->ap) || | |
1366 | !check_pair(dc, a->d, a->dp)) { | |
1367 | return false; | |
1368 | } | |
1369 | check_r0_write(dc, a->d); | |
1370 | ||
1371 | t0 = tcg_temp_new_i64(); | |
1372 | load_pair(dc, t0, a->a, a->ap); | |
1373 | fn(t0, cpu_env, t0); | |
1374 | save_pair(dc, t0, a->d, a->dp); | |
1375 | tcg_temp_free_i64(t0); | |
1376 | ||
1377 | gen_helper_update_fpcsr(cpu_env); | |
1378 | return true; | |
1379 | } | |
1380 | ||
1381 | static bool do_dpcmp(DisasContext *dc, arg_ab_pair *a, | |
1382 | void (*fn)(TCGv, TCGv_env, TCGv_i64, TCGv_i64), | |
1383 | bool inv, bool swap) | |
1384 | { | |
1385 | TCGv_i64 t0, t1; | |
1386 | ||
1387 | if (!check_of64a32s(dc) || | |
1388 | !check_pair(dc, a->a, a->ap) || | |
1389 | !check_pair(dc, a->b, a->bp)) { | |
1390 | return false; | |
1391 | } | |
1392 | ||
1393 | t0 = tcg_temp_new_i64(); | |
1394 | t1 = tcg_temp_new_i64(); | |
1395 | load_pair(dc, t0, a->a, a->ap); | |
1396 | load_pair(dc, t1, a->b, a->bp); | |
1397 | if (swap) { | |
1398 | fn(cpu_sr_f, cpu_env, t1, t0); | |
1399 | } else { | |
1400 | fn(cpu_sr_f, cpu_env, t0, t1); | |
1401 | } | |
1402 | tcg_temp_free_i64(t0); | |
1403 | tcg_temp_free_i64(t1); | |
1404 | ||
1405 | if (inv) { | |
1406 | tcg_gen_xori_tl(cpu_sr_f, cpu_sr_f, 1); | |
1407 | } | |
1408 | gen_helper_update_fpcsr(cpu_env); | |
1409 | return true; | |
1410 | } | |
1411 | ||
1412 | static bool trans_lf_add_d(DisasContext *dc, arg_dab_pair *a) | |
1413 | { | |
1414 | return do_dp3(dc, a, gen_helper_float_add_d); | |
1415 | } | |
1416 | ||
1417 | static bool trans_lf_sub_d(DisasContext *dc, arg_dab_pair *a) | |
1418 | { | |
1419 | return do_dp3(dc, a, gen_helper_float_sub_d); | |
1420 | } | |
1421 | ||
1422 | static bool trans_lf_mul_d(DisasContext *dc, arg_dab_pair *a) | |
1423 | { | |
1424 | return do_dp3(dc, a, gen_helper_float_mul_d); | |
1425 | } | |
1426 | ||
1427 | static bool trans_lf_div_d(DisasContext *dc, arg_dab_pair *a) | |
1428 | { | |
1429 | return do_dp3(dc, a, gen_helper_float_div_d); | |
1430 | } | |
1431 | ||
1432 | static bool trans_lf_rem_d(DisasContext *dc, arg_dab_pair *a) | |
1433 | { | |
1434 | return do_dp3(dc, a, gen_helper_float_rem_d); | |
1435 | } | |
1436 | ||
1437 | static bool trans_lf_itof_d(DisasContext *dc, arg_da_pair *a) | |
1438 | { | |
1439 | return do_dp2(dc, a, gen_helper_itofd); | |
1440 | } | |
1441 | ||
1442 | static bool trans_lf_ftoi_d(DisasContext *dc, arg_da_pair *a) | |
1443 | { | |
1444 | return do_dp2(dc, a, gen_helper_ftoid); | |
1445 | } | |
1446 | ||
1447 | static bool trans_lf_stod_d(DisasContext *dc, arg_lf_stod_d *a) | |
1448 | { | |
1449 | TCGv_i64 t0; | |
1450 | ||
1451 | if (!check_of64a32s(dc) || | |
1452 | !check_pair(dc, a->d, a->dp)) { | |
1453 | return false; | |
1454 | } | |
1455 | check_r0_write(dc, a->d); | |
1456 | ||
1457 | t0 = tcg_temp_new_i64(); | |
1458 | gen_helper_stod(t0, cpu_env, cpu_R(dc, a->a)); | |
1459 | save_pair(dc, t0, a->d, a->dp); | |
1460 | tcg_temp_free_i64(t0); | |
1461 | ||
1462 | gen_helper_update_fpcsr(cpu_env); | |
1463 | return true; | |
1464 | } | |
1465 | ||
1466 | static bool trans_lf_dtos_d(DisasContext *dc, arg_lf_dtos_d *a) | |
1467 | { | |
1468 | TCGv_i64 t0; | |
1469 | ||
1470 | if (!check_of64a32s(dc) || | |
1471 | !check_pair(dc, a->a, a->ap)) { | |
1472 | return false; | |
1473 | } | |
1474 | check_r0_write(dc, a->d); | |
1475 | ||
1476 | t0 = tcg_temp_new_i64(); | |
1477 | load_pair(dc, t0, a->a, a->ap); | |
1478 | gen_helper_dtos(cpu_R(dc, a->d), cpu_env, t0); | |
1479 | tcg_temp_free_i64(t0); | |
1480 | ||
1481 | gen_helper_update_fpcsr(cpu_env); | |
1482 | return true; | |
1483 | } | |
1484 | ||
1485 | static bool trans_lf_madd_d(DisasContext *dc, arg_dab_pair *a) | |
1486 | { | |
1487 | TCGv_i64 t0, t1, t2; | |
1488 | ||
1489 | if (!check_of64a32s(dc) || | |
1490 | !check_pair(dc, a->a, a->ap) || | |
1491 | !check_pair(dc, a->b, a->bp) || | |
1492 | !check_pair(dc, a->d, a->dp)) { | |
1493 | return false; | |
1494 | } | |
1495 | check_r0_write(dc, a->d); | |
1496 | ||
1497 | t0 = tcg_temp_new_i64(); | |
1498 | t1 = tcg_temp_new_i64(); | |
1499 | t2 = tcg_temp_new_i64(); | |
1500 | load_pair(dc, t0, a->d, a->dp); | |
1501 | load_pair(dc, t1, a->a, a->ap); | |
1502 | load_pair(dc, t2, a->b, a->bp); | |
1503 | gen_helper_float_madd_d(t0, cpu_env, t0, t1, t2); | |
1504 | save_pair(dc, t0, a->d, a->dp); | |
1505 | tcg_temp_free_i64(t0); | |
1506 | tcg_temp_free_i64(t1); | |
1507 | tcg_temp_free_i64(t2); | |
1508 | ||
1509 | gen_helper_update_fpcsr(cpu_env); | |
1510 | return true; | |
1511 | } | |
1512 | ||
1513 | static bool trans_lf_sfeq_d(DisasContext *dc, arg_ab_pair *a) | |
1514 | { | |
1515 | return do_dpcmp(dc, a, gen_helper_float_eq_d, false, false); | |
1516 | } | |
1517 | ||
1518 | static bool trans_lf_sfne_d(DisasContext *dc, arg_ab_pair *a) | |
1519 | { | |
1520 | return do_dpcmp(dc, a, gen_helper_float_eq_d, true, false); | |
1521 | } | |
1522 | ||
1523 | static bool trans_lf_sfgt_d(DisasContext *dc, arg_ab_pair *a) | |
1524 | { | |
1525 | return do_dpcmp(dc, a, gen_helper_float_lt_d, false, true); | |
1526 | } | |
1527 | ||
1528 | static bool trans_lf_sfge_d(DisasContext *dc, arg_ab_pair *a) | |
1529 | { | |
1530 | return do_dpcmp(dc, a, gen_helper_float_le_d, false, true); | |
1531 | } | |
1532 | ||
1533 | static bool trans_lf_sflt_d(DisasContext *dc, arg_ab_pair *a) | |
1534 | { | |
1535 | return do_dpcmp(dc, a, gen_helper_float_lt_d, false, false); | |
1536 | } | |
1537 | ||
1538 | static bool trans_lf_sfle_d(DisasContext *dc, arg_ab_pair *a) | |
1539 | { | |
1540 | return do_dpcmp(dc, a, gen_helper_float_le_d, false, false); | |
1541 | } | |
1542 | ||
1543 | static bool trans_lf_sfueq_d(DisasContext *dc, arg_ab_pair *a) | |
1544 | { | |
1545 | return do_dpcmp(dc, a, gen_helper_float_ueq_d, false, false); | |
1546 | } | |
1547 | ||
1548 | static bool trans_lf_sfule_d(DisasContext *dc, arg_ab_pair *a) | |
1549 | { | |
1550 | return do_dpcmp(dc, a, gen_helper_float_ule_d, false, false); | |
1551 | } | |
1552 | ||
1553 | static bool trans_lf_sfuge_d(DisasContext *dc, arg_ab_pair *a) | |
1554 | { | |
1555 | return do_dpcmp(dc, a, gen_helper_float_ule_d, false, true); | |
1556 | } | |
1557 | ||
1558 | static bool trans_lf_sfult_d(DisasContext *dc, arg_ab_pair *a) | |
1559 | { | |
1560 | return do_dpcmp(dc, a, gen_helper_float_ult_d, false, false); | |
1561 | } | |
1562 | ||
1563 | static bool trans_lf_sfugt_d(DisasContext *dc, arg_ab_pair *a) | |
1564 | { | |
1565 | return do_dpcmp(dc, a, gen_helper_float_ult_d, false, true); | |
1566 | } | |
1567 | ||
1568 | static bool trans_lf_sfun_d(DisasContext *dc, arg_ab_pair *a) | |
1569 | { | |
1570 | return do_dpcmp(dc, a, gen_helper_float_un_d, false, false); | |
1571 | } | |
1572 | ||
1573 | static void openrisc_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) | |
1574 | { | |
1575 | DisasContext *dc = container_of(dcb, DisasContext, base); | |
1576 | CPUOpenRISCState *env = cs->env_ptr; | |
1577 | int bound; | |
1578 | ||
1579 | dc->mem_idx = cpu_mmu_index(env, false); | |
1580 | dc->tb_flags = dc->base.tb->flags; | |
1581 | dc->delayed_branch = (dc->tb_flags & TB_FLAGS_DFLAG) != 0; | |
1582 | dc->cpucfgr = env->cpucfgr; | |
1583 | dc->avr = env->avr; | |
1584 | dc->jmp_pc_imm = -1; | |
1585 | ||
1586 | bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; | |
1587 | dc->base.max_insns = MIN(dc->base.max_insns, bound); | |
1588 | } | |
1589 | ||
1590 | static void openrisc_tr_tb_start(DisasContextBase *db, CPUState *cs) | |
1591 | { | |
1592 | DisasContext *dc = container_of(db, DisasContext, base); | |
1593 | ||
1594 | /* Allow the TCG optimizer to see that R0 == 0, | |
1595 | when it's true, which is the common case. */ | |
1596 | dc->zero = tcg_constant_tl(0); | |
1597 | if (dc->tb_flags & TB_FLAGS_R0_0) { | |
1598 | dc->R0 = dc->zero; | |
1599 | } else { | |
1600 | dc->R0 = cpu_regs[0]; | |
1601 | } | |
1602 | } | |
1603 | ||
1604 | static void openrisc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) | |
1605 | { | |
1606 | DisasContext *dc = container_of(dcbase, DisasContext, base); | |
1607 | ||
1608 | tcg_gen_insn_start(dc->base.pc_next, (dc->delayed_branch ? 1 : 0) | |
1609 | | (dc->base.num_insns > 1 ? 2 : 0)); | |
1610 | } | |
1611 | ||
1612 | static void openrisc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) | |
1613 | { | |
1614 | DisasContext *dc = container_of(dcbase, DisasContext, base); | |
1615 | OpenRISCCPU *cpu = OPENRISC_CPU(cs); | |
1616 | uint32_t insn = translator_ldl(&cpu->env, &dc->base, dc->base.pc_next); | |
1617 | ||
1618 | if (!decode(dc, insn)) { | |
1619 | gen_illegal_exception(dc); | |
1620 | } | |
1621 | dc->base.pc_next += 4; | |
1622 | ||
1623 | /* When exiting the delay slot normally, exit via jmp_pc. | |
1624 | * For DISAS_NORETURN, we have raised an exception and already exited. | |
1625 | * For DISAS_EXIT, we found l.rfe in a delay slot. There's nothing | |
1626 | * in the manual saying this is illegal, but it surely it should. | |
1627 | * At least or1ksim overrides pcnext and ignores the branch. | |
1628 | */ | |
1629 | if (dc->delayed_branch | |
1630 | && --dc->delayed_branch == 0 | |
1631 | && dc->base.is_jmp == DISAS_NEXT) { | |
1632 | dc->base.is_jmp = DISAS_JUMP; | |
1633 | } | |
1634 | } | |
1635 | ||
1636 | static void openrisc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) | |
1637 | { | |
1638 | DisasContext *dc = container_of(dcbase, DisasContext, base); | |
1639 | target_ulong jmp_dest; | |
1640 | ||
1641 | /* If we have already exited the TB, nothing following has effect. */ | |
1642 | if (dc->base.is_jmp == DISAS_NORETURN) { | |
1643 | return; | |
1644 | } | |
1645 | ||
1646 | /* Adjust the delayed branch state for the next TB. */ | |
1647 | if ((dc->tb_flags & TB_FLAGS_DFLAG ? 1 : 0) != (dc->delayed_branch != 0)) { | |
1648 | tcg_gen_movi_i32(cpu_dflag, dc->delayed_branch != 0); | |
1649 | } | |
1650 | ||
1651 | /* For DISAS_TOO_MANY, jump to the next insn. */ | |
1652 | jmp_dest = dc->base.pc_next; | |
1653 | tcg_gen_movi_tl(cpu_ppc, jmp_dest - 4); | |
1654 | ||
1655 | switch (dc->base.is_jmp) { | |
1656 | case DISAS_JUMP: | |
1657 | jmp_dest = dc->jmp_pc_imm; | |
1658 | if (jmp_dest == -1) { | |
1659 | /* The jump destination is indirect/computed; use jmp_pc. */ | |
1660 | tcg_gen_mov_tl(cpu_pc, jmp_pc); | |
1661 | tcg_gen_discard_tl(jmp_pc); | |
1662 | tcg_gen_lookup_and_goto_ptr(); | |
1663 | break; | |
1664 | } | |
1665 | /* The jump destination is direct; use jmp_pc_imm. | |
1666 | However, we will have stored into jmp_pc as well; | |
1667 | we know now that it wasn't needed. */ | |
1668 | tcg_gen_discard_tl(jmp_pc); | |
1669 | /* fallthru */ | |
1670 | ||
1671 | case DISAS_TOO_MANY: | |
1672 | if (translator_use_goto_tb(&dc->base, jmp_dest)) { | |
1673 | tcg_gen_goto_tb(0); | |
1674 | tcg_gen_movi_tl(cpu_pc, jmp_dest); | |
1675 | tcg_gen_exit_tb(dc->base.tb, 0); | |
1676 | break; | |
1677 | } | |
1678 | tcg_gen_movi_tl(cpu_pc, jmp_dest); | |
1679 | tcg_gen_lookup_and_goto_ptr(); | |
1680 | break; | |
1681 | ||
1682 | case DISAS_EXIT: | |
1683 | tcg_gen_exit_tb(NULL, 0); | |
1684 | break; | |
1685 | default: | |
1686 | g_assert_not_reached(); | |
1687 | } | |
1688 | } | |
1689 | ||
1690 | static void openrisc_tr_disas_log(const DisasContextBase *dcbase, | |
1691 | CPUState *cs, FILE *logfile) | |
1692 | { | |
1693 | DisasContext *s = container_of(dcbase, DisasContext, base); | |
1694 | ||
1695 | fprintf(logfile, "IN: %s\n", lookup_symbol(s->base.pc_first)); | |
1696 | target_disas(logfile, cs, s->base.pc_first, s->base.tb->size); | |
1697 | } | |
1698 | ||
1699 | static const TranslatorOps openrisc_tr_ops = { | |
1700 | .init_disas_context = openrisc_tr_init_disas_context, | |
1701 | .tb_start = openrisc_tr_tb_start, | |
1702 | .insn_start = openrisc_tr_insn_start, | |
1703 | .translate_insn = openrisc_tr_translate_insn, | |
1704 | .tb_stop = openrisc_tr_tb_stop, | |
1705 | .disas_log = openrisc_tr_disas_log, | |
1706 | }; | |
1707 | ||
1708 | void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, | |
1709 | target_ulong pc, void *host_pc) | |
1710 | { | |
1711 | DisasContext ctx; | |
1712 | ||
1713 | translator_loop(cs, tb, max_insns, pc, host_pc, | |
1714 | &openrisc_tr_ops, &ctx.base); | |
1715 | } | |
1716 | ||
1717 | void openrisc_cpu_dump_state(CPUState *cs, FILE *f, int flags) | |
1718 | { | |
1719 | OpenRISCCPU *cpu = OPENRISC_CPU(cs); | |
1720 | CPUOpenRISCState *env = &cpu->env; | |
1721 | int i; | |
1722 | ||
1723 | qemu_fprintf(f, "PC=%08x\n", env->pc); | |
1724 | for (i = 0; i < 32; ++i) { | |
1725 | qemu_fprintf(f, "R%02d=%08x%c", i, cpu_get_gpr(env, i), | |
1726 | (i % 4) == 3 ? '\n' : ' '); | |
1727 | } | |
1728 | } |