mirror of https://gitee.com/openkylin/qemu.git
target/microblaze: Convert mbar to decodetree
Split this out of the normal branch instructions, as it requires special handling. Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
f523531471
commit
ee8c7f9f9a
|
@ -127,6 +127,8 @@ lwea 110010 ..... ..... ..... 0001 000 0000 @typea
|
|||
lwx 110010 ..... ..... ..... 1000 000 0000 @typea
|
||||
lwi 111010 ..... ..... ................ @typeb
|
||||
|
||||
mbar 101110 imm:5 00010 0000 0000 0000 0100
|
||||
|
||||
mul 010000 ..... ..... ..... 000 0000 0000 @typea
|
||||
mulh 010000 ..... ..... ..... 000 0000 0001 @typea
|
||||
mulhu 010000 ..... ..... ..... 000 0000 0011 @typea
|
||||
|
|
|
@ -1127,6 +1127,52 @@ static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
|
||||
{
|
||||
int mbar_imm = arg->imm;
|
||||
|
||||
/* Data access memory barrier. */
|
||||
if ((mbar_imm & 2) == 0) {
|
||||
tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
|
||||
}
|
||||
|
||||
/* Sleep. */
|
||||
if (mbar_imm & 16) {
|
||||
TCGv_i32 tmp_1;
|
||||
|
||||
if (trap_userspace(dc, true)) {
|
||||
/* Sleep is a privileged instruction. */
|
||||
return true;
|
||||
}
|
||||
|
||||
t_sync_flags(dc);
|
||||
|
||||
tmp_1 = tcg_const_i32(1);
|
||||
tcg_gen_st_i32(tmp_1, cpu_env,
|
||||
-offsetof(MicroBlazeCPU, env)
|
||||
+offsetof(CPUState, halted));
|
||||
tcg_temp_free_i32(tmp_1);
|
||||
|
||||
tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
|
||||
|
||||
gen_raise_exception(dc, EXCP_HLT);
|
||||
}
|
||||
|
||||
/*
|
||||
* If !(mbar_imm & 1), this is an instruction access memory barrier
|
||||
* and we need to end the TB so that we recognize self-modified
|
||||
* code immediately.
|
||||
*
|
||||
* However, there are some data mbars that need the TB break
|
||||
* (and return to main loop) to recognize interrupts right away.
|
||||
* E.g. recognizing a change to an interrupt controller register.
|
||||
*
|
||||
* Therefore, choose to end the TB always.
|
||||
*/
|
||||
dc->cpustate_changed = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_zero(DisasContext *dc, arg_zero *arg)
|
||||
{
|
||||
/* If opcode_0_illegal, trap. */
|
||||
|
@ -1417,50 +1463,13 @@ static void dec_bcc(DisasContext *dc)
|
|||
|
||||
static void dec_br(DisasContext *dc)
|
||||
{
|
||||
unsigned int dslot, link, abs, mbar;
|
||||
unsigned int dslot, link, abs;
|
||||
uint32_t add_pc;
|
||||
|
||||
dslot = dc->ir & (1 << 20);
|
||||
abs = dc->ir & (1 << 19);
|
||||
link = dc->ir & (1 << 18);
|
||||
|
||||
/* Memory barrier. */
|
||||
mbar = (dc->ir >> 16) & 31;
|
||||
if (mbar == 2 && dc->imm == 4) {
|
||||
uint16_t mbar_imm = dc->rd;
|
||||
|
||||
/* Data access memory barrier. */
|
||||
if ((mbar_imm & 2) == 0) {
|
||||
tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
|
||||
}
|
||||
|
||||
/* mbar IMM & 16 decodes to sleep. */
|
||||
if (mbar_imm & 16) {
|
||||
TCGv_i32 tmp_1;
|
||||
|
||||
if (trap_userspace(dc, true)) {
|
||||
/* Sleep is a privileged instruction. */
|
||||
return;
|
||||
}
|
||||
|
||||
t_sync_flags(dc);
|
||||
|
||||
tmp_1 = tcg_const_i32(1);
|
||||
tcg_gen_st_i32(tmp_1, cpu_env,
|
||||
-offsetof(MicroBlazeCPU, env)
|
||||
+offsetof(CPUState, halted));
|
||||
tcg_temp_free_i32(tmp_1);
|
||||
|
||||
tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
|
||||
|
||||
gen_raise_exception(dc, EXCP_HLT);
|
||||
return;
|
||||
}
|
||||
/* Break the TB. */
|
||||
dc->cpustate_changed = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (dslot) {
|
||||
dec_setup_dslot(dc);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue