virtio-iommu: Implement RESV_MEM probe request
[qemu/ar7.git] / target / microblaze / translate.c
blobf6ff2591c35609e779546c58afb2f6ab6ef98326
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 "microblaze-decode.h"
28 #include "exec/cpu_ldst.h"
29 #include "exec/helper-gen.h"
30 #include "exec/translator.h"
31 #include "qemu/qemu-print.h"
33 #include "trace-tcg.h"
34 #include "exec/log.h"
37 #define SIM_COMPAT 0
38 #define DISAS_GNU 1
39 #define DISAS_MB 1
40 #if DISAS_MB && !SIM_COMPAT
41 # define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
42 #else
43 # define LOG_DIS(...) do { } while (0)
44 #endif
46 #define D(x)
48 #define EXTRACT_FIELD(src, start, end) \
49 (((src) >> start) & ((1 << (end - start + 1)) - 1))
51 /* is_jmp field values */
52 #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
53 #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
54 #define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
56 static TCGv_i32 env_debug;
57 static TCGv_i32 cpu_R[32];
58 static TCGv_i64 cpu_SR[14];
59 static TCGv_i32 env_imm;
60 static TCGv_i32 env_btaken;
61 static TCGv_i64 env_btarget;
62 static TCGv_i32 env_iflags;
63 static TCGv env_res_addr;
64 static TCGv_i32 env_res_val;
66 #include "exec/gen-icount.h"
68 /* This is the state at translation time. */
69 typedef struct DisasContext {
70 MicroBlazeCPU *cpu;
71 uint32_t pc;
73 /* Decoder. */
74 int type_b;
75 uint32_t ir;
76 uint8_t opcode;
77 uint8_t rd, ra, rb;
78 uint16_t imm;
80 unsigned int cpustate_changed;
81 unsigned int delayed_branch;
82 unsigned int tb_flags, synced_flags; /* tb dependent flags. */
83 unsigned int clear_imm;
84 int is_jmp;
86 #define JMP_NOJMP 0
87 #define JMP_DIRECT 1
88 #define JMP_DIRECT_CC 2
89 #define JMP_INDIRECT 3
90 unsigned int jmp;
91 uint32_t jmp_pc;
93 int abort_at_next_insn;
94 struct TranslationBlock *tb;
95 int singlestep_enabled;
96 } DisasContext;
98 static const char *regnames[] =
100 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
101 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
102 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
103 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
106 static const char *special_regnames[] =
108 "rpc", "rmsr", "sr2", "rear", "sr4", "resr", "sr6", "rfsr",
109 "sr8", "sr9", "sr10", "rbtr", "sr12", "redr"
112 static inline void t_sync_flags(DisasContext *dc)
114 /* Synch the tb dependent flags between translator and runtime. */
115 if (dc->tb_flags != dc->synced_flags) {
116 tcg_gen_movi_i32(env_iflags, dc->tb_flags);
117 dc->synced_flags = dc->tb_flags;
121 static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index)
123 TCGv_i32 tmp = tcg_const_i32(index);
125 t_sync_flags(dc);
126 tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc);
127 gen_helper_raise_exception(cpu_env, tmp);
128 tcg_temp_free_i32(tmp);
129 dc->is_jmp = DISAS_UPDATE;
132 static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
134 #ifndef CONFIG_USER_ONLY
135 return (dc->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
136 #else
137 return true;
138 #endif
141 static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
143 if (use_goto_tb(dc, dest)) {
144 tcg_gen_goto_tb(n);
145 tcg_gen_movi_i64(cpu_SR[SR_PC], dest);
146 tcg_gen_exit_tb(dc->tb, n);
147 } else {
148 tcg_gen_movi_i64(cpu_SR[SR_PC], dest);
149 tcg_gen_exit_tb(NULL, 0);
153 static void read_carry(DisasContext *dc, TCGv_i32 d)
155 tcg_gen_extrl_i64_i32(d, cpu_SR[SR_MSR]);
156 tcg_gen_shri_i32(d, d, 31);
160 * write_carry sets the carry bits in MSR based on bit 0 of v.
161 * v[31:1] are ignored.
163 static void write_carry(DisasContext *dc, TCGv_i32 v)
165 TCGv_i64 t0 = tcg_temp_new_i64();
166 tcg_gen_extu_i32_i64(t0, v);
167 /* Deposit bit 0 into MSR_C and the alias MSR_CC. */
168 tcg_gen_deposit_i64(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0, 2, 1);
169 tcg_gen_deposit_i64(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0, 31, 1);
170 tcg_temp_free_i64(t0);
173 static void write_carryi(DisasContext *dc, bool carry)
175 TCGv_i32 t0 = tcg_temp_new_i32();
176 tcg_gen_movi_i32(t0, carry);
177 write_carry(dc, t0);
178 tcg_temp_free_i32(t0);
182 * Returns true if the insn an illegal operation.
183 * If exceptions are enabled, an exception is raised.
185 static bool trap_illegal(DisasContext *dc, bool cond)
187 if (cond && (dc->tb_flags & MSR_EE_FLAG)
188 && dc->cpu->cfg.illegal_opcode_exception) {
189 tcg_gen_movi_i64(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
190 t_gen_raise_exception(dc, EXCP_HW_EXCP);
192 return cond;
196 * Returns true if the insn is illegal in userspace.
197 * If exceptions are enabled, an exception is raised.
199 static bool trap_userspace(DisasContext *dc, bool cond)
201 int mem_index = cpu_mmu_index(&dc->cpu->env, false);
202 bool cond_user = cond && mem_index == MMU_USER_IDX;
204 if (cond_user && (dc->tb_flags & MSR_EE_FLAG)) {
205 tcg_gen_movi_i64(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
206 t_gen_raise_exception(dc, EXCP_HW_EXCP);
208 return cond_user;
211 /* True if ALU operand b is a small immediate that may deserve
212 faster treatment. */
213 static inline int dec_alu_op_b_is_small_imm(DisasContext *dc)
215 /* Immediate insn without the imm prefix ? */
216 return dc->type_b && !(dc->tb_flags & IMM_FLAG);
219 static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc)
221 if (dc->type_b) {
222 if (dc->tb_flags & IMM_FLAG)
223 tcg_gen_ori_i32(env_imm, env_imm, dc->imm);
224 else
225 tcg_gen_movi_i32(env_imm, (int32_t)((int16_t)dc->imm));
226 return &env_imm;
227 } else
228 return &cpu_R[dc->rb];
231 static void dec_add(DisasContext *dc)
233 unsigned int k, c;
234 TCGv_i32 cf;
236 k = dc->opcode & 4;
237 c = dc->opcode & 2;
239 LOG_DIS("add%s%s%s r%d r%d r%d\n",
240 dc->type_b ? "i" : "", k ? "k" : "", c ? "c" : "",
241 dc->rd, dc->ra, dc->rb);
243 /* Take care of the easy cases first. */
244 if (k) {
245 /* k - keep carry, no need to update MSR. */
246 /* If rd == r0, it's a nop. */
247 if (dc->rd) {
248 tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
250 if (c) {
251 /* c - Add carry into the result. */
252 cf = tcg_temp_new_i32();
254 read_carry(dc, cf);
255 tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf);
256 tcg_temp_free_i32(cf);
259 return;
262 /* From now on, we can assume k is zero. So we need to update MSR. */
263 /* Extract carry. */
264 cf = tcg_temp_new_i32();
265 if (c) {
266 read_carry(dc, cf);
267 } else {
268 tcg_gen_movi_i32(cf, 0);
271 if (dc->rd) {
272 TCGv_i32 ncf = tcg_temp_new_i32();
273 gen_helper_carry(ncf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
274 tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
275 tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf);
276 write_carry(dc, ncf);
277 tcg_temp_free_i32(ncf);
278 } else {
279 gen_helper_carry(cf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
280 write_carry(dc, cf);
282 tcg_temp_free_i32(cf);
285 static void dec_sub(DisasContext *dc)
287 unsigned int u, cmp, k, c;
288 TCGv_i32 cf, na;
290 u = dc->imm & 2;
291 k = dc->opcode & 4;
292 c = dc->opcode & 2;
293 cmp = (dc->imm & 1) && (!dc->type_b) && k;
295 if (cmp) {
296 LOG_DIS("cmp%s r%d, r%d ir=%x\n", u ? "u" : "", dc->rd, dc->ra, dc->ir);
297 if (dc->rd) {
298 if (u)
299 gen_helper_cmpu(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
300 else
301 gen_helper_cmp(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
303 return;
306 LOG_DIS("sub%s%s r%d, r%d r%d\n",
307 k ? "k" : "", c ? "c" : "", dc->rd, dc->ra, dc->rb);
309 /* Take care of the easy cases first. */
310 if (k) {
311 /* k - keep carry, no need to update MSR. */
312 /* If rd == r0, it's a nop. */
313 if (dc->rd) {
314 tcg_gen_sub_i32(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
316 if (c) {
317 /* c - Add carry into the result. */
318 cf = tcg_temp_new_i32();
320 read_carry(dc, cf);
321 tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf);
322 tcg_temp_free_i32(cf);
325 return;
328 /* From now on, we can assume k is zero. So we need to update MSR. */
329 /* Extract carry. And complement a into na. */
330 cf = tcg_temp_new_i32();
331 na = tcg_temp_new_i32();
332 if (c) {
333 read_carry(dc, cf);
334 } else {
335 tcg_gen_movi_i32(cf, 1);
338 /* d = b + ~a + c. carry defaults to 1. */
339 tcg_gen_not_i32(na, cpu_R[dc->ra]);
341 if (dc->rd) {
342 TCGv_i32 ncf = tcg_temp_new_i32();
343 gen_helper_carry(ncf, na, *(dec_alu_op_b(dc)), cf);
344 tcg_gen_add_i32(cpu_R[dc->rd], na, *(dec_alu_op_b(dc)));
345 tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf);
346 write_carry(dc, ncf);
347 tcg_temp_free_i32(ncf);
348 } else {
349 gen_helper_carry(cf, na, *(dec_alu_op_b(dc)), cf);
350 write_carry(dc, cf);
352 tcg_temp_free_i32(cf);
353 tcg_temp_free_i32(na);
356 static void dec_pattern(DisasContext *dc)
358 unsigned int mode;
360 if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) {
361 return;
364 mode = dc->opcode & 3;
365 switch (mode) {
366 case 0:
367 /* pcmpbf. */
368 LOG_DIS("pcmpbf r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
369 if (dc->rd)
370 gen_helper_pcmpbf(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
371 break;
372 case 2:
373 LOG_DIS("pcmpeq r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
374 if (dc->rd) {
375 tcg_gen_setcond_i32(TCG_COND_EQ, cpu_R[dc->rd],
376 cpu_R[dc->ra], cpu_R[dc->rb]);
378 break;
379 case 3:
380 LOG_DIS("pcmpne r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
381 if (dc->rd) {
382 tcg_gen_setcond_i32(TCG_COND_NE, cpu_R[dc->rd],
383 cpu_R[dc->ra], cpu_R[dc->rb]);
385 break;
386 default:
387 cpu_abort(CPU(dc->cpu),
388 "unsupported pattern insn opcode=%x\n", dc->opcode);
389 break;
393 static void dec_and(DisasContext *dc)
395 unsigned int not;
397 if (!dc->type_b && (dc->imm & (1 << 10))) {
398 dec_pattern(dc);
399 return;
402 not = dc->opcode & (1 << 1);
403 LOG_DIS("and%s\n", not ? "n" : "");
405 if (!dc->rd)
406 return;
408 if (not) {
409 tcg_gen_andc_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
410 } else
411 tcg_gen_and_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
414 static void dec_or(DisasContext *dc)
416 if (!dc->type_b && (dc->imm & (1 << 10))) {
417 dec_pattern(dc);
418 return;
421 LOG_DIS("or r%d r%d r%d imm=%x\n", dc->rd, dc->ra, dc->rb, dc->imm);
422 if (dc->rd)
423 tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
426 static void dec_xor(DisasContext *dc)
428 if (!dc->type_b && (dc->imm & (1 << 10))) {
429 dec_pattern(dc);
430 return;
433 LOG_DIS("xor r%d\n", dc->rd);
434 if (dc->rd)
435 tcg_gen_xor_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
438 static inline void msr_read(DisasContext *dc, TCGv_i32 d)
440 tcg_gen_extrl_i64_i32(d, cpu_SR[SR_MSR]);
443 static inline void msr_write(DisasContext *dc, TCGv_i32 v)
445 TCGv_i64 t;
447 t = tcg_temp_new_i64();
448 dc->cpustate_changed = 1;
449 /* PVR bit is not writable. */
450 tcg_gen_extu_i32_i64(t, v);
451 tcg_gen_andi_i64(t, t, ~MSR_PVR);
452 tcg_gen_andi_i64(cpu_SR[SR_MSR], cpu_SR[SR_MSR], MSR_PVR);
453 tcg_gen_or_i64(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t);
454 tcg_temp_free_i64(t);
457 static void dec_msr(DisasContext *dc)
459 CPUState *cs = CPU(dc->cpu);
460 TCGv_i32 t0, t1;
461 unsigned int sr, rn;
462 bool to, clrset, extended = false;
464 sr = extract32(dc->imm, 0, 14);
465 to = extract32(dc->imm, 14, 1);
466 clrset = extract32(dc->imm, 15, 1) == 0;
467 dc->type_b = 1;
468 if (to) {
469 dc->cpustate_changed = 1;
472 /* Extended MSRs are only available if addr_size > 32. */
473 if (dc->cpu->cfg.addr_size > 32) {
474 /* The E-bit is encoded differently for To/From MSR. */
475 static const unsigned int e_bit[] = { 19, 24 };
477 extended = extract32(dc->imm, e_bit[to], 1);
480 /* msrclr and msrset. */
481 if (clrset) {
482 bool clr = extract32(dc->ir, 16, 1);
484 LOG_DIS("msr%s r%d imm=%x\n", clr ? "clr" : "set",
485 dc->rd, dc->imm);
487 if (!dc->cpu->cfg.use_msr_instr) {
488 /* nop??? */
489 return;
492 if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) {
493 return;
496 if (dc->rd)
497 msr_read(dc, cpu_R[dc->rd]);
499 t0 = tcg_temp_new_i32();
500 t1 = tcg_temp_new_i32();
501 msr_read(dc, t0);
502 tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc)));
504 if (clr) {
505 tcg_gen_not_i32(t1, t1);
506 tcg_gen_and_i32(t0, t0, t1);
507 } else
508 tcg_gen_or_i32(t0, t0, t1);
509 msr_write(dc, t0);
510 tcg_temp_free_i32(t0);
511 tcg_temp_free_i32(t1);
512 tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc + 4);
513 dc->is_jmp = DISAS_UPDATE;
514 return;
517 if (trap_userspace(dc, to)) {
518 return;
521 #if !defined(CONFIG_USER_ONLY)
522 /* Catch read/writes to the mmu block. */
523 if ((sr & ~0xff) == 0x1000) {
524 TCGv_i32 tmp_ext = tcg_const_i32(extended);
525 TCGv_i32 tmp_sr;
527 sr &= 7;
528 tmp_sr = tcg_const_i32(sr);
529 LOG_DIS("m%ss sr%d r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm);
530 if (to) {
531 gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]);
532 } else {
533 gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr);
535 tcg_temp_free_i32(tmp_sr);
536 tcg_temp_free_i32(tmp_ext);
537 return;
539 #endif
541 if (to) {
542 LOG_DIS("m%ss sr%x r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm);
543 switch (sr) {
544 case 0:
545 break;
546 case 1:
547 msr_write(dc, cpu_R[dc->ra]);
548 break;
549 case SR_EAR:
550 case SR_ESR:
551 case SR_FSR:
552 tcg_gen_extu_i32_i64(cpu_SR[sr], cpu_R[dc->ra]);
553 break;
554 case 0x800:
555 tcg_gen_st_i32(cpu_R[dc->ra],
556 cpu_env, offsetof(CPUMBState, slr));
557 break;
558 case 0x802:
559 tcg_gen_st_i32(cpu_R[dc->ra],
560 cpu_env, offsetof(CPUMBState, shr));
561 break;
562 default:
563 cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr);
564 break;
566 } else {
567 LOG_DIS("m%ss r%d sr%x imm=%x\n", to ? "t" : "f", dc->rd, sr, dc->imm);
569 switch (sr) {
570 case 0:
571 tcg_gen_movi_i32(cpu_R[dc->rd], dc->pc);
572 break;
573 case 1:
574 msr_read(dc, cpu_R[dc->rd]);
575 break;
576 case SR_EAR:
577 if (extended) {
578 tcg_gen_extrh_i64_i32(cpu_R[dc->rd], cpu_SR[sr]);
579 break;
581 case SR_ESR:
582 case SR_FSR:
583 case SR_BTR:
584 case SR_EDR:
585 tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_SR[sr]);
586 break;
587 case 0x800:
588 tcg_gen_ld_i32(cpu_R[dc->rd],
589 cpu_env, offsetof(CPUMBState, slr));
590 break;
591 case 0x802:
592 tcg_gen_ld_i32(cpu_R[dc->rd],
593 cpu_env, offsetof(CPUMBState, shr));
594 break;
595 case 0x2000 ... 0x200c:
596 rn = sr & 0xf;
597 tcg_gen_ld_i32(cpu_R[dc->rd],
598 cpu_env, offsetof(CPUMBState, pvr.regs[rn]));
599 break;
600 default:
601 cpu_abort(cs, "unknown mfs reg %x\n", sr);
602 break;
606 if (dc->rd == 0) {
607 tcg_gen_movi_i32(cpu_R[0], 0);
611 /* Multiplier unit. */
612 static void dec_mul(DisasContext *dc)
614 TCGv_i32 tmp;
615 unsigned int subcode;
617 if (trap_illegal(dc, !dc->cpu->cfg.use_hw_mul)) {
618 return;
621 subcode = dc->imm & 3;
623 if (dc->type_b) {
624 LOG_DIS("muli r%d r%d %x\n", dc->rd, dc->ra, dc->imm);
625 tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
626 return;
629 /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2. */
630 if (subcode >= 1 && subcode <= 3 && dc->cpu->cfg.use_hw_mul < 2) {
631 /* nop??? */
634 tmp = tcg_temp_new_i32();
635 switch (subcode) {
636 case 0:
637 LOG_DIS("mul r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
638 tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
639 break;
640 case 1:
641 LOG_DIS("mulh r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
642 tcg_gen_muls2_i32(tmp, cpu_R[dc->rd],
643 cpu_R[dc->ra], cpu_R[dc->rb]);
644 break;
645 case 2:
646 LOG_DIS("mulhsu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
647 tcg_gen_mulsu2_i32(tmp, cpu_R[dc->rd],
648 cpu_R[dc->ra], cpu_R[dc->rb]);
649 break;
650 case 3:
651 LOG_DIS("mulhu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
652 tcg_gen_mulu2_i32(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
653 break;
654 default:
655 cpu_abort(CPU(dc->cpu), "unknown MUL insn %x\n", subcode);
656 break;
658 tcg_temp_free_i32(tmp);
661 /* Div unit. */
662 static void dec_div(DisasContext *dc)
664 unsigned int u;
666 u = dc->imm & 2;
667 LOG_DIS("div\n");
669 if (trap_illegal(dc, !dc->cpu->cfg.use_div)) {
670 return;
673 if (u)
674 gen_helper_divu(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)),
675 cpu_R[dc->ra]);
676 else
677 gen_helper_divs(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)),
678 cpu_R[dc->ra]);
679 if (!dc->rd)
680 tcg_gen_movi_i32(cpu_R[dc->rd], 0);
683 static void dec_barrel(DisasContext *dc)
685 TCGv_i32 t0;
686 unsigned int imm_w, imm_s;
687 bool s, t, e = false, i = false;
689 if (trap_illegal(dc, !dc->cpu->cfg.use_barrel)) {
690 return;
693 if (dc->type_b) {
694 /* Insert and extract are only available in immediate mode. */
695 i = extract32(dc->imm, 15, 1);
696 e = extract32(dc->imm, 14, 1);
698 s = extract32(dc->imm, 10, 1);
699 t = extract32(dc->imm, 9, 1);
700 imm_w = extract32(dc->imm, 6, 5);
701 imm_s = extract32(dc->imm, 0, 5);
703 LOG_DIS("bs%s%s%s r%d r%d r%d\n",
704 e ? "e" : "",
705 s ? "l" : "r", t ? "a" : "l", dc->rd, dc->ra, dc->rb);
707 if (e) {
708 if (imm_w + imm_s > 32 || imm_w == 0) {
709 /* These inputs have an undefined behavior. */
710 qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
711 imm_w, imm_s);
712 } else {
713 tcg_gen_extract_i32(cpu_R[dc->rd], cpu_R[dc->ra], imm_s, imm_w);
715 } else if (i) {
716 int width = imm_w - imm_s + 1;
718 if (imm_w < imm_s) {
719 /* These inputs have an undefined behavior. */
720 qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
721 imm_w, imm_s);
722 } else {
723 tcg_gen_deposit_i32(cpu_R[dc->rd], cpu_R[dc->rd], cpu_R[dc->ra],
724 imm_s, width);
726 } else {
727 t0 = tcg_temp_new_i32();
729 tcg_gen_mov_i32(t0, *(dec_alu_op_b(dc)));
730 tcg_gen_andi_i32(t0, t0, 31);
732 if (s) {
733 tcg_gen_shl_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0);
734 } else {
735 if (t) {
736 tcg_gen_sar_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0);
737 } else {
738 tcg_gen_shr_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0);
741 tcg_temp_free_i32(t0);
745 static void dec_bit(DisasContext *dc)
747 CPUState *cs = CPU(dc->cpu);
748 TCGv_i32 t0;
749 unsigned int op;
751 op = dc->ir & ((1 << 9) - 1);
752 switch (op) {
753 case 0x21:
754 /* src. */
755 t0 = tcg_temp_new_i32();
757 LOG_DIS("src r%d r%d\n", dc->rd, dc->ra);
758 tcg_gen_extrl_i64_i32(t0, cpu_SR[SR_MSR]);
759 tcg_gen_andi_i32(t0, t0, MSR_CC);
760 write_carry(dc, cpu_R[dc->ra]);
761 if (dc->rd) {
762 tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1);
763 tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->rd], t0);
765 tcg_temp_free_i32(t0);
766 break;
768 case 0x1:
769 case 0x41:
770 /* srl. */
771 LOG_DIS("srl r%d r%d\n", dc->rd, dc->ra);
773 /* Update carry. Note that write carry only looks at the LSB. */
774 write_carry(dc, cpu_R[dc->ra]);
775 if (dc->rd) {
776 if (op == 0x41)
777 tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1);
778 else
779 tcg_gen_sari_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1);
781 break;
782 case 0x60:
783 LOG_DIS("ext8s r%d r%d\n", dc->rd, dc->ra);
784 tcg_gen_ext8s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
785 break;
786 case 0x61:
787 LOG_DIS("ext16s r%d r%d\n", dc->rd, dc->ra);
788 tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
789 break;
790 case 0x64:
791 case 0x66:
792 case 0x74:
793 case 0x76:
794 /* wdc. */
795 LOG_DIS("wdc r%d\n", dc->ra);
796 trap_userspace(dc, true);
797 break;
798 case 0x68:
799 /* wic. */
800 LOG_DIS("wic r%d\n", dc->ra);
801 trap_userspace(dc, true);
802 break;
803 case 0xe0:
804 if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) {
805 return;
807 if (dc->cpu->cfg.use_pcmp_instr) {
808 tcg_gen_clzi_i32(cpu_R[dc->rd], cpu_R[dc->ra], 32);
810 break;
811 case 0x1e0:
812 /* swapb */
813 LOG_DIS("swapb r%d r%d\n", dc->rd, dc->ra);
814 tcg_gen_bswap32_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
815 break;
816 case 0x1e2:
817 /*swaph */
818 LOG_DIS("swaph r%d r%d\n", dc->rd, dc->ra);
819 tcg_gen_rotri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 16);
820 break;
821 default:
822 cpu_abort(cs, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n",
823 dc->pc, op, dc->rd, dc->ra, dc->rb);
824 break;
828 static inline void sync_jmpstate(DisasContext *dc)
830 if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
831 if (dc->jmp == JMP_DIRECT) {
832 tcg_gen_movi_i32(env_btaken, 1);
834 dc->jmp = JMP_INDIRECT;
835 tcg_gen_movi_i64(env_btarget, dc->jmp_pc);
839 static void dec_imm(DisasContext *dc)
841 LOG_DIS("imm %x\n", dc->imm << 16);
842 tcg_gen_movi_i32(env_imm, (dc->imm << 16));
843 dc->tb_flags |= IMM_FLAG;
844 dc->clear_imm = 0;
847 static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t)
849 bool extimm = dc->tb_flags & IMM_FLAG;
850 /* Should be set to true if r1 is used by loadstores. */
851 bool stackprot = false;
852 TCGv_i32 t32;
854 /* All load/stores use ra. */
855 if (dc->ra == 1 && dc->cpu->cfg.stackprot) {
856 stackprot = true;
859 /* Treat the common cases first. */
860 if (!dc->type_b) {
861 if (ea) {
862 int addr_size = dc->cpu->cfg.addr_size;
864 if (addr_size == 32) {
865 tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]);
866 return;
869 tcg_gen_concat_i32_i64(t, cpu_R[dc->rb], cpu_R[dc->ra]);
870 if (addr_size < 64) {
871 /* Mask off out of range bits. */
872 tcg_gen_andi_i64(t, t, MAKE_64BIT_MASK(0, addr_size));
874 return;
877 /* If any of the regs is r0, set t to the value of the other reg. */
878 if (dc->ra == 0) {
879 tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]);
880 return;
881 } else if (dc->rb == 0) {
882 tcg_gen_extu_i32_tl(t, cpu_R[dc->ra]);
883 return;
886 if (dc->rb == 1 && dc->cpu->cfg.stackprot) {
887 stackprot = true;
890 t32 = tcg_temp_new_i32();
891 tcg_gen_add_i32(t32, cpu_R[dc->ra], cpu_R[dc->rb]);
892 tcg_gen_extu_i32_tl(t, t32);
893 tcg_temp_free_i32(t32);
895 if (stackprot) {
896 gen_helper_stackprot(cpu_env, t);
898 return;
900 /* Immediate. */
901 t32 = tcg_temp_new_i32();
902 if (!extimm) {
903 tcg_gen_addi_i32(t32, cpu_R[dc->ra], (int16_t)dc->imm);
904 } else {
905 tcg_gen_add_i32(t32, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
907 tcg_gen_extu_i32_tl(t, t32);
908 tcg_temp_free_i32(t32);
910 if (stackprot) {
911 gen_helper_stackprot(cpu_env, t);
913 return;
916 static void dec_load(DisasContext *dc)
918 TCGv_i32 v;
919 TCGv addr;
920 unsigned int size;
921 bool rev = false, ex = false, ea = false;
922 int mem_index = cpu_mmu_index(&dc->cpu->env, false);
923 MemOp mop;
925 mop = dc->opcode & 3;
926 size = 1 << mop;
927 if (!dc->type_b) {
928 ea = extract32(dc->ir, 7, 1);
929 rev = extract32(dc->ir, 9, 1);
930 ex = extract32(dc->ir, 10, 1);
932 mop |= MO_TE;
933 if (rev) {
934 mop ^= MO_BSWAP;
937 if (trap_illegal(dc, size > 4)) {
938 return;
941 if (trap_userspace(dc, ea)) {
942 return;
945 LOG_DIS("l%d%s%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
946 ex ? "x" : "",
947 ea ? "ea" : "");
949 t_sync_flags(dc);
950 addr = tcg_temp_new();
951 compute_ldst_addr(dc, ea, addr);
952 /* Extended addressing bypasses the MMU. */
953 mem_index = ea ? MMU_NOMMU_IDX : mem_index;
956 * When doing reverse accesses we need to do two things.
958 * 1. Reverse the address wrt endianness.
959 * 2. Byteswap the data lanes on the way back into the CPU core.
961 if (rev && size != 4) {
962 /* Endian reverse the address. t is addr. */
963 switch (size) {
964 case 1:
966 tcg_gen_xori_tl(addr, addr, 3);
967 break;
970 case 2:
971 /* 00 -> 10
972 10 -> 00. */
973 tcg_gen_xori_tl(addr, addr, 2);
974 break;
975 default:
976 cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
977 break;
981 /* lwx does not throw unaligned access errors, so force alignment */
982 if (ex) {
983 tcg_gen_andi_tl(addr, addr, ~3);
986 /* If we get a fault on a dslot, the jmpstate better be in sync. */
987 sync_jmpstate(dc);
989 /* Verify alignment if needed. */
991 * Microblaze gives MMU faults priority over faults due to
992 * unaligned addresses. That's why we speculatively do the load
993 * into v. If the load succeeds, we verify alignment of the
994 * address and if that succeeds we write into the destination reg.
996 v = tcg_temp_new_i32();
997 tcg_gen_qemu_ld_i32(v, addr, mem_index, mop);
999 if (dc->cpu->cfg.unaligned_exceptions && size > 1) {
1000 TCGv_i32 t0 = tcg_const_i32(0);
1001 TCGv_i32 treg = tcg_const_i32(dc->rd);
1002 TCGv_i32 tsize = tcg_const_i32(size - 1);
1004 tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc);
1005 gen_helper_memalign(cpu_env, addr, treg, t0, tsize);
1007 tcg_temp_free_i32(t0);
1008 tcg_temp_free_i32(treg);
1009 tcg_temp_free_i32(tsize);
1012 if (ex) {
1013 tcg_gen_mov_tl(env_res_addr, addr);
1014 tcg_gen_mov_i32(env_res_val, v);
1016 if (dc->rd) {
1017 tcg_gen_mov_i32(cpu_R[dc->rd], v);
1019 tcg_temp_free_i32(v);
1021 if (ex) { /* lwx */
1022 /* no support for AXI exclusive so always clear C */
1023 write_carryi(dc, 0);
1026 tcg_temp_free(addr);
1029 static void dec_store(DisasContext *dc)
1031 TCGv addr;
1032 TCGLabel *swx_skip = NULL;
1033 unsigned int size;
1034 bool rev = false, ex = false, ea = false;
1035 int mem_index = cpu_mmu_index(&dc->cpu->env, false);
1036 MemOp mop;
1038 mop = dc->opcode & 3;
1039 size = 1 << mop;
1040 if (!dc->type_b) {
1041 ea = extract32(dc->ir, 7, 1);
1042 rev = extract32(dc->ir, 9, 1);
1043 ex = extract32(dc->ir, 10, 1);
1045 mop |= MO_TE;
1046 if (rev) {
1047 mop ^= MO_BSWAP;
1050 if (trap_illegal(dc, size > 4)) {
1051 return;
1054 trap_userspace(dc, ea);
1056 LOG_DIS("s%d%s%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
1057 ex ? "x" : "",
1058 ea ? "ea" : "");
1059 t_sync_flags(dc);
1060 /* If we get a fault on a dslot, the jmpstate better be in sync. */
1061 sync_jmpstate(dc);
1062 /* SWX needs a temp_local. */
1063 addr = ex ? tcg_temp_local_new() : tcg_temp_new();
1064 compute_ldst_addr(dc, ea, addr);
1065 /* Extended addressing bypasses the MMU. */
1066 mem_index = ea ? MMU_NOMMU_IDX : mem_index;
1068 if (ex) { /* swx */
1069 TCGv_i32 tval;
1071 /* swx does not throw unaligned access errors, so force alignment */
1072 tcg_gen_andi_tl(addr, addr, ~3);
1074 write_carryi(dc, 1);
1075 swx_skip = gen_new_label();
1076 tcg_gen_brcond_tl(TCG_COND_NE, env_res_addr, addr, swx_skip);
1078 /* Compare the value loaded at lwx with current contents of
1079 the reserved location.
1080 FIXME: This only works for system emulation where we can expect
1081 this compare and the following write to be atomic. For user
1082 emulation we need to add atomicity between threads. */
1083 tval = tcg_temp_new_i32();
1084 tcg_gen_qemu_ld_i32(tval, addr, cpu_mmu_index(&dc->cpu->env, false),
1085 MO_TEUL);
1086 tcg_gen_brcond_i32(TCG_COND_NE, env_res_val, tval, swx_skip);
1087 write_carryi(dc, 0);
1088 tcg_temp_free_i32(tval);
1091 if (rev && size != 4) {
1092 /* Endian reverse the address. t is addr. */
1093 switch (size) {
1094 case 1:
1096 tcg_gen_xori_tl(addr, addr, 3);
1097 break;
1100 case 2:
1101 /* 00 -> 10
1102 10 -> 00. */
1103 /* Force addr into the temp. */
1104 tcg_gen_xori_tl(addr, addr, 2);
1105 break;
1106 default:
1107 cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
1108 break;
1111 tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop);
1113 /* Verify alignment if needed. */
1114 if (dc->cpu->cfg.unaligned_exceptions && size > 1) {
1115 TCGv_i32 t1 = tcg_const_i32(1);
1116 TCGv_i32 treg = tcg_const_i32(dc->rd);
1117 TCGv_i32 tsize = tcg_const_i32(size - 1);
1119 tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc);
1120 /* FIXME: if the alignment is wrong, we should restore the value
1121 * in memory. One possible way to achieve this is to probe
1122 * the MMU prior to the memaccess, thay way we could put
1123 * the alignment checks in between the probe and the mem
1124 * access.
1126 gen_helper_memalign(cpu_env, addr, treg, t1, tsize);
1128 tcg_temp_free_i32(t1);
1129 tcg_temp_free_i32(treg);
1130 tcg_temp_free_i32(tsize);
1133 if (ex) {
1134 gen_set_label(swx_skip);
1137 tcg_temp_free(addr);
1140 static inline void eval_cc(DisasContext *dc, unsigned int cc,
1141 TCGv_i32 d, TCGv_i32 a)
1143 static const int mb_to_tcg_cc[] = {
1144 [CC_EQ] = TCG_COND_EQ,
1145 [CC_NE] = TCG_COND_NE,
1146 [CC_LT] = TCG_COND_LT,
1147 [CC_LE] = TCG_COND_LE,
1148 [CC_GE] = TCG_COND_GE,
1149 [CC_GT] = TCG_COND_GT,
1152 switch (cc) {
1153 case CC_EQ:
1154 case CC_NE:
1155 case CC_LT:
1156 case CC_LE:
1157 case CC_GE:
1158 case CC_GT:
1159 tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0);
1160 break;
1161 default:
1162 cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc);
1163 break;
1167 static void eval_cond_jmp(DisasContext *dc, TCGv_i64 pc_true, TCGv_i64 pc_false)
1169 TCGv_i64 tmp_btaken = tcg_temp_new_i64();
1170 TCGv_i64 tmp_zero = tcg_const_i64(0);
1172 tcg_gen_extu_i32_i64(tmp_btaken, env_btaken);
1173 tcg_gen_movcond_i64(TCG_COND_NE, cpu_SR[SR_PC],
1174 tmp_btaken, tmp_zero,
1175 pc_true, pc_false);
1177 tcg_temp_free_i64(tmp_btaken);
1178 tcg_temp_free_i64(tmp_zero);
1181 static void dec_setup_dslot(DisasContext *dc)
1183 TCGv_i32 tmp = tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG));
1185 dc->delayed_branch = 2;
1186 dc->tb_flags |= D_FLAG;
1188 tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, bimm));
1189 tcg_temp_free_i32(tmp);
1192 static void dec_bcc(DisasContext *dc)
1194 unsigned int cc;
1195 unsigned int dslot;
1197 cc = EXTRACT_FIELD(dc->ir, 21, 23);
1198 dslot = dc->ir & (1 << 25);
1199 LOG_DIS("bcc%s r%d %x\n", dslot ? "d" : "", dc->ra, dc->imm);
1201 dc->delayed_branch = 1;
1202 if (dslot) {
1203 dec_setup_dslot(dc);
1206 if (dec_alu_op_b_is_small_imm(dc)) {
1207 int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend. */
1209 tcg_gen_movi_i64(env_btarget, dc->pc + offset);
1210 dc->jmp = JMP_DIRECT_CC;
1211 dc->jmp_pc = dc->pc + offset;
1212 } else {
1213 dc->jmp = JMP_INDIRECT;
1214 tcg_gen_extu_i32_i64(env_btarget, *(dec_alu_op_b(dc)));
1215 tcg_gen_addi_i64(env_btarget, env_btarget, dc->pc);
1216 tcg_gen_andi_i64(env_btarget, env_btarget, UINT32_MAX);
1218 eval_cc(dc, cc, env_btaken, cpu_R[dc->ra]);
1221 static void dec_br(DisasContext *dc)
1223 unsigned int dslot, link, abs, mbar;
1225 dslot = dc->ir & (1 << 20);
1226 abs = dc->ir & (1 << 19);
1227 link = dc->ir & (1 << 18);
1229 /* Memory barrier. */
1230 mbar = (dc->ir >> 16) & 31;
1231 if (mbar == 2 && dc->imm == 4) {
1232 /* mbar IMM & 16 decodes to sleep. */
1233 if (dc->rd & 16) {
1234 TCGv_i32 tmp_hlt = tcg_const_i32(EXCP_HLT);
1235 TCGv_i32 tmp_1 = tcg_const_i32(1);
1237 LOG_DIS("sleep\n");
1239 t_sync_flags(dc);
1240 tcg_gen_st_i32(tmp_1, cpu_env,
1241 -offsetof(MicroBlazeCPU, env)
1242 +offsetof(CPUState, halted));
1243 tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc + 4);
1244 gen_helper_raise_exception(cpu_env, tmp_hlt);
1245 tcg_temp_free_i32(tmp_hlt);
1246 tcg_temp_free_i32(tmp_1);
1247 return;
1249 LOG_DIS("mbar %d\n", dc->rd);
1250 /* Break the TB. */
1251 dc->cpustate_changed = 1;
1252 return;
1255 LOG_DIS("br%s%s%s%s imm=%x\n",
1256 abs ? "a" : "", link ? "l" : "",
1257 dc->type_b ? "i" : "", dslot ? "d" : "",
1258 dc->imm);
1260 dc->delayed_branch = 1;
1261 if (dslot) {
1262 dec_setup_dslot(dc);
1264 if (link && dc->rd)
1265 tcg_gen_movi_i32(cpu_R[dc->rd], dc->pc);
1267 dc->jmp = JMP_INDIRECT;
1268 if (abs) {
1269 tcg_gen_movi_i32(env_btaken, 1);
1270 tcg_gen_extu_i32_i64(env_btarget, *(dec_alu_op_b(dc)));
1271 if (link && !dslot) {
1272 if (!(dc->tb_flags & IMM_FLAG) && (dc->imm == 8 || dc->imm == 0x18))
1273 t_gen_raise_exception(dc, EXCP_BREAK);
1274 if (dc->imm == 0) {
1275 if (trap_userspace(dc, true)) {
1276 return;
1279 t_gen_raise_exception(dc, EXCP_DEBUG);
1282 } else {
1283 if (dec_alu_op_b_is_small_imm(dc)) {
1284 dc->jmp = JMP_DIRECT;
1285 dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm);
1286 } else {
1287 tcg_gen_movi_i32(env_btaken, 1);
1288 tcg_gen_extu_i32_i64(env_btarget, *(dec_alu_op_b(dc)));
1289 tcg_gen_addi_i64(env_btarget, env_btarget, dc->pc);
1290 tcg_gen_andi_i64(env_btarget, env_btarget, UINT32_MAX);
1295 static inline void do_rti(DisasContext *dc)
1297 TCGv_i32 t0, t1;
1298 t0 = tcg_temp_new_i32();
1299 t1 = tcg_temp_new_i32();
1300 tcg_gen_extrl_i64_i32(t1, cpu_SR[SR_MSR]);
1301 tcg_gen_shri_i32(t0, t1, 1);
1302 tcg_gen_ori_i32(t1, t1, MSR_IE);
1303 tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1305 tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1306 tcg_gen_or_i32(t1, t1, t0);
1307 msr_write(dc, t1);
1308 tcg_temp_free_i32(t1);
1309 tcg_temp_free_i32(t0);
1310 dc->tb_flags &= ~DRTI_FLAG;
1313 static inline void do_rtb(DisasContext *dc)
1315 TCGv_i32 t0, t1;
1316 t0 = tcg_temp_new_i32();
1317 t1 = tcg_temp_new_i32();
1318 tcg_gen_extrl_i64_i32(t1, cpu_SR[SR_MSR]);
1319 tcg_gen_andi_i32(t1, t1, ~MSR_BIP);
1320 tcg_gen_shri_i32(t0, t1, 1);
1321 tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1323 tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1324 tcg_gen_or_i32(t1, t1, t0);
1325 msr_write(dc, t1);
1326 tcg_temp_free_i32(t1);
1327 tcg_temp_free_i32(t0);
1328 dc->tb_flags &= ~DRTB_FLAG;
1331 static inline void do_rte(DisasContext *dc)
1333 TCGv_i32 t0, t1;
1334 t0 = tcg_temp_new_i32();
1335 t1 = tcg_temp_new_i32();
1337 tcg_gen_extrl_i64_i32(t1, cpu_SR[SR_MSR]);
1338 tcg_gen_ori_i32(t1, t1, MSR_EE);
1339 tcg_gen_andi_i32(t1, t1, ~MSR_EIP);
1340 tcg_gen_shri_i32(t0, t1, 1);
1341 tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1343 tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1344 tcg_gen_or_i32(t1, t1, t0);
1345 msr_write(dc, t1);
1346 tcg_temp_free_i32(t1);
1347 tcg_temp_free_i32(t0);
1348 dc->tb_flags &= ~DRTE_FLAG;
1351 static void dec_rts(DisasContext *dc)
1353 unsigned int b_bit, i_bit, e_bit;
1354 TCGv_i64 tmp64;
1356 i_bit = dc->ir & (1 << 21);
1357 b_bit = dc->ir & (1 << 22);
1358 e_bit = dc->ir & (1 << 23);
1360 if (trap_userspace(dc, i_bit || b_bit || e_bit)) {
1361 return;
1364 dec_setup_dslot(dc);
1366 if (i_bit) {
1367 LOG_DIS("rtid ir=%x\n", dc->ir);
1368 dc->tb_flags |= DRTI_FLAG;
1369 } else if (b_bit) {
1370 LOG_DIS("rtbd ir=%x\n", dc->ir);
1371 dc->tb_flags |= DRTB_FLAG;
1372 } else if (e_bit) {
1373 LOG_DIS("rted ir=%x\n", dc->ir);
1374 dc->tb_flags |= DRTE_FLAG;
1375 } else
1376 LOG_DIS("rts ir=%x\n", dc->ir);
1378 dc->jmp = JMP_INDIRECT;
1379 tcg_gen_movi_i32(env_btaken, 1);
1381 tmp64 = tcg_temp_new_i64();
1382 tcg_gen_extu_i32_i64(env_btarget, *(dec_alu_op_b(dc)));
1383 tcg_gen_extu_i32_i64(tmp64, cpu_R[dc->ra]);
1384 tcg_gen_add_i64(env_btarget, env_btarget, tmp64);
1385 tcg_gen_andi_i64(env_btarget, env_btarget, UINT32_MAX);
1386 tcg_temp_free_i64(tmp64);
1389 static int dec_check_fpuv2(DisasContext *dc)
1391 if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) {
1392 tcg_gen_movi_i64(cpu_SR[SR_ESR], ESR_EC_FPU);
1393 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1395 return (dc->cpu->cfg.use_fpu == 2) ? PVR2_USE_FPU2_MASK : 0;
1398 static void dec_fpu(DisasContext *dc)
1400 unsigned int fpu_insn;
1402 if (trap_illegal(dc, !dc->cpu->cfg.use_fpu)) {
1403 return;
1406 fpu_insn = (dc->ir >> 7) & 7;
1408 switch (fpu_insn) {
1409 case 0:
1410 gen_helper_fadd(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1411 cpu_R[dc->rb]);
1412 break;
1414 case 1:
1415 gen_helper_frsub(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1416 cpu_R[dc->rb]);
1417 break;
1419 case 2:
1420 gen_helper_fmul(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1421 cpu_R[dc->rb]);
1422 break;
1424 case 3:
1425 gen_helper_fdiv(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1426 cpu_R[dc->rb]);
1427 break;
1429 case 4:
1430 switch ((dc->ir >> 4) & 7) {
1431 case 0:
1432 gen_helper_fcmp_un(cpu_R[dc->rd], cpu_env,
1433 cpu_R[dc->ra], cpu_R[dc->rb]);
1434 break;
1435 case 1:
1436 gen_helper_fcmp_lt(cpu_R[dc->rd], cpu_env,
1437 cpu_R[dc->ra], cpu_R[dc->rb]);
1438 break;
1439 case 2:
1440 gen_helper_fcmp_eq(cpu_R[dc->rd], cpu_env,
1441 cpu_R[dc->ra], cpu_R[dc->rb]);
1442 break;
1443 case 3:
1444 gen_helper_fcmp_le(cpu_R[dc->rd], cpu_env,
1445 cpu_R[dc->ra], cpu_R[dc->rb]);
1446 break;
1447 case 4:
1448 gen_helper_fcmp_gt(cpu_R[dc->rd], cpu_env,
1449 cpu_R[dc->ra], cpu_R[dc->rb]);
1450 break;
1451 case 5:
1452 gen_helper_fcmp_ne(cpu_R[dc->rd], cpu_env,
1453 cpu_R[dc->ra], cpu_R[dc->rb]);
1454 break;
1455 case 6:
1456 gen_helper_fcmp_ge(cpu_R[dc->rd], cpu_env,
1457 cpu_R[dc->ra], cpu_R[dc->rb]);
1458 break;
1459 default:
1460 qemu_log_mask(LOG_UNIMP,
1461 "unimplemented fcmp fpu_insn=%x pc=%x"
1462 " opc=%x\n",
1463 fpu_insn, dc->pc, dc->opcode);
1464 dc->abort_at_next_insn = 1;
1465 break;
1467 break;
1469 case 5:
1470 if (!dec_check_fpuv2(dc)) {
1471 return;
1473 gen_helper_flt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
1474 break;
1476 case 6:
1477 if (!dec_check_fpuv2(dc)) {
1478 return;
1480 gen_helper_fint(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
1481 break;
1483 case 7:
1484 if (!dec_check_fpuv2(dc)) {
1485 return;
1487 gen_helper_fsqrt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
1488 break;
1490 default:
1491 qemu_log_mask(LOG_UNIMP, "unimplemented FPU insn fpu_insn=%x pc=%x"
1492 " opc=%x\n",
1493 fpu_insn, dc->pc, dc->opcode);
1494 dc->abort_at_next_insn = 1;
1495 break;
1499 static void dec_null(DisasContext *dc)
1501 if (trap_illegal(dc, true)) {
1502 return;
1504 qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", dc->pc, dc->opcode);
1505 dc->abort_at_next_insn = 1;
1508 /* Insns connected to FSL or AXI stream attached devices. */
1509 static void dec_stream(DisasContext *dc)
1511 TCGv_i32 t_id, t_ctrl;
1512 int ctrl;
1514 LOG_DIS("%s%s imm=%x\n", dc->rd ? "get" : "put",
1515 dc->type_b ? "" : "d", dc->imm);
1517 if (trap_userspace(dc, true)) {
1518 return;
1521 t_id = tcg_temp_new_i32();
1522 if (dc->type_b) {
1523 tcg_gen_movi_i32(t_id, dc->imm & 0xf);
1524 ctrl = dc->imm >> 10;
1525 } else {
1526 tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf);
1527 ctrl = dc->imm >> 5;
1530 t_ctrl = tcg_const_i32(ctrl);
1532 if (dc->rd == 0) {
1533 gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
1534 } else {
1535 gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
1537 tcg_temp_free_i32(t_id);
1538 tcg_temp_free_i32(t_ctrl);
1541 static struct decoder_info {
1542 struct {
1543 uint32_t bits;
1544 uint32_t mask;
1546 void (*dec)(DisasContext *dc);
1547 } decinfo[] = {
1548 {DEC_ADD, dec_add},
1549 {DEC_SUB, dec_sub},
1550 {DEC_AND, dec_and},
1551 {DEC_XOR, dec_xor},
1552 {DEC_OR, dec_or},
1553 {DEC_BIT, dec_bit},
1554 {DEC_BARREL, dec_barrel},
1555 {DEC_LD, dec_load},
1556 {DEC_ST, dec_store},
1557 {DEC_IMM, dec_imm},
1558 {DEC_BR, dec_br},
1559 {DEC_BCC, dec_bcc},
1560 {DEC_RTS, dec_rts},
1561 {DEC_FPU, dec_fpu},
1562 {DEC_MUL, dec_mul},
1563 {DEC_DIV, dec_div},
1564 {DEC_MSR, dec_msr},
1565 {DEC_STREAM, dec_stream},
1566 {{0, 0}, dec_null}
1569 static inline void decode(DisasContext *dc, uint32_t ir)
1571 int i;
1573 dc->ir = ir;
1574 LOG_DIS("%8.8x\t", dc->ir);
1576 if (ir == 0) {
1577 trap_illegal(dc, dc->cpu->cfg.opcode_0_illegal);
1578 /* Don't decode nop/zero instructions any further. */
1579 return;
1582 /* bit 2 seems to indicate insn type. */
1583 dc->type_b = ir & (1 << 29);
1585 dc->opcode = EXTRACT_FIELD(ir, 26, 31);
1586 dc->rd = EXTRACT_FIELD(ir, 21, 25);
1587 dc->ra = EXTRACT_FIELD(ir, 16, 20);
1588 dc->rb = EXTRACT_FIELD(ir, 11, 15);
1589 dc->imm = EXTRACT_FIELD(ir, 0, 15);
1591 /* Large switch for all insns. */
1592 for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
1593 if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
1594 decinfo[i].dec(dc);
1595 break;
1600 /* generate intermediate code for basic block 'tb'. */
1601 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
1603 CPUMBState *env = cs->env_ptr;
1604 MicroBlazeCPU *cpu = env_archcpu(env);
1605 uint32_t pc_start;
1606 struct DisasContext ctx;
1607 struct DisasContext *dc = &ctx;
1608 uint32_t page_start, org_flags;
1609 uint32_t npc;
1610 int num_insns;
1612 pc_start = tb->pc;
1613 dc->cpu = cpu;
1614 dc->tb = tb;
1615 org_flags = dc->synced_flags = dc->tb_flags = tb->flags;
1617 dc->is_jmp = DISAS_NEXT;
1618 dc->jmp = 0;
1619 dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
1620 if (dc->delayed_branch) {
1621 dc->jmp = JMP_INDIRECT;
1623 dc->pc = pc_start;
1624 dc->singlestep_enabled = cs->singlestep_enabled;
1625 dc->cpustate_changed = 0;
1626 dc->abort_at_next_insn = 0;
1628 if (pc_start & 3) {
1629 cpu_abort(cs, "Microblaze: unaligned PC=%x\n", pc_start);
1632 page_start = pc_start & TARGET_PAGE_MASK;
1633 num_insns = 0;
1635 gen_tb_start(tb);
1638 tcg_gen_insn_start(dc->pc);
1639 num_insns++;
1641 #if SIM_COMPAT
1642 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
1643 tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc);
1644 gen_helper_debug();
1646 #endif
1648 if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
1649 t_gen_raise_exception(dc, EXCP_DEBUG);
1650 dc->is_jmp = DISAS_UPDATE;
1651 /* The address covered by the breakpoint must be included in
1652 [tb->pc, tb->pc + tb->size) in order to for it to be
1653 properly cleared -- thus we increment the PC here so that
1654 the logic setting tb->size below does the right thing. */
1655 dc->pc += 4;
1656 break;
1659 /* Pretty disas. */
1660 LOG_DIS("%8.8x:\t", dc->pc);
1662 if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) {
1663 gen_io_start();
1666 dc->clear_imm = 1;
1667 decode(dc, cpu_ldl_code(env, dc->pc));
1668 if (dc->clear_imm)
1669 dc->tb_flags &= ~IMM_FLAG;
1670 dc->pc += 4;
1672 if (dc->delayed_branch) {
1673 dc->delayed_branch--;
1674 if (!dc->delayed_branch) {
1675 if (dc->tb_flags & DRTI_FLAG)
1676 do_rti(dc);
1677 if (dc->tb_flags & DRTB_FLAG)
1678 do_rtb(dc);
1679 if (dc->tb_flags & DRTE_FLAG)
1680 do_rte(dc);
1681 /* Clear the delay slot flag. */
1682 dc->tb_flags &= ~D_FLAG;
1683 /* If it is a direct jump, try direct chaining. */
1684 if (dc->jmp == JMP_INDIRECT) {
1685 TCGv_i64 tmp_pc = tcg_const_i64(dc->pc);
1686 eval_cond_jmp(dc, env_btarget, tmp_pc);
1687 tcg_temp_free_i64(tmp_pc);
1689 dc->is_jmp = DISAS_JUMP;
1690 } else if (dc->jmp == JMP_DIRECT) {
1691 t_sync_flags(dc);
1692 gen_goto_tb(dc, 0, dc->jmp_pc);
1693 dc->is_jmp = DISAS_TB_JUMP;
1694 } else if (dc->jmp == JMP_DIRECT_CC) {
1695 TCGLabel *l1 = gen_new_label();
1696 t_sync_flags(dc);
1697 /* Conditional jmp. */
1698 tcg_gen_brcondi_i32(TCG_COND_NE, env_btaken, 0, l1);
1699 gen_goto_tb(dc, 1, dc->pc);
1700 gen_set_label(l1);
1701 gen_goto_tb(dc, 0, dc->jmp_pc);
1703 dc->is_jmp = DISAS_TB_JUMP;
1705 break;
1708 if (cs->singlestep_enabled) {
1709 break;
1711 } while (!dc->is_jmp && !dc->cpustate_changed
1712 && !tcg_op_buf_full()
1713 && !singlestep
1714 && (dc->pc - page_start < TARGET_PAGE_SIZE)
1715 && num_insns < max_insns);
1717 npc = dc->pc;
1718 if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
1719 if (dc->tb_flags & D_FLAG) {
1720 dc->is_jmp = DISAS_UPDATE;
1721 tcg_gen_movi_i64(cpu_SR[SR_PC], npc);
1722 sync_jmpstate(dc);
1723 } else
1724 npc = dc->jmp_pc;
1727 /* Force an update if the per-tb cpu state has changed. */
1728 if (dc->is_jmp == DISAS_NEXT
1729 && (dc->cpustate_changed || org_flags != dc->tb_flags)) {
1730 dc->is_jmp = DISAS_UPDATE;
1731 tcg_gen_movi_i64(cpu_SR[SR_PC], npc);
1733 t_sync_flags(dc);
1735 if (unlikely(cs->singlestep_enabled)) {
1736 TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
1738 if (dc->is_jmp != DISAS_JUMP) {
1739 tcg_gen_movi_i64(cpu_SR[SR_PC], npc);
1741 gen_helper_raise_exception(cpu_env, tmp);
1742 tcg_temp_free_i32(tmp);
1743 } else {
1744 switch(dc->is_jmp) {
1745 case DISAS_NEXT:
1746 gen_goto_tb(dc, 1, npc);
1747 break;
1748 default:
1749 case DISAS_JUMP:
1750 case DISAS_UPDATE:
1751 /* indicate that the hash table must be used
1752 to find the next TB */
1753 tcg_gen_exit_tb(NULL, 0);
1754 break;
1755 case DISAS_TB_JUMP:
1756 /* nothing more to generate */
1757 break;
1760 gen_tb_end(tb, num_insns);
1762 tb->size = dc->pc - pc_start;
1763 tb->icount = num_insns;
1765 #ifdef DEBUG_DISAS
1766 #if !SIM_COMPAT
1767 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
1768 && qemu_log_in_addr_range(pc_start)) {
1769 FILE *logfile = qemu_log_lock();
1770 qemu_log("--------------\n");
1771 log_target_disas(cs, pc_start, dc->pc - pc_start);
1772 qemu_log_unlock(logfile);
1774 #endif
1775 #endif
1776 assert(!dc->abort_at_next_insn);
1779 void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1781 MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1782 CPUMBState *env = &cpu->env;
1783 int i;
1785 if (!env) {
1786 return;
1789 qemu_fprintf(f, "IN: PC=%" PRIx64 " %s\n",
1790 env->sregs[SR_PC], lookup_symbol(env->sregs[SR_PC]));
1791 qemu_fprintf(f, "rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " "
1792 "debug=%x imm=%x iflags=%x fsr=%" PRIx64 " "
1793 "rbtr=%" PRIx64 "\n",
1794 env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
1795 env->debug, env->imm, env->iflags, env->sregs[SR_FSR],
1796 env->sregs[SR_BTR]);
1797 qemu_fprintf(f, "btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) "
1798 "eip=%d ie=%d\n",
1799 env->btaken, env->btarget,
1800 (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
1801 (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
1802 (bool)(env->sregs[SR_MSR] & MSR_EIP),
1803 (bool)(env->sregs[SR_MSR] & MSR_IE));
1804 for (i = 0; i < 12; i++) {
1805 qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]);
1806 if ((i + 1) % 4 == 0) {
1807 qemu_fprintf(f, "\n");
1811 /* Registers that aren't modeled are reported as 0 */
1812 qemu_fprintf(f, "redr=%" PRIx64 " rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 "
1813 "rtlblo=0 rtlbhi=0\n", env->sregs[SR_EDR]);
1814 qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr);
1815 for (i = 0; i < 32; i++) {
1816 qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
1817 if ((i + 1) % 4 == 0)
1818 qemu_fprintf(f, "\n");
1820 qemu_fprintf(f, "\n\n");
1823 void mb_tcg_init(void)
1825 int i;
1827 env_debug = tcg_global_mem_new_i32(cpu_env,
1828 offsetof(CPUMBState, debug),
1829 "debug0");
1830 env_iflags = tcg_global_mem_new_i32(cpu_env,
1831 offsetof(CPUMBState, iflags),
1832 "iflags");
1833 env_imm = tcg_global_mem_new_i32(cpu_env,
1834 offsetof(CPUMBState, imm),
1835 "imm");
1836 env_btarget = tcg_global_mem_new_i64(cpu_env,
1837 offsetof(CPUMBState, btarget),
1838 "btarget");
1839 env_btaken = tcg_global_mem_new_i32(cpu_env,
1840 offsetof(CPUMBState, btaken),
1841 "btaken");
1842 env_res_addr = tcg_global_mem_new(cpu_env,
1843 offsetof(CPUMBState, res_addr),
1844 "res_addr");
1845 env_res_val = tcg_global_mem_new_i32(cpu_env,
1846 offsetof(CPUMBState, res_val),
1847 "res_val");
1848 for (i = 0; i < ARRAY_SIZE(cpu_R); i++) {
1849 cpu_R[i] = tcg_global_mem_new_i32(cpu_env,
1850 offsetof(CPUMBState, regs[i]),
1851 regnames[i]);
1853 for (i = 0; i < ARRAY_SIZE(cpu_SR); i++) {
1854 cpu_SR[i] = tcg_global_mem_new_i64(cpu_env,
1855 offsetof(CPUMBState, sregs[i]),
1856 special_regnames[i]);
1860 void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1861 target_ulong *data)
1863 env->sregs[SR_PC] = data[0];