tests: fixes aio-win32 about aio_remove_fd_handler, get it consistence with aio-posix.c
[qemu/ar7.git] / target / microblaze / translate.c
blobabfcc7e6c8bbe25a01559edd90ac164aafbf9f9e
1 /*
2 * Xilinx MicroBlaze emulation for qemu: main translation routines.
4 * Copyright (c) 2009 Edgar E. Iglesias.
5 * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
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 of the License, or (at your option) any later version.
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.
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/>.
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "disas/disas.h"
24 #include "exec/exec-all.h"
25 #include "tcg/tcg-op.h"
26 #include "exec/helper-proto.h"
27 #include "exec/cpu_ldst.h"
28 #include "exec/helper-gen.h"
29 #include "exec/translator.h"
30 #include "qemu/qemu-print.h"
32 #include "trace-tcg.h"
33 #include "exec/log.h"
35 #define EXTRACT_FIELD(src, start, end) \
36 (((src) >> start) & ((1 << (end - start + 1)) - 1))
38 /* is_jmp field values */
39 #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
40 #define DISAS_EXIT DISAS_TARGET_1 /* all cpu state modified dynamically */
42 /* cpu state besides pc was modified dynamically; update pc to next */
43 #define DISAS_EXIT_NEXT DISAS_TARGET_2
44 /* cpu state besides pc was modified dynamically; update pc to btarget */
45 #define DISAS_EXIT_JUMP DISAS_TARGET_3
47 static TCGv_i32 cpu_R[32];
48 static TCGv_i32 cpu_pc;
49 static TCGv_i32 cpu_msr;
50 static TCGv_i32 cpu_msr_c;
51 static TCGv_i32 cpu_imm;
52 static TCGv_i32 cpu_bvalue;
53 static TCGv_i32 cpu_btarget;
54 static TCGv_i32 cpu_iflags;
55 static TCGv cpu_res_addr;
56 static TCGv_i32 cpu_res_val;
58 #include "exec/gen-icount.h"
60 /* This is the state at translation time. */
61 typedef struct DisasContext {
62 DisasContextBase base;
63 const MicroBlazeCPUConfig *cfg;
65 /* TCG op of the current insn_start. */
66 TCGOp *insn_start;
68 TCGv_i32 r0;
69 bool r0_set;
71 /* Decoder. */
72 uint32_t ext_imm;
73 unsigned int tb_flags;
74 unsigned int tb_flags_to_set;
75 int mem_index;
77 /* Condition under which to jump, including NEVER and ALWAYS. */
78 TCGCond jmp_cond;
80 /* Immediate branch-taken destination, or -1 for indirect. */
81 uint32_t jmp_dest;
82 } DisasContext;
84 static int typeb_imm(DisasContext *dc, int x)
86 if (dc->tb_flags & IMM_FLAG) {
87 return deposit32(dc->ext_imm, 0, 16, x);
89 return x;
92 /* Include the auto-generated decoder. */
93 #include "decode-insns.c.inc"
95 static void t_sync_flags(DisasContext *dc)
97 /* Synch the tb dependent flags between translator and runtime. */
98 if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) {
99 tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK);
103 static void gen_raise_exception(DisasContext *dc, uint32_t index)
105 TCGv_i32 tmp = tcg_const_i32(index);
107 gen_helper_raise_exception(cpu_env, tmp);
108 tcg_temp_free_i32(tmp);
109 dc->base.is_jmp = DISAS_NORETURN;
112 static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
114 t_sync_flags(dc);
115 tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
116 gen_raise_exception(dc, index);
119 static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
121 TCGv_i32 tmp = tcg_const_i32(esr_ec);
122 tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr));
123 tcg_temp_free_i32(tmp);
125 gen_raise_exception_sync(dc, EXCP_HW_EXCP);
128 static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
130 #ifndef CONFIG_USER_ONLY
131 return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
132 #else
133 return true;
134 #endif
137 static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
139 if (dc->base.singlestep_enabled) {
140 TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
141 tcg_gen_movi_i32(cpu_pc, dest);
142 gen_helper_raise_exception(cpu_env, tmp);
143 tcg_temp_free_i32(tmp);
144 } else if (use_goto_tb(dc, dest)) {
145 tcg_gen_goto_tb(n);
146 tcg_gen_movi_i32(cpu_pc, dest);
147 tcg_gen_exit_tb(dc->base.tb, n);
148 } else {
149 tcg_gen_movi_i32(cpu_pc, dest);
150 tcg_gen_lookup_and_goto_ptr();
152 dc->base.is_jmp = DISAS_NORETURN;
156 * Returns true if the insn an illegal operation.
157 * If exceptions are enabled, an exception is raised.
159 static bool trap_illegal(DisasContext *dc, bool cond)
161 if (cond && (dc->tb_flags & MSR_EE)
162 && dc->cfg->illegal_opcode_exception) {
163 gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
165 return cond;
169 * Returns true if the insn is illegal in userspace.
170 * If exceptions are enabled, an exception is raised.
172 static bool trap_userspace(DisasContext *dc, bool cond)
174 bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
176 if (cond_user && (dc->tb_flags & MSR_EE)) {
177 gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
179 return cond_user;
183 * Return true, and log an error, if the current insn is
184 * within a delay slot.
186 static bool invalid_delay_slot(DisasContext *dc, const char *insn_type)
188 if (dc->tb_flags & D_FLAG) {
189 qemu_log_mask(LOG_GUEST_ERROR,
190 "Invalid insn in delay slot: %s at %08x\n",
191 insn_type, (uint32_t)dc->base.pc_next);
192 return true;
194 return false;
197 static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
199 if (likely(reg != 0)) {
200 return cpu_R[reg];
202 if (!dc->r0_set) {
203 if (dc->r0 == NULL) {
204 dc->r0 = tcg_temp_new_i32();
206 tcg_gen_movi_i32(dc->r0, 0);
207 dc->r0_set = true;
209 return dc->r0;
212 static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
214 if (likely(reg != 0)) {
215 return cpu_R[reg];
217 if (dc->r0 == NULL) {
218 dc->r0 = tcg_temp_new_i32();
220 return dc->r0;
223 static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
224 void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
226 TCGv_i32 rd, ra, rb;
228 if (arg->rd == 0 && !side_effects) {
229 return true;
232 rd = reg_for_write(dc, arg->rd);
233 ra = reg_for_read(dc, arg->ra);
234 rb = reg_for_read(dc, arg->rb);
235 fn(rd, ra, rb);
236 return true;
239 static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
240 void (*fn)(TCGv_i32, TCGv_i32))
242 TCGv_i32 rd, ra;
244 if (arg->rd == 0 && !side_effects) {
245 return true;
248 rd = reg_for_write(dc, arg->rd);
249 ra = reg_for_read(dc, arg->ra);
250 fn(rd, ra);
251 return true;
254 static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
255 void (*fni)(TCGv_i32, TCGv_i32, int32_t))
257 TCGv_i32 rd, ra;
259 if (arg->rd == 0 && !side_effects) {
260 return true;
263 rd = reg_for_write(dc, arg->rd);
264 ra = reg_for_read(dc, arg->ra);
265 fni(rd, ra, arg->imm);
266 return true;
269 static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
270 void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
272 TCGv_i32 rd, ra, imm;
274 if (arg->rd == 0 && !side_effects) {
275 return true;
278 rd = reg_for_write(dc, arg->rd);
279 ra = reg_for_read(dc, arg->ra);
280 imm = tcg_const_i32(arg->imm);
282 fn(rd, ra, imm);
284 tcg_temp_free_i32(imm);
285 return true;
288 #define DO_TYPEA(NAME, SE, FN) \
289 static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
290 { return do_typea(dc, a, SE, FN); }
292 #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
293 static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
294 { return dc->cfg->CFG && do_typea(dc, a, SE, FN); }
296 #define DO_TYPEA0(NAME, SE, FN) \
297 static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
298 { return do_typea0(dc, a, SE, FN); }
300 #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
301 static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
302 { return dc->cfg->CFG && do_typea0(dc, a, SE, FN); }
304 #define DO_TYPEBI(NAME, SE, FNI) \
305 static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
306 { return do_typeb_imm(dc, a, SE, FNI); }
308 #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
309 static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
310 { return dc->cfg->CFG && do_typeb_imm(dc, a, SE, FNI); }
312 #define DO_TYPEBV(NAME, SE, FN) \
313 static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
314 { return do_typeb_val(dc, a, SE, FN); }
316 #define ENV_WRAPPER2(NAME, HELPER) \
317 static void NAME(TCGv_i32 out, TCGv_i32 ina) \
318 { HELPER(out, cpu_env, ina); }
320 #define ENV_WRAPPER3(NAME, HELPER) \
321 static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
322 { HELPER(out, cpu_env, ina, inb); }
324 /* No input carry, but output carry. */
325 static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
327 TCGv_i32 zero = tcg_const_i32(0);
329 tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
331 tcg_temp_free_i32(zero);
334 /* Input and output carry. */
335 static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
337 TCGv_i32 zero = tcg_const_i32(0);
338 TCGv_i32 tmp = tcg_temp_new_i32();
340 tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
341 tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
343 tcg_temp_free_i32(tmp);
344 tcg_temp_free_i32(zero);
347 /* Input carry, but no output carry. */
348 static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
350 tcg_gen_add_i32(out, ina, inb);
351 tcg_gen_add_i32(out, out, cpu_msr_c);
354 DO_TYPEA(add, true, gen_add)
355 DO_TYPEA(addc, true, gen_addc)
356 DO_TYPEA(addk, false, tcg_gen_add_i32)
357 DO_TYPEA(addkc, true, gen_addkc)
359 DO_TYPEBV(addi, true, gen_add)
360 DO_TYPEBV(addic, true, gen_addc)
361 DO_TYPEBI(addik, false, tcg_gen_addi_i32)
362 DO_TYPEBV(addikc, true, gen_addkc)
364 static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
366 tcg_gen_andi_i32(out, ina, ~imm);
369 DO_TYPEA(and, false, tcg_gen_and_i32)
370 DO_TYPEBI(andi, false, tcg_gen_andi_i32)
371 DO_TYPEA(andn, false, tcg_gen_andc_i32)
372 DO_TYPEBI(andni, false, gen_andni)
374 static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
376 TCGv_i32 tmp = tcg_temp_new_i32();
377 tcg_gen_andi_i32(tmp, inb, 31);
378 tcg_gen_sar_i32(out, ina, tmp);
379 tcg_temp_free_i32(tmp);
382 static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
384 TCGv_i32 tmp = tcg_temp_new_i32();
385 tcg_gen_andi_i32(tmp, inb, 31);
386 tcg_gen_shr_i32(out, ina, tmp);
387 tcg_temp_free_i32(tmp);
390 static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
392 TCGv_i32 tmp = tcg_temp_new_i32();
393 tcg_gen_andi_i32(tmp, inb, 31);
394 tcg_gen_shl_i32(out, ina, tmp);
395 tcg_temp_free_i32(tmp);
398 static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
400 /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
401 int imm_w = extract32(imm, 5, 5);
402 int imm_s = extract32(imm, 0, 5);
404 if (imm_w + imm_s > 32 || imm_w == 0) {
405 /* These inputs have an undefined behavior. */
406 qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
407 imm_w, imm_s);
408 } else {
409 tcg_gen_extract_i32(out, ina, imm_s, imm_w);
413 static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
415 /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
416 int imm_w = extract32(imm, 5, 5);
417 int imm_s = extract32(imm, 0, 5);
418 int width = imm_w - imm_s + 1;
420 if (imm_w < imm_s) {
421 /* These inputs have an undefined behavior. */
422 qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
423 imm_w, imm_s);
424 } else {
425 tcg_gen_deposit_i32(out, out, ina, imm_s, width);
429 DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
430 DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
431 DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
433 DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
434 DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
435 DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
437 DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
438 DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
440 static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
442 tcg_gen_clzi_i32(out, ina, 32);
445 DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
447 static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
449 TCGv_i32 lt = tcg_temp_new_i32();
451 tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
452 tcg_gen_sub_i32(out, inb, ina);
453 tcg_gen_deposit_i32(out, out, lt, 31, 1);
454 tcg_temp_free_i32(lt);
457 static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
459 TCGv_i32 lt = tcg_temp_new_i32();
461 tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
462 tcg_gen_sub_i32(out, inb, ina);
463 tcg_gen_deposit_i32(out, out, lt, 31, 1);
464 tcg_temp_free_i32(lt);
467 DO_TYPEA(cmp, false, gen_cmp)
468 DO_TYPEA(cmpu, false, gen_cmpu)
470 ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
471 ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
472 ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
473 ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
474 ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
475 ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
476 ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
477 ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
478 ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
479 ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
480 ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
482 DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
483 DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
484 DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
485 DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
486 DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
487 DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
488 DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
489 DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
490 DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
491 DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
492 DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
494 ENV_WRAPPER2(gen_flt, gen_helper_flt)
495 ENV_WRAPPER2(gen_fint, gen_helper_fint)
496 ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
498 DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
499 DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
500 DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
502 /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
503 static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
505 gen_helper_divs(out, cpu_env, inb, ina);
508 static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
510 gen_helper_divu(out, cpu_env, inb, ina);
513 DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
514 DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
516 static bool trans_imm(DisasContext *dc, arg_imm *arg)
518 if (invalid_delay_slot(dc, "imm")) {
519 return true;
521 dc->ext_imm = arg->imm << 16;
522 tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
523 dc->tb_flags_to_set = IMM_FLAG;
524 return true;
527 static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
529 TCGv_i32 tmp = tcg_temp_new_i32();
530 tcg_gen_muls2_i32(tmp, out, ina, inb);
531 tcg_temp_free_i32(tmp);
534 static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
536 TCGv_i32 tmp = tcg_temp_new_i32();
537 tcg_gen_mulu2_i32(tmp, out, ina, inb);
538 tcg_temp_free_i32(tmp);
541 static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
543 TCGv_i32 tmp = tcg_temp_new_i32();
544 tcg_gen_mulsu2_i32(tmp, out, ina, inb);
545 tcg_temp_free_i32(tmp);
548 DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
549 DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
550 DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
551 DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
552 DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
554 DO_TYPEA(or, false, tcg_gen_or_i32)
555 DO_TYPEBI(ori, false, tcg_gen_ori_i32)
557 static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
559 tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
562 static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
564 tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
567 DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
568 DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
569 DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
571 /* No input carry, but output carry. */
572 static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
574 tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
575 tcg_gen_sub_i32(out, inb, ina);
578 /* Input and output carry. */
579 static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
581 TCGv_i32 zero = tcg_const_i32(0);
582 TCGv_i32 tmp = tcg_temp_new_i32();
584 tcg_gen_not_i32(tmp, ina);
585 tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
586 tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
588 tcg_temp_free_i32(zero);
589 tcg_temp_free_i32(tmp);
592 /* No input or output carry. */
593 static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
595 tcg_gen_sub_i32(out, inb, ina);
598 /* Input carry, no output carry. */
599 static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
601 TCGv_i32 nota = tcg_temp_new_i32();
603 tcg_gen_not_i32(nota, ina);
604 tcg_gen_add_i32(out, inb, nota);
605 tcg_gen_add_i32(out, out, cpu_msr_c);
607 tcg_temp_free_i32(nota);
610 DO_TYPEA(rsub, true, gen_rsub)
611 DO_TYPEA(rsubc, true, gen_rsubc)
612 DO_TYPEA(rsubk, false, gen_rsubk)
613 DO_TYPEA(rsubkc, true, gen_rsubkc)
615 DO_TYPEBV(rsubi, true, gen_rsub)
616 DO_TYPEBV(rsubic, true, gen_rsubc)
617 DO_TYPEBV(rsubik, false, gen_rsubk)
618 DO_TYPEBV(rsubikc, true, gen_rsubkc)
620 DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
621 DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
623 static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
625 tcg_gen_andi_i32(cpu_msr_c, ina, 1);
626 tcg_gen_sari_i32(out, ina, 1);
629 static void gen_src(TCGv_i32 out, TCGv_i32 ina)
631 TCGv_i32 tmp = tcg_temp_new_i32();
633 tcg_gen_mov_i32(tmp, cpu_msr_c);
634 tcg_gen_andi_i32(cpu_msr_c, ina, 1);
635 tcg_gen_extract2_i32(out, ina, tmp, 1);
637 tcg_temp_free_i32(tmp);
640 static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
642 tcg_gen_andi_i32(cpu_msr_c, ina, 1);
643 tcg_gen_shri_i32(out, ina, 1);
646 DO_TYPEA0(sra, false, gen_sra)
647 DO_TYPEA0(src, false, gen_src)
648 DO_TYPEA0(srl, false, gen_srl)
650 static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
652 tcg_gen_rotri_i32(out, ina, 16);
655 DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
656 DO_TYPEA0(swaph, false, gen_swaph)
658 static bool trans_wdic(DisasContext *dc, arg_wdic *a)
660 /* Cache operations are nops: only check for supervisor mode. */
661 trap_userspace(dc, true);
662 return true;
665 DO_TYPEA(xor, false, tcg_gen_xor_i32)
666 DO_TYPEBI(xori, false, tcg_gen_xori_i32)
668 static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
670 TCGv ret = tcg_temp_new();
672 /* If any of the regs is r0, set t to the value of the other reg. */
673 if (ra && rb) {
674 TCGv_i32 tmp = tcg_temp_new_i32();
675 tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
676 tcg_gen_extu_i32_tl(ret, tmp);
677 tcg_temp_free_i32(tmp);
678 } else if (ra) {
679 tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
680 } else if (rb) {
681 tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
682 } else {
683 tcg_gen_movi_tl(ret, 0);
686 if ((ra == 1 || rb == 1) && dc->cfg->stackprot) {
687 gen_helper_stackprot(cpu_env, ret);
689 return ret;
692 static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
694 TCGv ret = tcg_temp_new();
696 /* If any of the regs is r0, set t to the value of the other reg. */
697 if (ra) {
698 TCGv_i32 tmp = tcg_temp_new_i32();
699 tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
700 tcg_gen_extu_i32_tl(ret, tmp);
701 tcg_temp_free_i32(tmp);
702 } else {
703 tcg_gen_movi_tl(ret, (uint32_t)imm);
706 if (ra == 1 && dc->cfg->stackprot) {
707 gen_helper_stackprot(cpu_env, ret);
709 return ret;
712 #ifndef CONFIG_USER_ONLY
713 static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
715 int addr_size = dc->cfg->addr_size;
716 TCGv ret = tcg_temp_new();
718 if (addr_size == 32 || ra == 0) {
719 if (rb) {
720 tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
721 } else {
722 tcg_gen_movi_tl(ret, 0);
724 } else {
725 if (rb) {
726 tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
727 } else {
728 tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
729 tcg_gen_shli_tl(ret, ret, 32);
731 if (addr_size < 64) {
732 /* Mask off out of range bits. */
733 tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
736 return ret;
738 #endif
740 static void record_unaligned_ess(DisasContext *dc, int rd,
741 MemOp size, bool store)
743 uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1);
745 iflags |= ESR_ESS_FLAG;
746 iflags |= rd << 5;
747 iflags |= store * ESR_S;
748 iflags |= (size == MO_32) * ESR_W;
750 tcg_set_insn_start_param(dc->insn_start, 1, iflags);
753 static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
754 int mem_index, bool rev)
756 MemOp size = mop & MO_SIZE;
759 * When doing reverse accesses we need to do two things.
761 * 1. Reverse the address wrt endianness.
762 * 2. Byteswap the data lanes on the way back into the CPU core.
764 if (rev) {
765 if (size > MO_8) {
766 mop ^= MO_BSWAP;
768 if (size < MO_32) {
769 tcg_gen_xori_tl(addr, addr, 3 - size);
773 if (size > MO_8 &&
774 (dc->tb_flags & MSR_EE) &&
775 dc->cfg->unaligned_exceptions) {
776 record_unaligned_ess(dc, rd, size, false);
777 mop |= MO_ALIGN;
780 tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
782 tcg_temp_free(addr);
783 return true;
786 static bool trans_lbu(DisasContext *dc, arg_typea *arg)
788 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
789 return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
792 static bool trans_lbur(DisasContext *dc, arg_typea *arg)
794 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
795 return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
798 static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
800 if (trap_userspace(dc, true)) {
801 return true;
803 #ifdef CONFIG_USER_ONLY
804 return true;
805 #else
806 TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
807 return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
808 #endif
811 static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
813 TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
814 return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
817 static bool trans_lhu(DisasContext *dc, arg_typea *arg)
819 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
820 return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
823 static bool trans_lhur(DisasContext *dc, arg_typea *arg)
825 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
826 return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
829 static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
831 if (trap_userspace(dc, true)) {
832 return true;
834 #ifdef CONFIG_USER_ONLY
835 return true;
836 #else
837 TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
838 return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
839 #endif
842 static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
844 TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
845 return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
848 static bool trans_lw(DisasContext *dc, arg_typea *arg)
850 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
851 return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
854 static bool trans_lwr(DisasContext *dc, arg_typea *arg)
856 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
857 return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
860 static bool trans_lwea(DisasContext *dc, arg_typea *arg)
862 if (trap_userspace(dc, true)) {
863 return true;
865 #ifdef CONFIG_USER_ONLY
866 return true;
867 #else
868 TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
869 return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
870 #endif
873 static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
875 TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
876 return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
879 static bool trans_lwx(DisasContext *dc, arg_typea *arg)
881 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
883 /* lwx does not throw unaligned access errors, so force alignment */
884 tcg_gen_andi_tl(addr, addr, ~3);
886 tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL);
887 tcg_gen_mov_tl(cpu_res_addr, addr);
888 tcg_temp_free(addr);
890 if (arg->rd) {
891 tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
894 /* No support for AXI exclusive so always clear C */
895 tcg_gen_movi_i32(cpu_msr_c, 0);
896 return true;
899 static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
900 int mem_index, bool rev)
902 MemOp size = mop & MO_SIZE;
905 * When doing reverse accesses we need to do two things.
907 * 1. Reverse the address wrt endianness.
908 * 2. Byteswap the data lanes on the way back into the CPU core.
910 if (rev) {
911 if (size > MO_8) {
912 mop ^= MO_BSWAP;
914 if (size < MO_32) {
915 tcg_gen_xori_tl(addr, addr, 3 - size);
919 if (size > MO_8 &&
920 (dc->tb_flags & MSR_EE) &&
921 dc->cfg->unaligned_exceptions) {
922 record_unaligned_ess(dc, rd, size, true);
923 mop |= MO_ALIGN;
926 tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
928 tcg_temp_free(addr);
929 return true;
932 static bool trans_sb(DisasContext *dc, arg_typea *arg)
934 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
935 return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
938 static bool trans_sbr(DisasContext *dc, arg_typea *arg)
940 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
941 return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
944 static bool trans_sbea(DisasContext *dc, arg_typea *arg)
946 if (trap_userspace(dc, true)) {
947 return true;
949 #ifdef CONFIG_USER_ONLY
950 return true;
951 #else
952 TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
953 return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
954 #endif
957 static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
959 TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
960 return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
963 static bool trans_sh(DisasContext *dc, arg_typea *arg)
965 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
966 return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
969 static bool trans_shr(DisasContext *dc, arg_typea *arg)
971 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
972 return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
975 static bool trans_shea(DisasContext *dc, arg_typea *arg)
977 if (trap_userspace(dc, true)) {
978 return true;
980 #ifdef CONFIG_USER_ONLY
981 return true;
982 #else
983 TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
984 return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
985 #endif
988 static bool trans_shi(DisasContext *dc, arg_typeb *arg)
990 TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
991 return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
994 static bool trans_sw(DisasContext *dc, arg_typea *arg)
996 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
997 return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
1000 static bool trans_swr(DisasContext *dc, arg_typea *arg)
1002 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1003 return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
1006 static bool trans_swea(DisasContext *dc, arg_typea *arg)
1008 if (trap_userspace(dc, true)) {
1009 return true;
1011 #ifdef CONFIG_USER_ONLY
1012 return true;
1013 #else
1014 TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
1015 return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
1016 #endif
1019 static bool trans_swi(DisasContext *dc, arg_typeb *arg)
1021 TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
1022 return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
1025 static bool trans_swx(DisasContext *dc, arg_typea *arg)
1027 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1028 TCGLabel *swx_done = gen_new_label();
1029 TCGLabel *swx_fail = gen_new_label();
1030 TCGv_i32 tval;
1032 /* swx does not throw unaligned access errors, so force alignment */
1033 tcg_gen_andi_tl(addr, addr, ~3);
1036 * Compare the address vs the one we used during lwx.
1037 * On mismatch, the operation fails. On match, addr dies at the
1038 * branch, but we know we can use the equal version in the global.
1039 * In either case, addr is no longer needed.
1041 tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1042 tcg_temp_free(addr);
1045 * Compare the value loaded during lwx with current contents of
1046 * the reserved location.
1048 tval = tcg_temp_new_i32();
1050 tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1051 reg_for_write(dc, arg->rd),
1052 dc->mem_index, MO_TEUL);
1054 tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1055 tcg_temp_free_i32(tval);
1057 /* Success */
1058 tcg_gen_movi_i32(cpu_msr_c, 0);
1059 tcg_gen_br(swx_done);
1061 /* Failure */
1062 gen_set_label(swx_fail);
1063 tcg_gen_movi_i32(cpu_msr_c, 1);
1065 gen_set_label(swx_done);
1068 * Prevent the saved address from working again without another ldx.
1069 * Akin to the pseudocode setting reservation = 0.
1071 tcg_gen_movi_tl(cpu_res_addr, -1);
1072 return true;
1075 static void setup_dslot(DisasContext *dc, bool type_b)
1077 dc->tb_flags_to_set |= D_FLAG;
1078 if (type_b && (dc->tb_flags & IMM_FLAG)) {
1079 dc->tb_flags_to_set |= BIMM_FLAG;
1083 static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm,
1084 bool delay, bool abs, int link)
1086 uint32_t add_pc;
1088 if (invalid_delay_slot(dc, "branch")) {
1089 return true;
1091 if (delay) {
1092 setup_dslot(dc, dest_rb < 0);
1095 if (link) {
1096 tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next);
1099 /* Store the branch taken destination into btarget. */
1100 add_pc = abs ? 0 : dc->base.pc_next;
1101 if (dest_rb > 0) {
1102 dc->jmp_dest = -1;
1103 tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc);
1104 } else {
1105 dc->jmp_dest = add_pc + dest_imm;
1106 tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
1108 dc->jmp_cond = TCG_COND_ALWAYS;
1109 return true;
1112 #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK) \
1113 static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg) \
1114 { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); } \
1115 static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg) \
1116 { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); }
1118 DO_BR(br, bri, false, false, false)
1119 DO_BR(bra, brai, false, true, false)
1120 DO_BR(brd, brid, true, false, false)
1121 DO_BR(brad, braid, true, true, false)
1122 DO_BR(brld, brlid, true, false, true)
1123 DO_BR(brald, bralid, true, true, true)
1125 static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm,
1126 TCGCond cond, int ra, bool delay)
1128 TCGv_i32 zero, next;
1130 if (invalid_delay_slot(dc, "bcc")) {
1131 return true;
1133 if (delay) {
1134 setup_dslot(dc, dest_rb < 0);
1137 dc->jmp_cond = cond;
1139 /* Cache the condition register in cpu_bvalue across any delay slot. */
1140 tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra));
1142 /* Store the branch taken destination into btarget. */
1143 if (dest_rb > 0) {
1144 dc->jmp_dest = -1;
1145 tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next);
1146 } else {
1147 dc->jmp_dest = dc->base.pc_next + dest_imm;
1148 tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
1151 /* Compute the final destination into btarget. */
1152 zero = tcg_const_i32(0);
1153 next = tcg_const_i32(dc->base.pc_next + (delay + 1) * 4);
1154 tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget,
1155 reg_for_read(dc, ra), zero,
1156 cpu_btarget, next);
1157 tcg_temp_free_i32(zero);
1158 tcg_temp_free_i32(next);
1160 return true;
1163 #define DO_BCC(NAME, COND) \
1164 static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg) \
1165 { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); } \
1166 static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg) \
1167 { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); } \
1168 static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg) \
1169 { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); } \
1170 static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg) \
1171 { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); }
1173 DO_BCC(beq, TCG_COND_EQ)
1174 DO_BCC(bge, TCG_COND_GE)
1175 DO_BCC(bgt, TCG_COND_GT)
1176 DO_BCC(ble, TCG_COND_LE)
1177 DO_BCC(blt, TCG_COND_LT)
1178 DO_BCC(bne, TCG_COND_NE)
1180 static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
1182 if (trap_userspace(dc, true)) {
1183 return true;
1185 if (invalid_delay_slot(dc, "brk")) {
1186 return true;
1189 tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
1190 if (arg->rd) {
1191 tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1193 tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
1194 tcg_gen_movi_tl(cpu_res_addr, -1);
1196 dc->base.is_jmp = DISAS_EXIT;
1197 return true;
1200 static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
1202 uint32_t imm = arg->imm;
1204 if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
1205 return true;
1207 if (invalid_delay_slot(dc, "brki")) {
1208 return true;
1211 tcg_gen_movi_i32(cpu_pc, imm);
1212 if (arg->rd) {
1213 tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1215 tcg_gen_movi_tl(cpu_res_addr, -1);
1217 #ifdef CONFIG_USER_ONLY
1218 switch (imm) {
1219 case 0x8: /* syscall trap */
1220 gen_raise_exception_sync(dc, EXCP_SYSCALL);
1221 break;
1222 case 0x18: /* debug trap */
1223 gen_raise_exception_sync(dc, EXCP_DEBUG);
1224 break;
1225 default: /* eliminated with trap_userspace check */
1226 g_assert_not_reached();
1228 #else
1229 uint32_t msr_to_set = 0;
1231 if (imm != 0x18) {
1232 msr_to_set |= MSR_BIP;
1234 if (imm == 0x8 || imm == 0x18) {
1235 /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
1236 msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
1237 tcg_gen_andi_i32(cpu_msr, cpu_msr,
1238 ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
1240 tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
1241 dc->base.is_jmp = DISAS_EXIT;
1242 #endif
1244 return true;
1247 static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
1249 int mbar_imm = arg->imm;
1251 /* Note that mbar is a specialized branch instruction. */
1252 if (invalid_delay_slot(dc, "mbar")) {
1253 return true;
1256 /* Data access memory barrier. */
1257 if ((mbar_imm & 2) == 0) {
1258 tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1261 /* Sleep. */
1262 if (mbar_imm & 16) {
1263 TCGv_i32 tmp_1;
1265 if (trap_userspace(dc, true)) {
1266 /* Sleep is a privileged instruction. */
1267 return true;
1270 t_sync_flags(dc);
1272 tmp_1 = tcg_const_i32(1);
1273 tcg_gen_st_i32(tmp_1, cpu_env,
1274 -offsetof(MicroBlazeCPU, env)
1275 +offsetof(CPUState, halted));
1276 tcg_temp_free_i32(tmp_1);
1278 tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1280 gen_raise_exception(dc, EXCP_HLT);
1284 * If !(mbar_imm & 1), this is an instruction access memory barrier
1285 * and we need to end the TB so that we recognize self-modified
1286 * code immediately.
1288 * However, there are some data mbars that need the TB break
1289 * (and return to main loop) to recognize interrupts right away.
1290 * E.g. recognizing a change to an interrupt controller register.
1292 * Therefore, choose to end the TB always.
1294 dc->base.is_jmp = DISAS_EXIT_NEXT;
1295 return true;
1298 static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set)
1300 if (trap_userspace(dc, to_set)) {
1301 return true;
1303 if (invalid_delay_slot(dc, "rts")) {
1304 return true;
1307 dc->tb_flags_to_set |= to_set;
1308 setup_dslot(dc, true);
1310 dc->jmp_cond = TCG_COND_ALWAYS;
1311 dc->jmp_dest = -1;
1312 tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm);
1313 return true;
1316 #define DO_RTS(NAME, IFLAG) \
1317 static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \
1318 { return do_rts(dc, arg, IFLAG); }
1320 DO_RTS(rtbd, DRTB_FLAG)
1321 DO_RTS(rtid, DRTI_FLAG)
1322 DO_RTS(rted, DRTE_FLAG)
1323 DO_RTS(rtsd, 0)
1325 static bool trans_zero(DisasContext *dc, arg_zero *arg)
1327 /* If opcode_0_illegal, trap. */
1328 if (dc->cfg->opcode_0_illegal) {
1329 trap_illegal(dc, true);
1330 return true;
1333 * Otherwise, this is "add r0, r0, r0".
1334 * Continue to trans_add so that MSR[C] gets cleared.
1336 return false;
1339 static void msr_read(DisasContext *dc, TCGv_i32 d)
1341 TCGv_i32 t;
1343 /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
1344 t = tcg_temp_new_i32();
1345 tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
1346 tcg_gen_or_i32(d, cpu_msr, t);
1347 tcg_temp_free_i32(t);
1350 static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set)
1352 uint32_t imm = arg->imm;
1354 if (trap_userspace(dc, imm != MSR_C)) {
1355 return true;
1358 if (arg->rd) {
1359 msr_read(dc, cpu_R[arg->rd]);
1363 * Handle the carry bit separately.
1364 * This is the only bit that userspace can modify.
1366 if (imm & MSR_C) {
1367 tcg_gen_movi_i32(cpu_msr_c, set);
1371 * MSR_C and MSR_CC set above.
1372 * MSR_PVR is not writable, and is always clear.
1374 imm &= ~(MSR_C | MSR_CC | MSR_PVR);
1376 if (imm != 0) {
1377 if (set) {
1378 tcg_gen_ori_i32(cpu_msr, cpu_msr, imm);
1379 } else {
1380 tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm);
1382 dc->base.is_jmp = DISAS_EXIT_NEXT;
1384 return true;
1387 static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg)
1389 return do_msrclrset(dc, arg, false);
1392 static bool trans_msrset(DisasContext *dc, arg_type_msr *arg)
1394 return do_msrclrset(dc, arg, true);
1397 static bool trans_mts(DisasContext *dc, arg_mts *arg)
1399 if (trap_userspace(dc, true)) {
1400 return true;
1403 #ifdef CONFIG_USER_ONLY
1404 g_assert_not_reached();
1405 #else
1406 if (arg->e && arg->rs != 0x1003) {
1407 qemu_log_mask(LOG_GUEST_ERROR,
1408 "Invalid extended mts reg 0x%x\n", arg->rs);
1409 return true;
1412 TCGv_i32 src = reg_for_read(dc, arg->ra);
1413 switch (arg->rs) {
1414 case SR_MSR:
1415 /* Install MSR_C. */
1416 tcg_gen_extract_i32(cpu_msr_c, src, 2, 1);
1418 * Clear MSR_C and MSR_CC;
1419 * MSR_PVR is not writable, and is always clear.
1421 tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR));
1422 break;
1423 case SR_FSR:
1424 tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr));
1425 break;
1426 case 0x800:
1427 tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, slr));
1428 break;
1429 case 0x802:
1430 tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, shr));
1431 break;
1433 case 0x1000: /* PID */
1434 case 0x1001: /* ZPR */
1435 case 0x1002: /* TLBX */
1436 case 0x1003: /* TLBLO */
1437 case 0x1004: /* TLBHI */
1438 case 0x1005: /* TLBSX */
1440 TCGv_i32 tmp_ext = tcg_const_i32(arg->e);
1441 TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7);
1443 gen_helper_mmu_write(cpu_env, tmp_ext, tmp_reg, src);
1444 tcg_temp_free_i32(tmp_reg);
1445 tcg_temp_free_i32(tmp_ext);
1447 break;
1449 default:
1450 qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs);
1451 return true;
1453 dc->base.is_jmp = DISAS_EXIT_NEXT;
1454 return true;
1455 #endif
1458 static bool trans_mfs(DisasContext *dc, arg_mfs *arg)
1460 TCGv_i32 dest = reg_for_write(dc, arg->rd);
1462 if (arg->e) {
1463 switch (arg->rs) {
1464 case SR_EAR:
1466 TCGv_i64 t64 = tcg_temp_new_i64();
1467 tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
1468 tcg_gen_extrh_i64_i32(dest, t64);
1469 tcg_temp_free_i64(t64);
1471 return true;
1472 #ifndef CONFIG_USER_ONLY
1473 case 0x1003: /* TLBLO */
1474 /* Handled below. */
1475 break;
1476 #endif
1477 case 0x2006 ... 0x2009:
1478 /* High bits of PVR6-9 not implemented. */
1479 tcg_gen_movi_i32(dest, 0);
1480 return true;
1481 default:
1482 qemu_log_mask(LOG_GUEST_ERROR,
1483 "Invalid extended mfs reg 0x%x\n", arg->rs);
1484 return true;
1488 switch (arg->rs) {
1489 case SR_PC:
1490 tcg_gen_movi_i32(dest, dc->base.pc_next);
1491 break;
1492 case SR_MSR:
1493 msr_read(dc, dest);
1494 break;
1495 case SR_EAR:
1497 TCGv_i64 t64 = tcg_temp_new_i64();
1498 tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
1499 tcg_gen_extrl_i64_i32(dest, t64);
1500 tcg_temp_free_i64(t64);
1502 break;
1503 case SR_ESR:
1504 tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, esr));
1505 break;
1506 case SR_FSR:
1507 tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, fsr));
1508 break;
1509 case SR_BTR:
1510 tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, btr));
1511 break;
1512 case SR_EDR:
1513 tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, edr));
1514 break;
1515 case 0x800:
1516 tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, slr));
1517 break;
1518 case 0x802:
1519 tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, shr));
1520 break;
1522 #ifndef CONFIG_USER_ONLY
1523 case 0x1000: /* PID */
1524 case 0x1001: /* ZPR */
1525 case 0x1002: /* TLBX */
1526 case 0x1003: /* TLBLO */
1527 case 0x1004: /* TLBHI */
1528 case 0x1005: /* TLBSX */
1530 TCGv_i32 tmp_ext = tcg_const_i32(arg->e);
1531 TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7);
1533 gen_helper_mmu_read(dest, cpu_env, tmp_ext, tmp_reg);
1534 tcg_temp_free_i32(tmp_reg);
1535 tcg_temp_free_i32(tmp_ext);
1537 break;
1538 #endif
1540 case 0x2000 ... 0x200c:
1541 tcg_gen_ld_i32(dest, cpu_env,
1542 offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000])
1543 - offsetof(MicroBlazeCPU, env));
1544 break;
1545 default:
1546 qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs);
1547 break;
1549 return true;
1552 static void do_rti(DisasContext *dc)
1554 TCGv_i32 tmp = tcg_temp_new_i32();
1556 tcg_gen_shri_i32(tmp, cpu_msr, 1);
1557 tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE);
1558 tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM);
1559 tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM));
1560 tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1562 tcg_temp_free_i32(tmp);
1565 static void do_rtb(DisasContext *dc)
1567 TCGv_i32 tmp = tcg_temp_new_i32();
1569 tcg_gen_shri_i32(tmp, cpu_msr, 1);
1570 tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP));
1571 tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
1572 tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1574 tcg_temp_free_i32(tmp);
1577 static void do_rte(DisasContext *dc)
1579 TCGv_i32 tmp = tcg_temp_new_i32();
1581 tcg_gen_shri_i32(tmp, cpu_msr, 1);
1582 tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE);
1583 tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
1584 tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP));
1585 tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1587 tcg_temp_free_i32(tmp);
1590 /* Insns connected to FSL or AXI stream attached devices. */
1591 static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl)
1593 TCGv_i32 t_id, t_ctrl;
1595 if (trap_userspace(dc, true)) {
1596 return true;
1599 t_id = tcg_temp_new_i32();
1600 if (rb) {
1601 tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
1602 } else {
1603 tcg_gen_movi_i32(t_id, imm);
1606 t_ctrl = tcg_const_i32(ctrl);
1607 gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl);
1608 tcg_temp_free_i32(t_id);
1609 tcg_temp_free_i32(t_ctrl);
1610 return true;
1613 static bool trans_get(DisasContext *dc, arg_get *arg)
1615 return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl);
1618 static bool trans_getd(DisasContext *dc, arg_getd *arg)
1620 return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl);
1623 static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl)
1625 TCGv_i32 t_id, t_ctrl;
1627 if (trap_userspace(dc, true)) {
1628 return true;
1631 t_id = tcg_temp_new_i32();
1632 if (rb) {
1633 tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
1634 } else {
1635 tcg_gen_movi_i32(t_id, imm);
1638 t_ctrl = tcg_const_i32(ctrl);
1639 gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra));
1640 tcg_temp_free_i32(t_id);
1641 tcg_temp_free_i32(t_ctrl);
1642 return true;
1645 static bool trans_put(DisasContext *dc, arg_put *arg)
1647 return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl);
1650 static bool trans_putd(DisasContext *dc, arg_putd *arg)
1652 return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl);
1655 static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1657 DisasContext *dc = container_of(dcb, DisasContext, base);
1658 MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1659 int bound;
1661 dc->cfg = &cpu->cfg;
1662 dc->tb_flags = dc->base.tb->flags;
1663 dc->ext_imm = dc->base.tb->cs_base;
1664 dc->r0 = NULL;
1665 dc->r0_set = false;
1666 dc->mem_index = cpu_mmu_index(&cpu->env, false);
1667 dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER;
1668 dc->jmp_dest = -1;
1670 bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1671 dc->base.max_insns = MIN(dc->base.max_insns, bound);
1674 static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
1678 static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1680 DisasContext *dc = container_of(dcb, DisasContext, base);
1682 tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1683 dc->insn_start = tcg_last_op();
1686 static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs,
1687 const CPUBreakpoint *bp)
1689 DisasContext *dc = container_of(dcb, DisasContext, base);
1691 gen_raise_exception_sync(dc, EXCP_DEBUG);
1694 * The address covered by the breakpoint must be included in
1695 * [tb->pc, tb->pc + tb->size) in order to for it to be
1696 * properly cleared -- thus we increment the PC here so that
1697 * the logic setting tb->size below does the right thing.
1699 dc->base.pc_next += 4;
1700 return true;
1703 static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1705 DisasContext *dc = container_of(dcb, DisasContext, base);
1706 CPUMBState *env = cs->env_ptr;
1707 uint32_t ir;
1709 /* TODO: This should raise an exception, not terminate qemu. */
1710 if (dc->base.pc_next & 3) {
1711 cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1712 (uint32_t)dc->base.pc_next);
1715 dc->tb_flags_to_set = 0;
1717 ir = cpu_ldl_code(env, dc->base.pc_next);
1718 if (!decode(dc, ir)) {
1719 trap_illegal(dc, true);
1722 if (dc->r0) {
1723 tcg_temp_free_i32(dc->r0);
1724 dc->r0 = NULL;
1725 dc->r0_set = false;
1728 /* Discard the imm global when its contents cannot be used. */
1729 if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) {
1730 tcg_gen_discard_i32(cpu_imm);
1733 dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG);
1734 dc->tb_flags |= dc->tb_flags_to_set;
1735 dc->base.pc_next += 4;
1737 if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) {
1739 * Finish any return-from branch.
1741 uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
1742 if (unlikely(rt_ibe != 0)) {
1743 dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
1744 if (rt_ibe & DRTI_FLAG) {
1745 do_rti(dc);
1746 } else if (rt_ibe & DRTB_FLAG) {
1747 do_rtb(dc);
1748 } else {
1749 do_rte(dc);
1753 /* Complete the branch, ending the TB. */
1754 switch (dc->base.is_jmp) {
1755 case DISAS_NORETURN:
1757 * E.g. illegal insn in a delay slot. We've already exited
1758 * and will handle D_FLAG in mb_cpu_do_interrupt.
1760 break;
1761 case DISAS_NEXT:
1763 * Normal insn a delay slot.
1764 * However, the return-from-exception type insns should
1765 * return to the main loop, as they have adjusted MSR.
1767 dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP);
1768 break;
1769 case DISAS_EXIT_NEXT:
1771 * E.g. mts insn in a delay slot. Continue with btarget,
1772 * but still return to the main loop.
1774 dc->base.is_jmp = DISAS_EXIT_JUMP;
1775 break;
1776 default:
1777 g_assert_not_reached();
1782 static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1784 DisasContext *dc = container_of(dcb, DisasContext, base);
1786 if (dc->base.is_jmp == DISAS_NORETURN) {
1787 /* We have already exited the TB. */
1788 return;
1791 t_sync_flags(dc);
1793 switch (dc->base.is_jmp) {
1794 case DISAS_TOO_MANY:
1795 gen_goto_tb(dc, 0, dc->base.pc_next);
1796 return;
1798 case DISAS_EXIT:
1799 break;
1800 case DISAS_EXIT_NEXT:
1801 tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1802 break;
1803 case DISAS_EXIT_JUMP:
1804 tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1805 tcg_gen_discard_i32(cpu_btarget);
1806 break;
1808 case DISAS_JUMP:
1809 if (dc->jmp_dest != -1 && !cs->singlestep_enabled) {
1810 /* Direct jump. */
1811 tcg_gen_discard_i32(cpu_btarget);
1813 if (dc->jmp_cond != TCG_COND_ALWAYS) {
1814 /* Conditional direct jump. */
1815 TCGLabel *taken = gen_new_label();
1816 TCGv_i32 tmp = tcg_temp_new_i32();
1819 * Copy bvalue to a temp now, so we can discard bvalue.
1820 * This can avoid writing bvalue to memory when the
1821 * delay slot cannot raise an exception.
1823 tcg_gen_mov_i32(tmp, cpu_bvalue);
1824 tcg_gen_discard_i32(cpu_bvalue);
1826 tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken);
1827 gen_goto_tb(dc, 1, dc->base.pc_next);
1828 gen_set_label(taken);
1830 gen_goto_tb(dc, 0, dc->jmp_dest);
1831 return;
1834 /* Indirect jump (or direct jump w/ singlestep) */
1835 tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1836 tcg_gen_discard_i32(cpu_btarget);
1838 if (unlikely(cs->singlestep_enabled)) {
1839 gen_raise_exception(dc, EXCP_DEBUG);
1840 } else {
1841 tcg_gen_lookup_and_goto_ptr();
1843 return;
1845 default:
1846 g_assert_not_reached();
1849 /* Finish DISAS_EXIT_* */
1850 if (unlikely(cs->singlestep_enabled)) {
1851 gen_raise_exception(dc, EXCP_DEBUG);
1852 } else {
1853 tcg_gen_exit_tb(NULL, 0);
1857 static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs)
1859 qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first));
1860 log_target_disas(cs, dcb->pc_first, dcb->tb->size);
1863 static const TranslatorOps mb_tr_ops = {
1864 .init_disas_context = mb_tr_init_disas_context,
1865 .tb_start = mb_tr_tb_start,
1866 .insn_start = mb_tr_insn_start,
1867 .breakpoint_check = mb_tr_breakpoint_check,
1868 .translate_insn = mb_tr_translate_insn,
1869 .tb_stop = mb_tr_tb_stop,
1870 .disas_log = mb_tr_disas_log,
1873 void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
1875 DisasContext dc;
1876 translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns);
1879 void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1881 MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1882 CPUMBState *env = &cpu->env;
1883 uint32_t iflags;
1884 int i;
1886 qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n",
1887 env->pc, env->msr,
1888 (env->msr & MSR_UM) ? "user" : "kernel",
1889 (env->msr & MSR_UMS) ? "user" : "kernel",
1890 (bool)(env->msr & MSR_EIP),
1891 (bool)(env->msr & MSR_IE));
1893 iflags = env->iflags;
1894 qemu_fprintf(f, "iflags: 0x%08x", iflags);
1895 if (iflags & IMM_FLAG) {
1896 qemu_fprintf(f, " IMM(0x%08x)", env->imm);
1898 if (iflags & BIMM_FLAG) {
1899 qemu_fprintf(f, " BIMM");
1901 if (iflags & D_FLAG) {
1902 qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget);
1904 if (iflags & DRTI_FLAG) {
1905 qemu_fprintf(f, " DRTI");
1907 if (iflags & DRTE_FLAG) {
1908 qemu_fprintf(f, " DRTE");
1910 if (iflags & DRTB_FLAG) {
1911 qemu_fprintf(f, " DRTB");
1913 if (iflags & ESR_ESS_FLAG) {
1914 qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK);
1917 qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n"
1918 "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n",
1919 env->esr, env->fsr, env->btr, env->edr,
1920 env->ear, env->slr, env->shr);
1922 for (i = 0; i < 32; i++) {
1923 qemu_fprintf(f, "r%2.2d=%08x%c",
1924 i, env->regs[i], i % 4 == 3 ? '\n' : ' ');
1926 qemu_fprintf(f, "\n");
1929 void mb_tcg_init(void)
1931 #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1932 #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1934 static const struct {
1935 TCGv_i32 *var; int ofs; char name[8];
1936 } i32s[] = {
1938 * Note that r0 is handled specially in reg_for_read
1939 * and reg_for_write. Nothing should touch cpu_R[0].
1940 * Leave that element NULL, which will assert quickly
1941 * inside the tcg generator functions.
1943 R(1), R(2), R(3), R(4), R(5), R(6), R(7),
1944 R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15),
1945 R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1946 R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1948 SP(pc),
1949 SP(msr),
1950 SP(msr_c),
1951 SP(imm),
1952 SP(iflags),
1953 SP(bvalue),
1954 SP(btarget),
1955 SP(res_val),
1958 #undef R
1959 #undef SP
1961 for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1962 *i32s[i].var =
1963 tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name);
1966 cpu_res_addr =
1967 tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr");
1970 void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1971 target_ulong *data)
1973 env->pc = data[0];
1974 env->iflags = data[1];