aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2020-08-23 09:17:22 -0700
committerRichard Henderson <richard.henderson@linaro.org>2020-09-01 07:43:35 -0700
commitf523531471c9342020cda0ef5a2eccb7d77e7e34 (patch)
treec52e9f8dba13eb49436ad26f5db75dd7ae19301f /target
parent0c3da918de2ef8b1758d5e11b1c18c4f734c4401 (diff)
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>
Diffstat (limited to 'target')
-rw-r--r--target/microblaze/cpu.h2
-rw-r--r--target/microblaze/helper.c10
-rw-r--r--target/microblaze/insns.decode11
-rw-r--r--target/microblaze/translate.c107
4 files changed, 78 insertions, 52 deletions
diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h
index 63b8d93d41..1528749a0b 100644
--- a/target/microblaze/cpu.h
+++ b/target/microblaze/cpu.h
@@ -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
diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c
index 0e3be251a7..1667822fb7 100644
--- a/target/microblaze/helper.c
+++ b/target/microblaze/helper.c
@@ -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:
diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode
index 47b92b9cbc..9273a51d20 100644
--- a/target/microblaze/insns.decode
+++ b/target/microblaze/insns.decode
@@ -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
diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
index 3b63fd79e5..1c772b95d9 100644
--- a/target/microblaze/translate.c
+++ b/target/microblaze/translate.c
@@ -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);
}