target/microblaze: Convert brk and brki to decodetree
Split these out of the normal branch instructions, as they require special handling. Perform the entire operation inline, instead of raising EXCP_BREAK to do the work in mb_cpu_do_interrupt. This fixes a bug in that brki rd, imm, for imm != 0x18 is not supposed to set MSR_BIP. This fixes a bug in that imm == 0 is the reset vector and 0x18 is the debug vector, and neither should raise a tcg exception in system mode. Introduce EXCP_SYSCALL for microblaze-linux-user. 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
0c3da918de
commit
f523531471
@ -48,7 +48,7 @@ void cpu_loop(CPUMBState *env)
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
case EXCP_BREAK:
|
||||
case EXCP_SYSCALL:
|
||||
/* Return address is 4 bytes after the call. */
|
||||
env->regs[14] += 4;
|
||||
env->pc = env->regs[14];
|
||||
|
@ -31,7 +31,7 @@ typedef struct CPUMBState CPUMBState;
|
||||
|
||||
#define EXCP_MMU 1
|
||||
#define EXCP_IRQ 2
|
||||
#define EXCP_BREAK 3
|
||||
#define EXCP_SYSCALL 3 /* user-only */
|
||||
#define EXCP_HW_BREAK 4
|
||||
#define EXCP_HW_EXCP 5
|
||||
|
||||
|
@ -230,7 +230,6 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||
//log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
break;
|
||||
|
||||
case EXCP_BREAK:
|
||||
case EXCP_HW_BREAK:
|
||||
assert(!(env->iflags & IMM_FLAG));
|
||||
assert(!(env->iflags & D_FLAG));
|
||||
@ -242,13 +241,8 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||
msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
|
||||
msr |= t;
|
||||
msr |= MSR_BIP;
|
||||
if (cs->exception_index == EXCP_HW_BREAK) {
|
||||
env->regs[16] = env->pc;
|
||||
msr |= MSR_BIP;
|
||||
env->pc = cpu->cfg.base_vectors + 0x18;
|
||||
} else {
|
||||
env->pc = env->btarget;
|
||||
}
|
||||
env->regs[16] = env->pc;
|
||||
env->pc = cpu->cfg.base_vectors + 0x18;
|
||||
mb_cpu_write_msr(env, msr);
|
||||
break;
|
||||
default:
|
||||
|
@ -19,7 +19,9 @@
|
||||
|
||||
&typea0 rd ra
|
||||
&typea rd ra rb
|
||||
&typea_br rd rb
|
||||
&typeb rd ra imm
|
||||
&typeb_br rd imm
|
||||
|
||||
# Include any IMM prefix in the value reported.
|
||||
%extimm 0:s16 !function=typeb_imm
|
||||
@ -30,9 +32,15 @@
|
||||
# Officially typea, but with rb==0, which is not used.
|
||||
@typea0 ...... rd:5 ra:5 ................ &typea0
|
||||
|
||||
# Officially typea, but with ra as opcode.
|
||||
@typea_br ...... rd:5 ..... rb:5 ........... &typea_br
|
||||
|
||||
# Officially typeb, but any immediate extension is unused.
|
||||
@typeb_bs ...... rd:5 ra:5 ..... ...... imm:5 &typeb
|
||||
|
||||
# Officially typeb, but with ra as opcode.
|
||||
@typeb_br ...... rd:5 ..... ................ &typeb_br imm=%extimm
|
||||
|
||||
# For convenience, extract the two imm_w/imm_s fields, then pack
|
||||
# them back together as "imm". Doing this makes it easiest to
|
||||
# match the required zero at bit 5.
|
||||
@ -60,6 +68,9 @@ andi 101001 ..... ..... ................ @typeb
|
||||
andn 100011 ..... ..... ..... 000 0000 0000 @typea
|
||||
andni 101011 ..... ..... ................ @typeb
|
||||
|
||||
brk 100110 ..... 01100 ..... 000 0000 0000 @typea_br
|
||||
brki 101110 ..... 01100 ................ @typeb_br
|
||||
|
||||
bsrl 010001 ..... ..... ..... 000 0000 0000 @typea
|
||||
bsra 010001 ..... ..... ..... 010 0000 0000 @typea
|
||||
bsll 010001 ..... ..... ..... 100 0000 0000 @typea
|
||||
|
@ -1068,6 +1068,65 @@ static bool trans_swx(DisasContext *dc, arg_typea *arg)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
|
||||
{
|
||||
if (trap_userspace(dc, true)) {
|
||||
return true;
|
||||
}
|
||||
tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
|
||||
if (arg->rd) {
|
||||
tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
|
||||
}
|
||||
tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
|
||||
tcg_gen_movi_tl(cpu_res_addr, -1);
|
||||
|
||||
dc->base.is_jmp = DISAS_UPDATE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
|
||||
{
|
||||
uint32_t imm = arg->imm;
|
||||
|
||||
if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
|
||||
return true;
|
||||
}
|
||||
tcg_gen_movi_i32(cpu_pc, imm);
|
||||
if (arg->rd) {
|
||||
tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
|
||||
}
|
||||
tcg_gen_movi_tl(cpu_res_addr, -1);
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
switch (imm) {
|
||||
case 0x8: /* syscall trap */
|
||||
gen_raise_exception_sync(dc, EXCP_SYSCALL);
|
||||
break;
|
||||
case 0x18: /* debug trap */
|
||||
gen_raise_exception_sync(dc, EXCP_DEBUG);
|
||||
break;
|
||||
default: /* eliminated with trap_userspace check */
|
||||
g_assert_not_reached();
|
||||
}
|
||||
#else
|
||||
uint32_t msr_to_set = 0;
|
||||
|
||||
if (imm != 0x18) {
|
||||
msr_to_set |= MSR_BIP;
|
||||
}
|
||||
if (imm == 0x8 || imm == 0x18) {
|
||||
/* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
|
||||
msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
|
||||
tcg_gen_andi_i32(cpu_msr, cpu_msr,
|
||||
~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
|
||||
}
|
||||
tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
|
||||
dc->base.is_jmp = DISAS_UPDATE;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_zero(DisasContext *dc, arg_zero *arg)
|
||||
{
|
||||
/* If opcode_0_illegal, trap. */
|
||||
@ -1359,6 +1418,7 @@ static void dec_bcc(DisasContext *dc)
|
||||
static void dec_br(DisasContext *dc)
|
||||
{
|
||||
unsigned int dslot, link, abs, mbar;
|
||||
uint32_t add_pc;
|
||||
|
||||
dslot = dc->ir & (1 << 20);
|
||||
abs = dc->ir & (1 << 19);
|
||||
@ -1401,21 +1461,6 @@ static void dec_br(DisasContext *dc)
|
||||
return;
|
||||
}
|
||||
|
||||
if (abs && link && !dslot) {
|
||||
if (dc->type_b) {
|
||||
/* BRKI */
|
||||
uint32_t imm = dec_alu_typeb_imm(dc);
|
||||
if (trap_userspace(dc, imm != 8 && imm != 0x18)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* BRK */
|
||||
if (trap_userspace(dc, true)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dslot) {
|
||||
dec_setup_dslot(dc);
|
||||
}
|
||||
@ -1423,38 +1468,14 @@ static void dec_br(DisasContext *dc)
|
||||
tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next);
|
||||
}
|
||||
|
||||
if (abs) {
|
||||
if (dc->type_b) {
|
||||
uint32_t dest = dec_alu_typeb_imm(dc);
|
||||
|
||||
dc->jmp = JMP_DIRECT;
|
||||
dc->jmp_pc = dest;
|
||||
tcg_gen_movi_i32(cpu_btarget, dest);
|
||||
if (link && !dslot) {
|
||||
switch (dest) {
|
||||
case 8:
|
||||
case 0x18:
|
||||
gen_raise_exception_sync(dc, EXCP_BREAK);
|
||||
break;
|
||||
case 0:
|
||||
gen_raise_exception_sync(dc, EXCP_DEBUG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dc->jmp = JMP_INDIRECT;
|
||||
tcg_gen_mov_i32(cpu_btarget, cpu_R[dc->rb]);
|
||||
if (link && !dslot) {
|
||||
gen_raise_exception_sync(dc, EXCP_BREAK);
|
||||
}
|
||||
}
|
||||
} else if (dc->type_b) {
|
||||
add_pc = abs ? 0 : dc->base.pc_next;
|
||||
if (dc->type_b) {
|
||||
dc->jmp = JMP_DIRECT;
|
||||
dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc);
|
||||
dc->jmp_pc = add_pc + dec_alu_typeb_imm(dc);
|
||||
tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
|
||||
} else {
|
||||
dc->jmp = JMP_INDIRECT;
|
||||
tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next);
|
||||
tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], add_pc);
|
||||
}
|
||||
tcg_gen_movi_i32(cpu_btaken, 1);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user