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"
25 #include "exec/helper-proto.h"
26 #include "microblaze-decode.h"
27 #include "exec/cpu_ldst.h"
28 #include "exec/helper-gen.h"
30 #include "trace-tcg.h"
37 #if DISAS_MB && !SIM_COMPAT
38 # define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
40 # define LOG_DIS(...) do { } while (0)
45 #define EXTRACT_FIELD(src, start, end) \
46 (((src) >> start) & ((1 << (end - start + 1)) - 1))
48 static TCGv env_debug
;
49 static TCGv_ptr cpu_env
;
50 static TCGv cpu_R
[32];
51 static TCGv cpu_SR
[18];
53 static TCGv env_btaken
;
54 static TCGv env_btarget
;
55 static TCGv env_iflags
;
56 static TCGv env_res_addr
;
57 static TCGv env_res_val
;
59 #include "exec/gen-icount.h"
61 /* This is the state at translation time. */
62 typedef struct DisasContext
{
73 unsigned int cpustate_changed
;
74 unsigned int delayed_branch
;
75 unsigned int tb_flags
, synced_flags
; /* tb dependent flags. */
76 unsigned int clear_imm
;
81 #define JMP_DIRECT_CC 2
82 #define JMP_INDIRECT 3
86 int abort_at_next_insn
;
88 struct TranslationBlock
*tb
;
89 int singlestep_enabled
;
92 static const char *regnames
[] =
94 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
95 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
96 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
97 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
100 static const char *special_regnames
[] =
102 "rpc", "rmsr", "sr2", "sr3", "sr4", "sr5", "sr6", "sr7",
103 "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
104 "sr16", "sr17", "sr18"
107 static inline void t_sync_flags(DisasContext
*dc
)
109 /* Synch the tb dependent flags between translator and runtime. */
110 if (dc
->tb_flags
!= dc
->synced_flags
) {
111 tcg_gen_movi_tl(env_iflags
, dc
->tb_flags
);
112 dc
->synced_flags
= dc
->tb_flags
;
116 static inline void t_gen_raise_exception(DisasContext
*dc
, uint32_t index
)
118 TCGv_i32 tmp
= tcg_const_i32(index
);
121 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dc
->pc
);
122 gen_helper_raise_exception(cpu_env
, tmp
);
123 tcg_temp_free_i32(tmp
);
124 dc
->is_jmp
= DISAS_UPDATE
;
127 static void gen_goto_tb(DisasContext
*dc
, int n
, target_ulong dest
)
129 TranslationBlock
*tb
;
131 if ((tb
->pc
& TARGET_PAGE_MASK
) == (dest
& TARGET_PAGE_MASK
)) {
133 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dest
);
134 tcg_gen_exit_tb((uintptr_t)tb
+ n
);
136 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dest
);
141 static void read_carry(DisasContext
*dc
, TCGv d
)
143 tcg_gen_shri_tl(d
, cpu_SR
[SR_MSR
], 31);
147 * write_carry sets the carry bits in MSR based on bit 0 of v.
148 * v[31:1] are ignored.
150 static void write_carry(DisasContext
*dc
, TCGv v
)
152 TCGv t0
= tcg_temp_new();
153 tcg_gen_shli_tl(t0
, v
, 31);
154 tcg_gen_sari_tl(t0
, t0
, 31);
155 tcg_gen_andi_tl(t0
, t0
, (MSR_C
| MSR_CC
));
156 tcg_gen_andi_tl(cpu_SR
[SR_MSR
], cpu_SR
[SR_MSR
],
158 tcg_gen_or_tl(cpu_SR
[SR_MSR
], cpu_SR
[SR_MSR
], t0
);
162 static void write_carryi(DisasContext
*dc
, bool carry
)
164 TCGv t0
= tcg_temp_new();
165 tcg_gen_movi_tl(t0
, carry
);
170 /* True if ALU operand b is a small immediate that may deserve
172 static inline int dec_alu_op_b_is_small_imm(DisasContext
*dc
)
174 /* Immediate insn without the imm prefix ? */
175 return dc
->type_b
&& !(dc
->tb_flags
& IMM_FLAG
);
178 static inline TCGv
*dec_alu_op_b(DisasContext
*dc
)
181 if (dc
->tb_flags
& IMM_FLAG
)
182 tcg_gen_ori_tl(env_imm
, env_imm
, dc
->imm
);
184 tcg_gen_movi_tl(env_imm
, (int32_t)((int16_t)dc
->imm
));
187 return &cpu_R
[dc
->rb
];
190 static void dec_add(DisasContext
*dc
)
198 LOG_DIS("add%s%s%s r%d r%d r%d\n",
199 dc
->type_b
? "i" : "", k
? "k" : "", c
? "c" : "",
200 dc
->rd
, dc
->ra
, dc
->rb
);
202 /* Take care of the easy cases first. */
204 /* k - keep carry, no need to update MSR. */
205 /* If rd == r0, it's a nop. */
207 tcg_gen_add_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
210 /* c - Add carry into the result. */
214 tcg_gen_add_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->rd
], cf
);
221 /* From now on, we can assume k is zero. So we need to update MSR. */
227 tcg_gen_movi_tl(cf
, 0);
231 TCGv ncf
= tcg_temp_new();
232 gen_helper_carry(ncf
, cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)), cf
);
233 tcg_gen_add_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
234 tcg_gen_add_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->rd
], cf
);
235 write_carry(dc
, ncf
);
238 gen_helper_carry(cf
, cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)), cf
);
244 static void dec_sub(DisasContext
*dc
)
246 unsigned int u
, cmp
, k
, c
;
252 cmp
= (dc
->imm
& 1) && (!dc
->type_b
) && k
;
255 LOG_DIS("cmp%s r%d, r%d ir=%x\n", u
? "u" : "", dc
->rd
, dc
->ra
, dc
->ir
);
258 gen_helper_cmpu(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
260 gen_helper_cmp(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
265 LOG_DIS("sub%s%s r%d, r%d r%d\n",
266 k
? "k" : "", c
? "c" : "", dc
->rd
, dc
->ra
, dc
->rb
);
268 /* Take care of the easy cases first. */
270 /* k - keep carry, no need to update MSR. */
271 /* If rd == r0, it's a nop. */
273 tcg_gen_sub_tl(cpu_R
[dc
->rd
], *(dec_alu_op_b(dc
)), cpu_R
[dc
->ra
]);
276 /* c - Add carry into the result. */
280 tcg_gen_add_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->rd
], cf
);
287 /* From now on, we can assume k is zero. So we need to update MSR. */
288 /* Extract carry. And complement a into na. */
294 tcg_gen_movi_tl(cf
, 1);
297 /* d = b + ~a + c. carry defaults to 1. */
298 tcg_gen_not_tl(na
, cpu_R
[dc
->ra
]);
301 TCGv ncf
= tcg_temp_new();
302 gen_helper_carry(ncf
, na
, *(dec_alu_op_b(dc
)), cf
);
303 tcg_gen_add_tl(cpu_R
[dc
->rd
], na
, *(dec_alu_op_b(dc
)));
304 tcg_gen_add_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->rd
], cf
);
305 write_carry(dc
, ncf
);
308 gen_helper_carry(cf
, na
, *(dec_alu_op_b(dc
)), cf
);
315 static void dec_pattern(DisasContext
*dc
)
319 if ((dc
->tb_flags
& MSR_EE_FLAG
)
320 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)
321 && !((dc
->cpu
->env
.pvr
.regs
[2] & PVR2_USE_PCMP_INSTR
))) {
322 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
323 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
326 mode
= dc
->opcode
& 3;
330 LOG_DIS("pcmpbf r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
332 gen_helper_pcmpbf(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
335 LOG_DIS("pcmpeq r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
337 tcg_gen_setcond_tl(TCG_COND_EQ
, cpu_R
[dc
->rd
],
338 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
342 LOG_DIS("pcmpne r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
344 tcg_gen_setcond_tl(TCG_COND_NE
, cpu_R
[dc
->rd
],
345 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
349 cpu_abort(CPU(dc
->cpu
),
350 "unsupported pattern insn opcode=%x\n", dc
->opcode
);
355 static void dec_and(DisasContext
*dc
)
359 if (!dc
->type_b
&& (dc
->imm
& (1 << 10))) {
364 not = dc
->opcode
& (1 << 1);
365 LOG_DIS("and%s\n", not ? "n" : "");
371 tcg_gen_andc_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
373 tcg_gen_and_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
376 static void dec_or(DisasContext
*dc
)
378 if (!dc
->type_b
&& (dc
->imm
& (1 << 10))) {
383 LOG_DIS("or r%d r%d r%d imm=%x\n", dc
->rd
, dc
->ra
, dc
->rb
, dc
->imm
);
385 tcg_gen_or_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
388 static void dec_xor(DisasContext
*dc
)
390 if (!dc
->type_b
&& (dc
->imm
& (1 << 10))) {
395 LOG_DIS("xor r%d\n", dc
->rd
);
397 tcg_gen_xor_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
400 static inline void msr_read(DisasContext
*dc
, TCGv d
)
402 tcg_gen_mov_tl(d
, cpu_SR
[SR_MSR
]);
405 static inline void msr_write(DisasContext
*dc
, TCGv v
)
410 dc
->cpustate_changed
= 1;
411 /* PVR bit is not writable. */
412 tcg_gen_andi_tl(t
, v
, ~MSR_PVR
);
413 tcg_gen_andi_tl(cpu_SR
[SR_MSR
], cpu_SR
[SR_MSR
], MSR_PVR
);
414 tcg_gen_or_tl(cpu_SR
[SR_MSR
], cpu_SR
[SR_MSR
], v
);
418 static void dec_msr(DisasContext
*dc
)
420 CPUState
*cs
= CPU(dc
->cpu
);
422 unsigned int sr
, to
, rn
;
423 int mem_index
= cpu_mmu_index(&dc
->cpu
->env
, false);
425 sr
= dc
->imm
& ((1 << 14) - 1);
426 to
= dc
->imm
& (1 << 14);
429 dc
->cpustate_changed
= 1;
431 /* msrclr and msrset. */
432 if (!(dc
->imm
& (1 << 15))) {
433 unsigned int clr
= dc
->ir
& (1 << 16);
435 LOG_DIS("msr%s r%d imm=%x\n", clr
? "clr" : "set",
438 if (!(dc
->cpu
->env
.pvr
.regs
[2] & PVR2_USE_MSR_INSTR
)) {
443 if ((dc
->tb_flags
& MSR_EE_FLAG
)
444 && mem_index
== MMU_USER_IDX
&& (dc
->imm
!= 4 && dc
->imm
!= 0)) {
445 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
446 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
451 msr_read(dc
, cpu_R
[dc
->rd
]);
456 tcg_gen_mov_tl(t1
, *(dec_alu_op_b(dc
)));
459 tcg_gen_not_tl(t1
, t1
);
460 tcg_gen_and_tl(t0
, t0
, t1
);
462 tcg_gen_or_tl(t0
, t0
, t1
);
466 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dc
->pc
+ 4);
467 dc
->is_jmp
= DISAS_UPDATE
;
472 if ((dc
->tb_flags
& MSR_EE_FLAG
)
473 && mem_index
== MMU_USER_IDX
) {
474 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
475 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
480 #if !defined(CONFIG_USER_ONLY)
481 /* Catch read/writes to the mmu block. */
482 if ((sr
& ~0xff) == 0x1000) {
484 LOG_DIS("m%ss sr%d r%d imm=%x\n", to
? "t" : "f", sr
, dc
->ra
, dc
->imm
);
486 gen_helper_mmu_write(cpu_env
, tcg_const_tl(sr
), cpu_R
[dc
->ra
]);
488 gen_helper_mmu_read(cpu_R
[dc
->rd
], cpu_env
, tcg_const_tl(sr
));
494 LOG_DIS("m%ss sr%x r%d imm=%x\n", to
? "t" : "f", sr
, dc
->ra
, dc
->imm
);
499 msr_write(dc
, cpu_R
[dc
->ra
]);
502 tcg_gen_mov_tl(cpu_SR
[SR_EAR
], cpu_R
[dc
->ra
]);
505 tcg_gen_mov_tl(cpu_SR
[SR_ESR
], cpu_R
[dc
->ra
]);
508 tcg_gen_andi_tl(cpu_SR
[SR_FSR
], cpu_R
[dc
->ra
], 31);
511 tcg_gen_st_tl(cpu_R
[dc
->ra
], cpu_env
, offsetof(CPUMBState
, slr
));
514 tcg_gen_st_tl(cpu_R
[dc
->ra
], cpu_env
, offsetof(CPUMBState
, shr
));
517 cpu_abort(CPU(dc
->cpu
), "unknown mts reg %x\n", sr
);
521 LOG_DIS("m%ss r%d sr%x imm=%x\n", to
? "t" : "f", dc
->rd
, sr
, dc
->imm
);
525 tcg_gen_movi_tl(cpu_R
[dc
->rd
], dc
->pc
);
528 msr_read(dc
, cpu_R
[dc
->rd
]);
531 tcg_gen_mov_tl(cpu_R
[dc
->rd
], cpu_SR
[SR_EAR
]);
534 tcg_gen_mov_tl(cpu_R
[dc
->rd
], cpu_SR
[SR_ESR
]);
537 tcg_gen_mov_tl(cpu_R
[dc
->rd
], cpu_SR
[SR_FSR
]);
540 tcg_gen_mov_tl(cpu_R
[dc
->rd
], cpu_SR
[SR_BTR
]);
543 tcg_gen_ld_tl(cpu_R
[dc
->rd
], cpu_env
, offsetof(CPUMBState
, slr
));
546 tcg_gen_ld_tl(cpu_R
[dc
->rd
], cpu_env
, offsetof(CPUMBState
, shr
));
562 tcg_gen_ld_tl(cpu_R
[dc
->rd
],
563 cpu_env
, offsetof(CPUMBState
, pvr
.regs
[rn
]));
566 cpu_abort(cs
, "unknown mfs reg %x\n", sr
);
572 tcg_gen_movi_tl(cpu_R
[0], 0);
576 /* 64-bit signed mul, lower result in d and upper in d2. */
577 static void t_gen_muls(TCGv d
, TCGv d2
, TCGv a
, TCGv b
)
581 t0
= tcg_temp_new_i64();
582 t1
= tcg_temp_new_i64();
584 tcg_gen_ext_i32_i64(t0
, a
);
585 tcg_gen_ext_i32_i64(t1
, b
);
586 tcg_gen_mul_i64(t0
, t0
, t1
);
588 tcg_gen_extrl_i64_i32(d
, t0
);
589 tcg_gen_shri_i64(t0
, t0
, 32);
590 tcg_gen_extrl_i64_i32(d2
, t0
);
592 tcg_temp_free_i64(t0
);
593 tcg_temp_free_i64(t1
);
596 /* 64-bit unsigned muls, lower result in d and upper in d2. */
597 static void t_gen_mulu(TCGv d
, TCGv d2
, TCGv a
, TCGv b
)
601 t0
= tcg_temp_new_i64();
602 t1
= tcg_temp_new_i64();
604 tcg_gen_extu_i32_i64(t0
, a
);
605 tcg_gen_extu_i32_i64(t1
, b
);
606 tcg_gen_mul_i64(t0
, t0
, t1
);
608 tcg_gen_extrl_i64_i32(d
, t0
);
609 tcg_gen_shri_i64(t0
, t0
, 32);
610 tcg_gen_extrl_i64_i32(d2
, t0
);
612 tcg_temp_free_i64(t0
);
613 tcg_temp_free_i64(t1
);
616 /* Multiplier unit. */
617 static void dec_mul(DisasContext
*dc
)
620 unsigned int subcode
;
622 if ((dc
->tb_flags
& MSR_EE_FLAG
)
623 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)
624 && !(dc
->cpu
->env
.pvr
.regs
[0] & PVR0_USE_HW_MUL_MASK
)) {
625 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
626 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
630 subcode
= dc
->imm
& 3;
631 d
[0] = tcg_temp_new();
632 d
[1] = tcg_temp_new();
635 LOG_DIS("muli r%d r%d %x\n", dc
->rd
, dc
->ra
, dc
->imm
);
636 t_gen_mulu(cpu_R
[dc
->rd
], d
[1], cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
640 /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2. */
641 if (subcode
>= 1 && subcode
<= 3
642 && !((dc
->cpu
->env
.pvr
.regs
[2] & PVR2_USE_MUL64_MASK
))) {
648 LOG_DIS("mul r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
649 t_gen_mulu(cpu_R
[dc
->rd
], d
[1], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
652 LOG_DIS("mulh r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
653 t_gen_muls(d
[0], cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
656 LOG_DIS("mulhsu r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
657 t_gen_muls(d
[0], cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
660 LOG_DIS("mulhu r%d r%d r%d\n", dc
->rd
, dc
->ra
, dc
->rb
);
661 t_gen_mulu(d
[0], cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
664 cpu_abort(CPU(dc
->cpu
), "unknown MUL insn %x\n", subcode
);
673 static void dec_div(DisasContext
*dc
)
680 if ((dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)
681 && !((dc
->cpu
->env
.pvr
.regs
[0] & PVR0_USE_DIV_MASK
))) {
682 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
683 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
687 gen_helper_divu(cpu_R
[dc
->rd
], cpu_env
, *(dec_alu_op_b(dc
)),
690 gen_helper_divs(cpu_R
[dc
->rd
], cpu_env
, *(dec_alu_op_b(dc
)),
693 tcg_gen_movi_tl(cpu_R
[dc
->rd
], 0);
696 static void dec_barrel(DisasContext
*dc
)
701 if ((dc
->tb_flags
& MSR_EE_FLAG
)
702 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)
703 && !(dc
->cpu
->env
.pvr
.regs
[0] & PVR0_USE_BARREL_MASK
)) {
704 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
705 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
709 s
= dc
->imm
& (1 << 10);
710 t
= dc
->imm
& (1 << 9);
712 LOG_DIS("bs%s%s r%d r%d r%d\n",
713 s
? "l" : "r", t
? "a" : "l", dc
->rd
, dc
->ra
, dc
->rb
);
717 tcg_gen_mov_tl(t0
, *(dec_alu_op_b(dc
)));
718 tcg_gen_andi_tl(t0
, t0
, 31);
721 tcg_gen_shl_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], t0
);
724 tcg_gen_sar_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], t0
);
726 tcg_gen_shr_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], t0
);
730 static void dec_bit(DisasContext
*dc
)
732 CPUState
*cs
= CPU(dc
->cpu
);
735 int mem_index
= cpu_mmu_index(&dc
->cpu
->env
, false);
737 op
= dc
->ir
& ((1 << 9) - 1);
743 LOG_DIS("src r%d r%d\n", dc
->rd
, dc
->ra
);
744 tcg_gen_andi_tl(t0
, cpu_SR
[SR_MSR
], MSR_CC
);
745 write_carry(dc
, cpu_R
[dc
->ra
]);
747 tcg_gen_shri_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], 1);
748 tcg_gen_or_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->rd
], t0
);
756 LOG_DIS("srl r%d r%d\n", dc
->rd
, dc
->ra
);
758 /* Update carry. Note that write carry only looks at the LSB. */
759 write_carry(dc
, cpu_R
[dc
->ra
]);
762 tcg_gen_shri_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], 1);
764 tcg_gen_sari_tl(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], 1);
768 LOG_DIS("ext8s r%d r%d\n", dc
->rd
, dc
->ra
);
769 tcg_gen_ext8s_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
]);
772 LOG_DIS("ext16s r%d r%d\n", dc
->rd
, dc
->ra
);
773 tcg_gen_ext16s_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
]);
780 LOG_DIS("wdc r%d\n", dc
->ra
);
781 if ((dc
->tb_flags
& MSR_EE_FLAG
)
782 && mem_index
== MMU_USER_IDX
) {
783 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
784 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
790 LOG_DIS("wic r%d\n", dc
->ra
);
791 if ((dc
->tb_flags
& MSR_EE_FLAG
)
792 && mem_index
== MMU_USER_IDX
) {
793 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
794 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
799 if ((dc
->tb_flags
& MSR_EE_FLAG
)
800 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)
801 && !((dc
->cpu
->env
.pvr
.regs
[2] & PVR2_USE_PCMP_INSTR
))) {
802 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
803 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
805 if (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_USE_PCMP_INSTR
) {
806 gen_helper_clz(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
]);
811 LOG_DIS("swapb r%d r%d\n", dc
->rd
, dc
->ra
);
812 tcg_gen_bswap32_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
]);
816 LOG_DIS("swaph r%d r%d\n", dc
->rd
, dc
->ra
);
817 tcg_gen_rotri_i32(cpu_R
[dc
->rd
], cpu_R
[dc
->ra
], 16);
820 cpu_abort(cs
, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n",
821 dc
->pc
, op
, dc
->rd
, dc
->ra
, dc
->rb
);
826 static inline void sync_jmpstate(DisasContext
*dc
)
828 if (dc
->jmp
== JMP_DIRECT
|| dc
->jmp
== JMP_DIRECT_CC
) {
829 if (dc
->jmp
== JMP_DIRECT
) {
830 tcg_gen_movi_tl(env_btaken
, 1);
832 dc
->jmp
= JMP_INDIRECT
;
833 tcg_gen_movi_tl(env_btarget
, dc
->jmp_pc
);
837 static void dec_imm(DisasContext
*dc
)
839 LOG_DIS("imm %x\n", dc
->imm
<< 16);
840 tcg_gen_movi_tl(env_imm
, (dc
->imm
<< 16));
841 dc
->tb_flags
|= IMM_FLAG
;
845 static inline TCGv
*compute_ldst_addr(DisasContext
*dc
, TCGv
*t
)
847 unsigned int extimm
= dc
->tb_flags
& IMM_FLAG
;
848 /* Should be set to one if r1 is used by loadstores. */
851 /* All load/stores use ra. */
852 if (dc
->ra
== 1 && dc
->cpu
->cfg
.stackprot
) {
856 /* Treat the common cases first. */
858 /* If any of the regs is r0, return a ptr to the other. */
860 return &cpu_R
[dc
->rb
];
861 } else if (dc
->rb
== 0) {
862 return &cpu_R
[dc
->ra
];
865 if (dc
->rb
== 1 && dc
->cpu
->cfg
.stackprot
) {
870 tcg_gen_add_tl(*t
, cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
873 gen_helper_stackprot(cpu_env
, *t
);
880 return &cpu_R
[dc
->ra
];
883 tcg_gen_movi_tl(*t
, (int32_t)((int16_t)dc
->imm
));
884 tcg_gen_add_tl(*t
, cpu_R
[dc
->ra
], *t
);
887 tcg_gen_add_tl(*t
, cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
891 gen_helper_stackprot(cpu_env
, *t
);
896 static void dec_load(DisasContext
*dc
)
899 unsigned int size
, rev
= 0, ex
= 0;
902 mop
= dc
->opcode
& 3;
905 rev
= (dc
->ir
>> 9) & 1;
906 ex
= (dc
->ir
>> 10) & 1;
913 if (size
> 4 && (dc
->tb_flags
& MSR_EE_FLAG
)
914 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)) {
915 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
916 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
920 LOG_DIS("l%d%s%s%s\n", size
, dc
->type_b
? "i" : "", rev
? "r" : "",
924 addr
= compute_ldst_addr(dc
, &t
);
927 * When doing reverse accesses we need to do two things.
929 * 1. Reverse the address wrt endianness.
930 * 2. Byteswap the data lanes on the way back into the CPU core.
932 if (rev
&& size
!= 4) {
933 /* Endian reverse the address. t is addr. */
941 TCGv low
= tcg_temp_new();
943 /* Force addr into the temp. */
946 tcg_gen_mov_tl(t
, *addr
);
950 tcg_gen_andi_tl(low
, t
, 3);
951 tcg_gen_sub_tl(low
, tcg_const_tl(3), low
);
952 tcg_gen_andi_tl(t
, t
, ~3);
953 tcg_gen_or_tl(t
, t
, low
);
954 tcg_gen_mov_tl(env_imm
, t
);
962 /* Force addr into the temp. */
965 tcg_gen_xori_tl(t
, *addr
, 2);
968 tcg_gen_xori_tl(t
, t
, 2);
972 cpu_abort(CPU(dc
->cpu
), "Invalid reverse size\n");
977 /* lwx does not throw unaligned access errors, so force alignment */
979 /* Force addr into the temp. */
982 tcg_gen_mov_tl(t
, *addr
);
985 tcg_gen_andi_tl(t
, t
, ~3);
988 /* If we get a fault on a dslot, the jmpstate better be in sync. */
991 /* Verify alignment if needed. */
993 * Microblaze gives MMU faults priority over faults due to
994 * unaligned addresses. That's why we speculatively do the load
995 * into v. If the load succeeds, we verify alignment of the
996 * address and if that succeeds we write into the destination reg.
999 tcg_gen_qemu_ld_tl(v
, *addr
, cpu_mmu_index(&dc
->cpu
->env
, false), mop
);
1001 if ((dc
->cpu
->env
.pvr
.regs
[2] & PVR2_UNALIGNED_EXC_MASK
) && size
> 1) {
1002 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dc
->pc
);
1003 gen_helper_memalign(cpu_env
, *addr
, tcg_const_tl(dc
->rd
),
1004 tcg_const_tl(0), tcg_const_tl(size
- 1));
1008 tcg_gen_mov_tl(env_res_addr
, *addr
);
1009 tcg_gen_mov_tl(env_res_val
, v
);
1012 tcg_gen_mov_tl(cpu_R
[dc
->rd
], v
);
1017 /* no support for AXI exclusive so always clear C */
1018 write_carryi(dc
, 0);
1025 static void dec_store(DisasContext
*dc
)
1027 TCGv t
, *addr
, swx_addr
;
1028 TCGLabel
*swx_skip
= NULL
;
1029 unsigned int size
, rev
= 0, ex
= 0;
1032 mop
= dc
->opcode
& 3;
1035 rev
= (dc
->ir
>> 9) & 1;
1036 ex
= (dc
->ir
>> 10) & 1;
1043 if (size
> 4 && (dc
->tb_flags
& MSR_EE_FLAG
)
1044 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)) {
1045 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
1046 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1050 LOG_DIS("s%d%s%s%s\n", size
, dc
->type_b
? "i" : "", rev
? "r" : "",
1053 /* If we get a fault on a dslot, the jmpstate better be in sync. */
1055 addr
= compute_ldst_addr(dc
, &t
);
1057 swx_addr
= tcg_temp_local_new();
1061 /* Force addr into the swx_addr. */
1062 tcg_gen_mov_tl(swx_addr
, *addr
);
1064 /* swx does not throw unaligned access errors, so force alignment */
1065 tcg_gen_andi_tl(swx_addr
, swx_addr
, ~3);
1067 write_carryi(dc
, 1);
1068 swx_skip
= gen_new_label();
1069 tcg_gen_brcond_tl(TCG_COND_NE
, env_res_addr
, swx_addr
, swx_skip
);
1071 /* Compare the value loaded at lwx with current contents of
1072 the reserved location.
1073 FIXME: This only works for system emulation where we can expect
1074 this compare and the following write to be atomic. For user
1075 emulation we need to add atomicity between threads. */
1076 tval
= tcg_temp_new();
1077 tcg_gen_qemu_ld_tl(tval
, swx_addr
, cpu_mmu_index(&dc
->cpu
->env
, false),
1079 tcg_gen_brcond_tl(TCG_COND_NE
, env_res_val
, tval
, swx_skip
);
1080 write_carryi(dc
, 0);
1081 tcg_temp_free(tval
);
1084 if (rev
&& size
!= 4) {
1085 /* Endian reverse the address. t is addr. */
1093 TCGv low
= tcg_temp_new();
1095 /* Force addr into the temp. */
1098 tcg_gen_mov_tl(t
, *addr
);
1102 tcg_gen_andi_tl(low
, t
, 3);
1103 tcg_gen_sub_tl(low
, tcg_const_tl(3), low
);
1104 tcg_gen_andi_tl(t
, t
, ~3);
1105 tcg_gen_or_tl(t
, t
, low
);
1106 tcg_gen_mov_tl(env_imm
, t
);
1114 /* Force addr into the temp. */
1117 tcg_gen_xori_tl(t
, *addr
, 2);
1120 tcg_gen_xori_tl(t
, t
, 2);
1124 cpu_abort(CPU(dc
->cpu
), "Invalid reverse size\n");
1128 tcg_gen_qemu_st_tl(cpu_R
[dc
->rd
], *addr
, cpu_mmu_index(&dc
->cpu
->env
, false), mop
);
1130 /* Verify alignment if needed. */
1131 if ((dc
->cpu
->env
.pvr
.regs
[2] & PVR2_UNALIGNED_EXC_MASK
) && size
> 1) {
1132 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dc
->pc
);
1133 /* FIXME: if the alignment is wrong, we should restore the value
1134 * in memory. One possible way to achieve this is to probe
1135 * the MMU prior to the memaccess, thay way we could put
1136 * the alignment checks in between the probe and the mem
1139 gen_helper_memalign(cpu_env
, *addr
, tcg_const_tl(dc
->rd
),
1140 tcg_const_tl(1), tcg_const_tl(size
- 1));
1144 gen_set_label(swx_skip
);
1146 tcg_temp_free(swx_addr
);
1152 static inline void eval_cc(DisasContext
*dc
, unsigned int cc
,
1153 TCGv d
, TCGv a
, TCGv b
)
1157 tcg_gen_setcond_tl(TCG_COND_EQ
, d
, a
, b
);
1160 tcg_gen_setcond_tl(TCG_COND_NE
, d
, a
, b
);
1163 tcg_gen_setcond_tl(TCG_COND_LT
, d
, a
, b
);
1166 tcg_gen_setcond_tl(TCG_COND_LE
, d
, a
, b
);
1169 tcg_gen_setcond_tl(TCG_COND_GE
, d
, a
, b
);
1172 tcg_gen_setcond_tl(TCG_COND_GT
, d
, a
, b
);
1175 cpu_abort(CPU(dc
->cpu
), "Unknown condition code %x.\n", cc
);
1180 static void eval_cond_jmp(DisasContext
*dc
, TCGv pc_true
, TCGv pc_false
)
1182 TCGLabel
*l1
= gen_new_label();
1183 /* Conditional jmp. */
1184 tcg_gen_mov_tl(cpu_SR
[SR_PC
], pc_false
);
1185 tcg_gen_brcondi_tl(TCG_COND_EQ
, env_btaken
, 0, l1
);
1186 tcg_gen_mov_tl(cpu_SR
[SR_PC
], pc_true
);
1190 static void dec_bcc(DisasContext
*dc
)
1195 cc
= EXTRACT_FIELD(dc
->ir
, 21, 23);
1196 dslot
= dc
->ir
& (1 << 25);
1197 LOG_DIS("bcc%s r%d %x\n", dslot
? "d" : "", dc
->ra
, dc
->imm
);
1199 dc
->delayed_branch
= 1;
1201 dc
->delayed_branch
= 2;
1202 dc
->tb_flags
|= D_FLAG
;
1203 tcg_gen_st_tl(tcg_const_tl(dc
->type_b
&& (dc
->tb_flags
& IMM_FLAG
)),
1204 cpu_env
, offsetof(CPUMBState
, bimm
));
1207 if (dec_alu_op_b_is_small_imm(dc
)) {
1208 int32_t offset
= (int32_t)((int16_t)dc
->imm
); /* sign-extend. */
1210 tcg_gen_movi_tl(env_btarget
, dc
->pc
+ offset
);
1211 dc
->jmp
= JMP_DIRECT_CC
;
1212 dc
->jmp_pc
= dc
->pc
+ offset
;
1214 dc
->jmp
= JMP_INDIRECT
;
1215 tcg_gen_movi_tl(env_btarget
, dc
->pc
);
1216 tcg_gen_add_tl(env_btarget
, env_btarget
, *(dec_alu_op_b(dc
)));
1218 eval_cc(dc
, cc
, env_btaken
, cpu_R
[dc
->ra
], tcg_const_tl(0));
1221 static void dec_br(DisasContext
*dc
)
1223 unsigned int dslot
, link
, abs
, mbar
;
1224 int mem_index
= cpu_mmu_index(&dc
->cpu
->env
, false);
1226 dslot
= dc
->ir
& (1 << 20);
1227 abs
= dc
->ir
& (1 << 19);
1228 link
= dc
->ir
& (1 << 18);
1230 /* Memory barrier. */
1231 mbar
= (dc
->ir
>> 16) & 31;
1232 if (mbar
== 2 && dc
->imm
== 4) {
1233 /* mbar IMM & 16 decodes to sleep. */
1235 TCGv_i32 tmp_hlt
= tcg_const_i32(EXCP_HLT
);
1236 TCGv_i32 tmp_1
= tcg_const_i32(1);
1241 tcg_gen_st_i32(tmp_1
, cpu_env
,
1242 -offsetof(MicroBlazeCPU
, env
)
1243 +offsetof(CPUState
, halted
));
1244 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dc
->pc
+ 4);
1245 gen_helper_raise_exception(cpu_env
, tmp_hlt
);
1246 tcg_temp_free_i32(tmp_hlt
);
1247 tcg_temp_free_i32(tmp_1
);
1250 LOG_DIS("mbar %d\n", dc
->rd
);
1252 dc
->cpustate_changed
= 1;
1256 LOG_DIS("br%s%s%s%s imm=%x\n",
1257 abs
? "a" : "", link
? "l" : "",
1258 dc
->type_b
? "i" : "", dslot
? "d" : "",
1261 dc
->delayed_branch
= 1;
1263 dc
->delayed_branch
= 2;
1264 dc
->tb_flags
|= D_FLAG
;
1265 tcg_gen_st_tl(tcg_const_tl(dc
->type_b
&& (dc
->tb_flags
& IMM_FLAG
)),
1266 cpu_env
, offsetof(CPUMBState
, bimm
));
1269 tcg_gen_movi_tl(cpu_R
[dc
->rd
], dc
->pc
);
1271 dc
->jmp
= JMP_INDIRECT
;
1273 tcg_gen_movi_tl(env_btaken
, 1);
1274 tcg_gen_mov_tl(env_btarget
, *(dec_alu_op_b(dc
)));
1275 if (link
&& !dslot
) {
1276 if (!(dc
->tb_flags
& IMM_FLAG
) && (dc
->imm
== 8 || dc
->imm
== 0x18))
1277 t_gen_raise_exception(dc
, EXCP_BREAK
);
1279 if ((dc
->tb_flags
& MSR_EE_FLAG
) && mem_index
== MMU_USER_IDX
) {
1280 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
1281 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1285 t_gen_raise_exception(dc
, EXCP_DEBUG
);
1289 if (dec_alu_op_b_is_small_imm(dc
)) {
1290 dc
->jmp
= JMP_DIRECT
;
1291 dc
->jmp_pc
= dc
->pc
+ (int32_t)((int16_t)dc
->imm
);
1293 tcg_gen_movi_tl(env_btaken
, 1);
1294 tcg_gen_movi_tl(env_btarget
, dc
->pc
);
1295 tcg_gen_add_tl(env_btarget
, env_btarget
, *(dec_alu_op_b(dc
)));
1300 static inline void do_rti(DisasContext
*dc
)
1303 t0
= tcg_temp_new();
1304 t1
= tcg_temp_new();
1305 tcg_gen_shri_tl(t0
, cpu_SR
[SR_MSR
], 1);
1306 tcg_gen_ori_tl(t1
, cpu_SR
[SR_MSR
], MSR_IE
);
1307 tcg_gen_andi_tl(t0
, t0
, (MSR_VM
| MSR_UM
));
1309 tcg_gen_andi_tl(t1
, t1
, ~(MSR_VM
| MSR_UM
));
1310 tcg_gen_or_tl(t1
, t1
, t0
);
1314 dc
->tb_flags
&= ~DRTI_FLAG
;
1317 static inline void do_rtb(DisasContext
*dc
)
1320 t0
= tcg_temp_new();
1321 t1
= tcg_temp_new();
1322 tcg_gen_andi_tl(t1
, cpu_SR
[SR_MSR
], ~MSR_BIP
);
1323 tcg_gen_shri_tl(t0
, t1
, 1);
1324 tcg_gen_andi_tl(t0
, t0
, (MSR_VM
| MSR_UM
));
1326 tcg_gen_andi_tl(t1
, t1
, ~(MSR_VM
| MSR_UM
));
1327 tcg_gen_or_tl(t1
, t1
, t0
);
1331 dc
->tb_flags
&= ~DRTB_FLAG
;
1334 static inline void do_rte(DisasContext
*dc
)
1337 t0
= tcg_temp_new();
1338 t1
= tcg_temp_new();
1340 tcg_gen_ori_tl(t1
, cpu_SR
[SR_MSR
], MSR_EE
);
1341 tcg_gen_andi_tl(t1
, t1
, ~MSR_EIP
);
1342 tcg_gen_shri_tl(t0
, t1
, 1);
1343 tcg_gen_andi_tl(t0
, t0
, (MSR_VM
| MSR_UM
));
1345 tcg_gen_andi_tl(t1
, t1
, ~(MSR_VM
| MSR_UM
));
1346 tcg_gen_or_tl(t1
, t1
, t0
);
1350 dc
->tb_flags
&= ~DRTE_FLAG
;
1353 static void dec_rts(DisasContext
*dc
)
1355 unsigned int b_bit
, i_bit
, e_bit
;
1356 int mem_index
= cpu_mmu_index(&dc
->cpu
->env
, false);
1358 i_bit
= dc
->ir
& (1 << 21);
1359 b_bit
= dc
->ir
& (1 << 22);
1360 e_bit
= dc
->ir
& (1 << 23);
1362 dc
->delayed_branch
= 2;
1363 dc
->tb_flags
|= D_FLAG
;
1364 tcg_gen_st_tl(tcg_const_tl(dc
->type_b
&& (dc
->tb_flags
& IMM_FLAG
)),
1365 cpu_env
, offsetof(CPUMBState
, bimm
));
1368 LOG_DIS("rtid ir=%x\n", dc
->ir
);
1369 if ((dc
->tb_flags
& MSR_EE_FLAG
)
1370 && mem_index
== MMU_USER_IDX
) {
1371 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
1372 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1374 dc
->tb_flags
|= DRTI_FLAG
;
1376 LOG_DIS("rtbd ir=%x\n", dc
->ir
);
1377 if ((dc
->tb_flags
& MSR_EE_FLAG
)
1378 && mem_index
== MMU_USER_IDX
) {
1379 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
1380 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1382 dc
->tb_flags
|= DRTB_FLAG
;
1384 LOG_DIS("rted ir=%x\n", dc
->ir
);
1385 if ((dc
->tb_flags
& MSR_EE_FLAG
)
1386 && mem_index
== MMU_USER_IDX
) {
1387 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
1388 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1390 dc
->tb_flags
|= DRTE_FLAG
;
1392 LOG_DIS("rts ir=%x\n", dc
->ir
);
1394 dc
->jmp
= JMP_INDIRECT
;
1395 tcg_gen_movi_tl(env_btaken
, 1);
1396 tcg_gen_add_tl(env_btarget
, cpu_R
[dc
->ra
], *(dec_alu_op_b(dc
)));
1399 static int dec_check_fpuv2(DisasContext
*dc
)
1401 if ((dc
->cpu
->cfg
.use_fpu
!= 2) && (dc
->tb_flags
& MSR_EE_FLAG
)) {
1402 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_FPU
);
1403 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1405 return (dc
->cpu
->cfg
.use_fpu
== 2) ? 0 : PVR2_USE_FPU2_MASK
;
1408 static void dec_fpu(DisasContext
*dc
)
1410 unsigned int fpu_insn
;
1412 if ((dc
->tb_flags
& MSR_EE_FLAG
)
1413 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)
1414 && (dc
->cpu
->cfg
.use_fpu
!= 1)) {
1415 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
1416 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1420 fpu_insn
= (dc
->ir
>> 7) & 7;
1424 gen_helper_fadd(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
],
1429 gen_helper_frsub(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
],
1434 gen_helper_fmul(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
],
1439 gen_helper_fdiv(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
],
1444 switch ((dc
->ir
>> 4) & 7) {
1446 gen_helper_fcmp_un(cpu_R
[dc
->rd
], cpu_env
,
1447 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1450 gen_helper_fcmp_lt(cpu_R
[dc
->rd
], cpu_env
,
1451 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1454 gen_helper_fcmp_eq(cpu_R
[dc
->rd
], cpu_env
,
1455 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1458 gen_helper_fcmp_le(cpu_R
[dc
->rd
], cpu_env
,
1459 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1462 gen_helper_fcmp_gt(cpu_R
[dc
->rd
], cpu_env
,
1463 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1466 gen_helper_fcmp_ne(cpu_R
[dc
->rd
], cpu_env
,
1467 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1470 gen_helper_fcmp_ge(cpu_R
[dc
->rd
], cpu_env
,
1471 cpu_R
[dc
->ra
], cpu_R
[dc
->rb
]);
1474 qemu_log_mask(LOG_UNIMP
,
1475 "unimplemented fcmp fpu_insn=%x pc=%x"
1477 fpu_insn
, dc
->pc
, dc
->opcode
);
1478 dc
->abort_at_next_insn
= 1;
1484 if (!dec_check_fpuv2(dc
)) {
1487 gen_helper_flt(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
]);
1491 if (!dec_check_fpuv2(dc
)) {
1494 gen_helper_fint(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
]);
1498 if (!dec_check_fpuv2(dc
)) {
1501 gen_helper_fsqrt(cpu_R
[dc
->rd
], cpu_env
, cpu_R
[dc
->ra
]);
1505 qemu_log_mask(LOG_UNIMP
, "unimplemented FPU insn fpu_insn=%x pc=%x"
1507 fpu_insn
, dc
->pc
, dc
->opcode
);
1508 dc
->abort_at_next_insn
= 1;
1513 static void dec_null(DisasContext
*dc
)
1515 if ((dc
->tb_flags
& MSR_EE_FLAG
)
1516 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)) {
1517 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
1518 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1521 qemu_log_mask(LOG_GUEST_ERROR
, "unknown insn pc=%x opc=%x\n", dc
->pc
, dc
->opcode
);
1522 dc
->abort_at_next_insn
= 1;
1525 /* Insns connected to FSL or AXI stream attached devices. */
1526 static void dec_stream(DisasContext
*dc
)
1528 int mem_index
= cpu_mmu_index(&dc
->cpu
->env
, false);
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 ((dc
->tb_flags
& MSR_EE_FLAG
) && (mem_index
== MMU_USER_IDX
)) {
1536 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_PRIVINSN
);
1537 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1541 t_id
= tcg_temp_new();
1543 tcg_gen_movi_tl(t_id
, dc
->imm
& 0xf);
1544 ctrl
= dc
->imm
>> 10;
1546 tcg_gen_andi_tl(t_id
, cpu_R
[dc
->rb
], 0xf);
1547 ctrl
= dc
->imm
>> 5;
1550 t_ctrl
= tcg_const_tl(ctrl
);
1553 gen_helper_put(t_id
, t_ctrl
, cpu_R
[dc
->ra
]);
1555 gen_helper_get(cpu_R
[dc
->rd
], t_id
, t_ctrl
);
1557 tcg_temp_free(t_id
);
1558 tcg_temp_free(t_ctrl
);
1561 static struct decoder_info
{
1566 void (*dec
)(DisasContext
*dc
);
1574 {DEC_BARREL
, dec_barrel
},
1576 {DEC_ST
, dec_store
},
1585 {DEC_STREAM
, dec_stream
},
1589 static inline void decode(DisasContext
*dc
, uint32_t ir
)
1594 LOG_DIS("%8.8x\t", dc
->ir
);
1599 if ((dc
->tb_flags
& MSR_EE_FLAG
)
1600 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_ILL_OPCODE_EXC_MASK
)
1601 && (dc
->cpu
->env
.pvr
.regs
[2] & PVR2_OPCODE_0x0_ILL_MASK
)) {
1602 tcg_gen_movi_tl(cpu_SR
[SR_ESR
], ESR_EC_ILLEGAL_OP
);
1603 t_gen_raise_exception(dc
, EXCP_HW_EXCP
);
1607 LOG_DIS("nr_nops=%d\t", dc
->nr_nops
);
1609 if (dc
->nr_nops
> 4) {
1610 cpu_abort(CPU(dc
->cpu
), "fetching nop sequence\n");
1613 /* bit 2 seems to indicate insn type. */
1614 dc
->type_b
= ir
& (1 << 29);
1616 dc
->opcode
= EXTRACT_FIELD(ir
, 26, 31);
1617 dc
->rd
= EXTRACT_FIELD(ir
, 21, 25);
1618 dc
->ra
= EXTRACT_FIELD(ir
, 16, 20);
1619 dc
->rb
= EXTRACT_FIELD(ir
, 11, 15);
1620 dc
->imm
= EXTRACT_FIELD(ir
, 0, 15);
1622 /* Large switch for all insns. */
1623 for (i
= 0; i
< ARRAY_SIZE(decinfo
); i
++) {
1624 if ((dc
->opcode
& decinfo
[i
].mask
) == decinfo
[i
].bits
) {
1631 /* generate intermediate code for basic block 'tb'. */
1632 void gen_intermediate_code(CPUMBState
*env
, struct TranslationBlock
*tb
)
1634 MicroBlazeCPU
*cpu
= mb_env_get_cpu(env
);
1635 CPUState
*cs
= CPU(cpu
);
1637 struct DisasContext ctx
;
1638 struct DisasContext
*dc
= &ctx
;
1639 uint32_t next_page_start
, org_flags
;
1647 org_flags
= dc
->synced_flags
= dc
->tb_flags
= tb
->flags
;
1649 dc
->is_jmp
= DISAS_NEXT
;
1651 dc
->delayed_branch
= !!(dc
->tb_flags
& D_FLAG
);
1652 if (dc
->delayed_branch
) {
1653 dc
->jmp
= JMP_INDIRECT
;
1656 dc
->singlestep_enabled
= cs
->singlestep_enabled
;
1657 dc
->cpustate_changed
= 0;
1658 dc
->abort_at_next_insn
= 0;
1662 cpu_abort(cs
, "Microblaze: unaligned PC=%x\n", pc_start
);
1665 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM
)) {
1667 qemu_log("--------------\n");
1668 log_cpu_state(CPU(cpu
), 0);
1672 next_page_start
= (pc_start
& TARGET_PAGE_MASK
) + TARGET_PAGE_SIZE
;
1674 max_insns
= tb
->cflags
& CF_COUNT_MASK
;
1675 if (max_insns
== 0) {
1676 max_insns
= CF_COUNT_MASK
;
1678 if (max_insns
> TCG_MAX_INSNS
) {
1679 max_insns
= TCG_MAX_INSNS
;
1685 tcg_gen_insn_start(dc
->pc
);
1689 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM
)) {
1690 tcg_gen_movi_tl(cpu_SR
[SR_PC
], dc
->pc
);
1695 if (unlikely(cpu_breakpoint_test(cs
, dc
->pc
, BP_ANY
))) {
1696 t_gen_raise_exception(dc
, EXCP_DEBUG
);
1697 dc
->is_jmp
= DISAS_UPDATE
;
1698 /* The address covered by the breakpoint must be included in
1699 [tb->pc, tb->pc + tb->size) in order to for it to be
1700 properly cleared -- thus we increment the PC here so that
1701 the logic setting tb->size below does the right thing. */
1707 LOG_DIS("%8.8x:\t", dc
->pc
);
1709 if (num_insns
== max_insns
&& (tb
->cflags
& CF_LAST_IO
)) {
1714 decode(dc
, cpu_ldl_code(env
, dc
->pc
));
1716 dc
->tb_flags
&= ~IMM_FLAG
;
1719 if (dc
->delayed_branch
) {
1720 dc
->delayed_branch
--;
1721 if (!dc
->delayed_branch
) {
1722 if (dc
->tb_flags
& DRTI_FLAG
)
1724 if (dc
->tb_flags
& DRTB_FLAG
)
1726 if (dc
->tb_flags
& DRTE_FLAG
)
1728 /* Clear the delay slot flag. */
1729 dc
->tb_flags
&= ~D_FLAG
;
1730 /* If it is a direct jump, try direct chaining. */
1731 if (dc
->jmp
== JMP_INDIRECT
) {
1732 eval_cond_jmp(dc
, env_btarget
, tcg_const_tl(dc
->pc
));
1733 dc
->is_jmp
= DISAS_JUMP
;
1734 } else if (dc
->jmp
== JMP_DIRECT
) {
1736 gen_goto_tb(dc
, 0, dc
->jmp_pc
);
1737 dc
->is_jmp
= DISAS_TB_JUMP
;
1738 } else if (dc
->jmp
== JMP_DIRECT_CC
) {
1739 TCGLabel
*l1
= gen_new_label();
1741 /* Conditional jmp. */
1742 tcg_gen_brcondi_tl(TCG_COND_NE
, env_btaken
, 0, l1
);
1743 gen_goto_tb(dc
, 1, dc
->pc
);
1745 gen_goto_tb(dc
, 0, dc
->jmp_pc
);
1747 dc
->is_jmp
= DISAS_TB_JUMP
;
1752 if (cs
->singlestep_enabled
) {
1755 } while (!dc
->is_jmp
&& !dc
->cpustate_changed
1756 && !tcg_op_buf_full()
1758 && (dc
->pc
< next_page_start
)
1759 && num_insns
< max_insns
);
1762 if (dc
->jmp
== JMP_DIRECT
|| dc
->jmp
== JMP_DIRECT_CC
) {
1763 if (dc
->tb_flags
& D_FLAG
) {
1764 dc
->is_jmp
= DISAS_UPDATE
;
1765 tcg_gen_movi_tl(cpu_SR
[SR_PC
], npc
);
1771 if (tb
->cflags
& CF_LAST_IO
)
1773 /* Force an update if the per-tb cpu state has changed. */
1774 if (dc
->is_jmp
== DISAS_NEXT
1775 && (dc
->cpustate_changed
|| org_flags
!= dc
->tb_flags
)) {
1776 dc
->is_jmp
= DISAS_UPDATE
;
1777 tcg_gen_movi_tl(cpu_SR
[SR_PC
], npc
);
1781 if (unlikely(cs
->singlestep_enabled
)) {
1782 TCGv_i32 tmp
= tcg_const_i32(EXCP_DEBUG
);
1784 if (dc
->is_jmp
!= DISAS_JUMP
) {
1785 tcg_gen_movi_tl(cpu_SR
[SR_PC
], npc
);
1787 gen_helper_raise_exception(cpu_env
, tmp
);
1788 tcg_temp_free_i32(tmp
);
1790 switch(dc
->is_jmp
) {
1792 gen_goto_tb(dc
, 1, npc
);
1797 /* indicate that the hash table must be used
1798 to find the next TB */
1802 /* nothing more to generate */
1806 gen_tb_end(tb
, num_insns
);
1808 tb
->size
= dc
->pc
- pc_start
;
1809 tb
->icount
= num_insns
;
1813 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM
)) {
1816 log_target_disas(cs
, pc_start
, dc
->pc
- pc_start
, 0);
1818 qemu_log("\nisize=%d osize=%d\n",
1819 dc
->pc
- pc_start
, tcg_op_buf_count());
1823 assert(!dc
->abort_at_next_insn
);
1826 void mb_cpu_dump_state(CPUState
*cs
, FILE *f
, fprintf_function cpu_fprintf
,
1829 MicroBlazeCPU
*cpu
= MICROBLAZE_CPU(cs
);
1830 CPUMBState
*env
= &cpu
->env
;
1836 cpu_fprintf(f
, "IN: PC=%x %s\n",
1837 env
->sregs
[SR_PC
], lookup_symbol(env
->sregs
[SR_PC
]));
1838 cpu_fprintf(f
, "rmsr=%x resr=%x rear=%x debug=%x imm=%x iflags=%x fsr=%x\n",
1839 env
->sregs
[SR_MSR
], env
->sregs
[SR_ESR
], env
->sregs
[SR_EAR
],
1840 env
->debug
, env
->imm
, env
->iflags
, env
->sregs
[SR_FSR
]);
1841 cpu_fprintf(f
, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
1842 env
->btaken
, env
->btarget
,
1843 (env
->sregs
[SR_MSR
] & MSR_UM
) ? "user" : "kernel",
1844 (env
->sregs
[SR_MSR
] & MSR_UMS
) ? "user" : "kernel",
1845 (env
->sregs
[SR_MSR
] & MSR_EIP
),
1846 (env
->sregs
[SR_MSR
] & MSR_IE
));
1848 for (i
= 0; i
< 32; i
++) {
1849 cpu_fprintf(f
, "r%2.2d=%8.8x ", i
, env
->regs
[i
]);
1850 if ((i
+ 1) % 4 == 0)
1851 cpu_fprintf(f
, "\n");
1853 cpu_fprintf(f
, "\n\n");
1856 MicroBlazeCPU
*cpu_mb_init(const char *cpu_model
)
1860 cpu
= MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU
));
1862 object_property_set_bool(OBJECT(cpu
), true, "realized", NULL
);
1867 void mb_tcg_init(void)
1871 cpu_env
= tcg_global_reg_new_ptr(TCG_AREG0
, "env");
1873 env_debug
= tcg_global_mem_new(TCG_AREG0
,
1874 offsetof(CPUMBState
, debug
),
1876 env_iflags
= tcg_global_mem_new(TCG_AREG0
,
1877 offsetof(CPUMBState
, iflags
),
1879 env_imm
= tcg_global_mem_new(TCG_AREG0
,
1880 offsetof(CPUMBState
, imm
),
1882 env_btarget
= tcg_global_mem_new(TCG_AREG0
,
1883 offsetof(CPUMBState
, btarget
),
1885 env_btaken
= tcg_global_mem_new(TCG_AREG0
,
1886 offsetof(CPUMBState
, btaken
),
1888 env_res_addr
= tcg_global_mem_new(TCG_AREG0
,
1889 offsetof(CPUMBState
, res_addr
),
1891 env_res_val
= tcg_global_mem_new(TCG_AREG0
,
1892 offsetof(CPUMBState
, res_val
),
1894 for (i
= 0; i
< ARRAY_SIZE(cpu_R
); i
++) {
1895 cpu_R
[i
] = tcg_global_mem_new(TCG_AREG0
,
1896 offsetof(CPUMBState
, regs
[i
]),
1899 for (i
= 0; i
< ARRAY_SIZE(cpu_SR
); i
++) {
1900 cpu_SR
[i
] = tcg_global_mem_new(TCG_AREG0
,
1901 offsetof(CPUMBState
, sregs
[i
]),
1902 special_regnames
[i
]);
1906 void restore_state_to_opc(CPUMBState
*env
, TranslationBlock
*tb
,
1909 env
->sregs
[SR_PC
] = data
[0];