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"
23 #include "disas/disas.h"
24 #include "exec/exec-all.h"
26 #include "exec/helper-proto.h"
27 #include "microblaze-decode.h"
28 #include "exec/cpu_ldst.h"
29 #include "exec/helper-gen.h"
31 #include "trace-tcg.h"
38 #if DISAS_MB && !SIM_COMPAT
39 # define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
41 # define LOG_DIS(...) do { } while (0)
46 #define EXTRACT_FIELD(src, start, end) \
47 (((src) >> start) & ((1 << (end - start + 1)) - 1))
49 static TCGv env_debug
;
50 static TCGv_env cpu_env
;
51 static TCGv cpu_R
[32];
52 static TCGv cpu_SR
[18];
54 static TCGv env_btaken
;
55 static TCGv env_btarget
;
56 static TCGv env_iflags
;
57 static TCGv env_res_addr
;
58 static TCGv env_res_val
;
60 #include "exec/gen-icount.h"
62 /* This is the state at translation time. */
63 typedef struct DisasContext
{
74 unsigned int cpustate_changed
;
75 unsigned int delayed_branch
;
76 unsigned int tb_flags
, synced_flags
; /* tb dependent flags. */
77 unsigned int clear_imm
;
82 #define JMP_DIRECT_CC 2
83 #define JMP_INDIRECT 3
87 int abort_at_next_insn
;
89 struct TranslationBlock
*tb
;
90 int singlestep_enabled
;
93 static const char *regnames
[] =
95 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
96 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
97 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
98 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
101 static const char *special_regnames
[] =
103 "rpc", "rmsr", "sr2", "sr3", "sr4", "sr5", "sr6", "sr7",
104 "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
105 "sr16", "sr17", "sr18"
108 static inline void t_sync_flags(DisasContext
*dc
)
110 /* Synch the tb dependent flags between translator and runtime. */
111 if (dc
->tb_flags
!= dc
->synced_flags
) {
112 tcg_gen_movi_tl(env_iflags
, dc
->tb_flags
);
113 dc
->synced_flags
= dc
->tb_flags
;
117 static inline void t_gen_raise_exception(DisasContext
*dc
, uint32_t index
)
119 TCGv_i32 tmp
= tcg_const_i32(index
);
122 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dc
->pc
);
123 gen_helper_raise_exception(cpu_env
, tmp
);
124 tcg_temp_free_i32(tmp
);
125 dc
->is_jmp
= DISAS_UPDATE
;
128 static inline bool use_goto_tb(DisasContext
*dc
, target_ulong dest
)
130 #ifndef CONFIG_USER_ONLY
131 return (dc
->tb
->pc
& TARGET_PAGE_MASK
) == (dest
& TARGET_PAGE_MASK
);
137 static void gen_goto_tb(DisasContext
*dc
, int n
, target_ulong dest
)
139 if (use_goto_tb(dc
, dest
)) {
141 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dest
);
142 tcg_gen_exit_tb((uintptr_t)dc
->tb
+ n
);
144 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dest
);
149 static void read_carry(DisasContext
*dc
, TCGv d
)
151 tcg_gen_shri_tl(d
, cpu_SR
[SR_MSR
], 31);
155 * write_carry sets the carry bits in MSR based on bit 0 of v.
156 * v[31:1] are ignored.
158 static void write_carry(DisasContext
*dc
, TCGv v
)
160 TCGv t0
= tcg_temp_new();
161 tcg_gen_shli_tl(t0
, v
, 31);
162 tcg_gen_sari_tl(t0
, t0
, 31);
163 tcg_gen_andi_tl(t0
, t0
, (MSR_C
| MSR_CC
));
164 tcg_gen_andi_tl(cpu_SR
[SR_MSR
], cpu_SR
[SR_MSR
],
166 tcg_gen_or_tl(cpu_SR
[SR_MSR
], cpu_SR
[SR_MSR
], t0
);
170 static void write_carryi(DisasContext
*dc
, bool carry
)
172 TCGv t0
= tcg_temp_new();
173 tcg_gen_movi_tl(t0
, carry
);
178 /* True if ALU operand b is a small immediate that may deserve
180 static inline int dec_alu_op_b_is_small_imm(DisasContext
*dc
)
182 /* Immediate insn without the imm prefix ? */
183 return dc
->type_b
&& !(dc
->tb_flags
& IMM_FLAG
);
186 static inline TCGv
*dec_alu_op_b(DisasContext
*dc
)
189 if (dc
->tb_flags
& IMM_FLAG
)
190 tcg_gen_ori_tl(env_imm
, env_imm
, dc
->imm
);
192 tcg_gen_movi_tl(env_imm
, (int32_t)((int16_t)dc
->imm
));
195 return &cpu_R
[dc
->rb
];
198 static void dec_add(DisasContext
*dc
)
206 LOG_DIS("add%s%s%s r%d r%d r%d\n",
207 dc
->type_b
? "i" : "", k
? "k" : "", c
? "c" : "",
208 dc
->rd
, dc
->ra
, dc
->rb
);
210 /* Take care of the easy cases first. */
212 /* k - keep carry, no need to update MSR. */
213 /* If rd == r0, it's a nop. */
215 tcg_gen_add_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
218 /* c - Add carry into the result. */
222 tcg_gen_add_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->rd
], cf
);
229 /* From now on, we can assume k is zero. So we need to update MSR. */
235 tcg_gen_movi_tl(cf
, 0);
239 TCGv ncf
= tcg_temp_new();
240 gen_helper_carry(ncf
, cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)), cf
);
241 tcg_gen_add_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
242 tcg_gen_add_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->rd
], cf
);
243 write_carry(dc
, ncf
);
246 gen_helper_carry(cf
, cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)), cf
);
252 static void dec_sub(DisasContext
*dc
)
254 unsigned int u
, cmp
, k
, c
;
260 cmp
= (dc
->imm
& 1) && (!dc
->type_b
) && k
;
263 LOG_DIS("cmp%s r%d, r%d ir=%x\n", u
? "u" : "", dc
->rd
, dc
->ra
, dc
->ir
);
266 gen_helper_cmpu(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
268 gen_helper_cmp(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
273 LOG_DIS("sub%s%s r%d, r%d r%d\n",
274 k
? "k" : "", c
? "c" : "", dc
->rd
, dc
->ra
, dc
->rb
);
276 /* Take care of the easy cases first. */
278 /* k - keep carry, no need to update MSR. */
279 /* If rd == r0, it's a nop. */
281 tcg_gen_sub_tl(cpu_R
[dc
->rd
], *(dec_alu_op_b(dc
)), cpu_R
[dc
->ra
]);
284 /* c - Add carry into the result. */
288 tcg_gen_add_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->rd
], cf
);
295 /* From now on, we can assume k is zero. So we need to update MSR. */
296 /* Extract carry. And complement a into na. */
302 tcg_gen_movi_tl(cf
, 1);
305 /* d = b + ~a + c. carry defaults to 1. */
306 tcg_gen_not_tl(na
, cpu_R
[dc
->ra
]);
309 TCGv ncf
= tcg_temp_new();
310 gen_helper_carry(ncf
, na
, *(dec_alu_op_b(dc
)), cf
);
311 tcg_gen_add_tl(cpu_R
[dc
->rd
], na
, *(dec_alu_op_b(dc
)));
312 tcg_gen_add_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->rd
], cf
);
313 write_carry(dc
, ncf
);
316 gen_helper_carry(cf
, na
, *(dec_alu_op_b(dc
)), cf
);
323 static void dec_pattern(DisasContext
*dc
)
327 if ((dc
->tb_flags
& MSR_EE_FLAG
)
328 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)
329 && !dc
->cpu
->cfg
.use_pcmp_instr
) {
330 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
331 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
334 mode
= dc
->opcode
& 3;
338 LOG_DIS("pcmpbf r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
340 gen_helper_pcmpbf(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
343 LOG_DIS("pcmpeq r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
345 tcg_gen_setcond_tl(TCG_COND_EQ
, cpu_R
[dc
->rd
],
346 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
350 LOG_DIS("pcmpne r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
352 tcg_gen_setcond_tl(TCG_COND_NE
, cpu_R
[dc
->rd
],
353 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
357 cpu_abort(CPU(dc
->cpu
),
358 "unsupported pattern insn opcode=%x\n", dc
->opcode
);
363 static void dec_and(DisasContext
*dc
)
367 if (!dc
->type_b
&& (dc
->imm
& (1 << 10))) {
372 not = dc
->opcode
& (1 << 1);
373 LOG_DIS("and%s\n", not ? "n" : "");
379 tcg_gen_andc_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
381 tcg_gen_and_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
384 static void dec_or(DisasContext
*dc
)
386 if (!dc
->type_b
&& (dc
->imm
& (1 << 10))) {
391 LOG_DIS("or r%d r%d r%d imm=%x\n", dc
->rd
, dc
->ra
, dc
->rb
, dc
->imm
);
393 tcg_gen_or_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
396 static void dec_xor(DisasContext
*dc
)
398 if (!dc
->type_b
&& (dc
->imm
& (1 << 10))) {
403 LOG_DIS("xor r%d\n", dc
->rd
);
405 tcg_gen_xor_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
408 static inline void msr_read(DisasContext
*dc
, TCGv d
)
410 tcg_gen_mov_tl(d
, cpu_SR
[SR_MSR
]);
413 static inline void msr_write(DisasContext
*dc
, TCGv v
)
418 dc
->cpustate_changed
= 1;
419 /* PVR bit is not writable. */
420 tcg_gen_andi_tl(t
, v
, ~MSR_PVR
);
421 tcg_gen_andi_tl(cpu_SR
[SR_MSR
], cpu_SR
[SR_MSR
], MSR_PVR
);
422 tcg_gen_or_tl(cpu_SR
[SR_MSR
], cpu_SR
[SR_MSR
], v
);
426 static void dec_msr(DisasContext
*dc
)
428 CPUState
*cs
= CPU(dc
->cpu
);
430 unsigned int sr
, to
, rn
;
431 int mem_index
= cpu_mmu_index(&dc
->cpu
->env
, false);
433 sr
= dc
->imm
& ((1 << 14) - 1);
434 to
= dc
->imm
& (1 << 14);
437 dc
->cpustate_changed
= 1;
439 /* msrclr and msrset. */
440 if (!(dc
->imm
& (1 << 15))) {
441 unsigned int clr
= dc
->ir
& (1 << 16);
443 LOG_DIS("msr%s r%d imm=%x\n", clr
? "clr" : "set",
446 if (!dc
->cpu
->cfg
.use_msr_instr
) {
451 if ((dc
->tb_flags
& MSR_EE_FLAG
)
452 && mem_index
== MMU_USER_IDX
&& (dc
->imm
!= 4 && dc
->imm
!= 0)) {
453 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
454 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
459 msr_read(dc
, cpu_R
[dc
->rd
]);
464 tcg_gen_mov_tl(t1
, *(dec_alu_op_b(dc
)));
467 tcg_gen_not_tl(t1
, t1
);
468 tcg_gen_and_tl(t0
, t0
, t1
);
470 tcg_gen_or_tl(t0
, t0
, t1
);
474 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dc
->pc
+ 4);
475 dc
->is_jmp
= DISAS_UPDATE
;
480 if ((dc
->tb_flags
& MSR_EE_FLAG
)
481 && mem_index
== MMU_USER_IDX
) {
482 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
483 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
488 #if !defined(CONFIG_USER_ONLY)
489 /* Catch read/writes to the mmu block. */
490 if ((sr
& ~0xff) == 0x1000) {
492 LOG_DIS("m%ss sr%d r%d imm=%x\n", to
? "t" : "f", sr
, dc
->ra
, dc
->imm
);
494 gen_helper_mmu_write(cpu_env
, tcg_const_tl(sr
), cpu_R
[dc
->ra
]);
496 gen_helper_mmu_read(cpu_R
[dc
->rd
], cpu_env
, tcg_const_tl(sr
));
502 LOG_DIS("m%ss sr%x r%d imm=%x\n", to
? "t" : "f", sr
, dc
->ra
, dc
->imm
);
507 msr_write(dc
, cpu_R
[dc
->ra
]);
510 tcg_gen_mov_tl(cpu_SR
[SR_EAR
], cpu_R
[dc
->ra
]);
513 tcg_gen_mov_tl(cpu_SR
[SR_ESR
], cpu_R
[dc
->ra
]);
516 tcg_gen_andi_tl(cpu_SR
[SR_FSR
], cpu_R
[dc
->ra
], 31);
519 tcg_gen_st_tl(cpu_R
[dc
->ra
], cpu_env
, offsetof(CPUMBState
, slr
));
522 tcg_gen_st_tl(cpu_R
[dc
->ra
], cpu_env
, offsetof(CPUMBState
, shr
));
525 cpu_abort(CPU(dc
->cpu
), "unknown mts reg %x\n", sr
);
529 LOG_DIS("m%ss r%d sr%x imm=%x\n", to
? "t" : "f", dc
->rd
, sr
, dc
->imm
);
533 tcg_gen_movi_tl(cpu_R
[dc
->rd
], dc
->pc
);
536 msr_read(dc
, cpu_R
[dc
->rd
]);
539 tcg_gen_mov_tl(cpu_R
[dc
->rd
], cpu_SR
[SR_EAR
]);
542 tcg_gen_mov_tl(cpu_R
[dc
->rd
], cpu_SR
[SR_ESR
]);
545 tcg_gen_mov_tl(cpu_R
[dc
->rd
], cpu_SR
[SR_FSR
]);
548 tcg_gen_mov_tl(cpu_R
[dc
->rd
], cpu_SR
[SR_BTR
]);
551 tcg_gen_ld_tl(cpu_R
[dc
->rd
], cpu_env
, offsetof(CPUMBState
, slr
));
554 tcg_gen_ld_tl(cpu_R
[dc
->rd
], cpu_env
, offsetof(CPUMBState
, shr
));
570 tcg_gen_ld_tl(cpu_R
[dc
->rd
],
571 cpu_env
, offsetof(CPUMBState
, pvr
.regs
[rn
]));
574 cpu_abort(cs
, "unknown mfs reg %x\n", sr
);
580 tcg_gen_movi_tl(cpu_R
[0], 0);
584 /* Multiplier unit. */
585 static void dec_mul(DisasContext
*dc
)
588 unsigned int subcode
;
590 if ((dc
->tb_flags
& MSR_EE_FLAG
)
591 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)
592 && !dc
->cpu
->cfg
.use_hw_mul
) {
593 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
594 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
598 subcode
= dc
->imm
& 3;
601 LOG_DIS("muli r%d r%d %x\n", dc
->rd
, dc
->ra
, dc
->imm
);
602 tcg_gen_mul_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
606 /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2. */
607 if (subcode
>= 1 && subcode
<= 3 && dc
->cpu
->cfg
.use_hw_mul
< 2) {
611 tmp
= tcg_temp_new();
614 LOG_DIS("mul r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
615 tcg_gen_mul_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
618 LOG_DIS("mulh r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
619 tcg_gen_muls2_tl(tmp
, cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
622 LOG_DIS("mulhsu r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
623 tcg_gen_mulsu2_tl(tmp
, cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
626 LOG_DIS("mulhu r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
627 tcg_gen_mulu2_tl(tmp
, cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
630 cpu_abort(CPU(dc
->cpu
), "unknown MUL insn %x\n", subcode
);
637 static void dec_div(DisasContext
*dc
)
644 if ((dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)
645 && !dc
->cpu
->cfg
.use_div
) {
646 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
647 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
651 gen_helper_divu(cpu_R
[dc
->rd
], cpu_env
, *(dec_alu_op_b(dc
)),
654 gen_helper_divs(cpu_R
[dc
->rd
], cpu_env
, *(dec_alu_op_b(dc
)),
657 tcg_gen_movi_tl(cpu_R
[dc
->rd
], 0);
660 static void dec_barrel(DisasContext
*dc
)
663 unsigned int imm_w
, imm_s
;
664 bool s
, t
, e
= false, i
= false;
666 if ((dc
->tb_flags
& MSR_EE_FLAG
)
667 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)
668 && !dc
->cpu
->cfg
.use_barrel
) {
669 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
670 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
675 /* Insert and extract are only available in immediate mode. */
676 i
= extract32(dc
->imm
, 15, 1);
677 e
= extract32(dc
->imm
, 14, 1);
679 s
= extract32(dc
->imm
, 10, 1);
680 t
= extract32(dc
->imm
, 9, 1);
681 imm_w
= extract32(dc
->imm
, 6, 5);
682 imm_s
= extract32(dc
->imm
, 0, 5);
684 LOG_DIS("bs%s%s%s r%d r%d r%d\n",
686 s
? "l" : "r", t
? "a" : "l", dc
->rd
, dc
->ra
, dc
->rb
);
689 if (imm_w
+ imm_s
> 32 || imm_w
== 0) {
690 /* These inputs have an undefined behavior. */
691 qemu_log_mask(LOG_GUEST_ERROR
, "bsefi: Bad input w=%d s=%d\n",
694 tcg_gen_extract_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], imm_s
, imm_w
);
697 int width
= imm_w
- imm_s
+ 1;
700 /* These inputs have an undefined behavior. */
701 qemu_log_mask(LOG_GUEST_ERROR
, "bsifi: Bad input w=%d s=%d\n",
704 tcg_gen_deposit_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->rd
], cpu_R
[dc
->ra
],
710 tcg_gen_mov_tl(t0
, *(dec_alu_op_b(dc
)));
711 tcg_gen_andi_tl(t0
, t0
, 31);
714 tcg_gen_shl_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], t0
);
717 tcg_gen_sar_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], t0
);
719 tcg_gen_shr_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], t0
);
726 static void dec_bit(DisasContext
*dc
)
728 CPUState
*cs
= CPU(dc
->cpu
);
731 int mem_index
= cpu_mmu_index(&dc
->cpu
->env
, false);
733 op
= dc
->ir
& ((1 << 9) - 1);
739 LOG_DIS("src r%d r%d\n", dc
->rd
, dc
->ra
);
740 tcg_gen_andi_tl(t0
, cpu_SR
[SR_MSR
], MSR_CC
);
741 write_carry(dc
, cpu_R
[dc
->ra
]);
743 tcg_gen_shri_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], 1);
744 tcg_gen_or_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->rd
], t0
);
752 LOG_DIS("srl r%d r%d\n", dc
->rd
, dc
->ra
);
754 /* Update carry. Note that write carry only looks at the LSB. */
755 write_carry(dc
, cpu_R
[dc
->ra
]);
758 tcg_gen_shri_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], 1);
760 tcg_gen_sari_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], 1);
764 LOG_DIS("ext8s r%d r%d\n", dc
->rd
, dc
->ra
);
765 tcg_gen_ext8s_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
]);
768 LOG_DIS("ext16s r%d r%d\n", dc
->rd
, dc
->ra
);
769 tcg_gen_ext16s_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
]);
776 LOG_DIS("wdc r%d\n", dc
->ra
);
777 if ((dc
->tb_flags
& MSR_EE_FLAG
)
778 && mem_index
== MMU_USER_IDX
) {
779 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
780 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
786 LOG_DIS("wic r%d\n", dc
->ra
);
787 if ((dc
->tb_flags
& MSR_EE_FLAG
)
788 && mem_index
== MMU_USER_IDX
) {
789 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
790 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
795 if ((dc
->tb_flags
& MSR_EE_FLAG
)
796 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)
797 && !dc
->cpu
->cfg
.use_pcmp_instr
) {
798 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
799 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
801 if (dc
->cpu
->cfg
.use_pcmp_instr
) {
802 tcg_gen_clzi_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], 32);
807 LOG_DIS("swapb r%d r%d\n", dc
->rd
, dc
->ra
);
808 tcg_gen_bswap32_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
]);
812 LOG_DIS("swaph r%d r%d\n", dc
->rd
, dc
->ra
);
813 tcg_gen_rotri_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], 16);
816 cpu_abort(cs
, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n",
817 dc
->pc
, op
, dc
->rd
, dc
->ra
, dc
->rb
);
822 static inline void sync_jmpstate(DisasContext
*dc
)
824 if (dc
->jmp
== JMP_DIRECT
|| dc
->jmp
== JMP_DIRECT_CC
) {
825 if (dc
->jmp
== JMP_DIRECT
) {
826 tcg_gen_movi_tl(env_btaken
, 1);
828 dc
->jmp
= JMP_INDIRECT
;
829 tcg_gen_movi_tl(env_btarget
, dc
->jmp_pc
);
833 static void dec_imm(DisasContext
*dc
)
835 LOG_DIS("imm %x\n", dc
->imm
<< 16);
836 tcg_gen_movi_tl(env_imm
, (dc
->imm
<< 16));
837 dc
->tb_flags
|= IMM_FLAG
;
841 static inline TCGv
*compute_ldst_addr(DisasContext
*dc
, TCGv
*t
)
843 unsigned int extimm
= dc
->tb_flags
& IMM_FLAG
;
844 /* Should be set to one if r1 is used by loadstores. */
847 /* All load/stores use ra. */
848 if (dc
->ra
== 1 && dc
->cpu
->cfg
.stackprot
) {
852 /* Treat the common cases first. */
854 /* If any of the regs is r0, return a ptr to the other. */
856 return &cpu_R
[dc
->rb
];
857 } else if (dc
->rb
== 0) {
858 return &cpu_R
[dc
->ra
];
861 if (dc
->rb
== 1 && dc
->cpu
->cfg
.stackprot
) {
866 tcg_gen_add_tl(*t
, cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
869 gen_helper_stackprot(cpu_env
, *t
);
876 return &cpu_R
[dc
->ra
];
879 tcg_gen_movi_tl(*t
, (int32_t)((int16_t)dc
->imm
));
880 tcg_gen_add_tl(*t
, cpu_R
[dc
->ra
], *t
);
883 tcg_gen_add_tl(*t
, cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
887 gen_helper_stackprot(cpu_env
, *t
);
892 static void dec_load(DisasContext
*dc
)
895 unsigned int size
, rev
= 0, ex
= 0;
898 mop
= dc
->opcode
& 3;
901 rev
= (dc
->ir
>> 9) & 1;
902 ex
= (dc
->ir
>> 10) & 1;
909 if (size
> 4 && (dc
->tb_flags
& MSR_EE_FLAG
)
910 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)) {
911 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
912 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
916 LOG_DIS("l%d%s%s%s\n", size
, dc
->type_b
? "i" : "", rev
? "r" : "",
920 addr
= compute_ldst_addr(dc
, &t
);
923 * When doing reverse accesses we need to do two things.
925 * 1. Reverse the address wrt endianness.
926 * 2. Byteswap the data lanes on the way back into the CPU core.
928 if (rev
&& size
!= 4) {
929 /* Endian reverse the address. t is addr. */
937 TCGv low
= tcg_temp_new();
939 /* Force addr into the temp. */
942 tcg_gen_mov_tl(t
, *addr
);
946 tcg_gen_andi_tl(low
, t
, 3);
947 tcg_gen_sub_tl(low
, tcg_const_tl(3), low
);
948 tcg_gen_andi_tl(t
, t
, ~3);
949 tcg_gen_or_tl(t
, t
, low
);
950 tcg_gen_mov_tl(env_imm
, t
);
958 /* Force addr into the temp. */
961 tcg_gen_xori_tl(t
, *addr
, 2);
964 tcg_gen_xori_tl(t
, t
, 2);
968 cpu_abort(CPU(dc
->cpu
), "Invalid reverse size\n");
973 /* lwx does not throw unaligned access errors, so force alignment */
975 /* Force addr into the temp. */
978 tcg_gen_mov_tl(t
, *addr
);
981 tcg_gen_andi_tl(t
, t
, ~3);
984 /* If we get a fault on a dslot, the jmpstate better be in sync. */
987 /* Verify alignment if needed. */
989 * Microblaze gives MMU faults priority over faults due to
990 * unaligned addresses. That's why we speculatively do the load
991 * into v. If the load succeeds, we verify alignment of the
992 * address and if that succeeds we write into the destination reg.
995 tcg_gen_qemu_ld_tl(v
, *addr
, cpu_mmu_index(&dc
->cpu
->env
, false), mop
);
997 if ((dc
->cpu
->env
.pvr
.regs
[2] & PVR2_UNALIGNED_EXC_MASK
) && size
> 1) {
998 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dc
->pc
);
999 gen_helper_memalign(cpu_env
, *addr
, tcg_const_tl(dc
->rd
),
1000 tcg_const_tl(0), tcg_const_tl(size
- 1));
1004 tcg_gen_mov_tl(env_res_addr
, *addr
);
1005 tcg_gen_mov_tl(env_res_val
, v
);
1008 tcg_gen_mov_tl(cpu_R
[dc
->rd
], v
);
1013 /* no support for AXI exclusive so always clear C */
1014 write_carryi(dc
, 0);
1021 static void dec_store(DisasContext
*dc
)
1023 TCGv t
, *addr
, swx_addr
;
1024 TCGLabel
*swx_skip
= NULL
;
1025 unsigned int size
, rev
= 0, ex
= 0;
1028 mop
= dc
->opcode
& 3;
1031 rev
= (dc
->ir
>> 9) & 1;
1032 ex
= (dc
->ir
>> 10) & 1;
1039 if (size
> 4 && (dc
->tb_flags
& MSR_EE_FLAG
)
1040 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)) {
1041 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
1042 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1046 LOG_DIS("s%d%s%s%s\n", size
, dc
->type_b
? "i" : "", rev
? "r" : "",
1049 /* If we get a fault on a dslot, the jmpstate better be in sync. */
1051 addr
= compute_ldst_addr(dc
, &t
);
1053 swx_addr
= tcg_temp_local_new();
1057 /* Force addr into the swx_addr. */
1058 tcg_gen_mov_tl(swx_addr
, *addr
);
1060 /* swx does not throw unaligned access errors, so force alignment */
1061 tcg_gen_andi_tl(swx_addr
, swx_addr
, ~3);
1063 write_carryi(dc
, 1);
1064 swx_skip
= gen_new_label();
1065 tcg_gen_brcond_tl(TCG_COND_NE
, env_res_addr
, swx_addr
, swx_skip
);
1067 /* Compare the value loaded at lwx with current contents of
1068 the reserved location.
1069 FIXME: This only works for system emulation where we can expect
1070 this compare and the following write to be atomic. For user
1071 emulation we need to add atomicity between threads. */
1072 tval
= tcg_temp_new();
1073 tcg_gen_qemu_ld_tl(tval
, swx_addr
, cpu_mmu_index(&dc
->cpu
->env
, false),
1075 tcg_gen_brcond_tl(TCG_COND_NE
, env_res_val
, tval
, swx_skip
);
1076 write_carryi(dc
, 0);
1077 tcg_temp_free(tval
);
1080 if (rev
&& size
!= 4) {
1081 /* Endian reverse the address. t is addr. */
1089 TCGv low
= tcg_temp_new();
1091 /* Force addr into the temp. */
1094 tcg_gen_mov_tl(t
, *addr
);
1098 tcg_gen_andi_tl(low
, t
, 3);
1099 tcg_gen_sub_tl(low
, tcg_const_tl(3), low
);
1100 tcg_gen_andi_tl(t
, t
, ~3);
1101 tcg_gen_or_tl(t
, t
, low
);
1102 tcg_gen_mov_tl(env_imm
, t
);
1110 /* Force addr into the temp. */
1113 tcg_gen_xori_tl(t
, *addr
, 2);
1116 tcg_gen_xori_tl(t
, t
, 2);
1120 cpu_abort(CPU(dc
->cpu
), "Invalid reverse size\n");
1124 tcg_gen_qemu_st_tl(cpu_R
[dc
->rd
], *addr
, cpu_mmu_index(&dc
->cpu
->env
, false), mop
);
1126 /* Verify alignment if needed. */
1127 if ((dc
->cpu
->env
.pvr
.regs
[2] & PVR2_UNALIGNED_EXC_MASK
) && size
> 1) {
1128 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dc
->pc
);
1129 /* FIXME: if the alignment is wrong, we should restore the value
1130 * in memory. One possible way to achieve this is to probe
1131 * the MMU prior to the memaccess, thay way we could put
1132 * the alignment checks in between the probe and the mem
1135 gen_helper_memalign(cpu_env
, *addr
, tcg_const_tl(dc
->rd
),
1136 tcg_const_tl(1), tcg_const_tl(size
- 1));
1140 gen_set_label(swx_skip
);
1142 tcg_temp_free(swx_addr
);
1148 static inline void eval_cc(DisasContext
*dc
, unsigned int cc
,
1149 TCGv d
, TCGv a
, TCGv b
)
1153 tcg_gen_setcond_tl(TCG_COND_EQ
, d
, a
, b
);
1156 tcg_gen_setcond_tl(TCG_COND_NE
, d
, a
, b
);
1159 tcg_gen_setcond_tl(TCG_COND_LT
, d
, a
, b
);
1162 tcg_gen_setcond_tl(TCG_COND_LE
, d
, a
, b
);
1165 tcg_gen_setcond_tl(TCG_COND_GE
, d
, a
, b
);
1168 tcg_gen_setcond_tl(TCG_COND_GT
, d
, a
, b
);
1171 cpu_abort(CPU(dc
->cpu
), "Unknown condition code %x.\n", cc
);
1176 static void eval_cond_jmp(DisasContext
*dc
, TCGv pc_true
, TCGv pc_false
)
1178 TCGLabel
*l1
= gen_new_label();
1179 /* Conditional jmp. */
1180 tcg_gen_mov_tl(cpu_SR
[SR_PC
], pc_false
);
1181 tcg_gen_brcondi_tl(TCG_COND_EQ
, env_btaken
, 0, l1
);
1182 tcg_gen_mov_tl(cpu_SR
[SR_PC
], pc_true
);
1186 static void dec_bcc(DisasContext
*dc
)
1191 cc
= EXTRACT_FIELD(dc
->ir
, 21, 23);
1192 dslot
= dc
->ir
& (1 << 25);
1193 LOG_DIS("bcc%s r%d %x\n", dslot
? "d" : "", dc
->ra
, dc
->imm
);
1195 dc
->delayed_branch
= 1;
1197 dc
->delayed_branch
= 2;
1198 dc
->tb_flags
|= D_FLAG
;
1199 tcg_gen_st_tl(tcg_const_tl(dc
->type_b
&& (dc
->tb_flags
& IMM_FLAG
)),
1200 cpu_env
, offsetof(CPUMBState
, bimm
));
1203 if (dec_alu_op_b_is_small_imm(dc
)) {
1204 int32_t offset
= (int32_t)((int16_t)dc
->imm
); /* sign-extend. */
1206 tcg_gen_movi_tl(env_btarget
, dc
->pc
+ offset
);
1207 dc
->jmp
= JMP_DIRECT_CC
;
1208 dc
->jmp_pc
= dc
->pc
+ offset
;
1210 dc
->jmp
= JMP_INDIRECT
;
1211 tcg_gen_movi_tl(env_btarget
, dc
->pc
);
1212 tcg_gen_add_tl(env_btarget
, env_btarget
, *(dec_alu_op_b(dc
)));
1214 eval_cc(dc
, cc
, env_btaken
, cpu_R
[dc
->ra
], tcg_const_tl(0));
1217 static void dec_br(DisasContext
*dc
)
1219 unsigned int dslot
, link
, abs
, mbar
;
1220 int mem_index
= cpu_mmu_index(&dc
->cpu
->env
, false);
1222 dslot
= dc
->ir
& (1 << 20);
1223 abs
= dc
->ir
& (1 << 19);
1224 link
= dc
->ir
& (1 << 18);
1226 /* Memory barrier. */
1227 mbar
= (dc
->ir
>> 16) & 31;
1228 if (mbar
== 2 && dc
->imm
== 4) {
1229 /* mbar IMM & 16 decodes to sleep. */
1231 TCGv_i32 tmp_hlt
= tcg_const_i32(EXCP_HLT
);
1232 TCGv_i32 tmp_1
= tcg_const_i32(1);
1237 tcg_gen_st_i32(tmp_1
, cpu_env
,
1238 -offsetof(MicroBlazeCPU
, env
)
1239 +offsetof(CPUState
, halted
));
1240 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dc
->pc
+ 4);
1241 gen_helper_raise_exception(cpu_env
, tmp_hlt
);
1242 tcg_temp_free_i32(tmp_hlt
);
1243 tcg_temp_free_i32(tmp_1
);
1246 LOG_DIS("mbar %d\n", dc
->rd
);
1248 dc
->cpustate_changed
= 1;
1252 LOG_DIS("br%s%s%s%s imm=%x\n",
1253 abs
? "a" : "", link
? "l" : "",
1254 dc
->type_b
? "i" : "", dslot
? "d" : "",
1257 dc
->delayed_branch
= 1;
1259 dc
->delayed_branch
= 2;
1260 dc
->tb_flags
|= D_FLAG
;
1261 tcg_gen_st_tl(tcg_const_tl(dc
->type_b
&& (dc
->tb_flags
& IMM_FLAG
)),
1262 cpu_env
, offsetof(CPUMBState
, bimm
));
1265 tcg_gen_movi_tl(cpu_R
[dc
->rd
], dc
->pc
);
1267 dc
->jmp
= JMP_INDIRECT
;
1269 tcg_gen_movi_tl(env_btaken
, 1);
1270 tcg_gen_mov_tl(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
);
1275 if ((dc
->tb_flags
& MSR_EE_FLAG
) && mem_index
== MMU_USER_IDX
) {
1276 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
1277 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1281 t_gen_raise_exception(dc
, EXCP_DEBUG
);
1285 if (dec_alu_op_b_is_small_imm(dc
)) {
1286 dc
->jmp
= JMP_DIRECT
;
1287 dc
->jmp_pc
= dc
->pc
+ (int32_t)((int16_t)dc
->imm
);
1289 tcg_gen_movi_tl(env_btaken
, 1);
1290 tcg_gen_movi_tl(env_btarget
, dc
->pc
);
1291 tcg_gen_add_tl(env_btarget
, env_btarget
, *(dec_alu_op_b(dc
)));
1296 static inline void do_rti(DisasContext
*dc
)
1299 t0
= tcg_temp_new();
1300 t1
= tcg_temp_new();
1301 tcg_gen_shri_tl(t0
, cpu_SR
[SR_MSR
], 1);
1302 tcg_gen_ori_tl(t1
, cpu_SR
[SR_MSR
], MSR_IE
);
1303 tcg_gen_andi_tl(t0
, t0
, (MSR_VM
| MSR_UM
));
1305 tcg_gen_andi_tl(t1
, t1
, ~(MSR_VM
| MSR_UM
));
1306 tcg_gen_or_tl(t1
, t1
, t0
);
1310 dc
->tb_flags
&= ~DRTI_FLAG
;
1313 static inline void do_rtb(DisasContext
*dc
)
1316 t0
= tcg_temp_new();
1317 t1
= tcg_temp_new();
1318 tcg_gen_andi_tl(t1
, cpu_SR
[SR_MSR
], ~MSR_BIP
);
1319 tcg_gen_shri_tl(t0
, t1
, 1);
1320 tcg_gen_andi_tl(t0
, t0
, (MSR_VM
| MSR_UM
));
1322 tcg_gen_andi_tl(t1
, t1
, ~(MSR_VM
| MSR_UM
));
1323 tcg_gen_or_tl(t1
, t1
, t0
);
1327 dc
->tb_flags
&= ~DRTB_FLAG
;
1330 static inline void do_rte(DisasContext
*dc
)
1333 t0
= tcg_temp_new();
1334 t1
= tcg_temp_new();
1336 tcg_gen_ori_tl(t1
, cpu_SR
[SR_MSR
], MSR_EE
);
1337 tcg_gen_andi_tl(t1
, t1
, ~MSR_EIP
);
1338 tcg_gen_shri_tl(t0
, t1
, 1);
1339 tcg_gen_andi_tl(t0
, t0
, (MSR_VM
| MSR_UM
));
1341 tcg_gen_andi_tl(t1
, t1
, ~(MSR_VM
| MSR_UM
));
1342 tcg_gen_or_tl(t1
, t1
, t0
);
1346 dc
->tb_flags
&= ~DRTE_FLAG
;
1349 static void dec_rts(DisasContext
*dc
)
1351 unsigned int b_bit
, i_bit
, e_bit
;
1352 int mem_index
= cpu_mmu_index(&dc
->cpu
->env
, false);
1354 i_bit
= dc
->ir
& (1 << 21);
1355 b_bit
= dc
->ir
& (1 << 22);
1356 e_bit
= dc
->ir
& (1 << 23);
1358 dc
->delayed_branch
= 2;
1359 dc
->tb_flags
|= D_FLAG
;
1360 tcg_gen_st_tl(tcg_const_tl(dc
->type_b
&& (dc
->tb_flags
& IMM_FLAG
)),
1361 cpu_env
, offsetof(CPUMBState
, bimm
));
1364 LOG_DIS("rtid ir=%x\n", dc
->ir
);
1365 if ((dc
->tb_flags
& MSR_EE_FLAG
)
1366 && mem_index
== MMU_USER_IDX
) {
1367 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
1368 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1370 dc
->tb_flags
|= DRTI_FLAG
;
1372 LOG_DIS("rtbd ir=%x\n", dc
->ir
);
1373 if ((dc
->tb_flags
& MSR_EE_FLAG
)
1374 && mem_index
== MMU_USER_IDX
) {
1375 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
1376 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1378 dc
->tb_flags
|= DRTB_FLAG
;
1380 LOG_DIS("rted ir=%x\n", dc
->ir
);
1381 if ((dc
->tb_flags
& MSR_EE_FLAG
)
1382 && mem_index
== MMU_USER_IDX
) {
1383 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
1384 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1386 dc
->tb_flags
|= DRTE_FLAG
;
1388 LOG_DIS("rts ir=%x\n", dc
->ir
);
1390 dc
->jmp
= JMP_INDIRECT
;
1391 tcg_gen_movi_tl(env_btaken
, 1);
1392 tcg_gen_add_tl(env_btarget
, cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
1395 static int dec_check_fpuv2(DisasContext
*dc
)
1397 if ((dc
->cpu
->cfg
.use_fpu
!= 2) && (dc
->tb_flags
& MSR_EE_FLAG
)) {
1398 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_FPU
);
1399 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1401 return (dc
->cpu
->cfg
.use_fpu
== 2) ? 0 : PVR2_USE_FPU2_MASK
;
1404 static void dec_fpu(DisasContext
*dc
)
1406 unsigned int fpu_insn
;
1408 if ((dc
->tb_flags
& MSR_EE_FLAG
)
1409 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)
1410 && (dc
->cpu
->cfg
.use_fpu
!= 1)) {
1411 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
1412 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1416 fpu_insn
= (dc
->ir
>> 7) & 7;
1420 gen_helper_fadd(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
],
1425 gen_helper_frsub(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
],
1430 gen_helper_fmul(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
],
1435 gen_helper_fdiv(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
],
1440 switch ((dc
->ir
>> 4) & 7) {
1442 gen_helper_fcmp_un(cpu_R
[dc
->rd
], cpu_env
,
1443 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1446 gen_helper_fcmp_lt(cpu_R
[dc
->rd
], cpu_env
,
1447 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1450 gen_helper_fcmp_eq(cpu_R
[dc
->rd
], cpu_env
,
1451 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1454 gen_helper_fcmp_le(cpu_R
[dc
->rd
], cpu_env
,
1455 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1458 gen_helper_fcmp_gt(cpu_R
[dc
->rd
], cpu_env
,
1459 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1462 gen_helper_fcmp_ne(cpu_R
[dc
->rd
], cpu_env
,
1463 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1466 gen_helper_fcmp_ge(cpu_R
[dc
->rd
], cpu_env
,
1467 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1470 qemu_log_mask(LOG_UNIMP
,
1471 "unimplemented fcmp fpu_insn=%x pc=%x"
1473 fpu_insn
, dc
->pc
, dc
->opcode
);
1474 dc
->abort_at_next_insn
= 1;
1480 if (!dec_check_fpuv2(dc
)) {
1483 gen_helper_flt(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
]);
1487 if (!dec_check_fpuv2(dc
)) {
1490 gen_helper_fint(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
]);
1494 if (!dec_check_fpuv2(dc
)) {
1497 gen_helper_fsqrt(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
]);
1501 qemu_log_mask(LOG_UNIMP
, "unimplemented FPU insn fpu_insn=%x pc=%x"
1503 fpu_insn
, dc
->pc
, dc
->opcode
);
1504 dc
->abort_at_next_insn
= 1;
1509 static void dec_null(DisasContext
*dc
)
1511 if ((dc
->tb_flags
& MSR_EE_FLAG
)
1512 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)) {
1513 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
1514 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1517 qemu_log_mask(LOG_GUEST_ERROR
, "unknown insn pc=%x opc=%x\n", dc
->pc
, dc
->opcode
);
1518 dc
->abort_at_next_insn
= 1;
1521 /* Insns connected to FSL or AXI stream attached devices. */
1522 static void dec_stream(DisasContext
*dc
)
1524 int mem_index
= cpu_mmu_index(&dc
->cpu
->env
, false);
1525 TCGv_i32 t_id
, t_ctrl
;
1528 LOG_DIS("%s%s imm=%x\n", dc
->rd
? "get" : "put",
1529 dc
->type_b
? "" : "d", dc
->imm
);
1531 if ((dc
->tb_flags
& MSR_EE_FLAG
) && (mem_index
== MMU_USER_IDX
)) {
1532 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
1533 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1537 t_id
= tcg_temp_new();
1539 tcg_gen_movi_tl(t_id
, dc
->imm
& 0xf);
1540 ctrl
= dc
->imm
>> 10;
1542 tcg_gen_andi_tl(t_id
, cpu_R
[dc
->rb
], 0xf);
1543 ctrl
= dc
->imm
>> 5;
1546 t_ctrl
= tcg_const_tl(ctrl
);
1549 gen_helper_put(t_id
, t_ctrl
, cpu_R
[dc
->ra
]);
1551 gen_helper_get(cpu_R
[dc
->rd
], t_id
, t_ctrl
);
1553 tcg_temp_free(t_id
);
1554 tcg_temp_free(t_ctrl
);
1557 static struct decoder_info
{
1562 void (*dec
)(DisasContext
*dc
);
1570 {DEC_BARREL
, dec_barrel
},
1572 {DEC_ST
, dec_store
},
1581 {DEC_STREAM
, dec_stream
},
1585 static inline void decode(DisasContext
*dc
, uint32_t ir
)
1590 LOG_DIS("%8.8x\t", dc
->ir
);
1595 if ((dc
->tb_flags
& MSR_EE_FLAG
)
1596 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)
1597 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_OPCODE_0x0_ILL_MASK
)) {
1598 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
1599 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1603 LOG_DIS("nr_nops=%d\t", dc
->nr_nops
);
1605 if (dc
->nr_nops
> 4) {
1606 cpu_abort(CPU(dc
->cpu
), "fetching nop sequence\n");
1609 /* bit 2 seems to indicate insn type. */
1610 dc
->type_b
= ir
& (1 << 29);
1612 dc
->opcode
= EXTRACT_FIELD(ir
, 26, 31);
1613 dc
->rd
= EXTRACT_FIELD(ir
, 21, 25);
1614 dc
->ra
= EXTRACT_FIELD(ir
, 16, 20);
1615 dc
->rb
= EXTRACT_FIELD(ir
, 11, 15);
1616 dc
->imm
= EXTRACT_FIELD(ir
, 0, 15);
1618 /* Large switch for all insns. */
1619 for (i
= 0; i
< ARRAY_SIZE(decinfo
); i
++) {
1620 if ((dc
->opcode
& decinfo
[i
].mask
) == decinfo
[i
].bits
) {
1627 /* generate intermediate code for basic block 'tb'. */
1628 void gen_intermediate_code(CPUMBState
*env
, struct TranslationBlock
*tb
)
1630 MicroBlazeCPU
*cpu
= mb_env_get_cpu(env
);
1631 CPUState
*cs
= CPU(cpu
);
1633 struct DisasContext ctx
;
1634 struct DisasContext
*dc
= &ctx
;
1635 uint32_t next_page_start
, org_flags
;
1643 org_flags
= dc
->synced_flags
= dc
->tb_flags
= tb
->flags
;
1645 dc
->is_jmp
= DISAS_NEXT
;
1647 dc
->delayed_branch
= !!(dc
->tb_flags
& D_FLAG
);
1648 if (dc
->delayed_branch
) {
1649 dc
->jmp
= JMP_INDIRECT
;
1652 dc
->singlestep_enabled
= cs
->singlestep_enabled
;
1653 dc
->cpustate_changed
= 0;
1654 dc
->abort_at_next_insn
= 0;
1658 cpu_abort(cs
, "Microblaze: unaligned PC=%x\n", pc_start
);
1661 next_page_start
= (pc_start
& TARGET_PAGE_MASK
) + TARGET_PAGE_SIZE
;
1663 max_insns
= tb
->cflags
& CF_COUNT_MASK
;
1664 if (max_insns
== 0) {
1665 max_insns
= CF_COUNT_MASK
;
1667 if (max_insns
> TCG_MAX_INSNS
) {
1668 max_insns
= TCG_MAX_INSNS
;
1674 tcg_gen_insn_start(dc
->pc
);
1678 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM
)) {
1679 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dc
->pc
);
1684 if (unlikely(cpu_breakpoint_test(cs
, dc
->pc
, BP_ANY
))) {
1685 t_gen_raise_exception(dc
, EXCP_DEBUG
);
1686 dc
->is_jmp
= DISAS_UPDATE
;
1687 /* The address covered by the breakpoint must be included in
1688 [tb->pc, tb->pc + tb->size) in order to for it to be
1689 properly cleared -- thus we increment the PC here so that
1690 the logic setting tb->size below does the right thing. */
1696 LOG_DIS("%8.8x:\t", dc
->pc
);
1698 if (num_insns
== max_insns
&& (tb
->cflags
& CF_LAST_IO
)) {
1703 decode(dc
, cpu_ldl_code(env
, dc
->pc
));
1705 dc
->tb_flags
&= ~IMM_FLAG
;
1708 if (dc
->delayed_branch
) {
1709 dc
->delayed_branch
--;
1710 if (!dc
->delayed_branch
) {
1711 if (dc
->tb_flags
& DRTI_FLAG
)
1713 if (dc
->tb_flags
& DRTB_FLAG
)
1715 if (dc
->tb_flags
& DRTE_FLAG
)
1717 /* Clear the delay slot flag. */
1718 dc
->tb_flags
&= ~D_FLAG
;
1719 /* If it is a direct jump, try direct chaining. */
1720 if (dc
->jmp
== JMP_INDIRECT
) {
1721 eval_cond_jmp(dc
, env_btarget
, tcg_const_tl(dc
->pc
));
1722 dc
->is_jmp
= DISAS_JUMP
;
1723 } else if (dc
->jmp
== JMP_DIRECT
) {
1725 gen_goto_tb(dc
, 0, dc
->jmp_pc
);
1726 dc
->is_jmp
= DISAS_TB_JUMP
;
1727 } else if (dc
->jmp
== JMP_DIRECT_CC
) {
1728 TCGLabel
*l1
= gen_new_label();
1730 /* Conditional jmp. */
1731 tcg_gen_brcondi_tl(TCG_COND_NE
, env_btaken
, 0, l1
);
1732 gen_goto_tb(dc
, 1, dc
->pc
);
1734 gen_goto_tb(dc
, 0, dc
->jmp_pc
);
1736 dc
->is_jmp
= DISAS_TB_JUMP
;
1741 if (cs
->singlestep_enabled
) {
1744 } while (!dc
->is_jmp
&& !dc
->cpustate_changed
1745 && !tcg_op_buf_full()
1747 && (dc
->pc
< next_page_start
)
1748 && num_insns
< max_insns
);
1751 if (dc
->jmp
== JMP_DIRECT
|| dc
->jmp
== JMP_DIRECT_CC
) {
1752 if (dc
->tb_flags
& D_FLAG
) {
1753 dc
->is_jmp
= DISAS_UPDATE
;
1754 tcg_gen_movi_tl(cpu_SR
[SR_PC
], npc
);
1760 if (tb
->cflags
& CF_LAST_IO
)
1762 /* Force an update if the per-tb cpu state has changed. */
1763 if (dc
->is_jmp
== DISAS_NEXT
1764 && (dc
->cpustate_changed
|| org_flags
!= dc
->tb_flags
)) {
1765 dc
->is_jmp
= DISAS_UPDATE
;
1766 tcg_gen_movi_tl(cpu_SR
[SR_PC
], npc
);
1770 if (unlikely(cs
->singlestep_enabled
)) {
1771 TCGv_i32 tmp
= tcg_const_i32(EXCP_DEBUG
);
1773 if (dc
->is_jmp
!= DISAS_JUMP
) {
1774 tcg_gen_movi_tl(cpu_SR
[SR_PC
], npc
);
1776 gen_helper_raise_exception(cpu_env
, tmp
);
1777 tcg_temp_free_i32(tmp
);
1779 switch(dc
->is_jmp
) {
1781 gen_goto_tb(dc
, 1, npc
);
1786 /* indicate that the hash table must be used
1787 to find the next TB */
1791 /* nothing more to generate */
1795 gen_tb_end(tb
, num_insns
);
1797 tb
->size
= dc
->pc
- pc_start
;
1798 tb
->icount
= num_insns
;
1802 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM
)
1803 && qemu_log_in_addr_range(pc_start
)) {
1805 qemu_log("--------------\n");
1807 log_target_disas(cs
, pc_start
, dc
->pc
- pc_start
, 0);
1809 qemu_log("\nisize=%d osize=%d\n",
1810 dc
->pc
- pc_start
, tcg_op_buf_count());
1815 assert(!dc
->abort_at_next_insn
);
1818 void mb_cpu_dump_state(CPUState
*cs
, FILE *f
, fprintf_function cpu_fprintf
,
1821 MicroBlazeCPU
*cpu
= MICROBLAZE_CPU(cs
);
1822 CPUMBState
*env
= &cpu
->env
;
1828 cpu_fprintf(f
, "IN: PC=%x %s\n",
1829 env
->sregs
[SR_PC
], lookup_symbol(env
->sregs
[SR_PC
]));
1830 cpu_fprintf(f
, "rmsr=%x resr=%x rear=%x debug=%x imm=%x iflags=%x fsr=%x\n",
1831 env
->sregs
[SR_MSR
], env
->sregs
[SR_ESR
], env
->sregs
[SR_EAR
],
1832 env
->debug
, env
->imm
, env
->iflags
, env
->sregs
[SR_FSR
]);
1833 cpu_fprintf(f
, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
1834 env
->btaken
, env
->btarget
,
1835 (env
->sregs
[SR_MSR
] & MSR_UM
) ? "user" : "kernel",
1836 (env
->sregs
[SR_MSR
] & MSR_UMS
) ? "user" : "kernel",
1837 (env
->sregs
[SR_MSR
] & MSR_EIP
),
1838 (env
->sregs
[SR_MSR
] & MSR_IE
));
1840 for (i
= 0; i
< 32; i
++) {
1841 cpu_fprintf(f
, "r%2.2d=%8.8x ", i
, env
->regs
[i
]);
1842 if ((i
+ 1) % 4 == 0)
1843 cpu_fprintf(f
, "\n");
1845 cpu_fprintf(f
, "\n\n");
1848 MicroBlazeCPU
*cpu_mb_init(const char *cpu_model
)
1852 cpu
= MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU
));
1854 object_property_set_bool(OBJECT(cpu
), true, "realized", NULL
);
1859 void mb_tcg_init(void)
1863 cpu_env
= tcg_global_reg_new_ptr(TCG_AREG0
, "env");
1864 tcg_ctx
.tcg_env
= cpu_env
;
1866 env_debug
= tcg_global_mem_new(cpu_env
,
1867 offsetof(CPUMBState
, debug
),
1869 env_iflags
= tcg_global_mem_new(cpu_env
,
1870 offsetof(CPUMBState
, iflags
),
1872 env_imm
= tcg_global_mem_new(cpu_env
,
1873 offsetof(CPUMBState
, imm
),
1875 env_btarget
= tcg_global_mem_new(cpu_env
,
1876 offsetof(CPUMBState
, btarget
),
1878 env_btaken
= tcg_global_mem_new(cpu_env
,
1879 offsetof(CPUMBState
, btaken
),
1881 env_res_addr
= tcg_global_mem_new(cpu_env
,
1882 offsetof(CPUMBState
, res_addr
),
1884 env_res_val
= tcg_global_mem_new(cpu_env
,
1885 offsetof(CPUMBState
, res_val
),
1887 for (i
= 0; i
< ARRAY_SIZE(cpu_R
); i
++) {
1888 cpu_R
[i
] = tcg_global_mem_new(cpu_env
,
1889 offsetof(CPUMBState
, regs
[i
]),
1892 for (i
= 0; i
< ARRAY_SIZE(cpu_SR
); i
++) {
1893 cpu_SR
[i
] = tcg_global_mem_new(cpu_env
,
1894 offsetof(CPUMBState
, sregs
[i
]),
1895 special_regnames
[i
]);
1899 void restore_state_to_opc(CPUMBState
*env
, TranslationBlock
*tb
,
1902 env
->sregs
[SR_PC
] = data
[0];