]>
git.proxmox.com Git - mirror_qemu.git/blob - target/microblaze/translate.c
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"
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"
40 #if DISAS_MB && !SIM_COMPAT
41 # define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
43 # define LOG_DIS(...) do { } while (0)
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
{
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
;
88 #define JMP_DIRECT_CC 2
89 #define JMP_INDIRECT 3
93 int abort_at_next_insn
;
94 struct TranslationBlock
*tb
;
95 int singlestep_enabled
;
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
);
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
);
141 static void gen_goto_tb(DisasContext
*dc
, int n
, target_ulong dest
)
143 if (use_goto_tb(dc
, dest
)) {
145 tcg_gen_movi_i64(cpu_SR
[SR_PC
], dest
);
146 tcg_gen_exit_tb(dc
->tb
, n
);
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
);
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
);
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
);
211 /* True if ALU operand b is a small immediate that may deserve
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
)
222 if (dc
->tb_flags
& IMM_FLAG
)
223 tcg_gen_ori_i32(env_imm
, env_imm
, dc
->imm
);
225 tcg_gen_movi_i32(env_imm
, (int32_t)((int16_t)dc
->imm
));
228 return &cpu_R
[dc
->rb
];
231 static void dec_add(DisasContext
*dc
)
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. */
245 /* k - keep carry, no need to update MSR. */
246 /* If rd == r0, it's a nop. */
248 tcg_gen_add_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
251 /* c - Add carry into the result. */
252 cf
= tcg_temp_new_i32();
255 tcg_gen_add_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->rd
], cf
);
256 tcg_temp_free_i32(cf
);
262 /* From now on, we can assume k is zero. So we need to update MSR. */
264 cf
= tcg_temp_new_i32();
268 tcg_gen_movi_i32(cf
, 0);
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
);
279 gen_helper_carry(cf
, cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)), cf
);
282 tcg_temp_free_i32(cf
);
285 static void dec_sub(DisasContext
*dc
)
287 unsigned int u
, cmp
, k
, c
;
293 cmp
= (dc
->imm
& 1) && (!dc
->type_b
) && k
;
296 LOG_DIS("cmp%s r%d, r%d ir=%x\n", u
? "u" : "", dc
->rd
, dc
->ra
, dc
->ir
);
299 gen_helper_cmpu(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
301 gen_helper_cmp(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
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. */
311 /* k - keep carry, no need to update MSR. */
312 /* If rd == r0, it's a nop. */
314 tcg_gen_sub_i32(cpu_R
[dc
->rd
], *(dec_alu_op_b(dc
)), cpu_R
[dc
->ra
]);
317 /* c - Add carry into the result. */
318 cf
= tcg_temp_new_i32();
321 tcg_gen_add_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->rd
], cf
);
322 tcg_temp_free_i32(cf
);
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();
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
]);
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
);
349 gen_helper_carry(cf
, na
, *(dec_alu_op_b(dc
)), cf
);
352 tcg_temp_free_i32(cf
);
353 tcg_temp_free_i32(na
);
356 static void dec_pattern(DisasContext
*dc
)
360 if (trap_illegal(dc
, !dc
->cpu
->cfg
.use_pcmp_instr
)) {
364 mode
= dc
->opcode
& 3;
368 LOG_DIS("pcmpbf r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
370 gen_helper_pcmpbf(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
373 LOG_DIS("pcmpeq r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
375 tcg_gen_setcond_i32(TCG_COND_EQ
, cpu_R
[dc
->rd
],
376 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
380 LOG_DIS("pcmpne r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
382 tcg_gen_setcond_i32(TCG_COND_NE
, cpu_R
[dc
->rd
],
383 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
387 cpu_abort(CPU(dc
->cpu
),
388 "unsupported pattern insn opcode=%x\n", dc
->opcode
);
393 static void dec_and(DisasContext
*dc
)
397 if (!dc
->type_b
&& (dc
->imm
& (1 << 10))) {
402 not = dc
->opcode
& (1 << 1);
403 LOG_DIS("and%s\n", not ? "n" : "");
409 tcg_gen_andc_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
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))) {
421 LOG_DIS("or r%d r%d r%d imm=%x\n", dc
->rd
, dc
->ra
, dc
->rb
, dc
->imm
);
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))) {
433 LOG_DIS("xor r%d\n", 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
)
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
);
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;
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. */
482 bool clr
= extract32(dc
->ir
, 16, 1);
484 LOG_DIS("msr%s r%d imm=%x\n", clr
? "clr" : "set",
487 if (!dc
->cpu
->cfg
.use_msr_instr
) {
492 if (trap_userspace(dc
, dc
->imm
!= 4 && dc
->imm
!= 0)) {
497 msr_read(dc
, cpu_R
[dc
->rd
]);
499 t0
= tcg_temp_new_i32();
500 t1
= tcg_temp_new_i32();
502 tcg_gen_mov_i32(t1
, *(dec_alu_op_b(dc
)));
505 tcg_gen_not_i32(t1
, t1
);
506 tcg_gen_and_i32(t0
, t0
, t1
);
508 tcg_gen_or_i32(t0
, t0
, t1
);
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
;
517 if (trap_userspace(dc
, to
)) {
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
);
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
);
531 gen_helper_mmu_write(cpu_env
, tmp_ext
, tmp_sr
, cpu_R
[dc
->ra
]);
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
);
542 LOG_DIS("m%ss sr%x r%d imm=%x\n", to
? "t" : "f", sr
, dc
->ra
, dc
->imm
);
547 msr_write(dc
, cpu_R
[dc
->ra
]);
552 tcg_gen_extu_i32_i64(cpu_SR
[sr
], cpu_R
[dc
->ra
]);
555 tcg_gen_st_i32(cpu_R
[dc
->ra
],
556 cpu_env
, offsetof(CPUMBState
, slr
));
559 tcg_gen_st_i32(cpu_R
[dc
->ra
],
560 cpu_env
, offsetof(CPUMBState
, shr
));
563 cpu_abort(CPU(dc
->cpu
), "unknown mts reg %x\n", sr
);
567 LOG_DIS("m%ss r%d sr%x imm=%x\n", to
? "t" : "f", dc
->rd
, sr
, dc
->imm
);
571 tcg_gen_movi_i32(cpu_R
[dc
->rd
], dc
->pc
);
574 msr_read(dc
, cpu_R
[dc
->rd
]);
578 tcg_gen_extrh_i64_i32(cpu_R
[dc
->rd
], cpu_SR
[sr
]);
585 tcg_gen_extrl_i64_i32(cpu_R
[dc
->rd
], cpu_SR
[sr
]);
588 tcg_gen_ld_i32(cpu_R
[dc
->rd
],
589 cpu_env
, offsetof(CPUMBState
, slr
));
592 tcg_gen_ld_i32(cpu_R
[dc
->rd
],
593 cpu_env
, offsetof(CPUMBState
, shr
));
595 case 0x2000 ... 0x200c:
597 tcg_gen_ld_i32(cpu_R
[dc
->rd
],
598 cpu_env
, offsetof(CPUMBState
, pvr
.regs
[rn
]));
601 cpu_abort(cs
, "unknown mfs reg %x\n", sr
);
607 tcg_gen_movi_i32(cpu_R
[0], 0);
611 /* Multiplier unit. */
612 static void dec_mul(DisasContext
*dc
)
615 unsigned int subcode
;
617 if (trap_illegal(dc
, !dc
->cpu
->cfg
.use_hw_mul
)) {
621 subcode
= dc
->imm
& 3;
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
)));
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) {
634 tmp
= tcg_temp_new_i32();
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
]);
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
]);
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
]);
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
]);
655 cpu_abort(CPU(dc
->cpu
), "unknown MUL insn %x\n", subcode
);
658 tcg_temp_free_i32(tmp
);
662 static void dec_div(DisasContext
*dc
)
669 if (trap_illegal(dc
, !dc
->cpu
->cfg
.use_div
)) {
674 gen_helper_divu(cpu_R
[dc
->rd
], cpu_env
, *(dec_alu_op_b(dc
)),
677 gen_helper_divs(cpu_R
[dc
->rd
], cpu_env
, *(dec_alu_op_b(dc
)),
680 tcg_gen_movi_i32(cpu_R
[dc
->rd
], 0);
683 static void dec_barrel(DisasContext
*dc
)
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
)) {
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",
705 s
? "l" : "r", t
? "a" : "l", dc
->rd
, dc
->ra
, dc
->rb
);
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",
713 tcg_gen_extract_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], imm_s
, imm_w
);
716 int width
= imm_w
- imm_s
+ 1;
719 /* These inputs have an undefined behavior. */
720 qemu_log_mask(LOG_GUEST_ERROR
, "bsifi: Bad input w=%d s=%d\n",
723 tcg_gen_deposit_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->rd
], cpu_R
[dc
->ra
],
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);
733 tcg_gen_shl_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], t0
);
736 tcg_gen_sar_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], t0
);
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
);
751 op
= dc
->ir
& ((1 << 9) - 1);
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
]);
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
);
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
]);
777 tcg_gen_shri_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], 1);
779 tcg_gen_sari_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], 1);
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
]);
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
]);
795 LOG_DIS("wdc r%d\n", dc
->ra
);
796 trap_userspace(dc
, true);
800 LOG_DIS("wic r%d\n", dc
->ra
);
801 trap_userspace(dc
, true);
804 if (trap_illegal(dc
, !dc
->cpu
->cfg
.use_pcmp_instr
)) {
807 if (dc
->cpu
->cfg
.use_pcmp_instr
) {
808 tcg_gen_clzi_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], 32);
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
]);
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);
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
);
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
;
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;
854 /* All load/stores use ra. */
855 if (dc
->ra
== 1 && dc
->cpu
->cfg
.stackprot
) {
859 /* Treat the common cases first. */
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
]);
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
));
877 /* If any of the regs is r0, set t to the value of the other reg. */
879 tcg_gen_extu_i32_tl(t
, cpu_R
[dc
->rb
]);
881 } else if (dc
->rb
== 0) {
882 tcg_gen_extu_i32_tl(t
, cpu_R
[dc
->ra
]);
886 if (dc
->rb
== 1 && dc
->cpu
->cfg
.stackprot
) {
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
);
896 gen_helper_stackprot(cpu_env
, t
);
901 t32
= tcg_temp_new_i32();
903 tcg_gen_addi_i32(t32
, cpu_R
[dc
->ra
], (int16_t)dc
->imm
);
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
);
911 gen_helper_stackprot(cpu_env
, t
);
916 static void dec_load(DisasContext
*dc
)
921 bool rev
= false, ex
= false, ea
= false;
922 int mem_index
= cpu_mmu_index(&dc
->cpu
->env
, false);
925 mop
= dc
->opcode
& 3;
928 ea
= extract32(dc
->ir
, 7, 1);
929 rev
= extract32(dc
->ir
, 9, 1);
930 ex
= extract32(dc
->ir
, 10, 1);
937 if (trap_illegal(dc
, size
> 4)) {
941 if (trap_userspace(dc
, ea
)) {
945 LOG_DIS("l%d%s%s%s%s\n", size
, dc
->type_b
? "i" : "", rev
? "r" : "",
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. */
966 tcg_gen_xori_tl(addr
, addr
, 3);
973 tcg_gen_xori_tl(addr
, addr
, 2);
976 cpu_abort(CPU(dc
->cpu
), "Invalid reverse size\n");
981 /* lwx does not throw unaligned access errors, so force alignment */
983 tcg_gen_andi_tl(addr
, addr
, ~3);
986 /* If we get a fault on a dslot, the jmpstate better be in sync. */
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
);
1013 tcg_gen_mov_tl(env_res_addr
, addr
);
1014 tcg_gen_mov_i32(env_res_val
, v
);
1017 tcg_gen_mov_i32(cpu_R
[dc
->rd
], v
);
1019 tcg_temp_free_i32(v
);
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
)
1032 TCGLabel
*swx_skip
= NULL
;
1034 bool rev
= false, ex
= false, ea
= false;
1035 int mem_index
= cpu_mmu_index(&dc
->cpu
->env
, false);
1038 mop
= dc
->opcode
& 3;
1041 ea
= extract32(dc
->ir
, 7, 1);
1042 rev
= extract32(dc
->ir
, 9, 1);
1043 ex
= extract32(dc
->ir
, 10, 1);
1050 if (trap_illegal(dc
, size
> 4)) {
1054 trap_userspace(dc
, ea
);
1056 LOG_DIS("s%d%s%s%s%s\n", size
, dc
->type_b
? "i" : "", rev
? "r" : "",
1060 /* If we get a fault on a dslot, the jmpstate better be in sync. */
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
;
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
);
1079 * Compare the value loaded at lwx with current contents of
1080 * the reserved location.
1082 tval
= tcg_temp_new_i32();
1084 tcg_gen_atomic_cmpxchg_i32(tval
, addr
, env_res_val
,
1085 cpu_R
[dc
->rd
], mem_index
,
1088 tcg_gen_brcond_i32(TCG_COND_NE
, env_res_val
, tval
, swx_skip
);
1089 write_carryi(dc
, 0);
1090 tcg_temp_free_i32(tval
);
1093 if (rev
&& size
!= 4) {
1094 /* Endian reverse the address. t is addr. */
1098 tcg_gen_xori_tl(addr
, addr
, 3);
1105 /* Force addr into the temp. */
1106 tcg_gen_xori_tl(addr
, addr
, 2);
1109 cpu_abort(CPU(dc
->cpu
), "Invalid reverse size\n");
1115 tcg_gen_qemu_st_i32(cpu_R
[dc
->rd
], addr
, mem_index
, mop
);
1118 /* Verify alignment if needed. */
1119 if (dc
->cpu
->cfg
.unaligned_exceptions
&& size
> 1) {
1120 TCGv_i32 t1
= tcg_const_i32(1);
1121 TCGv_i32 treg
= tcg_const_i32(dc
->rd
);
1122 TCGv_i32 tsize
= tcg_const_i32(size
- 1);
1124 tcg_gen_movi_i64(cpu_SR
[SR_PC
], dc
->pc
);
1125 /* FIXME: if the alignment is wrong, we should restore the value
1126 * in memory. One possible way to achieve this is to probe
1127 * the MMU prior to the memaccess, thay way we could put
1128 * the alignment checks in between the probe and the mem
1131 gen_helper_memalign(cpu_env
, addr
, treg
, t1
, tsize
);
1133 tcg_temp_free_i32(t1
);
1134 tcg_temp_free_i32(treg
);
1135 tcg_temp_free_i32(tsize
);
1139 gen_set_label(swx_skip
);
1142 tcg_temp_free(addr
);
1145 static inline void eval_cc(DisasContext
*dc
, unsigned int cc
,
1146 TCGv_i32 d
, TCGv_i32 a
)
1148 static const int mb_to_tcg_cc
[] = {
1149 [CC_EQ
] = TCG_COND_EQ
,
1150 [CC_NE
] = TCG_COND_NE
,
1151 [CC_LT
] = TCG_COND_LT
,
1152 [CC_LE
] = TCG_COND_LE
,
1153 [CC_GE
] = TCG_COND_GE
,
1154 [CC_GT
] = TCG_COND_GT
,
1164 tcg_gen_setcondi_i32(mb_to_tcg_cc
[cc
], d
, a
, 0);
1167 cpu_abort(CPU(dc
->cpu
), "Unknown condition code %x.\n", cc
);
1172 static void eval_cond_jmp(DisasContext
*dc
, TCGv_i64 pc_true
, TCGv_i64 pc_false
)
1174 TCGv_i64 tmp_btaken
= tcg_temp_new_i64();
1175 TCGv_i64 tmp_zero
= tcg_const_i64(0);
1177 tcg_gen_extu_i32_i64(tmp_btaken
, env_btaken
);
1178 tcg_gen_movcond_i64(TCG_COND_NE
, cpu_SR
[SR_PC
],
1179 tmp_btaken
, tmp_zero
,
1182 tcg_temp_free_i64(tmp_btaken
);
1183 tcg_temp_free_i64(tmp_zero
);
1186 static void dec_setup_dslot(DisasContext
*dc
)
1188 TCGv_i32 tmp
= tcg_const_i32(dc
->type_b
&& (dc
->tb_flags
& IMM_FLAG
));
1190 dc
->delayed_branch
= 2;
1191 dc
->tb_flags
|= D_FLAG
;
1193 tcg_gen_st_i32(tmp
, cpu_env
, offsetof(CPUMBState
, bimm
));
1194 tcg_temp_free_i32(tmp
);
1197 static void dec_bcc(DisasContext
*dc
)
1202 cc
= EXTRACT_FIELD(dc
->ir
, 21, 23);
1203 dslot
= dc
->ir
& (1 << 25);
1204 LOG_DIS("bcc%s r%d %x\n", dslot
? "d" : "", dc
->ra
, dc
->imm
);
1206 dc
->delayed_branch
= 1;
1208 dec_setup_dslot(dc
);
1211 if (dec_alu_op_b_is_small_imm(dc
)) {
1212 int32_t offset
= (int32_t)((int16_t)dc
->imm
); /* sign-extend. */
1214 tcg_gen_movi_i64(env_btarget
, dc
->pc
+ offset
);
1215 dc
->jmp
= JMP_DIRECT_CC
;
1216 dc
->jmp_pc
= dc
->pc
+ offset
;
1218 dc
->jmp
= JMP_INDIRECT
;
1219 tcg_gen_extu_i32_i64(env_btarget
, *(dec_alu_op_b(dc
)));
1220 tcg_gen_addi_i64(env_btarget
, env_btarget
, dc
->pc
);
1221 tcg_gen_andi_i64(env_btarget
, env_btarget
, UINT32_MAX
);
1223 eval_cc(dc
, cc
, env_btaken
, cpu_R
[dc
->ra
]);
1226 static void dec_br(DisasContext
*dc
)
1228 unsigned int dslot
, link
, abs
, mbar
;
1230 dslot
= dc
->ir
& (1 << 20);
1231 abs
= dc
->ir
& (1 << 19);
1232 link
= dc
->ir
& (1 << 18);
1234 /* Memory barrier. */
1235 mbar
= (dc
->ir
>> 16) & 31;
1236 if (mbar
== 2 && dc
->imm
== 4) {
1237 uint16_t mbar_imm
= dc
->rd
;
1239 LOG_DIS("mbar %d\n", mbar_imm
);
1241 /* Data access memory barrier. */
1242 if ((mbar_imm
& 2) == 0) {
1243 tcg_gen_mb(TCG_BAR_SC
| TCG_MO_ALL
);
1246 /* mbar IMM & 16 decodes to sleep. */
1247 if (mbar_imm
& 16) {
1248 TCGv_i32 tmp_hlt
= tcg_const_i32(EXCP_HLT
);
1249 TCGv_i32 tmp_1
= tcg_const_i32(1);
1253 if (trap_userspace(dc
, true)) {
1254 /* Sleep is a privileged instruction. */
1259 tcg_gen_st_i32(tmp_1
, cpu_env
,
1260 -offsetof(MicroBlazeCPU
, env
)
1261 +offsetof(CPUState
, halted
));
1262 tcg_gen_movi_i64(cpu_SR
[SR_PC
], dc
->pc
+ 4);
1263 gen_helper_raise_exception(cpu_env
, tmp_hlt
);
1264 tcg_temp_free_i32(tmp_hlt
);
1265 tcg_temp_free_i32(tmp_1
);
1269 dc
->cpustate_changed
= 1;
1273 LOG_DIS("br%s%s%s%s imm=%x\n",
1274 abs
? "a" : "", link
? "l" : "",
1275 dc
->type_b
? "i" : "", dslot
? "d" : "",
1278 dc
->delayed_branch
= 1;
1280 dec_setup_dslot(dc
);
1283 tcg_gen_movi_i32(cpu_R
[dc
->rd
], dc
->pc
);
1285 dc
->jmp
= JMP_INDIRECT
;
1287 tcg_gen_movi_i32(env_btaken
, 1);
1288 tcg_gen_extu_i32_i64(env_btarget
, *(dec_alu_op_b(dc
)));
1289 if (link
&& !dslot
) {
1290 if (!(dc
->tb_flags
& IMM_FLAG
) && (dc
->imm
== 8 || dc
->imm
== 0x18))
1291 t_gen_raise_exception(dc
, EXCP_BREAK
);
1293 if (trap_userspace(dc
, true)) {
1297 t_gen_raise_exception(dc
, EXCP_DEBUG
);
1301 if (dec_alu_op_b_is_small_imm(dc
)) {
1302 dc
->jmp
= JMP_DIRECT
;
1303 dc
->jmp_pc
= dc
->pc
+ (int32_t)((int16_t)dc
->imm
);
1305 tcg_gen_movi_i32(env_btaken
, 1);
1306 tcg_gen_extu_i32_i64(env_btarget
, *(dec_alu_op_b(dc
)));
1307 tcg_gen_addi_i64(env_btarget
, env_btarget
, dc
->pc
);
1308 tcg_gen_andi_i64(env_btarget
, env_btarget
, UINT32_MAX
);
1313 static inline void do_rti(DisasContext
*dc
)
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_shri_i32(t0
, t1
, 1);
1320 tcg_gen_ori_i32(t1
, t1
, MSR_IE
);
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
);
1326 tcg_temp_free_i32(t1
);
1327 tcg_temp_free_i32(t0
);
1328 dc
->tb_flags
&= ~DRTI_FLAG
;
1331 static inline void do_rtb(DisasContext
*dc
)
1334 t0
= tcg_temp_new_i32();
1335 t1
= tcg_temp_new_i32();
1336 tcg_gen_extrl_i64_i32(t1
, cpu_SR
[SR_MSR
]);
1337 tcg_gen_andi_i32(t1
, t1
, ~MSR_BIP
);
1338 tcg_gen_shri_i32(t0
, t1
, 1);
1339 tcg_gen_andi_i32(t0
, t0
, (MSR_VM
| MSR_UM
));
1341 tcg_gen_andi_i32(t1
, t1
, ~(MSR_VM
| MSR_UM
));
1342 tcg_gen_or_i32(t1
, t1
, t0
);
1344 tcg_temp_free_i32(t1
);
1345 tcg_temp_free_i32(t0
);
1346 dc
->tb_flags
&= ~DRTB_FLAG
;
1349 static inline void do_rte(DisasContext
*dc
)
1352 t0
= tcg_temp_new_i32();
1353 t1
= tcg_temp_new_i32();
1355 tcg_gen_extrl_i64_i32(t1
, cpu_SR
[SR_MSR
]);
1356 tcg_gen_ori_i32(t1
, t1
, MSR_EE
);
1357 tcg_gen_andi_i32(t1
, t1
, ~MSR_EIP
);
1358 tcg_gen_shri_i32(t0
, t1
, 1);
1359 tcg_gen_andi_i32(t0
, t0
, (MSR_VM
| MSR_UM
));
1361 tcg_gen_andi_i32(t1
, t1
, ~(MSR_VM
| MSR_UM
));
1362 tcg_gen_or_i32(t1
, t1
, t0
);
1364 tcg_temp_free_i32(t1
);
1365 tcg_temp_free_i32(t0
);
1366 dc
->tb_flags
&= ~DRTE_FLAG
;
1369 static void dec_rts(DisasContext
*dc
)
1371 unsigned int b_bit
, i_bit
, e_bit
;
1374 i_bit
= dc
->ir
& (1 << 21);
1375 b_bit
= dc
->ir
& (1 << 22);
1376 e_bit
= dc
->ir
& (1 << 23);
1378 if (trap_userspace(dc
, i_bit
|| b_bit
|| e_bit
)) {
1382 dec_setup_dslot(dc
);
1385 LOG_DIS("rtid ir=%x\n", dc
->ir
);
1386 dc
->tb_flags
|= DRTI_FLAG
;
1388 LOG_DIS("rtbd ir=%x\n", dc
->ir
);
1389 dc
->tb_flags
|= DRTB_FLAG
;
1391 LOG_DIS("rted ir=%x\n", dc
->ir
);
1392 dc
->tb_flags
|= DRTE_FLAG
;
1394 LOG_DIS("rts ir=%x\n", dc
->ir
);
1396 dc
->jmp
= JMP_INDIRECT
;
1397 tcg_gen_movi_i32(env_btaken
, 1);
1399 tmp64
= tcg_temp_new_i64();
1400 tcg_gen_extu_i32_i64(env_btarget
, *(dec_alu_op_b(dc
)));
1401 tcg_gen_extu_i32_i64(tmp64
, cpu_R
[dc
->ra
]);
1402 tcg_gen_add_i64(env_btarget
, env_btarget
, tmp64
);
1403 tcg_gen_andi_i64(env_btarget
, env_btarget
, UINT32_MAX
);
1404 tcg_temp_free_i64(tmp64
);
1407 static int dec_check_fpuv2(DisasContext
*dc
)
1409 if ((dc
->cpu
->cfg
.use_fpu
!= 2) && (dc
->tb_flags
& MSR_EE_FLAG
)) {
1410 tcg_gen_movi_i64(cpu_SR
[SR_ESR
], ESR_EC_FPU
);
1411 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1413 return (dc
->cpu
->cfg
.use_fpu
== 2) ? PVR2_USE_FPU2_MASK
: 0;
1416 static void dec_fpu(DisasContext
*dc
)
1418 unsigned int fpu_insn
;
1420 if (trap_illegal(dc
, !dc
->cpu
->cfg
.use_fpu
)) {
1424 fpu_insn
= (dc
->ir
>> 7) & 7;
1428 gen_helper_fadd(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
],
1433 gen_helper_frsub(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
],
1438 gen_helper_fmul(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
],
1443 gen_helper_fdiv(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
],
1448 switch ((dc
->ir
>> 4) & 7) {
1450 gen_helper_fcmp_un(cpu_R
[dc
->rd
], cpu_env
,
1451 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1454 gen_helper_fcmp_lt(cpu_R
[dc
->rd
], cpu_env
,
1455 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1458 gen_helper_fcmp_eq(cpu_R
[dc
->rd
], cpu_env
,
1459 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1462 gen_helper_fcmp_le(cpu_R
[dc
->rd
], cpu_env
,
1463 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1466 gen_helper_fcmp_gt(cpu_R
[dc
->rd
], cpu_env
,
1467 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1470 gen_helper_fcmp_ne(cpu_R
[dc
->rd
], cpu_env
,
1471 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1474 gen_helper_fcmp_ge(cpu_R
[dc
->rd
], cpu_env
,
1475 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1478 qemu_log_mask(LOG_UNIMP
,
1479 "unimplemented fcmp fpu_insn=%x pc=%x"
1481 fpu_insn
, dc
->pc
, dc
->opcode
);
1482 dc
->abort_at_next_insn
= 1;
1488 if (!dec_check_fpuv2(dc
)) {
1491 gen_helper_flt(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
]);
1495 if (!dec_check_fpuv2(dc
)) {
1498 gen_helper_fint(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
]);
1502 if (!dec_check_fpuv2(dc
)) {
1505 gen_helper_fsqrt(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
]);
1509 qemu_log_mask(LOG_UNIMP
, "unimplemented FPU insn fpu_insn=%x pc=%x"
1511 fpu_insn
, dc
->pc
, dc
->opcode
);
1512 dc
->abort_at_next_insn
= 1;
1517 static void dec_null(DisasContext
*dc
)
1519 if (trap_illegal(dc
, true)) {
1522 qemu_log_mask(LOG_GUEST_ERROR
, "unknown insn pc=%x opc=%x\n", dc
->pc
, dc
->opcode
);
1523 dc
->abort_at_next_insn
= 1;
1526 /* Insns connected to FSL or AXI stream attached devices. */
1527 static void dec_stream(DisasContext
*dc
)
1529 TCGv_i32 t_id
, t_ctrl
;
1532 LOG_DIS("%s%s imm=%x\n", dc
->rd
? "get" : "put",
1533 dc
->type_b
? "" : "d", dc
->imm
);
1535 if (trap_userspace(dc
, true)) {
1539 t_id
= tcg_temp_new_i32();
1541 tcg_gen_movi_i32(t_id
, dc
->imm
& 0xf);
1542 ctrl
= dc
->imm
>> 10;
1544 tcg_gen_andi_i32(t_id
, cpu_R
[dc
->rb
], 0xf);
1545 ctrl
= dc
->imm
>> 5;
1548 t_ctrl
= tcg_const_i32(ctrl
);
1551 gen_helper_put(t_id
, t_ctrl
, cpu_R
[dc
->ra
]);
1553 gen_helper_get(cpu_R
[dc
->rd
], t_id
, t_ctrl
);
1555 tcg_temp_free_i32(t_id
);
1556 tcg_temp_free_i32(t_ctrl
);
1559 static struct decoder_info
{
1564 void (*dec
)(DisasContext
*dc
);
1572 {DEC_BARREL
, dec_barrel
},
1574 {DEC_ST
, dec_store
},
1583 {DEC_STREAM
, dec_stream
},
1587 static inline void decode(DisasContext
*dc
, uint32_t ir
)
1592 LOG_DIS("%8.8x\t", dc
->ir
);
1595 trap_illegal(dc
, dc
->cpu
->cfg
.opcode_0_illegal
);
1596 /* Don't decode nop/zero instructions any further. */
1600 /* bit 2 seems to indicate insn type. */
1601 dc
->type_b
= ir
& (1 << 29);
1603 dc
->opcode
= EXTRACT_FIELD(ir
, 26, 31);
1604 dc
->rd
= EXTRACT_FIELD(ir
, 21, 25);
1605 dc
->ra
= EXTRACT_FIELD(ir
, 16, 20);
1606 dc
->rb
= EXTRACT_FIELD(ir
, 11, 15);
1607 dc
->imm
= EXTRACT_FIELD(ir
, 0, 15);
1609 /* Large switch for all insns. */
1610 for (i
= 0; i
< ARRAY_SIZE(decinfo
); i
++) {
1611 if ((dc
->opcode
& decinfo
[i
].mask
) == decinfo
[i
].bits
) {
1618 /* generate intermediate code for basic block 'tb'. */
1619 void gen_intermediate_code(CPUState
*cs
, TranslationBlock
*tb
, int max_insns
)
1621 CPUMBState
*env
= cs
->env_ptr
;
1622 MicroBlazeCPU
*cpu
= env_archcpu(env
);
1624 struct DisasContext ctx
;
1625 struct DisasContext
*dc
= &ctx
;
1626 uint32_t page_start
, org_flags
;
1633 org_flags
= dc
->synced_flags
= dc
->tb_flags
= tb
->flags
;
1635 dc
->is_jmp
= DISAS_NEXT
;
1637 dc
->delayed_branch
= !!(dc
->tb_flags
& D_FLAG
);
1638 if (dc
->delayed_branch
) {
1639 dc
->jmp
= JMP_INDIRECT
;
1642 dc
->singlestep_enabled
= cs
->singlestep_enabled
;
1643 dc
->cpustate_changed
= 0;
1644 dc
->abort_at_next_insn
= 0;
1647 cpu_abort(cs
, "Microblaze: unaligned PC=%x\n", pc_start
);
1650 page_start
= pc_start
& TARGET_PAGE_MASK
;
1656 tcg_gen_insn_start(dc
->pc
);
1660 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM
)) {
1661 tcg_gen_movi_i64(cpu_SR
[SR_PC
], dc
->pc
);
1666 if (unlikely(cpu_breakpoint_test(cs
, dc
->pc
, BP_ANY
))) {
1667 t_gen_raise_exception(dc
, EXCP_DEBUG
);
1668 dc
->is_jmp
= DISAS_UPDATE
;
1669 /* The address covered by the breakpoint must be included in
1670 [tb->pc, tb->pc + tb->size) in order to for it to be
1671 properly cleared -- thus we increment the PC here so that
1672 the logic setting tb->size below does the right thing. */
1678 LOG_DIS("%8.8x:\t", dc
->pc
);
1680 if (num_insns
== max_insns
&& (tb_cflags(tb
) & CF_LAST_IO
)) {
1685 decode(dc
, cpu_ldl_code(env
, dc
->pc
));
1687 dc
->tb_flags
&= ~IMM_FLAG
;
1690 if (dc
->delayed_branch
) {
1691 dc
->delayed_branch
--;
1692 if (!dc
->delayed_branch
) {
1693 if (dc
->tb_flags
& DRTI_FLAG
)
1695 if (dc
->tb_flags
& DRTB_FLAG
)
1697 if (dc
->tb_flags
& DRTE_FLAG
)
1699 /* Clear the delay slot flag. */
1700 dc
->tb_flags
&= ~D_FLAG
;
1701 /* If it is a direct jump, try direct chaining. */
1702 if (dc
->jmp
== JMP_INDIRECT
) {
1703 TCGv_i64 tmp_pc
= tcg_const_i64(dc
->pc
);
1704 eval_cond_jmp(dc
, env_btarget
, tmp_pc
);
1705 tcg_temp_free_i64(tmp_pc
);
1707 dc
->is_jmp
= DISAS_JUMP
;
1708 } else if (dc
->jmp
== JMP_DIRECT
) {
1710 gen_goto_tb(dc
, 0, dc
->jmp_pc
);
1711 dc
->is_jmp
= DISAS_TB_JUMP
;
1712 } else if (dc
->jmp
== JMP_DIRECT_CC
) {
1713 TCGLabel
*l1
= gen_new_label();
1715 /* Conditional jmp. */
1716 tcg_gen_brcondi_i32(TCG_COND_NE
, env_btaken
, 0, l1
);
1717 gen_goto_tb(dc
, 1, dc
->pc
);
1719 gen_goto_tb(dc
, 0, dc
->jmp_pc
);
1721 dc
->is_jmp
= DISAS_TB_JUMP
;
1726 if (cs
->singlestep_enabled
) {
1729 } while (!dc
->is_jmp
&& !dc
->cpustate_changed
1730 && !tcg_op_buf_full()
1732 && (dc
->pc
- page_start
< TARGET_PAGE_SIZE
)
1733 && num_insns
< max_insns
);
1736 if (dc
->jmp
== JMP_DIRECT
|| dc
->jmp
== JMP_DIRECT_CC
) {
1737 if (dc
->tb_flags
& D_FLAG
) {
1738 dc
->is_jmp
= DISAS_UPDATE
;
1739 tcg_gen_movi_i64(cpu_SR
[SR_PC
], npc
);
1745 /* Force an update if the per-tb cpu state has changed. */
1746 if (dc
->is_jmp
== DISAS_NEXT
1747 && (dc
->cpustate_changed
|| org_flags
!= dc
->tb_flags
)) {
1748 dc
->is_jmp
= DISAS_UPDATE
;
1749 tcg_gen_movi_i64(cpu_SR
[SR_PC
], npc
);
1753 if (unlikely(cs
->singlestep_enabled
)) {
1754 TCGv_i32 tmp
= tcg_const_i32(EXCP_DEBUG
);
1756 if (dc
->is_jmp
!= DISAS_JUMP
) {
1757 tcg_gen_movi_i64(cpu_SR
[SR_PC
], npc
);
1759 gen_helper_raise_exception(cpu_env
, tmp
);
1760 tcg_temp_free_i32(tmp
);
1762 switch(dc
->is_jmp
) {
1764 gen_goto_tb(dc
, 1, npc
);
1769 /* indicate that the hash table must be used
1770 to find the next TB */
1771 tcg_gen_exit_tb(NULL
, 0);
1774 /* nothing more to generate */
1778 gen_tb_end(tb
, num_insns
);
1780 tb
->size
= dc
->pc
- pc_start
;
1781 tb
->icount
= num_insns
;
1785 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM
)
1786 && qemu_log_in_addr_range(pc_start
)) {
1787 FILE *logfile
= qemu_log_lock();
1788 qemu_log("--------------\n");
1789 log_target_disas(cs
, pc_start
, dc
->pc
- pc_start
);
1790 qemu_log_unlock(logfile
);
1794 assert(!dc
->abort_at_next_insn
);
1797 void mb_cpu_dump_state(CPUState
*cs
, FILE *f
, int flags
)
1799 MicroBlazeCPU
*cpu
= MICROBLAZE_CPU(cs
);
1800 CPUMBState
*env
= &cpu
->env
;
1807 qemu_fprintf(f
, "IN: PC=%" PRIx64
" %s\n",
1808 env
->sregs
[SR_PC
], lookup_symbol(env
->sregs
[SR_PC
]));
1809 qemu_fprintf(f
, "rmsr=%" PRIx64
" resr=%" PRIx64
" rear=%" PRIx64
" "
1810 "debug=%x imm=%x iflags=%x fsr=%" PRIx64
" "
1811 "rbtr=%" PRIx64
"\n",
1812 env
->sregs
[SR_MSR
], env
->sregs
[SR_ESR
], env
->sregs
[SR_EAR
],
1813 env
->debug
, env
->imm
, env
->iflags
, env
->sregs
[SR_FSR
],
1814 env
->sregs
[SR_BTR
]);
1815 qemu_fprintf(f
, "btaken=%d btarget=%" PRIx64
" mode=%s(saved=%s) "
1817 env
->btaken
, env
->btarget
,
1818 (env
->sregs
[SR_MSR
] & MSR_UM
) ? "user" : "kernel",
1819 (env
->sregs
[SR_MSR
] & MSR_UMS
) ? "user" : "kernel",
1820 (bool)(env
->sregs
[SR_MSR
] & MSR_EIP
),
1821 (bool)(env
->sregs
[SR_MSR
] & MSR_IE
));
1822 for (i
= 0; i
< 12; i
++) {
1823 qemu_fprintf(f
, "rpvr%2.2d=%8.8x ", i
, env
->pvr
.regs
[i
]);
1824 if ((i
+ 1) % 4 == 0) {
1825 qemu_fprintf(f
, "\n");
1829 /* Registers that aren't modeled are reported as 0 */
1830 qemu_fprintf(f
, "redr=%" PRIx64
" rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 "
1831 "rtlblo=0 rtlbhi=0\n", env
->sregs
[SR_EDR
]);
1832 qemu_fprintf(f
, "slr=%x shr=%x\n", env
->slr
, env
->shr
);
1833 for (i
= 0; i
< 32; i
++) {
1834 qemu_fprintf(f
, "r%2.2d=%8.8x ", i
, env
->regs
[i
]);
1835 if ((i
+ 1) % 4 == 0)
1836 qemu_fprintf(f
, "\n");
1838 qemu_fprintf(f
, "\n\n");
1841 void mb_tcg_init(void)
1845 env_debug
= tcg_global_mem_new_i32(cpu_env
,
1846 offsetof(CPUMBState
, debug
),
1848 env_iflags
= tcg_global_mem_new_i32(cpu_env
,
1849 offsetof(CPUMBState
, iflags
),
1851 env_imm
= tcg_global_mem_new_i32(cpu_env
,
1852 offsetof(CPUMBState
, imm
),
1854 env_btarget
= tcg_global_mem_new_i64(cpu_env
,
1855 offsetof(CPUMBState
, btarget
),
1857 env_btaken
= tcg_global_mem_new_i32(cpu_env
,
1858 offsetof(CPUMBState
, btaken
),
1860 env_res_addr
= tcg_global_mem_new(cpu_env
,
1861 offsetof(CPUMBState
, res_addr
),
1863 env_res_val
= tcg_global_mem_new_i32(cpu_env
,
1864 offsetof(CPUMBState
, res_val
),
1866 for (i
= 0; i
< ARRAY_SIZE(cpu_R
); i
++) {
1867 cpu_R
[i
] = tcg_global_mem_new_i32(cpu_env
,
1868 offsetof(CPUMBState
, regs
[i
]),
1871 for (i
= 0; i
< ARRAY_SIZE(cpu_SR
); i
++) {
1872 cpu_SR
[i
] = tcg_global_mem_new_i64(cpu_env
,
1873 offsetof(CPUMBState
, sregs
[i
]),
1874 special_regnames
[i
]);
1878 void restore_state_to_opc(CPUMBState
*env
, TranslationBlock
*tb
,
1881 env
->sregs
[SR_PC
] = data
[0];