From cdc05fb4c3b47c5f2d1abd71dbec034436012056 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Aug 2020 13:10:47 -0700 Subject: [PATCH 01/76] tests/tcg: Add microblaze to arches filter Not attempting to use a single cross-compiler for both big-endian and little-endian at this time. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- tests/tcg/configure.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh index 7d714f902a..598a50cd4f 100755 --- a/tests/tcg/configure.sh +++ b/tests/tcg/configure.sh @@ -94,7 +94,7 @@ for target in $target_list; do xtensa|xtensaeb) arches=xtensa ;; - alpha|cris|hppa|i386|lm32|m68k|openrisc|riscv64|s390x|sh4|sparc64) + alpha|cris|hppa|i386|lm32|microblaze|microblazeel|m68k|openrisc|riscv64|s390x|sh4|sparc64) arches=$target ;; *) From 4c71dc37fb56bd41893c74cb5d164a2a009e8a1f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Aug 2020 13:11:43 -0700 Subject: [PATCH 02/76] tests/tcg: Do not require FE_TOWARDZERO This is optional in ISO C, and not all cpus provide it. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- tests/tcg/multiarch/float_convs.c | 2 ++ tests/tcg/multiarch/float_madds.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/tcg/multiarch/float_convs.c b/tests/tcg/multiarch/float_convs.c index 47e24b8b16..e9be75c2d5 100644 --- a/tests/tcg/multiarch/float_convs.c +++ b/tests/tcg/multiarch/float_convs.c @@ -30,7 +30,9 @@ float_mapping round_flags[] = { #ifdef FE_DOWNWARD { FE_DOWNWARD, "downwards" }, #endif +#ifdef FE_TOWARDZERO { FE_TOWARDZERO, "to zero" } +#endif }; static void print_input(float input) diff --git a/tests/tcg/multiarch/float_madds.c b/tests/tcg/multiarch/float_madds.c index eceb4ae38b..e422608ccd 100644 --- a/tests/tcg/multiarch/float_madds.c +++ b/tests/tcg/multiarch/float_madds.c @@ -29,7 +29,9 @@ float_mapping round_flags[] = { #ifdef FE_DOWNWARD { FE_DOWNWARD, "downwards" }, #endif +#ifdef FE_TOWARDZERO { FE_TOWARDZERO, "to zero" } +#endif }; From 853c93ed0d7d462224a6d74c474cf89981a2561b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Aug 2020 13:12:53 -0700 Subject: [PATCH 03/76] tests/tcg: Do not require FE_* exception bits Define anything that is missing as 0, so that flags & FE_FOO is false for any missing FOO. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- tests/tcg/multiarch/float_helpers.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/tcg/multiarch/float_helpers.h b/tests/tcg/multiarch/float_helpers.h index 6337bc66c1..309f3f4bf1 100644 --- a/tests/tcg/multiarch/float_helpers.h +++ b/tests/tcg/multiarch/float_helpers.h @@ -8,6 +8,23 @@ #include +/* Some hosts do not have support for all of these; not required by ISO C. */ +#ifndef FE_OVERFLOW +#define FE_OVERFLOW 0 +#endif +#ifndef FE_UNDERFLOW +#define FE_UNDERFLOW 0 +#endif +#ifndef FE_DIVBYZERO +#define FE_DIVBYZERO 0 +#endif +#ifndef FE_INEXACT +#define FE_INEXACT 0 +#endif +#ifndef FE_INVALID +#define FE_INVALID 0 +#endif + /* Number of constants in each table */ int get_num_f16(void); int get_num_f32(void); From 8a42ddf013738a15c9cb739b9dfc07500cb27a21 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Aug 2020 11:26:59 -0700 Subject: [PATCH 04/76] target/microblaze: Tidy gdbstub Use an enumeration for the gdb register mapping. Use one switch statement for the entire dispatch. Drop sreg_map and simply enumerate those cases explicitly. Force r0 to have value 0 and ignore writes. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/gdbstub.c | 193 +++++++++++++++++++----------------- 1 file changed, 101 insertions(+), 92 deletions(-) diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c index 73e8973597..e65ec051a5 100644 --- a/target/microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c @@ -21,58 +21,80 @@ #include "cpu.h" #include "exec/gdbstub.h" +/* + * GDB expects SREGs in the following order: + * PC, MSR, EAR, ESR, FSR, BTR, EDR, PID, ZPR, TLBX, TLBSX, TLBLO, TLBHI. + * + * PID, ZPR, TLBx, TLBsx, TLBLO, and TLBHI aren't modeled, so we don't + * map them to anything and return a value of 0 instead. + */ + +enum { + GDB_PC = 32 + 0, + GDB_MSR = 32 + 1, + GDB_EAR = 32 + 2, + GDB_ESR = 32 + 3, + GDB_FSR = 32 + 4, + GDB_BTR = 32 + 5, + GDB_PVR0 = 32 + 6, + GDB_PVR11 = 32 + 17, + GDB_EDR = 32 + 18, + GDB_SLR = 32 + 25, + GDB_SHR = 32 + 26, +}; + int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); + CPUClass *cc = CPU_GET_CLASS(cs); CPUMBState *env = &cpu->env; - /* - * GDB expects SREGs in the following order: - * PC, MSR, EAR, ESR, FSR, BTR, EDR, PID, ZPR, TLBX, TLBSX, TLBLO, TLBHI. - * They aren't stored in this order, so make a map. - * PID, ZPR, TLBx, TLBsx, TLBLO, and TLBHI aren't modeled, so we don't - * map them to anything and return a value of 0 instead. - */ - static const uint8_t sreg_map[6] = { - SR_PC, - SR_MSR, - SR_EAR, - SR_ESR, - SR_FSR, - SR_BTR - }; + uint32_t val; - /* - * GDB expects registers to be reported in this order: - * R0-R31 - * PC-BTR - * PVR0-PVR11 - * EDR-TLBHI - * SLR-SHR - */ - if (n < 32) { - return gdb_get_reg32(mem_buf, env->regs[n]); - } else { - n -= 32; - switch (n) { - case 0 ... 5: - return gdb_get_reg32(mem_buf, env->sregs[sreg_map[n]]); - /* PVR12 is intentionally skipped */ - case 6 ... 17: - n -= 6; - return gdb_get_reg32(mem_buf, env->pvr.regs[n]); - case 18: - return gdb_get_reg32(mem_buf, env->sregs[SR_EDR]); - /* Other SRegs aren't modeled, so report a value of 0 */ - case 19 ... 24: - return gdb_get_reg32(mem_buf, 0); - case 25: - return gdb_get_reg32(mem_buf, env->slr); - case 26: - return gdb_get_reg32(mem_buf, env->shr); - default: - return 0; - } + if (n > cc->gdb_num_core_regs) { + return 0; } + + switch (n) { + case 1 ... 31: + val = env->regs[n]; + break; + case GDB_PC: + val = env->sregs[SR_PC]; + break; + case GDB_MSR: + val = env->sregs[SR_MSR]; + break; + case GDB_EAR: + val = env->sregs[SR_EAR]; + break; + case GDB_ESR: + val = env->sregs[SR_ESR]; + break; + case GDB_FSR: + val = env->sregs[SR_FSR]; + break; + case GDB_BTR: + val = env->sregs[SR_BTR]; + break; + case GDB_PVR0 ... GDB_PVR11: + /* PVR12 is intentionally skipped */ + val = env->pvr.regs[n - GDB_PVR0]; + break; + case GDB_EDR: + val = env->sregs[SR_EDR]; + break; + case GDB_SLR: + val = env->slr; + break; + case GDB_SHR: + val = env->shr; + break; + default: + /* Other SRegs aren't modeled, so report a value of 0 */ + val = 0; + break; + } + return gdb_get_reg32(mem_buf, val); } int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) @@ -82,60 +104,47 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) CPUMBState *env = &cpu->env; uint32_t tmp; - /* - * GDB expects SREGs in the following order: - * PC, MSR, EAR, ESR, FSR, BTR, EDR, PID, ZPR, TLBX, TLBSX, TLBLO, TLBHI. - * They aren't stored in this order, so make a map. - * PID, ZPR, TLBx, TLBsx, TLBLO, and TLBHI aren't modeled, so we don't - * map them to anything. - */ - static const uint8_t sreg_map[6] = { - SR_PC, - SR_MSR, - SR_EAR, - SR_ESR, - SR_FSR, - SR_BTR - }; - if (n > cc->gdb_num_core_regs) { return 0; } tmp = ldl_p(mem_buf); - /* - * GDB expects registers to be reported in this order: - * R0-R31 - * PC-BTR - * PVR0-PVR11 - * EDR-TLBHI - * SLR-SHR - */ - if (n < 32) { + switch (n) { + case 1 ... 31: env->regs[n] = tmp; - } else { - n -= 32; - switch (n) { - case 0 ... 5: - env->sregs[sreg_map[n]] = tmp; - break; + break; + case GDB_PC: + env->sregs[SR_PC] = tmp; + break; + case GDB_MSR: + env->sregs[SR_MSR] = tmp; + break; + case GDB_EAR: + env->sregs[SR_EAR] = tmp; + break; + case GDB_ESR: + env->sregs[SR_ESR] = tmp; + break; + case GDB_FSR: + env->sregs[SR_FSR] = tmp; + break; + case GDB_BTR: + env->sregs[SR_BTR] = tmp; + break; + case GDB_PVR0 ... GDB_PVR11: /* PVR12 is intentionally skipped */ - case 6 ... 17: - n -= 6; - env->pvr.regs[n] = tmp; - break; - /* Only EDR is modeled in these indeces, so ignore the rest */ - case 18: - env->sregs[SR_EDR] = tmp; - break; - case 25: - env->slr = tmp; - break; - case 26: - env->shr = tmp; - break; - } + env->pvr.regs[n - GDB_PVR0] = tmp; + break; + case GDB_EDR: + env->sregs[SR_EDR] = tmp; + break; + case GDB_SLR: + env->slr = tmp; + break; + case GDB_SHR: + env->shr = tmp; + break; } return 4; } From 76e8187d0078e6b926a9a648fb755df4dd266e05 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 21:33:32 -0700 Subject: [PATCH 05/76] target/microblaze: Split out PC from env->sregs Begin eliminating the sregs array in favor of individual members. Does not correct the width of pc, yet. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- linux-user/microblaze/cpu_loop.c | 12 +++++------ linux-user/microblaze/signal.c | 8 ++++---- target/microblaze/cpu.c | 4 ++-- target/microblaze/cpu.h | 3 ++- target/microblaze/gdbstub.c | 4 ++-- target/microblaze/helper.c | 34 ++++++++++++++++---------------- target/microblaze/mmu.c | 2 +- target/microblaze/op_helper.c | 2 +- target/microblaze/translate.c | 10 +++++++--- 9 files changed, 42 insertions(+), 37 deletions(-) diff --git a/linux-user/microblaze/cpu_loop.c b/linux-user/microblaze/cpu_loop.c index 3e0a7f730b..3c693086f4 100644 --- a/linux-user/microblaze/cpu_loop.c +++ b/linux-user/microblaze/cpu_loop.c @@ -51,7 +51,7 @@ void cpu_loop(CPUMBState *env) case EXCP_BREAK: /* Return address is 4 bytes after the call. */ env->regs[14] += 4; - env->sregs[SR_PC] = env->regs[14]; + env->pc = env->regs[14]; ret = do_syscall(env, env->regs[12], env->regs[5], @@ -63,7 +63,7 @@ void cpu_loop(CPUMBState *env) 0, 0); if (ret == -TARGET_ERESTARTSYS) { /* Wind back to before the syscall. */ - env->sregs[SR_PC] -= 4; + env->pc -= 4; } else if (ret != -TARGET_QEMU_ESIGRETURN) { env->regs[3] = ret; } @@ -73,13 +73,13 @@ void cpu_loop(CPUMBState *env) * not a userspace-usable register, as the kernel may clobber it * at any point.) */ - env->regs[14] = env->sregs[SR_PC]; + env->regs[14] = env->pc; break; case EXCP_HW_EXCP: - env->regs[17] = env->sregs[SR_PC] + 4; + env->regs[17] = env->pc + 4; if (env->iflags & D_FLAG) { env->sregs[SR_ESR] |= 1 << 12; - env->sregs[SR_PC] -= 4; + env->pc -= 4; /* FIXME: if branch was immed, replay the imm as well. */ } @@ -165,5 +165,5 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) env->regs[29] = regs->r29; env->regs[30] = regs->r30; env->regs[31] = regs->r31; - env->sregs[SR_PC] = regs->pc; + env->pc = regs->pc; } diff --git a/linux-user/microblaze/signal.c b/linux-user/microblaze/signal.c index 80950c2181..b4eeef4673 100644 --- a/linux-user/microblaze/signal.c +++ b/linux-user/microblaze/signal.c @@ -87,7 +87,7 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env) __put_user(env->regs[29], &sc->regs.r29); __put_user(env->regs[30], &sc->regs.r30); __put_user(env->regs[31], &sc->regs.r31); - __put_user(env->sregs[SR_PC], &sc->regs.pc); + __put_user(env->pc, &sc->regs.pc); } static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env) @@ -124,7 +124,7 @@ static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env) __get_user(env->regs[29], &sc->regs.r29); __get_user(env->regs[30], &sc->regs.r30); __get_user(env->regs[31], &sc->regs.r31); - __get_user(env->sregs[SR_PC], &sc->regs.pc); + __get_user(env->pc, &sc->regs.pc); } static abi_ulong get_sigframe(struct target_sigaction *ka, @@ -188,7 +188,7 @@ void setup_frame(int sig, struct target_sigaction *ka, env->regs[7] = frame_addr += offsetof(typeof(*frame), uc); /* Offset of 4 to handle microblaze rtid r14, 0 */ - env->sregs[SR_PC] = (unsigned long)ka->_sa_handler; + env->pc = (unsigned long)ka->_sa_handler; unlock_user_struct(frame, frame_addr, 1); return; @@ -228,7 +228,7 @@ long do_sigreturn(CPUMBState *env) restore_sigcontext(&frame->uc.tuc_mcontext, env); /* We got here through a sigreturn syscall, our path back is via an rtb insn so setup r14 for that. */ - env->regs[14] = env->sregs[SR_PC]; + env->regs[14] = env->pc; unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 51e5c85b10..bde9992535 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -79,7 +79,7 @@ static void mb_cpu_set_pc(CPUState *cs, vaddr value) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); - cpu->env.sregs[SR_PC] = value; + cpu->env.pc = value; } static bool mb_cpu_has_work(CPUState *cs) @@ -117,7 +117,7 @@ static void mb_cpu_reset(DeviceState *dev) /* Disable stack protector. */ env->shr = ~0; - env->sregs[SR_PC] = cpu->cfg.base_vectors; + env->pc = cpu->cfg.base_vectors; #if defined(CONFIG_USER_ONLY) /* start in user mode with interrupts enabled. */ diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index a31134b65c..d1f91bb318 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -236,6 +236,7 @@ struct CPUMBState { uint32_t imm; uint32_t regs[32]; + uint64_t pc; uint64_t sregs[14]; float_status fp_status; /* Stack protectors. Yes, it's a hw feature. */ @@ -351,7 +352,7 @@ typedef MicroBlazeCPU ArchCPU; static inline void cpu_get_tb_cpu_state(CPUMBState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { - *pc = env->sregs[SR_PC]; + *pc = env->pc; *cs_base = 0; *flags = (env->iflags & IFLAGS_TB_MASK) | (env->sregs[SR_MSR] & (MSR_UM | MSR_VM | MSR_EE)); diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c index e65ec051a5..9ea31f8d2f 100644 --- a/target/microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c @@ -59,7 +59,7 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) val = env->regs[n]; break; case GDB_PC: - val = env->sregs[SR_PC]; + val = env->pc; break; case GDB_MSR: val = env->sregs[SR_MSR]; @@ -115,7 +115,7 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->regs[n] = tmp; break; case GDB_PC: - env->sregs[SR_PC] = tmp; + env->pc = tmp; break; case GDB_MSR: env->sregs[SR_MSR] = tmp; diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index ab2ceeb055..5c392deea4 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -35,7 +35,7 @@ void mb_cpu_do_interrupt(CPUState *cs) cs->exception_index = -1; env->res_addr = RES_ADDR_NONE; - env->regs[14] = env->sregs[SR_PC]; + env->regs[14] = env->pc; } bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size, @@ -126,7 +126,7 @@ void mb_cpu_do_interrupt(CPUState *cs) return; } - env->regs[17] = env->sregs[SR_PC] + 4; + env->regs[17] = env->pc + 4; env->sregs[SR_ESR] &= ~(1 << 12); /* Exception breaks branch + dslot sequence? */ @@ -145,15 +145,15 @@ void mb_cpu_do_interrupt(CPUState *cs) qemu_log_mask(CPU_LOG_INT, "hw exception at pc=%" PRIx64 " ear=%" PRIx64 " " "esr=%" PRIx64 " iflags=%x\n", - env->sregs[SR_PC], env->sregs[SR_EAR], + env->pc, env->sregs[SR_EAR], env->sregs[SR_ESR], env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); env->iflags &= ~(IMM_FLAG | D_FLAG); - env->sregs[SR_PC] = cpu->cfg.base_vectors + 0x20; + env->pc = cpu->cfg.base_vectors + 0x20; break; case EXCP_MMU: - env->regs[17] = env->sregs[SR_PC]; + env->regs[17] = env->pc; env->sregs[SR_ESR] &= ~(1 << 12); /* Exception breaks branch + dslot sequence? */ @@ -169,7 +169,7 @@ void mb_cpu_do_interrupt(CPUState *cs) qemu_log_mask(CPU_LOG_INT, "bimm exception at pc=%" PRIx64 " " "iflags=%x\n", - env->sregs[SR_PC], env->iflags); + env->pc, env->iflags); env->regs[17] -= 4; log_cpu_state_mask(CPU_LOG_INT, cs, 0); } @@ -188,10 +188,10 @@ void mb_cpu_do_interrupt(CPUState *cs) qemu_log_mask(CPU_LOG_INT, "exception at pc=%" PRIx64 " ear=%" PRIx64 " " "iflags=%x\n", - env->sregs[SR_PC], env->sregs[SR_EAR], env->iflags); + env->pc, env->sregs[SR_EAR], env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); env->iflags &= ~(IMM_FLAG | D_FLAG); - env->sregs[SR_PC] = cpu->cfg.base_vectors + 0x20; + env->pc = cpu->cfg.base_vectors + 0x20; break; case EXCP_IRQ: @@ -209,14 +209,14 @@ void mb_cpu_do_interrupt(CPUState *cs) { const char *sym; - sym = lookup_symbol(env->sregs[SR_PC]); + sym = lookup_symbol(env->pc); if (sym && (!strcmp("netif_rx", sym) || !strcmp("process_backlog", sym))) { qemu_log( "interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n", - env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags, + env->pc, env->sregs[SR_MSR], t, env->iflags, sym); log_cpu_state(cs, 0); @@ -226,14 +226,14 @@ void mb_cpu_do_interrupt(CPUState *cs) qemu_log_mask(CPU_LOG_INT, "interrupt at pc=%" PRIx64 " msr=%" PRIx64 " %x " "iflags=%x\n", - env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags); + env->pc, env->sregs[SR_MSR], t, env->iflags); env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \ | MSR_UM | MSR_IE); env->sregs[SR_MSR] |= t; - env->regs[14] = env->sregs[SR_PC]; - env->sregs[SR_PC] = cpu->cfg.base_vectors + 0x10; + env->regs[14] = env->pc; + env->pc = cpu->cfg.base_vectors + 0x10; //log_cpu_state_mask(CPU_LOG_INT, cs, 0); break; @@ -245,17 +245,17 @@ void mb_cpu_do_interrupt(CPUState *cs) qemu_log_mask(CPU_LOG_INT, "break at pc=%" PRIx64 " msr=%" PRIx64 " %x " "iflags=%x\n", - env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags); + env->pc, env->sregs[SR_MSR], t, env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); env->sregs[SR_MSR] |= t; env->sregs[SR_MSR] |= MSR_BIP; if (cs->exception_index == EXCP_HW_BREAK) { - env->regs[16] = env->sregs[SR_PC]; + env->regs[16] = env->pc; env->sregs[SR_MSR] |= MSR_BIP; - env->sregs[SR_PC] = cpu->cfg.base_vectors + 0x18; + env->pc = cpu->cfg.base_vectors + 0x18; } else - env->sregs[SR_PC] = env->btarget; + env->pc = env->btarget; break; default: cpu_abort(cs, "unhandled exception type=%d\n", diff --git a/target/microblaze/mmu.c b/target/microblaze/mmu.c index 6763421ba2..3f403b567b 100644 --- a/target/microblaze/mmu.c +++ b/target/microblaze/mmu.c @@ -251,7 +251,7 @@ void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v) if (i < 3 && !(v & TLB_VALID) && qemu_loglevel_mask(~0)) qemu_log_mask(LOG_GUEST_ERROR, "invalidating index %x at pc=%" PRIx64 "\n", - i, env->sregs[SR_PC]); + i, env->pc); env->mmu.tids[i] = env->mmu.regs[MMU_R_PID] & 0xff; mmu_flush_idx(env, i); } diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index f3b17a95b3..2deef32740 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -75,7 +75,7 @@ void helper_debug(CPUMBState *env) { int i; - qemu_log("PC=%" PRIx64 "\n", env->sregs[SR_PC]); + qemu_log("PC=%" PRIx64 "\n", env->pc); qemu_log("rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " "debug[%x] imm=%x iflags=%x\n", env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR], diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index a96cb21d96..9f6815cc1f 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1805,7 +1805,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) } qemu_fprintf(f, "IN: PC=%" PRIx64 " %s\n", - env->sregs[SR_PC], lookup_symbol(env->sregs[SR_PC])); + env->pc, lookup_symbol(env->pc)); qemu_fprintf(f, "rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " "debug=%x imm=%x iflags=%x fsr=%" PRIx64 " " "rbtr=%" PRIx64 "\n", @@ -1868,7 +1868,11 @@ void mb_tcg_init(void) offsetof(CPUMBState, regs[i]), regnames[i]); } - for (i = 0; i < ARRAY_SIZE(cpu_SR); i++) { + + cpu_SR[SR_PC] = + tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, pc), "rpc"); + + for (i = 1; i < ARRAY_SIZE(cpu_SR); i++) { cpu_SR[i] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, sregs[i]), special_regnames[i]); @@ -1878,5 +1882,5 @@ void mb_tcg_init(void) void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, target_ulong *data) { - env->sregs[SR_PC] = data[0]; + env->pc = data[0]; } From 2e5282caa8eb6b5bab6c62cba902be1996dcb713 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 21:41:10 -0700 Subject: [PATCH 06/76] target/microblaze: Split out MSR from env->sregs Continue eliminating the sregs array in favor of individual members. Does not correct the width of MSR, yet. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.c | 4 +-- target/microblaze/cpu.h | 7 ++--- target/microblaze/gdbstub.c | 4 +-- target/microblaze/helper.c | 49 +++++++++++++++++------------------ target/microblaze/op_helper.c | 22 ++++++++-------- target/microblaze/translate.c | 14 +++++----- 6 files changed, 51 insertions(+), 49 deletions(-) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index bde9992535..0eac068570 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -121,9 +121,9 @@ static void mb_cpu_reset(DeviceState *dev) #if defined(CONFIG_USER_ONLY) /* start in user mode with interrupts enabled. */ - env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM; + env->msr = MSR_EE | MSR_IE | MSR_VM | MSR_UM; #else - env->sregs[SR_MSR] = 0; + env->msr = 0; mmu_init(&env->mmu); env->mmu.c_mmu = 3; env->mmu.c_mmu_tlb_access = 3; diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index d1f91bb318..36de61d9f9 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -237,6 +237,7 @@ struct CPUMBState { uint32_t imm; uint32_t regs[32]; uint64_t pc; + uint64_t msr; uint64_t sregs[14]; float_status fp_status; /* Stack protectors. Yes, it's a hw feature. */ @@ -355,7 +356,7 @@ static inline void cpu_get_tb_cpu_state(CPUMBState *env, target_ulong *pc, *pc = env->pc; *cs_base = 0; *flags = (env->iflags & IFLAGS_TB_MASK) | - (env->sregs[SR_MSR] & (MSR_UM | MSR_VM | MSR_EE)); + (env->msr & (MSR_UM | MSR_VM | MSR_EE)); } #if !defined(CONFIG_USER_ONLY) @@ -370,11 +371,11 @@ static inline int cpu_mmu_index(CPUMBState *env, bool ifetch) MicroBlazeCPU *cpu = env_archcpu(env); /* Are we in nommu mode?. */ - if (!(env->sregs[SR_MSR] & MSR_VM) || !cpu->cfg.use_mmu) { + if (!(env->msr & MSR_VM) || !cpu->cfg.use_mmu) { return MMU_NOMMU_IDX; } - if (env->sregs[SR_MSR] & MSR_UM) { + if (env->msr & MSR_UM) { return MMU_USER_IDX; } return MMU_KERNEL_IDX; diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c index 9ea31f8d2f..e4c4936a7a 100644 --- a/target/microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c @@ -62,7 +62,7 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) val = env->pc; break; case GDB_MSR: - val = env->sregs[SR_MSR]; + val = env->msr; break; case GDB_EAR: val = env->sregs[SR_EAR]; @@ -118,7 +118,7 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->pc = tmp; break; case GDB_MSR: - env->sregs[SR_MSR] = tmp; + env->msr = tmp; break; case GDB_EAR: env->sregs[SR_EAR] = tmp; diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index 5c392deea4..a18314540f 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -117,7 +117,7 @@ void mb_cpu_do_interrupt(CPUState *cs) /* IMM flag cannot propagate across a branch and into the dslot. */ assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG))); assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG))); -/* assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions. */ +/* assert(env->msr & (MSR_EE)); Only for HW exceptions. */ env->res_addr = RES_ADDR_NONE; switch (cs->exception_index) { case EXCP_HW_EXCP: @@ -136,11 +136,11 @@ void mb_cpu_do_interrupt(CPUState *cs) } /* Disable the MMU. */ - t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; - env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); - env->sregs[SR_MSR] |= t; + t = (env->msr & (MSR_VM | MSR_UM)) << 1; + env->msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); + env->msr |= t; /* Exception in progress. */ - env->sregs[SR_MSR] |= MSR_EIP; + env->msr |= MSR_EIP; qemu_log_mask(CPU_LOG_INT, "hw exception at pc=%" PRIx64 " ear=%" PRIx64 " " @@ -179,11 +179,11 @@ void mb_cpu_do_interrupt(CPUState *cs) } /* Disable the MMU. */ - t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; - env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); - env->sregs[SR_MSR] |= t; + t = (env->msr & (MSR_VM | MSR_UM)) << 1; + env->msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); + env->msr |= t; /* Exception in progress. */ - env->sregs[SR_MSR] |= MSR_EIP; + env->msr |= MSR_EIP; qemu_log_mask(CPU_LOG_INT, "exception at pc=%" PRIx64 " ear=%" PRIx64 " " @@ -195,11 +195,11 @@ void mb_cpu_do_interrupt(CPUState *cs) break; case EXCP_IRQ: - assert(!(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))); - assert(env->sregs[SR_MSR] & MSR_IE); + assert(!(env->msr & (MSR_EIP | MSR_BIP))); + assert(env->msr & MSR_IE); assert(!(env->iflags & D_FLAG)); - t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; + t = (env->msr & (MSR_VM | MSR_UM)) << 1; #if 0 #include "disas/disas.h" @@ -216,7 +216,7 @@ void mb_cpu_do_interrupt(CPUState *cs) qemu_log( "interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n", - env->pc, env->sregs[SR_MSR], t, env->iflags, + env->pc, env->msr, t, env->iflags, sym); log_cpu_state(cs, 0); @@ -226,11 +226,10 @@ void mb_cpu_do_interrupt(CPUState *cs) qemu_log_mask(CPU_LOG_INT, "interrupt at pc=%" PRIx64 " msr=%" PRIx64 " %x " "iflags=%x\n", - env->pc, env->sregs[SR_MSR], t, env->iflags); + env->pc, env->msr, t, env->iflags); - env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \ - | MSR_UM | MSR_IE); - env->sregs[SR_MSR] |= t; + env->msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM | MSR_IE); + env->msr |= t; env->regs[14] = env->pc; env->pc = cpu->cfg.base_vectors + 0x10; @@ -241,18 +240,18 @@ void mb_cpu_do_interrupt(CPUState *cs) case EXCP_HW_BREAK: assert(!(env->iflags & IMM_FLAG)); assert(!(env->iflags & D_FLAG)); - t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; + t = (env->msr & (MSR_VM | MSR_UM)) << 1; qemu_log_mask(CPU_LOG_INT, "break at pc=%" PRIx64 " msr=%" PRIx64 " %x " "iflags=%x\n", - env->pc, env->sregs[SR_MSR], t, env->iflags); + env->pc, env->msr, t, env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); - env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); - env->sregs[SR_MSR] |= t; - env->sregs[SR_MSR] |= MSR_BIP; + env->msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); + env->msr |= t; + env->msr |= MSR_BIP; if (cs->exception_index == EXCP_HW_BREAK) { env->regs[16] = env->pc; - env->sregs[SR_MSR] |= MSR_BIP; + env->msr |= MSR_BIP; env->pc = cpu->cfg.base_vectors + 0x18; } else env->pc = env->btarget; @@ -293,8 +292,8 @@ bool mb_cpu_exec_interrupt(CPUState *cs, int interrupt_request) CPUMBState *env = &cpu->env; if ((interrupt_request & CPU_INTERRUPT_HARD) - && (env->sregs[SR_MSR] & MSR_IE) - && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP)) + && (env->msr & MSR_IE) + && !(env->msr & (MSR_EIP | MSR_BIP)) && !(env->iflags & (D_FLAG | IMM_FLAG))) { cs->exception_index = EXCP_IRQ; mb_cpu_do_interrupt(cs); diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index 2deef32740..3668382d36 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -78,14 +78,14 @@ void helper_debug(CPUMBState *env) qemu_log("PC=%" PRIx64 "\n", env->pc); qemu_log("rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " "debug[%x] imm=%x iflags=%x\n", - env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR], + env->msr, env->sregs[SR_ESR], env->sregs[SR_EAR], env->debug, env->imm, env->iflags); qemu_log("btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) eip=%d ie=%d\n", env->btaken, env->btarget, - (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel", - (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel", - (bool)(env->sregs[SR_MSR] & MSR_EIP), - (bool)(env->sregs[SR_MSR] & MSR_IE)); + (env->msr & MSR_UM) ? "user" : "kernel", + (env->msr & MSR_UMS) ? "user" : "kernel", + (bool)(env->msr & MSR_EIP), + (bool)(env->msr & MSR_IE)); for (i = 0; i < 32; i++) { qemu_log("r%2.2d=%8.8x ", i, env->regs[i]); if ((i + 1) % 4 == 0) @@ -135,15 +135,15 @@ static inline int div_prepare(CPUMBState *env, uint32_t a, uint32_t b) MicroBlazeCPU *cpu = env_archcpu(env); if (b == 0) { - env->sregs[SR_MSR] |= MSR_DZ; + env->msr |= MSR_DZ; - if ((env->sregs[SR_MSR] & MSR_EE) && cpu->cfg.div_zero_exception) { + if ((env->msr & MSR_EE) && cpu->cfg.div_zero_exception) { env->sregs[SR_ESR] = ESR_EC_DIVZERO; helper_raise_exception(env, EXCP_HW_EXCP); } return 0; } - env->sregs[SR_MSR] &= ~MSR_DZ; + env->msr &= ~MSR_DZ; return 1; } @@ -192,7 +192,7 @@ static void update_fpu_flags(CPUMBState *env, int flags) } if (raise && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK) - && (env->sregs[SR_MSR] & MSR_EE)) { + && (env->msr & MSR_EE)) { raise_fpu_exception(env); } } @@ -437,7 +437,7 @@ void helper_memalign(CPUMBState *env, target_ulong addr, if (mask == 3) { env->sregs[SR_ESR] |= 1 << 11; } - if (!(env->sregs[SR_MSR] & MSR_EE)) { + if (!(env->msr & MSR_EE)) { return; } helper_raise_exception(env, EXCP_HW_EXCP); @@ -484,7 +484,7 @@ void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, env = &cpu->env; cpu_restore_state(cs, retaddr, true); - if (!(env->sregs[SR_MSR] & MSR_EE)) { + if (!(env->msr & MSR_EE)) { return; } diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 9f6815cc1f..9f2dcd82cd 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1809,16 +1809,16 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, "rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " "debug=%x imm=%x iflags=%x fsr=%" PRIx64 " " "rbtr=%" PRIx64 "\n", - env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR], + env->msr, env->sregs[SR_ESR], env->sregs[SR_EAR], env->debug, env->imm, env->iflags, env->sregs[SR_FSR], env->sregs[SR_BTR]); qemu_fprintf(f, "btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) " "eip=%d ie=%d\n", env->btaken, env->btarget, - (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel", - (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel", - (bool)(env->sregs[SR_MSR] & MSR_EIP), - (bool)(env->sregs[SR_MSR] & MSR_IE)); + (env->msr & MSR_UM) ? "user" : "kernel", + (env->msr & MSR_UMS) ? "user" : "kernel", + (bool)(env->msr & MSR_EIP), + (bool)(env->msr & MSR_IE)); for (i = 0; i < 12; i++) { qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]); if ((i + 1) % 4 == 0) { @@ -1871,8 +1871,10 @@ void mb_tcg_init(void) cpu_SR[SR_PC] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, pc), "rpc"); + cpu_SR[SR_MSR] = + tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, msr), "rmsr"); - for (i = 1; i < ARRAY_SIZE(cpu_SR); i++) { + for (i = SR_MSR + 1; i < ARRAY_SIZE(cpu_SR); i++) { cpu_SR[i] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, sregs[i]), special_regnames[i]); From b2e80a3c191e90dee7ad05df303c237d9819bee4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 21:46:10 -0700 Subject: [PATCH 07/76] target/microblaze: Split out EAR from env->sregs Continue eliminating the sregs array in favor of individual members. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 1 + target/microblaze/gdbstub.c | 4 ++-- target/microblaze/helper.c | 6 +++--- target/microblaze/op_helper.c | 8 ++++---- target/microblaze/translate.c | 6 ++++-- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 36de61d9f9..c9035b410e 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -238,6 +238,7 @@ struct CPUMBState { uint32_t regs[32]; uint64_t pc; uint64_t msr; + uint64_t ear; uint64_t sregs[14]; float_status fp_status; /* Stack protectors. Yes, it's a hw feature. */ diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c index e4c4936a7a..e33a613efe 100644 --- a/target/microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c @@ -65,7 +65,7 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) val = env->msr; break; case GDB_EAR: - val = env->sregs[SR_EAR]; + val = env->ear; break; case GDB_ESR: val = env->sregs[SR_ESR]; @@ -121,7 +121,7 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->msr = tmp; break; case GDB_EAR: - env->sregs[SR_EAR] = tmp; + env->ear = tmp; break; case GDB_ESR: env->sregs[SR_ESR] = tmp; diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index a18314540f..afe9634781 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -85,7 +85,7 @@ bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size, qemu_log_mask(CPU_LOG_MMU, "mmu=%d miss v=%" VADDR_PRIx "\n", mmu_idx, address); - env->sregs[SR_EAR] = address; + env->ear = address; switch (lu.err) { case ERR_PROT: env->sregs[SR_ESR] = access_type == MMU_INST_FETCH ? 17 : 16; @@ -145,7 +145,7 @@ void mb_cpu_do_interrupt(CPUState *cs) qemu_log_mask(CPU_LOG_INT, "hw exception at pc=%" PRIx64 " ear=%" PRIx64 " " "esr=%" PRIx64 " iflags=%x\n", - env->pc, env->sregs[SR_EAR], + env->pc, env->ear, env->sregs[SR_ESR], env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); env->iflags &= ~(IMM_FLAG | D_FLAG); @@ -188,7 +188,7 @@ void mb_cpu_do_interrupt(CPUState *cs) qemu_log_mask(CPU_LOG_INT, "exception at pc=%" PRIx64 " ear=%" PRIx64 " " "iflags=%x\n", - env->pc, env->sregs[SR_EAR], env->iflags); + env->pc, env->ear, env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); env->iflags &= ~(IMM_FLAG | D_FLAG); env->pc = cpu->cfg.base_vectors + 0x20; diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index 3668382d36..5bacd29663 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -78,7 +78,7 @@ void helper_debug(CPUMBState *env) qemu_log("PC=%" PRIx64 "\n", env->pc); qemu_log("rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " "debug[%x] imm=%x iflags=%x\n", - env->msr, env->sregs[SR_ESR], env->sregs[SR_EAR], + env->msr, env->sregs[SR_ESR], env->ear, env->debug, env->imm, env->iflags); qemu_log("btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) eip=%d ie=%d\n", env->btaken, env->btarget, @@ -431,7 +431,7 @@ void helper_memalign(CPUMBState *env, target_ulong addr, "unaligned access addr=" TARGET_FMT_lx " mask=%x, wr=%d dr=r%d\n", addr, mask, wr, dr); - env->sregs[SR_EAR] = addr; + env->ear = addr; env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \ | (dr & 31) << 5; if (mask == 3) { @@ -450,7 +450,7 @@ void helper_stackprot(CPUMBState *env, target_ulong addr) qemu_log_mask(CPU_LOG_INT, "Stack protector violation at " TARGET_FMT_lx " %x %x\n", addr, env->slr, env->shr); - env->sregs[SR_EAR] = addr; + env->ear = addr; env->sregs[SR_ESR] = ESR_EC_STACKPROT; helper_raise_exception(env, EXCP_HW_EXCP); } @@ -488,7 +488,7 @@ void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, return; } - env->sregs[SR_EAR] = addr; + env->ear = addr; if (access_type == MMU_INST_FETCH) { if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) { env->sregs[SR_ESR] = ESR_EC_INSN_BUS; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 9f2dcd82cd..62747b02f3 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1809,7 +1809,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, "rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " "debug=%x imm=%x iflags=%x fsr=%" PRIx64 " " "rbtr=%" PRIx64 "\n", - env->msr, env->sregs[SR_ESR], env->sregs[SR_EAR], + env->msr, env->sregs[SR_ESR], env->ear, env->debug, env->imm, env->iflags, env->sregs[SR_FSR], env->sregs[SR_BTR]); qemu_fprintf(f, "btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) " @@ -1873,8 +1873,10 @@ void mb_tcg_init(void) tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, pc), "rpc"); cpu_SR[SR_MSR] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, msr), "rmsr"); + cpu_SR[SR_EAR] = + tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, ear), "rear"); - for (i = SR_MSR + 1; i < ARRAY_SIZE(cpu_SR); i++) { + for (i = SR_EAR + 1; i < ARRAY_SIZE(cpu_SR); i++) { cpu_SR[i] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, sregs[i]), special_regnames[i]); From 78e9caf2f9410c8b90bb6d5a6449c750056c3f8a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 21:50:35 -0700 Subject: [PATCH 08/76] target/microblaze: Split out ESR from env->sregs Continue eliminating the sregs array in favor of individual members. Does not correct the width of ESR, yet. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- linux-user/microblaze/cpu_loop.c | 6 +++--- target/microblaze/cpu.h | 1 + target/microblaze/gdbstub.c | 4 ++-- target/microblaze/helper.c | 18 +++++++++--------- target/microblaze/op_helper.c | 17 ++++++++--------- target/microblaze/translate.c | 6 ++++-- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/linux-user/microblaze/cpu_loop.c b/linux-user/microblaze/cpu_loop.c index 3c693086f4..c10e3e0261 100644 --- a/linux-user/microblaze/cpu_loop.c +++ b/linux-user/microblaze/cpu_loop.c @@ -78,14 +78,14 @@ void cpu_loop(CPUMBState *env) case EXCP_HW_EXCP: env->regs[17] = env->pc + 4; if (env->iflags & D_FLAG) { - env->sregs[SR_ESR] |= 1 << 12; + env->esr |= 1 << 12; env->pc -= 4; /* FIXME: if branch was immed, replay the imm as well. */ } env->iflags &= ~(IMM_FLAG | D_FLAG); - switch (env->sregs[SR_ESR] & 31) { + switch (env->esr & 31) { case ESR_EC_DIVZERO: info.si_signo = TARGET_SIGFPE; info.si_errno = 0; @@ -107,7 +107,7 @@ void cpu_loop(CPUMBState *env) break; default: fprintf(stderr, "Unhandled hw-exception: 0x%" PRIx64 "\n", - env->sregs[SR_ESR] & ESR_EC_MASK); + env->esr & ESR_EC_MASK); cpu_dump_state(cs, stderr, 0); exit(EXIT_FAILURE); break; diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index c9035b410e..7d94af43ed 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -239,6 +239,7 @@ struct CPUMBState { uint64_t pc; uint64_t msr; uint64_t ear; + uint64_t esr; uint64_t sregs[14]; float_status fp_status; /* Stack protectors. Yes, it's a hw feature. */ diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c index e33a613efe..05e22f233d 100644 --- a/target/microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c @@ -68,7 +68,7 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) val = env->ear; break; case GDB_ESR: - val = env->sregs[SR_ESR]; + val = env->esr; break; case GDB_FSR: val = env->sregs[SR_FSR]; @@ -124,7 +124,7 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->ear = tmp; break; case GDB_ESR: - env->sregs[SR_ESR] = tmp; + env->esr = tmp; break; case GDB_FSR: env->sregs[SR_FSR] = tmp; diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index afe9634781..ea290be780 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -88,12 +88,12 @@ bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size, env->ear = address; switch (lu.err) { case ERR_PROT: - env->sregs[SR_ESR] = access_type == MMU_INST_FETCH ? 17 : 16; - env->sregs[SR_ESR] |= (access_type == MMU_DATA_STORE) << 10; + env->esr = access_type == MMU_INST_FETCH ? 17 : 16; + env->esr |= (access_type == MMU_DATA_STORE) << 10; break; case ERR_MISS: - env->sregs[SR_ESR] = access_type == MMU_INST_FETCH ? 19 : 18; - env->sregs[SR_ESR] |= (access_type == MMU_DATA_STORE) << 10; + env->esr = access_type == MMU_INST_FETCH ? 19 : 18; + env->esr |= (access_type == MMU_DATA_STORE) << 10; break; default: abort(); @@ -127,11 +127,11 @@ void mb_cpu_do_interrupt(CPUState *cs) } env->regs[17] = env->pc + 4; - env->sregs[SR_ESR] &= ~(1 << 12); + env->esr &= ~(1 << 12); /* Exception breaks branch + dslot sequence? */ if (env->iflags & D_FLAG) { - env->sregs[SR_ESR] |= 1 << 12 ; + env->esr |= 1 << 12 ; env->sregs[SR_BTR] = env->btarget; } @@ -146,7 +146,7 @@ void mb_cpu_do_interrupt(CPUState *cs) "hw exception at pc=%" PRIx64 " ear=%" PRIx64 " " "esr=%" PRIx64 " iflags=%x\n", env->pc, env->ear, - env->sregs[SR_ESR], env->iflags); + env->esr, env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); env->iflags &= ~(IMM_FLAG | D_FLAG); env->pc = cpu->cfg.base_vectors + 0x20; @@ -155,11 +155,11 @@ void mb_cpu_do_interrupt(CPUState *cs) case EXCP_MMU: env->regs[17] = env->pc; - env->sregs[SR_ESR] &= ~(1 << 12); + env->esr &= ~(1 << 12); /* Exception breaks branch + dslot sequence? */ if (env->iflags & D_FLAG) { D(qemu_log("D_FLAG set at exception bimm=%d\n", env->bimm)); - env->sregs[SR_ESR] |= 1 << 12 ; + env->esr |= 1 << 12 ; env->sregs[SR_BTR] = env->btarget; /* Reexecute the branch. */ diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index 5bacd29663..f01cf9be64 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -78,7 +78,7 @@ void helper_debug(CPUMBState *env) qemu_log("PC=%" PRIx64 "\n", env->pc); qemu_log("rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " "debug[%x] imm=%x iflags=%x\n", - env->msr, env->sregs[SR_ESR], env->ear, + env->msr, env->esr, env->ear, env->debug, env->imm, env->iflags); qemu_log("btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) eip=%d ie=%d\n", env->btaken, env->btarget, @@ -138,7 +138,7 @@ static inline int div_prepare(CPUMBState *env, uint32_t a, uint32_t b) env->msr |= MSR_DZ; if ((env->msr & MSR_EE) && cpu->cfg.div_zero_exception) { - env->sregs[SR_ESR] = ESR_EC_DIVZERO; + env->esr = ESR_EC_DIVZERO; helper_raise_exception(env, EXCP_HW_EXCP); } return 0; @@ -166,7 +166,7 @@ uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b) /* raise FPU exception. */ static void raise_fpu_exception(CPUMBState *env) { - env->sregs[SR_ESR] = ESR_EC_FPU; + env->esr = ESR_EC_FPU; helper_raise_exception(env, EXCP_HW_EXCP); } @@ -432,10 +432,9 @@ void helper_memalign(CPUMBState *env, target_ulong addr, " mask=%x, wr=%d dr=r%d\n", addr, mask, wr, dr); env->ear = addr; - env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \ - | (dr & 31) << 5; + env->esr = ESR_EC_UNALIGNED_DATA | (wr << 10) | (dr & 31) << 5; if (mask == 3) { - env->sregs[SR_ESR] |= 1 << 11; + env->esr |= 1 << 11; } if (!(env->msr & MSR_EE)) { return; @@ -451,7 +450,7 @@ void helper_stackprot(CPUMBState *env, target_ulong addr) TARGET_FMT_lx " %x %x\n", addr, env->slr, env->shr); env->ear = addr; - env->sregs[SR_ESR] = ESR_EC_STACKPROT; + env->esr = ESR_EC_STACKPROT; helper_raise_exception(env, EXCP_HW_EXCP); } } @@ -491,12 +490,12 @@ void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, env->ear = addr; if (access_type == MMU_INST_FETCH) { if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) { - env->sregs[SR_ESR] = ESR_EC_INSN_BUS; + env->esr = ESR_EC_INSN_BUS; helper_raise_exception(env, EXCP_HW_EXCP); } } else { if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) { - env->sregs[SR_ESR] = ESR_EC_DATA_BUS; + env->esr = ESR_EC_DATA_BUS; helper_raise_exception(env, EXCP_HW_EXCP); } } diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 62747b02f3..411c7b6e49 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1809,7 +1809,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, "rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " "debug=%x imm=%x iflags=%x fsr=%" PRIx64 " " "rbtr=%" PRIx64 "\n", - env->msr, env->sregs[SR_ESR], env->ear, + env->msr, env->esr, env->ear, env->debug, env->imm, env->iflags, env->sregs[SR_FSR], env->sregs[SR_BTR]); qemu_fprintf(f, "btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) " @@ -1875,8 +1875,10 @@ void mb_tcg_init(void) tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, msr), "rmsr"); cpu_SR[SR_EAR] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, ear), "rear"); + cpu_SR[SR_ESR] = + tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, esr), "resr"); - for (i = SR_EAR + 1; i < ARRAY_SIZE(cpu_SR); i++) { + for (i = SR_ESR + 1; i < ARRAY_SIZE(cpu_SR); i++) { cpu_SR[i] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, sregs[i]), special_regnames[i]); From 5a8e01366c5dfe93f608e7d37f385962495d5161 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 21:54:38 -0700 Subject: [PATCH 09/76] target/microblaze: Split out FSR from env->sregs Continue eliminating the sregs array in favor of individual members. Does not correct the width of FSR, yet. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- linux-user/microblaze/cpu_loop.c | 4 ++-- target/microblaze/cpu.h | 1 + target/microblaze/gdbstub.c | 4 ++-- target/microblaze/op_helper.c | 8 ++++---- target/microblaze/translate.c | 6 ++++-- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/linux-user/microblaze/cpu_loop.c b/linux-user/microblaze/cpu_loop.c index c10e3e0261..da5e98b784 100644 --- a/linux-user/microblaze/cpu_loop.c +++ b/linux-user/microblaze/cpu_loop.c @@ -96,10 +96,10 @@ void cpu_loop(CPUMBState *env) case ESR_EC_FPU: info.si_signo = TARGET_SIGFPE; info.si_errno = 0; - if (env->sregs[SR_FSR] & FSR_IO) { + if (env->fsr & FSR_IO) { info.si_code = TARGET_FPE_FLTINV; } - if (env->sregs[SR_FSR] & FSR_DZ) { + if (env->fsr & FSR_DZ) { info.si_code = TARGET_FPE_FLTDIV; } info._sifields._sigfault._addr = 0; diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 7d94af43ed..bcafef99b0 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -240,6 +240,7 @@ struct CPUMBState { uint64_t msr; uint64_t ear; uint64_t esr; + uint64_t fsr; uint64_t sregs[14]; float_status fp_status; /* Stack protectors. Yes, it's a hw feature. */ diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c index 05e22f233d..2634ce49fc 100644 --- a/target/microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c @@ -71,7 +71,7 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) val = env->esr; break; case GDB_FSR: - val = env->sregs[SR_FSR]; + val = env->fsr; break; case GDB_BTR: val = env->sregs[SR_BTR]; @@ -127,7 +127,7 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->esr = tmp; break; case GDB_FSR: - env->sregs[SR_FSR] = tmp; + env->fsr = tmp; break; case GDB_BTR: env->sregs[SR_BTR] = tmp; diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index f01cf9be64..ae57d45536 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -175,19 +175,19 @@ static void update_fpu_flags(CPUMBState *env, int flags) int raise = 0; if (flags & float_flag_invalid) { - env->sregs[SR_FSR] |= FSR_IO; + env->fsr |= FSR_IO; raise = 1; } if (flags & float_flag_divbyzero) { - env->sregs[SR_FSR] |= FSR_DZ; + env->fsr |= FSR_DZ; raise = 1; } if (flags & float_flag_overflow) { - env->sregs[SR_FSR] |= FSR_OF; + env->fsr |= FSR_OF; raise = 1; } if (flags & float_flag_underflow) { - env->sregs[SR_FSR] |= FSR_UF; + env->fsr |= FSR_UF; raise = 1; } if (raise diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 411c7b6e49..c58c49ea8f 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1810,7 +1810,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) "debug=%x imm=%x iflags=%x fsr=%" PRIx64 " " "rbtr=%" PRIx64 "\n", env->msr, env->esr, env->ear, - env->debug, env->imm, env->iflags, env->sregs[SR_FSR], + env->debug, env->imm, env->iflags, env->fsr, env->sregs[SR_BTR]); qemu_fprintf(f, "btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) " "eip=%d ie=%d\n", @@ -1877,8 +1877,10 @@ void mb_tcg_init(void) tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, ear), "rear"); cpu_SR[SR_ESR] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, esr), "resr"); + cpu_SR[SR_FSR] = + tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, fsr), "rfsr"); - for (i = SR_ESR + 1; i < ARRAY_SIZE(cpu_SR); i++) { + for (i = SR_FSR + 1; i < ARRAY_SIZE(cpu_SR); i++) { cpu_SR[i] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, sregs[i]), special_regnames[i]); From 6fbf78f24a43c57925dc4e789dc236cdec443987 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 21:58:40 -0700 Subject: [PATCH 10/76] target/microblaze: Split out BTR from env->sregs Continue eliminating the sregs array in favor of individual members. Does not correct the width of BTR, yet. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 1 + target/microblaze/gdbstub.c | 4 ++-- target/microblaze/helper.c | 4 ++-- target/microblaze/translate.c | 6 ++++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index bcafef99b0..deddb47abb 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -241,6 +241,7 @@ struct CPUMBState { uint64_t ear; uint64_t esr; uint64_t fsr; + uint64_t btr; uint64_t sregs[14]; float_status fp_status; /* Stack protectors. Yes, it's a hw feature. */ diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c index 2634ce49fc..cde8c169bf 100644 --- a/target/microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c @@ -74,7 +74,7 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) val = env->fsr; break; case GDB_BTR: - val = env->sregs[SR_BTR]; + val = env->btr; break; case GDB_PVR0 ... GDB_PVR11: /* PVR12 is intentionally skipped */ @@ -130,7 +130,7 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->fsr = tmp; break; case GDB_BTR: - env->sregs[SR_BTR] = tmp; + env->btr = tmp; break; case GDB_PVR0 ... GDB_PVR11: /* PVR12 is intentionally skipped */ diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index ea290be780..b240dc76f6 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -132,7 +132,7 @@ void mb_cpu_do_interrupt(CPUState *cs) /* Exception breaks branch + dslot sequence? */ if (env->iflags & D_FLAG) { env->esr |= 1 << 12 ; - env->sregs[SR_BTR] = env->btarget; + env->btr = env->btarget; } /* Disable the MMU. */ @@ -160,7 +160,7 @@ void mb_cpu_do_interrupt(CPUState *cs) if (env->iflags & D_FLAG) { D(qemu_log("D_FLAG set at exception bimm=%d\n", env->bimm)); env->esr |= 1 << 12 ; - env->sregs[SR_BTR] = env->btarget; + env->btr = env->btarget; /* Reexecute the branch. */ env->regs[17] -= 4; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index c58c49ea8f..469e1f103a 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1811,7 +1811,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) "rbtr=%" PRIx64 "\n", env->msr, env->esr, env->ear, env->debug, env->imm, env->iflags, env->fsr, - env->sregs[SR_BTR]); + env->btr); qemu_fprintf(f, "btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) " "eip=%d ie=%d\n", env->btaken, env->btarget, @@ -1879,8 +1879,10 @@ void mb_tcg_init(void) tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, esr), "resr"); cpu_SR[SR_FSR] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, fsr), "rfsr"); + cpu_SR[SR_BTR] = + tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, btr), "rbtr"); - for (i = SR_FSR + 1; i < ARRAY_SIZE(cpu_SR); i++) { + for (i = SR_BTR + 1; i < ARRAY_SIZE(cpu_SR); i++) { cpu_SR[i] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, sregs[i]), special_regnames[i]); From af20a93acb5e9da63976e113656d09e4bcbdddac Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 22:05:29 -0700 Subject: [PATCH 11/76] target/microblaze: Split out EDR from env->sregs Finish eliminating the sregs array in favor of individual members. Does not correct the width of EDR, yet. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- linux-user/elfload.c | 9 ++++++--- target/microblaze/cpu.h | 2 +- target/microblaze/gdbstub.c | 4 ++-- target/microblaze/translate.c | 16 +++------------- 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 69936dcd45..58b3f4ef4d 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1038,9 +1038,12 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env (*regs)[pos++] = tswapreg(env->regs[i]); } - for (i = 0; i < 6; i++) { - (*regs)[pos++] = tswapreg(env->sregs[i]); - } + (*regs)[pos++] = tswapreg(env->pc); + (*regs)[pos++] = tswapreg(env->msr); + (*regs)[pos++] = 0; + (*regs)[pos++] = tswapreg(env->ear); + (*regs)[pos++] = 0; + (*regs)[pos++] = tswapreg(env->esr); } #endif /* TARGET_MICROBLAZE */ diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index deddb47abb..610ddfb719 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -242,7 +242,7 @@ struct CPUMBState { uint64_t esr; uint64_t fsr; uint64_t btr; - uint64_t sregs[14]; + uint64_t edr; float_status fp_status; /* Stack protectors. Yes, it's a hw feature. */ uint32_t slr, shr; diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c index cde8c169bf..9cba9d2215 100644 --- a/target/microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c @@ -81,7 +81,7 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) val = env->pvr.regs[n - GDB_PVR0]; break; case GDB_EDR: - val = env->sregs[SR_EDR]; + val = env->edr; break; case GDB_SLR: val = env->slr; @@ -137,7 +137,7 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->pvr.regs[n - GDB_PVR0] = tmp; break; case GDB_EDR: - env->sregs[SR_EDR] = tmp; + env->edr = tmp; break; case GDB_SLR: env->slr = tmp; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 469e1f103a..7d307e6b48 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -103,12 +103,6 @@ static const char *regnames[] = "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", }; -static const char *special_regnames[] = -{ - "rpc", "rmsr", "sr2", "rear", "sr4", "resr", "sr6", "rfsr", - "sr8", "sr9", "sr10", "rbtr", "sr12", "redr" -}; - static inline void t_sync_flags(DisasContext *dc) { /* Synch the tb dependent flags between translator and runtime. */ @@ -1828,7 +1822,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) /* Registers that aren't modeled are reported as 0 */ qemu_fprintf(f, "redr=%" PRIx64 " rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 " - "rtlblo=0 rtlbhi=0\n", env->sregs[SR_EDR]); + "rtlblo=0 rtlbhi=0\n", env->edr); qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr); for (i = 0; i < 32; i++) { qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); @@ -1881,12 +1875,8 @@ void mb_tcg_init(void) tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, fsr), "rfsr"); cpu_SR[SR_BTR] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, btr), "rbtr"); - - for (i = SR_BTR + 1; i < ARRAY_SIZE(cpu_SR); i++) { - cpu_SR[i] = tcg_global_mem_new_i64(cpu_env, - offsetof(CPUMBState, sregs[i]), - special_regnames[i]); - } + cpu_SR[SR_EDR] = + tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, edr), "redr"); } void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, From aa28e6d4c70d16415ad110a173c8af618fbceb96 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 22:12:42 -0700 Subject: [PATCH 12/76] target/microblaze: Split the cpu_SR array Similar to splitting the sregs array, this will allow further fixes and cleanups. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 106 +++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 41 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 7d307e6b48..19d7b8abfd 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -55,7 +55,13 @@ static TCGv_i32 env_debug; static TCGv_i32 cpu_R[32]; -static TCGv_i64 cpu_SR[14]; +static TCGv_i64 cpu_pc; +static TCGv_i64 cpu_msr; +static TCGv_i64 cpu_ear; +static TCGv_i64 cpu_esr; +static TCGv_i64 cpu_fsr; +static TCGv_i64 cpu_btr; +static TCGv_i64 cpu_edr; static TCGv_i32 env_imm; static TCGv_i32 env_btaken; static TCGv_i64 env_btarget; @@ -117,7 +123,7 @@ static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index) TCGv_i32 tmp = tcg_const_i32(index); t_sync_flags(dc); - tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc); + tcg_gen_movi_i64(cpu_pc, dc->pc); gen_helper_raise_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); dc->is_jmp = DISAS_UPDATE; @@ -136,17 +142,17 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) { if (use_goto_tb(dc, dest)) { tcg_gen_goto_tb(n); - tcg_gen_movi_i64(cpu_SR[SR_PC], dest); + tcg_gen_movi_i64(cpu_pc, dest); tcg_gen_exit_tb(dc->tb, n); } else { - tcg_gen_movi_i64(cpu_SR[SR_PC], dest); + tcg_gen_movi_i64(cpu_pc, dest); tcg_gen_exit_tb(NULL, 0); } } static void read_carry(DisasContext *dc, TCGv_i32 d) { - tcg_gen_extrl_i64_i32(d, cpu_SR[SR_MSR]); + tcg_gen_extrl_i64_i32(d, cpu_msr); tcg_gen_shri_i32(d, d, 31); } @@ -159,8 +165,8 @@ static void write_carry(DisasContext *dc, TCGv_i32 v) TCGv_i64 t0 = tcg_temp_new_i64(); tcg_gen_extu_i32_i64(t0, v); /* Deposit bit 0 into MSR_C and the alias MSR_CC. */ - tcg_gen_deposit_i64(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0, 2, 1); - tcg_gen_deposit_i64(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0, 31, 1); + tcg_gen_deposit_i64(cpu_msr, cpu_msr, t0, 2, 1); + tcg_gen_deposit_i64(cpu_msr, cpu_msr, t0, 31, 1); tcg_temp_free_i64(t0); } @@ -180,7 +186,7 @@ static bool trap_illegal(DisasContext *dc, bool cond) { if (cond && (dc->tb_flags & MSR_EE_FLAG) && dc->cpu->cfg.illegal_opcode_exception) { - tcg_gen_movi_i64(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP); + tcg_gen_movi_i64(cpu_esr, ESR_EC_ILLEGAL_OP); t_gen_raise_exception(dc, EXCP_HW_EXCP); } return cond; @@ -196,7 +202,7 @@ static bool trap_userspace(DisasContext *dc, bool cond) bool cond_user = cond && mem_index == MMU_USER_IDX; if (cond_user && (dc->tb_flags & MSR_EE_FLAG)) { - tcg_gen_movi_i64(cpu_SR[SR_ESR], ESR_EC_PRIVINSN); + tcg_gen_movi_i64(cpu_esr, ESR_EC_PRIVINSN); t_gen_raise_exception(dc, EXCP_HW_EXCP); } return cond_user; @@ -431,7 +437,7 @@ static void dec_xor(DisasContext *dc) static inline void msr_read(DisasContext *dc, TCGv_i32 d) { - tcg_gen_extrl_i64_i32(d, cpu_SR[SR_MSR]); + tcg_gen_extrl_i64_i32(d, cpu_msr); } static inline void msr_write(DisasContext *dc, TCGv_i32 v) @@ -443,8 +449,8 @@ static inline void msr_write(DisasContext *dc, TCGv_i32 v) /* PVR bit is not writable. */ tcg_gen_extu_i32_i64(t, v); tcg_gen_andi_i64(t, t, ~MSR_PVR); - tcg_gen_andi_i64(cpu_SR[SR_MSR], cpu_SR[SR_MSR], MSR_PVR); - tcg_gen_or_i64(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t); + tcg_gen_andi_i64(cpu_msr, cpu_msr, MSR_PVR); + tcg_gen_or_i64(cpu_msr, cpu_msr, t); tcg_temp_free_i64(t); } @@ -503,7 +509,7 @@ static void dec_msr(DisasContext *dc) msr_write(dc, t0); tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); - tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc + 4); + tcg_gen_movi_i64(cpu_pc, dc->pc + 4); dc->is_jmp = DISAS_UPDATE; return; } @@ -535,15 +541,25 @@ static void dec_msr(DisasContext *dc) if (to) { LOG_DIS("m%ss sr%x r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm); switch (sr) { - case 0: + case SR_PC: break; - case 1: + case SR_MSR: msr_write(dc, cpu_R[dc->ra]); break; case SR_EAR: + tcg_gen_extu_i32_i64(cpu_ear, cpu_R[dc->ra]); + break; case SR_ESR: + tcg_gen_extu_i32_i64(cpu_esr, cpu_R[dc->ra]); + break; case SR_FSR: - tcg_gen_extu_i32_i64(cpu_SR[sr], cpu_R[dc->ra]); + tcg_gen_extu_i32_i64(cpu_fsr, cpu_R[dc->ra]); + break; + case SR_BTR: + tcg_gen_extu_i32_i64(cpu_btr, cpu_R[dc->ra]); + break; + case SR_EDR: + tcg_gen_extu_i32_i64(cpu_edr, cpu_R[dc->ra]); break; case 0x800: tcg_gen_st_i32(cpu_R[dc->ra], @@ -561,22 +577,30 @@ static void dec_msr(DisasContext *dc) LOG_DIS("m%ss r%d sr%x imm=%x\n", to ? "t" : "f", dc->rd, sr, dc->imm); switch (sr) { - case 0: + case SR_PC: tcg_gen_movi_i32(cpu_R[dc->rd], dc->pc); break; - case 1: + case SR_MSR: msr_read(dc, cpu_R[dc->rd]); break; case SR_EAR: if (extended) { - tcg_gen_extrh_i64_i32(cpu_R[dc->rd], cpu_SR[sr]); - break; + tcg_gen_extrh_i64_i32(cpu_R[dc->rd], cpu_ear); + } else { + tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_ear); } + break; case SR_ESR: + tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_esr); + break; case SR_FSR: + tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_fsr); + break; case SR_BTR: + tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_btr); + break; case SR_EDR: - tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_SR[sr]); + tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_edr); break; case 0x800: tcg_gen_ld_i32(cpu_R[dc->rd], @@ -749,7 +773,7 @@ static void dec_bit(DisasContext *dc) t0 = tcg_temp_new_i32(); LOG_DIS("src r%d r%d\n", dc->rd, dc->ra); - tcg_gen_extrl_i64_i32(t0, cpu_SR[SR_MSR]); + tcg_gen_extrl_i64_i32(t0, cpu_msr); tcg_gen_andi_i32(t0, t0, MSR_CC); write_carry(dc, cpu_R[dc->ra]); if (dc->rd) { @@ -995,7 +1019,7 @@ static void dec_load(DisasContext *dc) TCGv_i32 treg = tcg_const_i32(dc->rd); TCGv_i32 tsize = tcg_const_i32(size - 1); - tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc); + tcg_gen_movi_i64(cpu_pc, dc->pc); gen_helper_memalign(cpu_env, addr, treg, t0, tsize); tcg_temp_free_i32(t0); @@ -1115,7 +1139,7 @@ static void dec_store(DisasContext *dc) TCGv_i32 treg = tcg_const_i32(dc->rd); TCGv_i32 tsize = tcg_const_i32(size - 1); - tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc); + tcg_gen_movi_i64(cpu_pc, dc->pc); /* FIXME: if the alignment is wrong, we should restore the value * in memory. One possible way to achieve this is to probe * the MMU prior to the memaccess, thay way we could put @@ -1169,7 +1193,7 @@ static void eval_cond_jmp(DisasContext *dc, TCGv_i64 pc_true, TCGv_i64 pc_false) TCGv_i64 tmp_zero = tcg_const_i64(0); tcg_gen_extu_i32_i64(tmp_btaken, env_btaken); - tcg_gen_movcond_i64(TCG_COND_NE, cpu_SR[SR_PC], + tcg_gen_movcond_i64(TCG_COND_NE, cpu_pc, tmp_btaken, tmp_zero, pc_true, pc_false); @@ -1253,7 +1277,7 @@ static void dec_br(DisasContext *dc) tcg_gen_st_i32(tmp_1, cpu_env, -offsetof(MicroBlazeCPU, env) +offsetof(CPUState, halted)); - tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc + 4); + tcg_gen_movi_i64(cpu_pc, dc->pc + 4); gen_helper_raise_exception(cpu_env, tmp_hlt); tcg_temp_free_i32(tmp_hlt); tcg_temp_free_i32(tmp_1); @@ -1309,7 +1333,7 @@ static inline void do_rti(DisasContext *dc) TCGv_i32 t0, t1; t0 = tcg_temp_new_i32(); t1 = tcg_temp_new_i32(); - tcg_gen_extrl_i64_i32(t1, cpu_SR[SR_MSR]); + tcg_gen_extrl_i64_i32(t1, cpu_msr); tcg_gen_shri_i32(t0, t1, 1); tcg_gen_ori_i32(t1, t1, MSR_IE); tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); @@ -1327,7 +1351,7 @@ static inline void do_rtb(DisasContext *dc) TCGv_i32 t0, t1; t0 = tcg_temp_new_i32(); t1 = tcg_temp_new_i32(); - tcg_gen_extrl_i64_i32(t1, cpu_SR[SR_MSR]); + tcg_gen_extrl_i64_i32(t1, cpu_msr); tcg_gen_andi_i32(t1, t1, ~MSR_BIP); tcg_gen_shri_i32(t0, t1, 1); tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); @@ -1346,7 +1370,7 @@ static inline void do_rte(DisasContext *dc) t0 = tcg_temp_new_i32(); t1 = tcg_temp_new_i32(); - tcg_gen_extrl_i64_i32(t1, cpu_SR[SR_MSR]); + tcg_gen_extrl_i64_i32(t1, cpu_msr); tcg_gen_ori_i32(t1, t1, MSR_EE); tcg_gen_andi_i32(t1, t1, ~MSR_EIP); tcg_gen_shri_i32(t0, t1, 1); @@ -1401,7 +1425,7 @@ static void dec_rts(DisasContext *dc) static int dec_check_fpuv2(DisasContext *dc) { if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) { - tcg_gen_movi_i64(cpu_SR[SR_ESR], ESR_EC_FPU); + tcg_gen_movi_i64(cpu_esr, ESR_EC_FPU); t_gen_raise_exception(dc, EXCP_HW_EXCP); } return (dc->cpu->cfg.use_fpu == 2) ? PVR2_USE_FPU2_MASK : 0; @@ -1652,7 +1676,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) #if SIM_COMPAT if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { - tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc); + tcg_gen_movi_i64(cpu_pc, dc->pc); gen_helper_debug(); } #endif @@ -1730,7 +1754,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { if (dc->tb_flags & D_FLAG) { dc->is_jmp = DISAS_UPDATE; - tcg_gen_movi_i64(cpu_SR[SR_PC], npc); + tcg_gen_movi_i64(cpu_pc, npc); sync_jmpstate(dc); } else npc = dc->jmp_pc; @@ -1740,7 +1764,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) if (dc->is_jmp == DISAS_NEXT && (dc->cpustate_changed || org_flags != dc->tb_flags)) { dc->is_jmp = DISAS_UPDATE; - tcg_gen_movi_i64(cpu_SR[SR_PC], npc); + tcg_gen_movi_i64(cpu_pc, npc); } t_sync_flags(dc); @@ -1748,7 +1772,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); if (dc->is_jmp != DISAS_JUMP) { - tcg_gen_movi_i64(cpu_SR[SR_PC], npc); + tcg_gen_movi_i64(cpu_pc, npc); } gen_helper_raise_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); @@ -1863,19 +1887,19 @@ void mb_tcg_init(void) regnames[i]); } - cpu_SR[SR_PC] = + cpu_pc = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, pc), "rpc"); - cpu_SR[SR_MSR] = + cpu_msr = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, msr), "rmsr"); - cpu_SR[SR_EAR] = + cpu_ear = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, ear), "rear"); - cpu_SR[SR_ESR] = + cpu_esr = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, esr), "resr"); - cpu_SR[SR_FSR] = + cpu_fsr = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, fsr), "rfsr"); - cpu_SR[SR_BTR] = + cpu_btr = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, btr), "rbtr"); - cpu_SR[SR_EDR] = + cpu_edr = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, edr), "redr"); } From 0f96e96bd5144b1a834fed2b53a17fcf46637dcb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 22:25:16 -0700 Subject: [PATCH 13/76] target/microblaze: Fix width of PC and BTARGET The program counter is only 32-bits wide. Do not use a 64-bit type to represent it. Since they are so closely related, fix btarget at the same time. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 4 +- target/microblaze/helper.c | 16 +++---- target/microblaze/mmu.c | 4 +- target/microblaze/op_helper.c | 4 +- target/microblaze/translate.c | 78 ++++++++++++++--------------------- 5 files changed, 43 insertions(+), 63 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 610ddfb719..f4c3c09b09 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -231,12 +231,12 @@ typedef struct CPUMBState CPUMBState; struct CPUMBState { uint32_t debug; uint32_t btaken; - uint64_t btarget; + uint32_t btarget; uint32_t bimm; uint32_t imm; uint32_t regs[32]; - uint64_t pc; + uint32_t pc; uint64_t msr; uint64_t ear; uint64_t esr; diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index b240dc76f6..b95617a81a 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -143,7 +143,7 @@ void mb_cpu_do_interrupt(CPUState *cs) env->msr |= MSR_EIP; qemu_log_mask(CPU_LOG_INT, - "hw exception at pc=%" PRIx64 " ear=%" PRIx64 " " + "hw exception at pc=%x ear=%" PRIx64 " " "esr=%" PRIx64 " iflags=%x\n", env->pc, env->ear, env->esr, env->iflags); @@ -167,8 +167,7 @@ void mb_cpu_do_interrupt(CPUState *cs) /* was the branch immprefixed?. */ if (env->bimm) { qemu_log_mask(CPU_LOG_INT, - "bimm exception at pc=%" PRIx64 " " - "iflags=%x\n", + "bimm exception at pc=%x iflags=%x\n", env->pc, env->iflags); env->regs[17] -= 4; log_cpu_state_mask(CPU_LOG_INT, cs, 0); @@ -186,8 +185,7 @@ void mb_cpu_do_interrupt(CPUState *cs) env->msr |= MSR_EIP; qemu_log_mask(CPU_LOG_INT, - "exception at pc=%" PRIx64 " ear=%" PRIx64 " " - "iflags=%x\n", + "exception at pc=%x ear=%" PRIx64 " iflags=%x\n", env->pc, env->ear, env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); env->iflags &= ~(IMM_FLAG | D_FLAG); @@ -224,8 +222,7 @@ void mb_cpu_do_interrupt(CPUState *cs) } #endif qemu_log_mask(CPU_LOG_INT, - "interrupt at pc=%" PRIx64 " msr=%" PRIx64 " %x " - "iflags=%x\n", + "interrupt at pc=%x msr=%" PRIx64 " %x iflags=%x\n", env->pc, env->msr, t, env->iflags); env->msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM | MSR_IE); @@ -242,9 +239,8 @@ void mb_cpu_do_interrupt(CPUState *cs) assert(!(env->iflags & D_FLAG)); t = (env->msr & (MSR_VM | MSR_UM)) << 1; qemu_log_mask(CPU_LOG_INT, - "break at pc=%" PRIx64 " msr=%" PRIx64 " %x " - "iflags=%x\n", - env->pc, env->msr, t, env->iflags); + "break at pc=%x msr=%" PRIx64 " %x iflags=%x\n", + env->pc, env->msr, t, env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); env->msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); env->msr |= t; diff --git a/target/microblaze/mmu.c b/target/microblaze/mmu.c index 3f403b567b..6e583d78d9 100644 --- a/target/microblaze/mmu.c +++ b/target/microblaze/mmu.c @@ -250,8 +250,8 @@ void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v) if (rn == MMU_R_TLBHI) { if (i < 3 && !(v & TLB_VALID) && qemu_loglevel_mask(~0)) qemu_log_mask(LOG_GUEST_ERROR, - "invalidating index %x at pc=%" PRIx64 "\n", - i, env->pc); + "invalidating index %x at pc=%x\n", + i, env->pc); env->mmu.tids[i] = env->mmu.regs[MMU_R_PID] & 0xff; mmu_flush_idx(env, i); } diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index ae57d45536..fdf706a723 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -75,12 +75,12 @@ void helper_debug(CPUMBState *env) { int i; - qemu_log("PC=%" PRIx64 "\n", env->pc); + qemu_log("PC=%08x\n", env->pc); qemu_log("rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " "debug[%x] imm=%x iflags=%x\n", env->msr, env->esr, env->ear, env->debug, env->imm, env->iflags); - qemu_log("btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) eip=%d ie=%d\n", + qemu_log("btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", env->btaken, env->btarget, (env->msr & MSR_UM) ? "user" : "kernel", (env->msr & MSR_UMS) ? "user" : "kernel", diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 19d7b8abfd..72783c1d8a 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -55,7 +55,7 @@ static TCGv_i32 env_debug; static TCGv_i32 cpu_R[32]; -static TCGv_i64 cpu_pc; +static TCGv_i32 cpu_pc; static TCGv_i64 cpu_msr; static TCGv_i64 cpu_ear; static TCGv_i64 cpu_esr; @@ -64,7 +64,7 @@ static TCGv_i64 cpu_btr; static TCGv_i64 cpu_edr; static TCGv_i32 env_imm; static TCGv_i32 env_btaken; -static TCGv_i64 env_btarget; +static TCGv_i32 cpu_btarget; static TCGv_i32 env_iflags; static TCGv env_res_addr; static TCGv_i32 env_res_val; @@ -123,7 +123,7 @@ static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index) TCGv_i32 tmp = tcg_const_i32(index); t_sync_flags(dc); - tcg_gen_movi_i64(cpu_pc, dc->pc); + tcg_gen_movi_i32(cpu_pc, dc->pc); gen_helper_raise_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); dc->is_jmp = DISAS_UPDATE; @@ -142,10 +142,10 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) { if (use_goto_tb(dc, dest)) { tcg_gen_goto_tb(n); - tcg_gen_movi_i64(cpu_pc, dest); + tcg_gen_movi_i32(cpu_pc, dest); tcg_gen_exit_tb(dc->tb, n); } else { - tcg_gen_movi_i64(cpu_pc, dest); + tcg_gen_movi_i32(cpu_pc, dest); tcg_gen_exit_tb(NULL, 0); } } @@ -509,7 +509,7 @@ static void dec_msr(DisasContext *dc) msr_write(dc, t0); tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); - tcg_gen_movi_i64(cpu_pc, dc->pc + 4); + tcg_gen_movi_i32(cpu_pc, dc->pc + 4); dc->is_jmp = DISAS_UPDATE; return; } @@ -850,7 +850,7 @@ static inline void sync_jmpstate(DisasContext *dc) tcg_gen_movi_i32(env_btaken, 1); } dc->jmp = JMP_INDIRECT; - tcg_gen_movi_i64(env_btarget, dc->jmp_pc); + tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); } } @@ -1019,7 +1019,7 @@ static void dec_load(DisasContext *dc) TCGv_i32 treg = tcg_const_i32(dc->rd); TCGv_i32 tsize = tcg_const_i32(size - 1); - tcg_gen_movi_i64(cpu_pc, dc->pc); + tcg_gen_movi_i32(cpu_pc, dc->pc); gen_helper_memalign(cpu_env, addr, treg, t0, tsize); tcg_temp_free_i32(t0); @@ -1139,7 +1139,7 @@ static void dec_store(DisasContext *dc) TCGv_i32 treg = tcg_const_i32(dc->rd); TCGv_i32 tsize = tcg_const_i32(size - 1); - tcg_gen_movi_i64(cpu_pc, dc->pc); + tcg_gen_movi_i32(cpu_pc, dc->pc); /* FIXME: if the alignment is wrong, we should restore the value * in memory. One possible way to achieve this is to probe * the MMU prior to the memaccess, thay way we could put @@ -1187,18 +1187,15 @@ static inline void eval_cc(DisasContext *dc, unsigned int cc, } } -static void eval_cond_jmp(DisasContext *dc, TCGv_i64 pc_true, TCGv_i64 pc_false) +static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false) { - TCGv_i64 tmp_btaken = tcg_temp_new_i64(); - TCGv_i64 tmp_zero = tcg_const_i64(0); + TCGv_i32 zero = tcg_const_i32(0); - tcg_gen_extu_i32_i64(tmp_btaken, env_btaken); - tcg_gen_movcond_i64(TCG_COND_NE, cpu_pc, - tmp_btaken, tmp_zero, + tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc, + env_btaken, zero, pc_true, pc_false); - tcg_temp_free_i64(tmp_btaken); - tcg_temp_free_i64(tmp_zero); + tcg_temp_free_i32(zero); } static void dec_setup_dslot(DisasContext *dc) @@ -1229,14 +1226,12 @@ static void dec_bcc(DisasContext *dc) if (dec_alu_op_b_is_small_imm(dc)) { int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend. */ - tcg_gen_movi_i64(env_btarget, dc->pc + offset); + tcg_gen_movi_i32(cpu_btarget, dc->pc + offset); dc->jmp = JMP_DIRECT_CC; dc->jmp_pc = dc->pc + offset; } else { dc->jmp = JMP_INDIRECT; - tcg_gen_extu_i32_i64(env_btarget, *(dec_alu_op_b(dc))); - tcg_gen_addi_i64(env_btarget, env_btarget, dc->pc); - tcg_gen_andi_i64(env_btarget, env_btarget, UINT32_MAX); + tcg_gen_addi_i32(cpu_btarget, *dec_alu_op_b(dc), dc->pc); } eval_cc(dc, cc, env_btaken, cpu_R[dc->ra]); } @@ -1277,7 +1272,7 @@ static void dec_br(DisasContext *dc) tcg_gen_st_i32(tmp_1, cpu_env, -offsetof(MicroBlazeCPU, env) +offsetof(CPUState, halted)); - tcg_gen_movi_i64(cpu_pc, dc->pc + 4); + tcg_gen_movi_i32(cpu_pc, dc->pc + 4); gen_helper_raise_exception(cpu_env, tmp_hlt); tcg_temp_free_i32(tmp_hlt); tcg_temp_free_i32(tmp_1); @@ -1303,7 +1298,7 @@ static void dec_br(DisasContext *dc) dc->jmp = JMP_INDIRECT; if (abs) { tcg_gen_movi_i32(env_btaken, 1); - tcg_gen_extu_i32_i64(env_btarget, *(dec_alu_op_b(dc))); + tcg_gen_mov_i32(cpu_btarget, *(dec_alu_op_b(dc))); if (link && !dslot) { if (!(dc->tb_flags & IMM_FLAG) && (dc->imm == 8 || dc->imm == 0x18)) t_gen_raise_exception(dc, EXCP_BREAK); @@ -1321,9 +1316,7 @@ static void dec_br(DisasContext *dc) dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm); } else { tcg_gen_movi_i32(env_btaken, 1); - tcg_gen_extu_i32_i64(env_btarget, *(dec_alu_op_b(dc))); - tcg_gen_addi_i64(env_btarget, env_btarget, dc->pc); - tcg_gen_andi_i64(env_btarget, env_btarget, UINT32_MAX); + tcg_gen_addi_i32(cpu_btarget, *dec_alu_op_b(dc), dc->pc); } } } @@ -1387,7 +1380,6 @@ static inline void do_rte(DisasContext *dc) static void dec_rts(DisasContext *dc) { unsigned int b_bit, i_bit, e_bit; - TCGv_i64 tmp64; i_bit = dc->ir & (1 << 21); b_bit = dc->ir & (1 << 22); @@ -1413,13 +1405,7 @@ static void dec_rts(DisasContext *dc) dc->jmp = JMP_INDIRECT; tcg_gen_movi_i32(env_btaken, 1); - - tmp64 = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(env_btarget, *(dec_alu_op_b(dc))); - tcg_gen_extu_i32_i64(tmp64, cpu_R[dc->ra]); - tcg_gen_add_i64(env_btarget, env_btarget, tmp64); - tcg_gen_andi_i64(env_btarget, env_btarget, UINT32_MAX); - tcg_temp_free_i64(tmp64); + tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc)); } static int dec_check_fpuv2(DisasContext *dc) @@ -1676,7 +1662,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) #if SIM_COMPAT if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { - tcg_gen_movi_i64(cpu_pc, dc->pc); + tcg_gen_movi_i32(cpu_pc, dc->pc); gen_helper_debug(); } #endif @@ -1718,10 +1704,9 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) dc->tb_flags &= ~D_FLAG; /* If it is a direct jump, try direct chaining. */ if (dc->jmp == JMP_INDIRECT) { - TCGv_i64 tmp_pc = tcg_const_i64(dc->pc); - eval_cond_jmp(dc, env_btarget, tmp_pc); - tcg_temp_free_i64(tmp_pc); - + TCGv_i32 tmp_pc = tcg_const_i32(dc->pc); + eval_cond_jmp(dc, cpu_btarget, tmp_pc); + tcg_temp_free_i32(tmp_pc); dc->is_jmp = DISAS_JUMP; } else if (dc->jmp == JMP_DIRECT) { t_sync_flags(dc); @@ -1754,7 +1739,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { if (dc->tb_flags & D_FLAG) { dc->is_jmp = DISAS_UPDATE; - tcg_gen_movi_i64(cpu_pc, npc); + tcg_gen_movi_i32(cpu_pc, npc); sync_jmpstate(dc); } else npc = dc->jmp_pc; @@ -1764,7 +1749,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) if (dc->is_jmp == DISAS_NEXT && (dc->cpustate_changed || org_flags != dc->tb_flags)) { dc->is_jmp = DISAS_UPDATE; - tcg_gen_movi_i64(cpu_pc, npc); + tcg_gen_movi_i32(cpu_pc, npc); } t_sync_flags(dc); @@ -1772,7 +1757,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); if (dc->is_jmp != DISAS_JUMP) { - tcg_gen_movi_i64(cpu_pc, npc); + tcg_gen_movi_i32(cpu_pc, npc); } gen_helper_raise_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); @@ -1822,7 +1807,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) return; } - qemu_fprintf(f, "IN: PC=%" PRIx64 " %s\n", + qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc)); qemu_fprintf(f, "rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " "debug=%x imm=%x iflags=%x fsr=%" PRIx64 " " @@ -1830,8 +1815,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) env->msr, env->esr, env->ear, env->debug, env->imm, env->iflags, env->fsr, env->btr); - qemu_fprintf(f, "btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) " - "eip=%d ie=%d\n", + qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", env->btaken, env->btarget, (env->msr & MSR_UM) ? "user" : "kernel", (env->msr & MSR_UMS) ? "user" : "kernel", @@ -1869,7 +1853,7 @@ void mb_tcg_init(void) env_imm = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, imm), "imm"); - env_btarget = tcg_global_mem_new_i64(cpu_env, + cpu_btarget = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, btarget), "btarget"); env_btaken = tcg_global_mem_new_i32(cpu_env, @@ -1888,7 +1872,7 @@ void mb_tcg_init(void) } cpu_pc = - tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, pc), "rpc"); + tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, pc), "rpc"); cpu_msr = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, msr), "rmsr"); cpu_ear = From 3e0e16ae1e0048a21a91674061ec9c43c5d7a76c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 22:33:37 -0700 Subject: [PATCH 14/76] target/microblaze: Fix width of MSR The machine status register is only 32-bits wide. Do not use a 64-bit type to represent it. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 2 +- target/microblaze/helper.c | 4 ++-- target/microblaze/op_helper.c | 2 +- target/microblaze/translate.c | 38 ++++++++++++----------------------- 4 files changed, 17 insertions(+), 29 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index f4c3c09b09..019e5dfa26 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -237,7 +237,7 @@ struct CPUMBState { uint32_t imm; uint32_t regs[32]; uint32_t pc; - uint64_t msr; + uint32_t msr; uint64_t ear; uint64_t esr; uint64_t fsr; diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index b95617a81a..af79091fd2 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -222,7 +222,7 @@ void mb_cpu_do_interrupt(CPUState *cs) } #endif qemu_log_mask(CPU_LOG_INT, - "interrupt at pc=%x msr=%" PRIx64 " %x iflags=%x\n", + "interrupt at pc=%x msr=%x %x iflags=%x\n", env->pc, env->msr, t, env->iflags); env->msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM | MSR_IE); @@ -239,7 +239,7 @@ void mb_cpu_do_interrupt(CPUState *cs) assert(!(env->iflags & D_FLAG)); t = (env->msr & (MSR_VM | MSR_UM)) << 1; qemu_log_mask(CPU_LOG_INT, - "break at pc=%x msr=%" PRIx64 " %x iflags=%x\n", + "break at pc=%x msr=%x %x iflags=%x\n", env->pc, env->msr, t, env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); env->msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index fdf706a723..a7f6cb71f1 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -76,7 +76,7 @@ void helper_debug(CPUMBState *env) int i; qemu_log("PC=%08x\n", env->pc); - qemu_log("rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " + qemu_log("rmsr=%x resr=%" PRIx64 " rear=%" PRIx64 " " "debug[%x] imm=%x iflags=%x\n", env->msr, env->esr, env->ear, env->debug, env->imm, env->iflags); diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 72783c1d8a..0e71e7ed01 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -56,7 +56,7 @@ static TCGv_i32 env_debug; static TCGv_i32 cpu_R[32]; static TCGv_i32 cpu_pc; -static TCGv_i64 cpu_msr; +static TCGv_i32 cpu_msr; static TCGv_i64 cpu_ear; static TCGv_i64 cpu_esr; static TCGv_i64 cpu_fsr; @@ -152,8 +152,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) static void read_carry(DisasContext *dc, TCGv_i32 d) { - tcg_gen_extrl_i64_i32(d, cpu_msr); - tcg_gen_shri_i32(d, d, 31); + tcg_gen_shri_i32(d, cpu_msr, 31); } /* @@ -162,12 +161,9 @@ static void read_carry(DisasContext *dc, TCGv_i32 d) */ static void write_carry(DisasContext *dc, TCGv_i32 v) { - TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(t0, v); /* Deposit bit 0 into MSR_C and the alias MSR_CC. */ - tcg_gen_deposit_i64(cpu_msr, cpu_msr, t0, 2, 1); - tcg_gen_deposit_i64(cpu_msr, cpu_msr, t0, 31, 1); - tcg_temp_free_i64(t0); + tcg_gen_deposit_i32(cpu_msr, cpu_msr, v, 2, 1); + tcg_gen_deposit_i32(cpu_msr, cpu_msr, v, 31, 1); } static void write_carryi(DisasContext *dc, bool carry) @@ -437,21 +433,14 @@ static void dec_xor(DisasContext *dc) static inline void msr_read(DisasContext *dc, TCGv_i32 d) { - tcg_gen_extrl_i64_i32(d, cpu_msr); + tcg_gen_mov_i32(d, cpu_msr); } static inline void msr_write(DisasContext *dc, TCGv_i32 v) { - TCGv_i64 t; - - t = tcg_temp_new_i64(); dc->cpustate_changed = 1; - /* PVR bit is not writable. */ - tcg_gen_extu_i32_i64(t, v); - tcg_gen_andi_i64(t, t, ~MSR_PVR); - tcg_gen_andi_i64(cpu_msr, cpu_msr, MSR_PVR); - tcg_gen_or_i64(cpu_msr, cpu_msr, t); - tcg_temp_free_i64(t); + /* PVR bit is not writable, and is never set. */ + tcg_gen_andi_i32(cpu_msr, v, ~MSR_PVR); } static void dec_msr(DisasContext *dc) @@ -773,8 +762,7 @@ static void dec_bit(DisasContext *dc) t0 = tcg_temp_new_i32(); LOG_DIS("src r%d r%d\n", dc->rd, dc->ra); - tcg_gen_extrl_i64_i32(t0, cpu_msr); - tcg_gen_andi_i32(t0, t0, MSR_CC); + tcg_gen_andi_i32(t0, cpu_msr, MSR_CC); write_carry(dc, cpu_R[dc->ra]); if (dc->rd) { tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); @@ -1326,7 +1314,7 @@ static inline void do_rti(DisasContext *dc) TCGv_i32 t0, t1; t0 = tcg_temp_new_i32(); t1 = tcg_temp_new_i32(); - tcg_gen_extrl_i64_i32(t1, cpu_msr); + tcg_gen_mov_i32(t1, cpu_msr); tcg_gen_shri_i32(t0, t1, 1); tcg_gen_ori_i32(t1, t1, MSR_IE); tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); @@ -1344,7 +1332,7 @@ static inline void do_rtb(DisasContext *dc) TCGv_i32 t0, t1; t0 = tcg_temp_new_i32(); t1 = tcg_temp_new_i32(); - tcg_gen_extrl_i64_i32(t1, cpu_msr); + tcg_gen_mov_i32(t1, cpu_msr); tcg_gen_andi_i32(t1, t1, ~MSR_BIP); tcg_gen_shri_i32(t0, t1, 1); tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); @@ -1363,7 +1351,7 @@ static inline void do_rte(DisasContext *dc) t0 = tcg_temp_new_i32(); t1 = tcg_temp_new_i32(); - tcg_gen_extrl_i64_i32(t1, cpu_msr); + tcg_gen_mov_i32(t1, cpu_msr); tcg_gen_ori_i32(t1, t1, MSR_EE); tcg_gen_andi_i32(t1, t1, ~MSR_EIP); tcg_gen_shri_i32(t0, t1, 1); @@ -1809,7 +1797,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc)); - qemu_fprintf(f, "rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " + qemu_fprintf(f, "rmsr=%x resr=%" PRIx64 " rear=%" PRIx64 " " "debug=%x imm=%x iflags=%x fsr=%" PRIx64 " " "rbtr=%" PRIx64 "\n", env->msr, env->esr, env->ear, @@ -1874,7 +1862,7 @@ void mb_tcg_init(void) cpu_pc = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, pc), "rpc"); cpu_msr = - tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, msr), "rmsr"); + tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, msr), "rmsr"); cpu_ear = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, ear), "rear"); cpu_esr = From 6efd55995a224787baa712500b82ef21a148d38e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 22:37:40 -0700 Subject: [PATCH 15/76] target/microblaze: Fix width of ESR The exception status register is only 32-bits wide. Do not use a 64-bit type to represent it. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- linux-user/microblaze/cpu_loop.c | 2 +- target/microblaze/cpu.h | 2 +- target/microblaze/helper.c | 2 +- target/microblaze/op_helper.c | 2 +- target/microblaze/translate.c | 16 ++++++++-------- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/linux-user/microblaze/cpu_loop.c b/linux-user/microblaze/cpu_loop.c index da5e98b784..3de99ea311 100644 --- a/linux-user/microblaze/cpu_loop.c +++ b/linux-user/microblaze/cpu_loop.c @@ -106,7 +106,7 @@ void cpu_loop(CPUMBState *env) queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; default: - fprintf(stderr, "Unhandled hw-exception: 0x%" PRIx64 "\n", + fprintf(stderr, "Unhandled hw-exception: 0x%x\n", env->esr & ESR_EC_MASK); cpu_dump_state(cs, stderr, 0); exit(EXIT_FAILURE); diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 019e5dfa26..aaac0c9a6c 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -239,7 +239,7 @@ struct CPUMBState { uint32_t pc; uint32_t msr; uint64_t ear; - uint64_t esr; + uint32_t esr; uint64_t fsr; uint64_t btr; uint64_t edr; diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index af79091fd2..b2373f6a23 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -144,7 +144,7 @@ void mb_cpu_do_interrupt(CPUState *cs) qemu_log_mask(CPU_LOG_INT, "hw exception at pc=%x ear=%" PRIx64 " " - "esr=%" PRIx64 " iflags=%x\n", + "esr=%x iflags=%x\n", env->pc, env->ear, env->esr, env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index a7f6cb71f1..dc2bec0c99 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -76,7 +76,7 @@ void helper_debug(CPUMBState *env) int i; qemu_log("PC=%08x\n", env->pc); - qemu_log("rmsr=%x resr=%" PRIx64 " rear=%" PRIx64 " " + qemu_log("rmsr=%x resr=%x rear=%" PRIx64 " " "debug[%x] imm=%x iflags=%x\n", env->msr, env->esr, env->ear, env->debug, env->imm, env->iflags); diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 0e71e7ed01..f63aae6de9 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -58,7 +58,7 @@ static TCGv_i32 cpu_R[32]; static TCGv_i32 cpu_pc; static TCGv_i32 cpu_msr; static TCGv_i64 cpu_ear; -static TCGv_i64 cpu_esr; +static TCGv_i32 cpu_esr; static TCGv_i64 cpu_fsr; static TCGv_i64 cpu_btr; static TCGv_i64 cpu_edr; @@ -182,7 +182,7 @@ static bool trap_illegal(DisasContext *dc, bool cond) { if (cond && (dc->tb_flags & MSR_EE_FLAG) && dc->cpu->cfg.illegal_opcode_exception) { - tcg_gen_movi_i64(cpu_esr, ESR_EC_ILLEGAL_OP); + tcg_gen_movi_i32(cpu_esr, ESR_EC_ILLEGAL_OP); t_gen_raise_exception(dc, EXCP_HW_EXCP); } return cond; @@ -198,7 +198,7 @@ static bool trap_userspace(DisasContext *dc, bool cond) bool cond_user = cond && mem_index == MMU_USER_IDX; if (cond_user && (dc->tb_flags & MSR_EE_FLAG)) { - tcg_gen_movi_i64(cpu_esr, ESR_EC_PRIVINSN); + tcg_gen_movi_i32(cpu_esr, ESR_EC_PRIVINSN); t_gen_raise_exception(dc, EXCP_HW_EXCP); } return cond_user; @@ -539,7 +539,7 @@ static void dec_msr(DisasContext *dc) tcg_gen_extu_i32_i64(cpu_ear, cpu_R[dc->ra]); break; case SR_ESR: - tcg_gen_extu_i32_i64(cpu_esr, cpu_R[dc->ra]); + tcg_gen_mov_i32(cpu_esr, cpu_R[dc->ra]); break; case SR_FSR: tcg_gen_extu_i32_i64(cpu_fsr, cpu_R[dc->ra]); @@ -580,7 +580,7 @@ static void dec_msr(DisasContext *dc) } break; case SR_ESR: - tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_esr); + tcg_gen_mov_i32(cpu_R[dc->rd], cpu_esr); break; case SR_FSR: tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_fsr); @@ -1399,7 +1399,7 @@ static void dec_rts(DisasContext *dc) static int dec_check_fpuv2(DisasContext *dc) { if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) { - tcg_gen_movi_i64(cpu_esr, ESR_EC_FPU); + tcg_gen_movi_i32(cpu_esr, ESR_EC_FPU); t_gen_raise_exception(dc, EXCP_HW_EXCP); } return (dc->cpu->cfg.use_fpu == 2) ? PVR2_USE_FPU2_MASK : 0; @@ -1797,7 +1797,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc)); - qemu_fprintf(f, "rmsr=%x resr=%" PRIx64 " rear=%" PRIx64 " " + qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " " "debug=%x imm=%x iflags=%x fsr=%" PRIx64 " " "rbtr=%" PRIx64 "\n", env->msr, env->esr, env->ear, @@ -1866,7 +1866,7 @@ void mb_tcg_init(void) cpu_ear = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, ear), "rear"); cpu_esr = - tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, esr), "resr"); + tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, esr), "resr"); cpu_fsr = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, fsr), "rfsr"); cpu_btr = From 86017ccfbd2b39371bd47dd7d2bed69ee184c3e5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 22:40:23 -0700 Subject: [PATCH 16/76] target/microblaze: Fix width of FSR The exception status register is only 32-bits wide. Do not use a 64-bit type to represent it. Since cpu_fsr is only used during MSR and MTR instructions, we can just as easily use an explicit load and store, so eliminate the variable. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 2 +- target/microblaze/translate.c | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index aaac0c9a6c..34177f9b28 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -240,7 +240,7 @@ struct CPUMBState { uint32_t msr; uint64_t ear; uint32_t esr; - uint64_t fsr; + uint32_t fsr; uint64_t btr; uint64_t edr; float_status fp_status; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index f63aae6de9..3fc2feda3d 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -59,7 +59,6 @@ static TCGv_i32 cpu_pc; static TCGv_i32 cpu_msr; static TCGv_i64 cpu_ear; static TCGv_i32 cpu_esr; -static TCGv_i64 cpu_fsr; static TCGv_i64 cpu_btr; static TCGv_i64 cpu_edr; static TCGv_i32 env_imm; @@ -542,7 +541,8 @@ static void dec_msr(DisasContext *dc) tcg_gen_mov_i32(cpu_esr, cpu_R[dc->ra]); break; case SR_FSR: - tcg_gen_extu_i32_i64(cpu_fsr, cpu_R[dc->ra]); + tcg_gen_st_i32(cpu_R[dc->ra], + cpu_env, offsetof(CPUMBState, fsr)); break; case SR_BTR: tcg_gen_extu_i32_i64(cpu_btr, cpu_R[dc->ra]); @@ -583,7 +583,8 @@ static void dec_msr(DisasContext *dc) tcg_gen_mov_i32(cpu_R[dc->rd], cpu_esr); break; case SR_FSR: - tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_fsr); + tcg_gen_ld_i32(cpu_R[dc->rd], + cpu_env, offsetof(CPUMBState, fsr)); break; case SR_BTR: tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_btr); @@ -1798,7 +1799,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc)); qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " " - "debug=%x imm=%x iflags=%x fsr=%" PRIx64 " " + "debug=%x imm=%x iflags=%x fsr=%x " "rbtr=%" PRIx64 "\n", env->msr, env->esr, env->ear, env->debug, env->imm, env->iflags, env->fsr, @@ -1867,8 +1868,6 @@ void mb_tcg_init(void) tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, ear), "rear"); cpu_esr = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, esr), "resr"); - cpu_fsr = - tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, fsr), "rfsr"); cpu_btr = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, btr), "rbtr"); cpu_edr = From ccf628b7939c542cf9e46e9aaa2b0acf0888ec52 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 22:44:49 -0700 Subject: [PATCH 17/76] target/microblaze: Fix width of BTR The branch target register is only 32-bits wide. Do not use a 64-bit type to represent it. Since cpu_btr is only used during MSR and MTR instructions, we can just as easily use an explicit load and store, so eliminate the variable. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 2 +- target/microblaze/translate.c | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 34177f9b28..72f068a5fd 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -241,7 +241,7 @@ struct CPUMBState { uint64_t ear; uint32_t esr; uint32_t fsr; - uint64_t btr; + uint32_t btr; uint64_t edr; float_status fp_status; /* Stack protectors. Yes, it's a hw feature. */ diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 3fc2feda3d..a2bba0fe61 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -59,7 +59,6 @@ static TCGv_i32 cpu_pc; static TCGv_i32 cpu_msr; static TCGv_i64 cpu_ear; static TCGv_i32 cpu_esr; -static TCGv_i64 cpu_btr; static TCGv_i64 cpu_edr; static TCGv_i32 env_imm; static TCGv_i32 env_btaken; @@ -545,7 +544,8 @@ static void dec_msr(DisasContext *dc) cpu_env, offsetof(CPUMBState, fsr)); break; case SR_BTR: - tcg_gen_extu_i32_i64(cpu_btr, cpu_R[dc->ra]); + tcg_gen_st_i32(cpu_R[dc->ra], + cpu_env, offsetof(CPUMBState, btr)); break; case SR_EDR: tcg_gen_extu_i32_i64(cpu_edr, cpu_R[dc->ra]); @@ -587,7 +587,8 @@ static void dec_msr(DisasContext *dc) cpu_env, offsetof(CPUMBState, fsr)); break; case SR_BTR: - tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_btr); + tcg_gen_ld_i32(cpu_R[dc->rd], + cpu_env, offsetof(CPUMBState, btr)); break; case SR_EDR: tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_edr); @@ -1799,8 +1800,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc)); qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " " - "debug=%x imm=%x iflags=%x fsr=%x " - "rbtr=%" PRIx64 "\n", + "debug=%x imm=%x iflags=%x fsr=%x rbtr=%x\n", env->msr, env->esr, env->ear, env->debug, env->imm, env->iflags, env->fsr, env->btr); @@ -1868,8 +1868,6 @@ void mb_tcg_init(void) tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, ear), "rear"); cpu_esr = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, esr), "resr"); - cpu_btr = - tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, btr), "rbtr"); cpu_edr = tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, edr), "redr"); } From 39db007eda4310f305fdbc712d59d99284bf11d4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 22:48:18 -0700 Subject: [PATCH 18/76] target/microblaze: Fix width of EDR The exception data register is only 32-bits wide. Do not use a 64-bit type to represent it. Since cpu_edr is only used during MSR and MTR instructions, we can just as easily use an explicit load and store, so eliminate the variable. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 2 +- target/microblaze/translate.c | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 72f068a5fd..b88acba12b 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -242,7 +242,7 @@ struct CPUMBState { uint32_t esr; uint32_t fsr; uint32_t btr; - uint64_t edr; + uint32_t edr; float_status fp_status; /* Stack protectors. Yes, it's a hw feature. */ uint32_t slr, shr; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index a2bba0fe61..a862ac4055 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -59,7 +59,6 @@ static TCGv_i32 cpu_pc; static TCGv_i32 cpu_msr; static TCGv_i64 cpu_ear; static TCGv_i32 cpu_esr; -static TCGv_i64 cpu_edr; static TCGv_i32 env_imm; static TCGv_i32 env_btaken; static TCGv_i32 cpu_btarget; @@ -548,7 +547,8 @@ static void dec_msr(DisasContext *dc) cpu_env, offsetof(CPUMBState, btr)); break; case SR_EDR: - tcg_gen_extu_i32_i64(cpu_edr, cpu_R[dc->ra]); + tcg_gen_st_i32(cpu_R[dc->ra], + cpu_env, offsetof(CPUMBState, edr)); break; case 0x800: tcg_gen_st_i32(cpu_R[dc->ra], @@ -591,7 +591,8 @@ static void dec_msr(DisasContext *dc) cpu_env, offsetof(CPUMBState, btr)); break; case SR_EDR: - tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_edr); + tcg_gen_ld_i32(cpu_R[dc->rd], + cpu_env, offsetof(CPUMBState, edr)); break; case 0x800: tcg_gen_ld_i32(cpu_R[dc->rd], @@ -1818,7 +1819,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) } /* Registers that aren't modeled are reported as 0 */ - qemu_fprintf(f, "redr=%" PRIx64 " rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 " + qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 " "rtlblo=0 rtlbhi=0\n", env->edr); qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr); for (i = 0; i < 32; i++) { @@ -1868,8 +1869,6 @@ void mb_tcg_init(void) tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, ear), "rear"); cpu_esr = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, esr), "resr"); - cpu_edr = - tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, edr), "redr"); } void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, From dbdb77c4df97205f9fbe1ec10ad35c1cb9729c12 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 22:54:53 -0700 Subject: [PATCH 19/76] target/microblaze: Remove cpu_ear Since cpu_ear is only used during MSR and MTR instructions, we can just as easily use an explicit load and store, so eliminate the variable. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index a862ac4055..f5ca25cead 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -57,7 +57,6 @@ static TCGv_i32 env_debug; static TCGv_i32 cpu_R[32]; static TCGv_i32 cpu_pc; static TCGv_i32 cpu_msr; -static TCGv_i64 cpu_ear; static TCGv_i32 cpu_esr; static TCGv_i32 env_imm; static TCGv_i32 env_btaken; @@ -533,7 +532,12 @@ static void dec_msr(DisasContext *dc) msr_write(dc, cpu_R[dc->ra]); break; case SR_EAR: - tcg_gen_extu_i32_i64(cpu_ear, cpu_R[dc->ra]); + { + TCGv_i64 t64 = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]); + tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear)); + tcg_temp_free_i64(t64); + } break; case SR_ESR: tcg_gen_mov_i32(cpu_esr, cpu_R[dc->ra]); @@ -573,10 +577,15 @@ static void dec_msr(DisasContext *dc) msr_read(dc, cpu_R[dc->rd]); break; case SR_EAR: - if (extended) { - tcg_gen_extrh_i64_i32(cpu_R[dc->rd], cpu_ear); - } else { - tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_ear); + { + TCGv_i64 t64 = tcg_temp_new_i64(); + tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); + if (extended) { + tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64); + } else { + tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64); + } + tcg_temp_free_i64(t64); } break; case SR_ESR: @@ -1865,8 +1874,6 @@ void mb_tcg_init(void) tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, pc), "rpc"); cpu_msr = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, msr), "rmsr"); - cpu_ear = - tcg_global_mem_new_i64(cpu_env, offsetof(CPUMBState, ear), "rear"); cpu_esr = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, esr), "resr"); } From 41ba37c4778e9364348e4ffe448650ae5e4b3563 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Aug 2020 20:49:18 -0700 Subject: [PATCH 20/76] target/microblaze: Tidy raising of exceptions Split out gen_raise_exception which does no cpu state sync. Rename t_gen_raise_exception to gen_raise_exception_sync to emphasize that it does a sync. Create gen_raise_hw_excp to simplify code raising EXCP_HW_EXCP. Since there is now only one use of cpu_esr, perform a store instead and remove the TCG variable. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 62 +++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index f5ca25cead..9a00a78b8a 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -57,7 +57,6 @@ static TCGv_i32 env_debug; static TCGv_i32 cpu_R[32]; static TCGv_i32 cpu_pc; static TCGv_i32 cpu_msr; -static TCGv_i32 cpu_esr; static TCGv_i32 env_imm; static TCGv_i32 env_btaken; static TCGv_i32 cpu_btarget; @@ -114,17 +113,31 @@ static inline void t_sync_flags(DisasContext *dc) } } -static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index) +static void gen_raise_exception(DisasContext *dc, uint32_t index) { TCGv_i32 tmp = tcg_const_i32(index); - t_sync_flags(dc); - tcg_gen_movi_i32(cpu_pc, dc->pc); gen_helper_raise_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); dc->is_jmp = DISAS_UPDATE; } +static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) +{ + t_sync_flags(dc); + tcg_gen_movi_i32(cpu_pc, dc->pc); + gen_raise_exception(dc, index); +} + +static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) +{ + TCGv_i32 tmp = tcg_const_i32(esr_ec); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); + tcg_temp_free_i32(tmp); + + gen_raise_exception_sync(dc, EXCP_HW_EXCP); +} + static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) { #ifndef CONFIG_USER_ONLY @@ -178,8 +191,7 @@ static bool trap_illegal(DisasContext *dc, bool cond) { if (cond && (dc->tb_flags & MSR_EE_FLAG) && dc->cpu->cfg.illegal_opcode_exception) { - tcg_gen_movi_i32(cpu_esr, ESR_EC_ILLEGAL_OP); - t_gen_raise_exception(dc, EXCP_HW_EXCP); + gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); } return cond; } @@ -194,8 +206,7 @@ static bool trap_userspace(DisasContext *dc, bool cond) bool cond_user = cond && mem_index == MMU_USER_IDX; if (cond_user && (dc->tb_flags & MSR_EE_FLAG)) { - tcg_gen_movi_i32(cpu_esr, ESR_EC_PRIVINSN); - t_gen_raise_exception(dc, EXCP_HW_EXCP); + gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); } return cond_user; } @@ -540,7 +551,8 @@ static void dec_msr(DisasContext *dc) } break; case SR_ESR: - tcg_gen_mov_i32(cpu_esr, cpu_R[dc->ra]); + tcg_gen_st_i32(cpu_R[dc->ra], + cpu_env, offsetof(CPUMBState, esr)); break; case SR_FSR: tcg_gen_st_i32(cpu_R[dc->ra], @@ -589,7 +601,8 @@ static void dec_msr(DisasContext *dc) } break; case SR_ESR: - tcg_gen_mov_i32(cpu_R[dc->rd], cpu_esr); + tcg_gen_ld_i32(cpu_R[dc->rd], + cpu_env, offsetof(CPUMBState, esr)); break; case SR_FSR: tcg_gen_ld_i32(cpu_R[dc->rd], @@ -1258,8 +1271,7 @@ static void dec_br(DisasContext *dc) /* mbar IMM & 16 decodes to sleep. */ if (mbar_imm & 16) { - TCGv_i32 tmp_hlt = tcg_const_i32(EXCP_HLT); - TCGv_i32 tmp_1 = tcg_const_i32(1); + TCGv_i32 tmp_1; LOG_DIS("sleep\n"); @@ -1269,13 +1281,16 @@ static void dec_br(DisasContext *dc) } 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_gen_movi_i32(cpu_pc, dc->pc + 4); - gen_helper_raise_exception(cpu_env, tmp_hlt); - tcg_temp_free_i32(tmp_hlt); tcg_temp_free_i32(tmp_1); + + tcg_gen_movi_i32(cpu_pc, dc->pc + 4); + + gen_raise_exception(dc, EXCP_HLT); return; } /* Break the TB. */ @@ -1300,14 +1315,15 @@ static void dec_br(DisasContext *dc) tcg_gen_movi_i32(env_btaken, 1); tcg_gen_mov_i32(cpu_btarget, *(dec_alu_op_b(dc))); if (link && !dslot) { - if (!(dc->tb_flags & IMM_FLAG) && (dc->imm == 8 || dc->imm == 0x18)) - t_gen_raise_exception(dc, EXCP_BREAK); + if (!(dc->tb_flags & IMM_FLAG) && + (dc->imm == 8 || dc->imm == 0x18)) { + gen_raise_exception_sync(dc, EXCP_BREAK); + } if (dc->imm == 0) { if (trap_userspace(dc, true)) { return; } - - t_gen_raise_exception(dc, EXCP_DEBUG); + gen_raise_exception_sync(dc, EXCP_DEBUG); } } } else { @@ -1411,8 +1427,7 @@ static void dec_rts(DisasContext *dc) static int dec_check_fpuv2(DisasContext *dc) { if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) { - tcg_gen_movi_i32(cpu_esr, ESR_EC_FPU); - t_gen_raise_exception(dc, EXCP_HW_EXCP); + gen_raise_hw_excp(dc, ESR_EC_FPU); } return (dc->cpu->cfg.use_fpu == 2) ? PVR2_USE_FPU2_MASK : 0; } @@ -1668,8 +1683,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) #endif if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { - t_gen_raise_exception(dc, EXCP_DEBUG); - dc->is_jmp = DISAS_UPDATE; + gen_raise_exception_sync(dc, EXCP_DEBUG); /* The address covered by the breakpoint must be included in [tb->pc, tb->pc + tb->size) in order to for it to be properly cleared -- thus we increment the PC here so that @@ -1874,8 +1888,6 @@ void mb_tcg_init(void) tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, pc), "rpc"); cpu_msr = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, msr), "rmsr"); - cpu_esr = - tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, esr), "resr"); } void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, From 41060b74bf4597b8260205bf1b6ed43c3b1696d7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Aug 2020 07:35:19 -0700 Subject: [PATCH 21/76] target/microblaze: Mark raise_exception as noreturn This will allow tcg to remove any dead code that might follow an exception. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/microblaze/helper.h b/target/microblaze/helper.h index 2f8bdea22b..820711366d 100644 --- a/target/microblaze/helper.h +++ b/target/microblaze/helper.h @@ -1,4 +1,4 @@ -DEF_HELPER_2(raise_exception, void, env, i32) +DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32) DEF_HELPER_1(debug, void, env) DEF_HELPER_FLAGS_3(carry, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_2(cmp, i32, i32, i32) From eb2022b7d0dcf5be089f9519ac096ebe60b46797 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Aug 2020 06:46:04 -0700 Subject: [PATCH 22/76] target/microblaze: Remove helper_debug and env->debug This is not used, and seems redundant with -d cpu. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 1 - target/microblaze/helper.h | 1 - target/microblaze/op_helper.c | 23 ----------------------- target/microblaze/translate.c | 16 ++-------------- 4 files changed, 2 insertions(+), 39 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index b88acba12b..7708c9a3d3 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -229,7 +229,6 @@ typedef struct CPUMBState CPUMBState; #define STREAM_NONBLOCK (1 << 4) struct CPUMBState { - uint32_t debug; uint32_t btaken; uint32_t btarget; uint32_t bimm; diff --git a/target/microblaze/helper.h b/target/microblaze/helper.h index 820711366d..9309142f8d 100644 --- a/target/microblaze/helper.h +++ b/target/microblaze/helper.h @@ -1,5 +1,4 @@ DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32) -DEF_HELPER_1(debug, void, env) DEF_HELPER_FLAGS_3(carry, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_2(cmp, i32, i32, i32) DEF_HELPER_2(cmpu, i32, i32, i32) diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index dc2bec0c99..d79202c3f8 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -71,29 +71,6 @@ void helper_raise_exception(CPUMBState *env, uint32_t index) cpu_loop_exit(cs); } -void helper_debug(CPUMBState *env) -{ - int i; - - qemu_log("PC=%08x\n", env->pc); - qemu_log("rmsr=%x resr=%x rear=%" PRIx64 " " - "debug[%x] imm=%x iflags=%x\n", - env->msr, env->esr, env->ear, - env->debug, env->imm, env->iflags); - qemu_log("btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", - env->btaken, env->btarget, - (env->msr & MSR_UM) ? "user" : "kernel", - (env->msr & MSR_UMS) ? "user" : "kernel", - (bool)(env->msr & MSR_EIP), - (bool)(env->msr & MSR_IE)); - for (i = 0; i < 32; i++) { - qemu_log("r%2.2d=%8.8x ", i, env->regs[i]); - if ((i + 1) % 4 == 0) - qemu_log("\n"); - } - qemu_log("\n\n"); -} - static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin) { uint32_t cout = 0; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 9a00a78b8a..ecfa6b86a4 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -53,7 +53,6 @@ #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ #define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */ -static TCGv_i32 env_debug; static TCGv_i32 cpu_R[32]; static TCGv_i32 cpu_pc; static TCGv_i32 cpu_msr; @@ -1675,13 +1674,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) tcg_gen_insn_start(dc->pc); num_insns++; -#if SIM_COMPAT - if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { - tcg_gen_movi_i32(cpu_pc, dc->pc); - gen_helper_debug(); - } -#endif - if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { gen_raise_exception_sync(dc, EXCP_DEBUG); /* The address covered by the breakpoint must be included in @@ -1824,10 +1816,9 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc)); qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " " - "debug=%x imm=%x iflags=%x fsr=%x rbtr=%x\n", + "imm=%x iflags=%x fsr=%x rbtr=%x\n", env->msr, env->esr, env->ear, - env->debug, env->imm, env->iflags, env->fsr, - env->btr); + env->imm, env->iflags, env->fsr, env->btr); qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", env->btaken, env->btarget, (env->msr & MSR_UM) ? "user" : "kernel", @@ -1857,9 +1848,6 @@ void mb_tcg_init(void) { int i; - env_debug = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMBState, debug), - "debug0"); env_iflags = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, iflags), "iflags"); From 9b1585589dd4f9a1357f49d233039db6c4788bf3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Aug 2020 06:47:54 -0700 Subject: [PATCH 23/76] target/microblaze: Rename env_* tcg variables to cpu_* This is cpu_imm, cpu_btaken, cpu_iflags, cpu_res_addr and cpu_res_val. It is standard for these file-scope globals to begin with cpu_*. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 54 +++++++++++++++++------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index ecfa6b86a4..9aa63ddcc5 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -56,12 +56,12 @@ static TCGv_i32 cpu_R[32]; static TCGv_i32 cpu_pc; static TCGv_i32 cpu_msr; -static TCGv_i32 env_imm; -static TCGv_i32 env_btaken; +static TCGv_i32 cpu_imm; +static TCGv_i32 cpu_btaken; static TCGv_i32 cpu_btarget; -static TCGv_i32 env_iflags; -static TCGv env_res_addr; -static TCGv_i32 env_res_val; +static TCGv_i32 cpu_iflags; +static TCGv cpu_res_addr; +static TCGv_i32 cpu_res_val; #include "exec/gen-icount.h" @@ -107,7 +107,7 @@ static inline void t_sync_flags(DisasContext *dc) { /* Synch the tb dependent flags between translator and runtime. */ if (dc->tb_flags != dc->synced_flags) { - tcg_gen_movi_i32(env_iflags, dc->tb_flags); + tcg_gen_movi_i32(cpu_iflags, dc->tb_flags); dc->synced_flags = dc->tb_flags; } } @@ -222,10 +222,10 @@ static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc) { if (dc->type_b) { if (dc->tb_flags & IMM_FLAG) - tcg_gen_ori_i32(env_imm, env_imm, dc->imm); + tcg_gen_ori_i32(cpu_imm, cpu_imm, dc->imm); else - tcg_gen_movi_i32(env_imm, (int32_t)((int16_t)dc->imm)); - return &env_imm; + tcg_gen_movi_i32(cpu_imm, (int32_t)((int16_t)dc->imm)); + return &cpu_imm; } else return &cpu_R[dc->rb]; } @@ -859,7 +859,7 @@ static inline void sync_jmpstate(DisasContext *dc) { if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { if (dc->jmp == JMP_DIRECT) { - tcg_gen_movi_i32(env_btaken, 1); + tcg_gen_movi_i32(cpu_btaken, 1); } dc->jmp = JMP_INDIRECT; tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); @@ -869,7 +869,7 @@ static inline void sync_jmpstate(DisasContext *dc) static void dec_imm(DisasContext *dc) { LOG_DIS("imm %x\n", dc->imm << 16); - tcg_gen_movi_i32(env_imm, (dc->imm << 16)); + tcg_gen_movi_i32(cpu_imm, (dc->imm << 16)); dc->tb_flags |= IMM_FLAG; dc->clear_imm = 0; } @@ -1040,8 +1040,8 @@ static void dec_load(DisasContext *dc) } if (ex) { - tcg_gen_mov_tl(env_res_addr, addr); - tcg_gen_mov_i32(env_res_val, v); + tcg_gen_mov_tl(cpu_res_addr, addr); + tcg_gen_mov_i32(cpu_res_val, v); } if (dc->rd) { tcg_gen_mov_i32(cpu_R[dc->rd], v); @@ -1103,7 +1103,7 @@ static void dec_store(DisasContext *dc) write_carryi(dc, 1); swx_skip = gen_new_label(); - tcg_gen_brcond_tl(TCG_COND_NE, env_res_addr, addr, swx_skip); + tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_skip); /* * Compare the value loaded at lwx with current contents of @@ -1111,11 +1111,11 @@ static void dec_store(DisasContext *dc) */ tval = tcg_temp_new_i32(); - tcg_gen_atomic_cmpxchg_i32(tval, addr, env_res_val, + tcg_gen_atomic_cmpxchg_i32(tval, addr, cpu_res_val, cpu_R[dc->rd], mem_index, mop); - tcg_gen_brcond_i32(TCG_COND_NE, env_res_val, tval, swx_skip); + tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_skip); write_carryi(dc, 0); tcg_temp_free_i32(tval); } @@ -1204,7 +1204,7 @@ static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false) TCGv_i32 zero = tcg_const_i32(0); tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc, - env_btaken, zero, + cpu_btaken, zero, pc_true, pc_false); tcg_temp_free_i32(zero); @@ -1245,7 +1245,7 @@ static void dec_bcc(DisasContext *dc) dc->jmp = JMP_INDIRECT; tcg_gen_addi_i32(cpu_btarget, *dec_alu_op_b(dc), dc->pc); } - eval_cc(dc, cc, env_btaken, cpu_R[dc->ra]); + eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]); } static void dec_br(DisasContext *dc) @@ -1311,7 +1311,7 @@ static void dec_br(DisasContext *dc) dc->jmp = JMP_INDIRECT; if (abs) { - tcg_gen_movi_i32(env_btaken, 1); + tcg_gen_movi_i32(cpu_btaken, 1); tcg_gen_mov_i32(cpu_btarget, *(dec_alu_op_b(dc))); if (link && !dslot) { if (!(dc->tb_flags & IMM_FLAG) && @@ -1330,7 +1330,7 @@ static void dec_br(DisasContext *dc) dc->jmp = JMP_DIRECT; dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm); } else { - tcg_gen_movi_i32(env_btaken, 1); + tcg_gen_movi_i32(cpu_btaken, 1); tcg_gen_addi_i32(cpu_btarget, *dec_alu_op_b(dc), dc->pc); } } @@ -1419,7 +1419,7 @@ static void dec_rts(DisasContext *dc) LOG_DIS("rts ir=%x\n", dc->ir); dc->jmp = JMP_INDIRECT; - tcg_gen_movi_i32(env_btaken, 1); + tcg_gen_movi_i32(cpu_btaken, 1); tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc)); } @@ -1722,7 +1722,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) TCGLabel *l1 = gen_new_label(); t_sync_flags(dc); /* Conditional jmp. */ - tcg_gen_brcondi_i32(TCG_COND_NE, env_btaken, 0, l1); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1); gen_goto_tb(dc, 1, dc->pc); gen_set_label(l1); gen_goto_tb(dc, 0, dc->jmp_pc); @@ -1848,22 +1848,22 @@ void mb_tcg_init(void) { int i; - env_iflags = tcg_global_mem_new_i32(cpu_env, + cpu_iflags = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, iflags), "iflags"); - env_imm = tcg_global_mem_new_i32(cpu_env, + cpu_imm = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, imm), "imm"); cpu_btarget = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, btarget), "btarget"); - env_btaken = tcg_global_mem_new_i32(cpu_env, + cpu_btaken = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, btaken), "btaken"); - env_res_addr = tcg_global_mem_new(cpu_env, + cpu_res_addr = tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); - env_res_val = tcg_global_mem_new_i32(cpu_env, + cpu_res_val = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, res_val), "res_val"); for (i = 0; i < ARRAY_SIZE(cpu_R); i++) { From 480d29a8fa842ca94297600397041f0efb0c7bd0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Aug 2020 06:29:47 -0700 Subject: [PATCH 24/76] target/microblaze: Tidy mb_tcg_init All of the tcg globals can be recorded in the same table. Drop the "r" prefix from "rpc" and "rmsr". Obviates the need for regnames[], which was incorrectly not const. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 62 +++++++++++++++-------------------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 9aa63ddcc5..e709884f2d 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -95,14 +95,6 @@ typedef struct DisasContext { int singlestep_enabled; } DisasContext; -static const char *regnames[] = -{ - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", -}; - static inline void t_sync_flags(DisasContext *dc) { /* Synch the tb dependent flags between translator and runtime. */ @@ -1846,36 +1838,36 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) void mb_tcg_init(void) { - int i; +#define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } +#define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } - cpu_iflags = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMBState, iflags), - "iflags"); - cpu_imm = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMBState, imm), - "imm"); - cpu_btarget = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMBState, btarget), - "btarget"); - cpu_btaken = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMBState, btaken), - "btaken"); - cpu_res_addr = tcg_global_mem_new(cpu_env, - offsetof(CPUMBState, res_addr), - "res_addr"); - cpu_res_val = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMBState, res_val), - "res_val"); - for (i = 0; i < ARRAY_SIZE(cpu_R); i++) { - cpu_R[i] = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMBState, regs[i]), - regnames[i]); + static const struct { + TCGv_i32 *var; int ofs; char name[8]; + } i32s[] = { + R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), + R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), + R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), + R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), + + SP(pc), + SP(msr), + SP(imm), + SP(iflags), + SP(btaken), + SP(btarget), + SP(res_val), + }; + +#undef R +#undef SP + + for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { + *i32s[i].var = + tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); } - cpu_pc = - tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, pc), "rpc"); - cpu_msr = - tcg_global_mem_new_i32(cpu_env, offsetof(CPUMBState, msr), "rmsr"); + cpu_res_addr = + tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); } void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, From 1074c0fb9153f631ce93f7e7d74b935fdcb0d82a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Aug 2020 11:58:23 -0700 Subject: [PATCH 25/76] target/microblaze: Split out MSR[C] to its own variable Having the MSR[C] bit separate will improve arithmetic that operates on the carry bit. Having mb_cpu_read_msr() populate MSR[CC] will prevent the carry copy not matching the carry bit. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- linux-user/elfload.c | 2 +- target/microblaze/cpu.c | 4 +- target/microblaze/cpu.h | 19 +++++++- target/microblaze/gdbstub.c | 4 +- target/microblaze/helper.c | 58 +++++++++++----------- target/microblaze/translate.c | 91 +++++++++++------------------------ 6 files changed, 82 insertions(+), 96 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 58b3f4ef4d..04c28cbb9e 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1039,7 +1039,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env } (*regs)[pos++] = tswapreg(env->pc); - (*regs)[pos++] = tswapreg(env->msr); + (*regs)[pos++] = tswapreg(mb_cpu_read_msr(env)); (*regs)[pos++] = 0; (*regs)[pos++] = tswapreg(env->ear); (*regs)[pos++] = 0; diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 0eac068570..1eabf5cc3f 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -121,9 +121,9 @@ static void mb_cpu_reset(DeviceState *dev) #if defined(CONFIG_USER_ONLY) /* start in user mode with interrupts enabled. */ - env->msr = MSR_EE | MSR_IE | MSR_VM | MSR_UM; + mb_cpu_write_msr(env, MSR_EE | MSR_IE | MSR_VM | MSR_UM); #else - env->msr = 0; + mb_cpu_write_msr(env, 0); mmu_init(&env->mmu); env->mmu.c_mmu = 3; env->mmu.c_mmu_tlb_access = 3; diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 7708c9a3d3..7066878ac7 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -236,7 +236,8 @@ struct CPUMBState { uint32_t imm; uint32_t regs[32]; uint32_t pc; - uint32_t msr; + uint32_t msr; /* All bits of MSR except MSR[C] and MSR[CC] */ + uint32_t msr_c; /* MSR[C], in low bit; other bits must be 0 */ uint64_t ear; uint32_t esr; uint32_t fsr; @@ -327,6 +328,22 @@ hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int mb_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +static inline uint32_t mb_cpu_read_msr(const CPUMBState *env) +{ + /* Replicate MSR[C] to MSR[CC]. */ + return env->msr | (env->msr_c * (MSR_C | MSR_CC)); +} + +static inline void mb_cpu_write_msr(CPUMBState *env, uint32_t val) +{ + env->msr_c = (val >> 2) & 1; + /* + * Clear both MSR[C] and MSR[CC] from the saved copy. + * MSR_PVR is not writable and is always clear. + */ + env->msr = val & ~(MSR_C | MSR_CC | MSR_PVR); +} + void mb_tcg_init(void); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c index 9cba9d2215..08d6a0e807 100644 --- a/target/microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c @@ -62,7 +62,7 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) val = env->pc; break; case GDB_MSR: - val = env->msr; + val = mb_cpu_read_msr(env); break; case GDB_EAR: val = env->ear; @@ -118,7 +118,7 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->pc = tmp; break; case GDB_MSR: - env->msr = tmp; + mb_cpu_write_msr(env, tmp); break; case GDB_EAR: env->ear = tmp; diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index b2373f6a23..9a95456401 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -112,12 +112,11 @@ void mb_cpu_do_interrupt(CPUState *cs) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); CPUMBState *env = &cpu->env; - uint32_t t; + uint32_t t, msr = mb_cpu_read_msr(env); /* IMM flag cannot propagate across a branch and into the dslot. */ assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG))); assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG))); -/* assert(env->msr & (MSR_EE)); Only for HW exceptions. */ env->res_addr = RES_ADDR_NONE; switch (cs->exception_index) { case EXCP_HW_EXCP: @@ -136,11 +135,12 @@ void mb_cpu_do_interrupt(CPUState *cs) } /* Disable the MMU. */ - t = (env->msr & (MSR_VM | MSR_UM)) << 1; - env->msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); - env->msr |= t; + t = (msr & (MSR_VM | MSR_UM)) << 1; + msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); + msr |= t; /* Exception in progress. */ - env->msr |= MSR_EIP; + msr |= MSR_EIP; + mb_cpu_write_msr(env, msr); qemu_log_mask(CPU_LOG_INT, "hw exception at pc=%x ear=%" PRIx64 " " @@ -178,11 +178,12 @@ void mb_cpu_do_interrupt(CPUState *cs) } /* Disable the MMU. */ - t = (env->msr & (MSR_VM | MSR_UM)) << 1; - env->msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); - env->msr |= t; + t = (msr & (MSR_VM | MSR_UM)) << 1; + msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); + msr |= t; /* Exception in progress. */ - env->msr |= MSR_EIP; + msr |= MSR_EIP; + mb_cpu_write_msr(env, msr); qemu_log_mask(CPU_LOG_INT, "exception at pc=%x ear=%" PRIx64 " iflags=%x\n", @@ -193,11 +194,11 @@ void mb_cpu_do_interrupt(CPUState *cs) break; case EXCP_IRQ: - assert(!(env->msr & (MSR_EIP | MSR_BIP))); - assert(env->msr & MSR_IE); + assert(!(msr & (MSR_EIP | MSR_BIP))); + assert(msr & MSR_IE); assert(!(env->iflags & D_FLAG)); - t = (env->msr & (MSR_VM | MSR_UM)) << 1; + t = (msr & (MSR_VM | MSR_UM)) << 1; #if 0 #include "disas/disas.h" @@ -212,21 +213,20 @@ void mb_cpu_do_interrupt(CPUState *cs) && (!strcmp("netif_rx", sym) || !strcmp("process_backlog", sym))) { - qemu_log( - "interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n", - env->pc, env->msr, t, env->iflags, - sym); + qemu_log("interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n", + env->pc, msr, t, env->iflags, sym); log_cpu_state(cs, 0); } } #endif qemu_log_mask(CPU_LOG_INT, - "interrupt at pc=%x msr=%x %x iflags=%x\n", - env->pc, env->msr, t, env->iflags); + "interrupt at pc=%x msr=%x %x iflags=%x\n", + env->pc, msr, t, env->iflags); - env->msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM | MSR_IE); - env->msr |= t; + msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM | MSR_IE); + msr |= t; + mb_cpu_write_msr(env, msr); env->regs[14] = env->pc; env->pc = cpu->cfg.base_vectors + 0x10; @@ -237,20 +237,22 @@ void mb_cpu_do_interrupt(CPUState *cs) case EXCP_HW_BREAK: assert(!(env->iflags & IMM_FLAG)); assert(!(env->iflags & D_FLAG)); - t = (env->msr & (MSR_VM | MSR_UM)) << 1; + t = (msr & (MSR_VM | MSR_UM)) << 1; qemu_log_mask(CPU_LOG_INT, "break at pc=%x msr=%x %x iflags=%x\n", - env->pc, env->msr, t, env->iflags); + env->pc, msr, t, env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); - env->msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); - env->msr |= t; - env->msr |= MSR_BIP; + 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; - env->msr |= MSR_BIP; + msr |= MSR_BIP; env->pc = cpu->cfg.base_vectors + 0x18; - } else + } else { env->pc = env->btarget; + } + mb_cpu_write_msr(env, msr); break; default: cpu_abort(cs, "unhandled exception type=%d\n", diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index e709884f2d..0c9b4ffa5a 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -56,6 +56,7 @@ static TCGv_i32 cpu_R[32]; static TCGv_i32 cpu_pc; static TCGv_i32 cpu_msr; +static TCGv_i32 cpu_msr_c; static TCGv_i32 cpu_imm; static TCGv_i32 cpu_btaken; static TCGv_i32 cpu_btarget; @@ -150,30 +151,6 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) } } -static void read_carry(DisasContext *dc, TCGv_i32 d) -{ - tcg_gen_shri_i32(d, cpu_msr, 31); -} - -/* - * write_carry sets the carry bits in MSR based on bit 0 of v. - * v[31:1] are ignored. - */ -static void write_carry(DisasContext *dc, TCGv_i32 v) -{ - /* Deposit bit 0 into MSR_C and the alias MSR_CC. */ - tcg_gen_deposit_i32(cpu_msr, cpu_msr, v, 2, 1); - tcg_gen_deposit_i32(cpu_msr, cpu_msr, v, 31, 1); -} - -static void write_carryi(DisasContext *dc, bool carry) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - tcg_gen_movi_i32(t0, carry); - write_carry(dc, t0); - tcg_temp_free_i32(t0); -} - /* * Returns true if the insn an illegal operation. * If exceptions are enabled, an exception is raised. @@ -243,11 +220,7 @@ static void dec_add(DisasContext *dc) if (c) { /* c - Add carry into the result. */ - cf = tcg_temp_new_i32(); - - read_carry(dc, cf); - tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf); - tcg_temp_free_i32(cf); + tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cpu_msr_c); } } return; @@ -257,21 +230,15 @@ static void dec_add(DisasContext *dc) /* Extract carry. */ cf = tcg_temp_new_i32(); if (c) { - read_carry(dc, cf); + tcg_gen_mov_i32(cf, cpu_msr_c); } else { tcg_gen_movi_i32(cf, 0); } + gen_helper_carry(cpu_msr_c, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf); if (dc->rd) { - TCGv_i32 ncf = tcg_temp_new_i32(); - gen_helper_carry(ncf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf); tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf); - write_carry(dc, ncf); - tcg_temp_free_i32(ncf); - } else { - gen_helper_carry(cf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf); - write_carry(dc, cf); } tcg_temp_free_i32(cf); } @@ -309,11 +276,7 @@ static void dec_sub(DisasContext *dc) if (c) { /* c - Add carry into the result. */ - cf = tcg_temp_new_i32(); - - read_carry(dc, cf); - tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf); - tcg_temp_free_i32(cf); + tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cpu_msr_c); } } return; @@ -324,7 +287,7 @@ static void dec_sub(DisasContext *dc) cf = tcg_temp_new_i32(); na = tcg_temp_new_i32(); if (c) { - read_carry(dc, cf); + tcg_gen_mov_i32(cf, cpu_msr_c); } else { tcg_gen_movi_i32(cf, 1); } @@ -332,16 +295,10 @@ static void dec_sub(DisasContext *dc) /* d = b + ~a + c. carry defaults to 1. */ tcg_gen_not_i32(na, cpu_R[dc->ra]); + gen_helper_carry(cpu_msr_c, na, *(dec_alu_op_b(dc)), cf); if (dc->rd) { - TCGv_i32 ncf = tcg_temp_new_i32(); - gen_helper_carry(ncf, na, *(dec_alu_op_b(dc)), cf); tcg_gen_add_i32(cpu_R[dc->rd], na, *(dec_alu_op_b(dc))); tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf); - write_carry(dc, ncf); - tcg_temp_free_i32(ncf); - } else { - gen_helper_carry(cf, na, *(dec_alu_op_b(dc)), cf); - write_carry(dc, cf); } tcg_temp_free_i32(cf); tcg_temp_free_i32(na); @@ -429,16 +386,26 @@ static void dec_xor(DisasContext *dc) tcg_gen_xor_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); } -static inline void msr_read(DisasContext *dc, TCGv_i32 d) +static void msr_read(DisasContext *dc, TCGv_i32 d) { - tcg_gen_mov_i32(d, cpu_msr); + TCGv_i32 t; + + /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ + t = tcg_temp_new_i32(); + tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); + tcg_gen_or_i32(d, cpu_msr, t); + tcg_temp_free_i32(t); } -static inline void msr_write(DisasContext *dc, TCGv_i32 v) +static void msr_write(DisasContext *dc, TCGv_i32 v) { dc->cpustate_changed = 1; - /* PVR bit is not writable, and is never set. */ - tcg_gen_andi_i32(cpu_msr, v, ~MSR_PVR); + + /* Install MSR_C. */ + tcg_gen_extract_i32(cpu_msr_c, v, 2, 1); + + /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */ + tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR)); } static void dec_msr(DisasContext *dc) @@ -778,8 +745,8 @@ static void dec_bit(DisasContext *dc) t0 = tcg_temp_new_i32(); LOG_DIS("src r%d r%d\n", dc->rd, dc->ra); - tcg_gen_andi_i32(t0, cpu_msr, MSR_CC); - write_carry(dc, cpu_R[dc->ra]); + tcg_gen_shli_i32(t0, cpu_msr_c, 31); + tcg_gen_andi_i32(cpu_msr_c, cpu_R[dc->ra], 1); if (dc->rd) { tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->rd], t0); @@ -792,8 +759,7 @@ static void dec_bit(DisasContext *dc) /* srl. */ LOG_DIS("srl r%d r%d\n", dc->rd, dc->ra); - /* Update carry. Note that write carry only looks at the LSB. */ - write_carry(dc, cpu_R[dc->ra]); + tcg_gen_andi_i32(cpu_msr_c, cpu_R[dc->ra], 1); if (dc->rd) { if (op == 0x41) tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); @@ -1042,7 +1008,7 @@ static void dec_load(DisasContext *dc) if (ex) { /* lwx */ /* no support for AXI exclusive so always clear C */ - write_carryi(dc, 0); + tcg_gen_movi_i32(cpu_msr_c, 0); } tcg_temp_free(addr); @@ -1093,7 +1059,7 @@ static void dec_store(DisasContext *dc) /* swx does not throw unaligned access errors, so force alignment */ tcg_gen_andi_tl(addr, addr, ~3); - write_carryi(dc, 1); + tcg_gen_movi_i32(cpu_msr_c, 1); swx_skip = gen_new_label(); tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_skip); @@ -1108,7 +1074,7 @@ static void dec_store(DisasContext *dc) mop); tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_skip); - write_carryi(dc, 0); + tcg_gen_movi_i32(cpu_msr_c, 0); tcg_temp_free_i32(tval); } @@ -1851,6 +1817,7 @@ void mb_tcg_init(void) SP(pc), SP(msr), + SP(msr_c), SP(imm), SP(iflags), SP(btaken), From a2b80dbd96569338a4ac3f32aebbbd2d9a7f9718 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 16:53:08 -0700 Subject: [PATCH 26/76] target/microblaze: Use DISAS_NORETURN Both exceptions and gen_goto_tb do not return. Use the official DISAS_NORETURN enumerator for this case. This eliminates all use of DISAS_TB_JUMP. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 0c9b4ffa5a..53ca0bfb38 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -51,7 +51,6 @@ /* is_jmp field values */ #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ -#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */ static TCGv_i32 cpu_R[32]; static TCGv_i32 cpu_pc; @@ -111,7 +110,7 @@ static void gen_raise_exception(DisasContext *dc, uint32_t index) gen_helper_raise_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); - dc->is_jmp = DISAS_UPDATE; + dc->is_jmp = DISAS_NORETURN; } static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) @@ -149,6 +148,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) tcg_gen_movi_i32(cpu_pc, dest); tcg_gen_exit_tb(NULL, 0); } + dc->is_jmp = DISAS_NORETURN; } /* @@ -1675,7 +1675,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) } else if (dc->jmp == JMP_DIRECT) { t_sync_flags(dc); gen_goto_tb(dc, 0, dc->jmp_pc); - dc->is_jmp = DISAS_TB_JUMP; } else if (dc->jmp == JMP_DIRECT_CC) { TCGLabel *l1 = gen_new_label(); t_sync_flags(dc); @@ -1684,8 +1683,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) gen_goto_tb(dc, 1, dc->pc); gen_set_label(l1); gen_goto_tb(dc, 0, dc->jmp_pc); - - dc->is_jmp = DISAS_TB_JUMP; } break; } @@ -1717,7 +1714,9 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) } t_sync_flags(dc); - if (unlikely(cs->singlestep_enabled)) { + if (dc->is_jmp == DISAS_NORETURN) { + /* nothing more to generate */ + } else if (unlikely(cs->singlestep_enabled)) { TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); if (dc->is_jmp != DISAS_JUMP) { @@ -1730,16 +1729,14 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) case DISAS_NEXT: gen_goto_tb(dc, 1, npc); break; - default: case DISAS_JUMP: case DISAS_UPDATE: /* indicate that the hash table must be used to find the next TB */ tcg_gen_exit_tb(NULL, 0); break; - case DISAS_TB_JUMP: - /* nothing more to generate */ - break; + default: + g_assert_not_reached(); } } gen_tb_end(tb, num_insns); From 0b46fa08213b5e575b14a6dc883b45af8c37f6f6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 20:12:21 -0700 Subject: [PATCH 27/76] target/microblaze: Check singlestep_enabled in gen_goto_tb Do not use goto_tb if we're single-stepping. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 53ca0bfb38..2e753fa621 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -140,7 +140,12 @@ static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) { - if (use_goto_tb(dc, dest)) { + if (dc->singlestep_enabled) { + TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); + tcg_gen_movi_i32(cpu_pc, dest); + gen_helper_raise_exception(cpu_env, tmp); + tcg_temp_free_i32(tmp); + } else if (use_goto_tb(dc, dest)) { tcg_gen_goto_tb(n); tcg_gen_movi_i32(cpu_pc, dest); tcg_gen_exit_tb(dc->tb, n); From d4705ae084461ed4b507cdac886d2b8ff29452eb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 15:50:21 -0700 Subject: [PATCH 28/76] target/microblaze: Convert to DisasContextBase Part one of conversion to the generic translator_loop is to use the DisasContextBase and the members therein. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 102 +++++++++++++++++----------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 2e753fa621..45b1555f85 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -67,8 +67,8 @@ static TCGv_i32 cpu_res_val; /* This is the state at translation time. */ typedef struct DisasContext { + DisasContextBase base; MicroBlazeCPU *cpu; - uint32_t pc; /* Decoder. */ int type_b; @@ -81,7 +81,6 @@ typedef struct DisasContext { unsigned int delayed_branch; unsigned int tb_flags, synced_flags; /* tb dependent flags. */ unsigned int clear_imm; - int is_jmp; #define JMP_NOJMP 0 #define JMP_DIRECT 1 @@ -91,8 +90,6 @@ typedef struct DisasContext { uint32_t jmp_pc; int abort_at_next_insn; - struct TranslationBlock *tb; - int singlestep_enabled; } DisasContext; static inline void t_sync_flags(DisasContext *dc) @@ -110,13 +107,13 @@ static void gen_raise_exception(DisasContext *dc, uint32_t index) gen_helper_raise_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); - dc->is_jmp = DISAS_NORETURN; + dc->base.is_jmp = DISAS_NORETURN; } static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) { t_sync_flags(dc); - tcg_gen_movi_i32(cpu_pc, dc->pc); + tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); gen_raise_exception(dc, index); } @@ -132,7 +129,7 @@ static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) { #ifndef CONFIG_USER_ONLY - return (dc->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); + return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); #else return true; #endif @@ -140,7 +137,7 @@ static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) { - if (dc->singlestep_enabled) { + if (dc->base.singlestep_enabled) { TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); tcg_gen_movi_i32(cpu_pc, dest); gen_helper_raise_exception(cpu_env, tmp); @@ -148,12 +145,12 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) } else if (use_goto_tb(dc, dest)) { tcg_gen_goto_tb(n); tcg_gen_movi_i32(cpu_pc, dest); - tcg_gen_exit_tb(dc->tb, n); + tcg_gen_exit_tb(dc->base.tb, n); } else { tcg_gen_movi_i32(cpu_pc, dest); tcg_gen_exit_tb(NULL, 0); } - dc->is_jmp = DISAS_NORETURN; + dc->base.is_jmp = DISAS_NORETURN; } /* @@ -468,8 +465,8 @@ static void dec_msr(DisasContext *dc) msr_write(dc, t0); tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); - tcg_gen_movi_i32(cpu_pc, dc->pc + 4); - dc->is_jmp = DISAS_UPDATE; + tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); + dc->base.is_jmp = DISAS_UPDATE; return; } @@ -546,7 +543,7 @@ static void dec_msr(DisasContext *dc) switch (sr) { case SR_PC: - tcg_gen_movi_i32(cpu_R[dc->rd], dc->pc); + tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); break; case SR_MSR: msr_read(dc, cpu_R[dc->rd]); @@ -813,7 +810,7 @@ static void dec_bit(DisasContext *dc) break; default: cpu_abort(cs, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n", - dc->pc, op, dc->rd, dc->ra, dc->rb); + (uint32_t)dc->base.pc_next, op, dc->rd, dc->ra, dc->rb); break; } } @@ -994,7 +991,7 @@ static void dec_load(DisasContext *dc) TCGv_i32 treg = tcg_const_i32(dc->rd); TCGv_i32 tsize = tcg_const_i32(size - 1); - tcg_gen_movi_i32(cpu_pc, dc->pc); + tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); gen_helper_memalign(cpu_env, addr, treg, t0, tsize); tcg_temp_free_i32(t0); @@ -1114,7 +1111,7 @@ static void dec_store(DisasContext *dc) TCGv_i32 treg = tcg_const_i32(dc->rd); TCGv_i32 tsize = tcg_const_i32(size - 1); - tcg_gen_movi_i32(cpu_pc, dc->pc); + tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); /* FIXME: if the alignment is wrong, we should restore the value * in memory. One possible way to achieve this is to probe * the MMU prior to the memaccess, thay way we could put @@ -1201,12 +1198,12 @@ static void dec_bcc(DisasContext *dc) if (dec_alu_op_b_is_small_imm(dc)) { int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend. */ - tcg_gen_movi_i32(cpu_btarget, dc->pc + offset); + tcg_gen_movi_i32(cpu_btarget, dc->base.pc_next + offset); dc->jmp = JMP_DIRECT_CC; - dc->jmp_pc = dc->pc + offset; + dc->jmp_pc = dc->base.pc_next + offset; } else { dc->jmp = JMP_INDIRECT; - tcg_gen_addi_i32(cpu_btarget, *dec_alu_op_b(dc), dc->pc); + tcg_gen_addi_i32(cpu_btarget, *dec_alu_op_b(dc), dc->base.pc_next); } eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]); } @@ -1250,7 +1247,7 @@ static void dec_br(DisasContext *dc) +offsetof(CPUState, halted)); tcg_temp_free_i32(tmp_1); - tcg_gen_movi_i32(cpu_pc, dc->pc + 4); + tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); gen_raise_exception(dc, EXCP_HLT); return; @@ -1270,7 +1267,7 @@ static void dec_br(DisasContext *dc) dec_setup_dslot(dc); } if (link && dc->rd) - tcg_gen_movi_i32(cpu_R[dc->rd], dc->pc); + tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); dc->jmp = JMP_INDIRECT; if (abs) { @@ -1291,10 +1288,10 @@ static void dec_br(DisasContext *dc) } else { if (dec_alu_op_b_is_small_imm(dc)) { dc->jmp = JMP_DIRECT; - dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm); + dc->jmp_pc = dc->base.pc_next + (int32_t)((int16_t)dc->imm); } else { tcg_gen_movi_i32(cpu_btaken, 1); - tcg_gen_addi_i32(cpu_btarget, *dec_alu_op_b(dc), dc->pc); + tcg_gen_addi_i32(cpu_btarget, *dec_alu_op_b(dc), dc->base.pc_next); } } } @@ -1459,7 +1456,8 @@ static void dec_fpu(DisasContext *dc) qemu_log_mask(LOG_UNIMP, "unimplemented fcmp fpu_insn=%x pc=%x" " opc=%x\n", - fpu_insn, dc->pc, dc->opcode); + fpu_insn, (uint32_t)dc->base.pc_next, + dc->opcode); dc->abort_at_next_insn = 1; break; } @@ -1489,7 +1487,7 @@ static void dec_fpu(DisasContext *dc) default: qemu_log_mask(LOG_UNIMP, "unimplemented FPU insn fpu_insn=%x pc=%x" " opc=%x\n", - fpu_insn, dc->pc, dc->opcode); + fpu_insn, (uint32_t)dc->base.pc_next, dc->opcode); dc->abort_at_next_insn = 1; break; } @@ -1500,7 +1498,8 @@ static void dec_null(DisasContext *dc) if (trap_illegal(dc, true)) { return; } - qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", dc->pc, dc->opcode); + qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", + (uint32_t)dc->base.pc_next, dc->opcode); dc->abort_at_next_insn = 1; } @@ -1610,19 +1609,20 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) pc_start = tb->pc; dc->cpu = cpu; - dc->tb = tb; org_flags = dc->synced_flags = dc->tb_flags = tb->flags; - dc->is_jmp = DISAS_NEXT; dc->jmp = 0; dc->delayed_branch = !!(dc->tb_flags & D_FLAG); if (dc->delayed_branch) { dc->jmp = JMP_INDIRECT; } - dc->pc = pc_start; - dc->singlestep_enabled = cs->singlestep_enabled; + dc->base.pc_first = pc_start; + dc->base.pc_next = pc_start; + dc->base.singlestep_enabled = cs->singlestep_enabled; dc->cpustate_changed = 0; dc->abort_at_next_insn = 0; + dc->base.is_jmp = DISAS_NEXT; + dc->base.tb = tb; if (pc_start & 3) { cpu_abort(cs, "Microblaze: unaligned PC=%x\n", pc_start); @@ -1634,31 +1634,31 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) gen_tb_start(tb); do { - tcg_gen_insn_start(dc->pc); + tcg_gen_insn_start(dc->base.pc_next); num_insns++; - if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { + if (unlikely(cpu_breakpoint_test(cs, dc->base.pc_next, BP_ANY))) { gen_raise_exception_sync(dc, EXCP_DEBUG); /* The address covered by the breakpoint must be included in [tb->pc, tb->pc + tb->size) in order to for it to be properly cleared -- thus we increment the PC here so that the logic setting tb->size below does the right thing. */ - dc->pc += 4; + dc->base.pc_next += 4; break; } /* Pretty disas. */ - LOG_DIS("%8.8x:\t", dc->pc); + LOG_DIS("%8.8x:\t", (uint32_t)dc->base.pc_next); if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) { gen_io_start(); } dc->clear_imm = 1; - decode(dc, cpu_ldl_code(env, dc->pc)); + decode(dc, cpu_ldl_code(env, dc->base.pc_next)); if (dc->clear_imm) dc->tb_flags &= ~IMM_FLAG; - dc->pc += 4; + dc->base.pc_next += 4; if (dc->delayed_branch) { dc->delayed_branch--; @@ -1673,10 +1673,10 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) dc->tb_flags &= ~D_FLAG; /* If it is a direct jump, try direct chaining. */ if (dc->jmp == JMP_INDIRECT) { - TCGv_i32 tmp_pc = tcg_const_i32(dc->pc); + TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next); eval_cond_jmp(dc, cpu_btarget, tmp_pc); tcg_temp_free_i32(tmp_pc); - dc->is_jmp = DISAS_JUMP; + dc->base.is_jmp = DISAS_JUMP; } else if (dc->jmp == JMP_DIRECT) { t_sync_flags(dc); gen_goto_tb(dc, 0, dc->jmp_pc); @@ -1685,26 +1685,26 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) t_sync_flags(dc); /* Conditional jmp. */ tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1); - gen_goto_tb(dc, 1, dc->pc); + gen_goto_tb(dc, 1, dc->base.pc_next); gen_set_label(l1); gen_goto_tb(dc, 0, dc->jmp_pc); } break; } } - if (cs->singlestep_enabled) { + if (dc->base.singlestep_enabled) { break; } - } while (!dc->is_jmp && !dc->cpustate_changed + } while (!dc->base.is_jmp && !dc->cpustate_changed && !tcg_op_buf_full() && !singlestep - && (dc->pc - page_start < TARGET_PAGE_SIZE) + && (dc->base.pc_next - page_start < TARGET_PAGE_SIZE) && num_insns < max_insns); - npc = dc->pc; + npc = dc->base.pc_next; if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { if (dc->tb_flags & D_FLAG) { - dc->is_jmp = DISAS_UPDATE; + dc->base.is_jmp = DISAS_UPDATE; tcg_gen_movi_i32(cpu_pc, npc); sync_jmpstate(dc); } else @@ -1712,25 +1712,25 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) } /* Force an update if the per-tb cpu state has changed. */ - if (dc->is_jmp == DISAS_NEXT + if (dc->base.is_jmp == DISAS_NEXT && (dc->cpustate_changed || org_flags != dc->tb_flags)) { - dc->is_jmp = DISAS_UPDATE; + dc->base.is_jmp = DISAS_UPDATE; tcg_gen_movi_i32(cpu_pc, npc); } t_sync_flags(dc); - if (dc->is_jmp == DISAS_NORETURN) { + if (dc->base.is_jmp == DISAS_NORETURN) { /* nothing more to generate */ } else if (unlikely(cs->singlestep_enabled)) { TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); - if (dc->is_jmp != DISAS_JUMP) { + if (dc->base.is_jmp != DISAS_JUMP) { tcg_gen_movi_i32(cpu_pc, npc); } gen_helper_raise_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); } else { - switch(dc->is_jmp) { + switch (dc->base.is_jmp) { case DISAS_NEXT: gen_goto_tb(dc, 1, npc); break; @@ -1746,7 +1746,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) } gen_tb_end(tb, num_insns); - tb->size = dc->pc - pc_start; + tb->size = dc->base.pc_next - pc_start; tb->icount = num_insns; #ifdef DEBUG_DISAS @@ -1755,7 +1755,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) && qemu_log_in_addr_range(pc_start)) { FILE *logfile = qemu_log_lock(); qemu_log("--------------\n"); - log_target_disas(cs, pc_start, dc->pc - pc_start); + log_target_disas(cs, pc_start, dc->base.pc_next - pc_start); qemu_log_unlock(logfile); } #endif From 372122e3e7fe1134dbd232aa4f9f56ffef84143a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 20:56:05 -0700 Subject: [PATCH 29/76] target/microblaze: Convert to translator_loop Finish the conversion to the generic translator_loop. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 289 ++++++++++++++++++---------------- 1 file changed, 149 insertions(+), 140 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 45b1555f85..6a9710d76d 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1595,172 +1595,181 @@ static inline void decode(DisasContext *dc, uint32_t ir) } } -/* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) { - CPUMBState *env = cs->env_ptr; - MicroBlazeCPU *cpu = env_archcpu(env); - uint32_t pc_start; - struct DisasContext ctx; - struct DisasContext *dc = &ctx; - uint32_t page_start, org_flags; - uint32_t npc; - int num_insns; + DisasContext *dc = container_of(dcb, DisasContext, base); + MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); + int bound; - pc_start = tb->pc; dc->cpu = cpu; - org_flags = dc->synced_flags = dc->tb_flags = tb->flags; - - dc->jmp = 0; + dc->synced_flags = dc->tb_flags = dc->base.tb->flags; dc->delayed_branch = !!(dc->tb_flags & D_FLAG); - if (dc->delayed_branch) { - dc->jmp = JMP_INDIRECT; - } - dc->base.pc_first = pc_start; - dc->base.pc_next = pc_start; - dc->base.singlestep_enabled = cs->singlestep_enabled; + dc->jmp = dc->delayed_branch ? JMP_INDIRECT : JMP_NOJMP; dc->cpustate_changed = 0; dc->abort_at_next_insn = 0; - dc->base.is_jmp = DISAS_NEXT; - dc->base.tb = tb; - if (pc_start & 3) { - cpu_abort(cs, "Microblaze: unaligned PC=%x\n", pc_start); + bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; + dc->base.max_insns = MIN(dc->base.max_insns, bound); +} + +static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) +{ +} + +static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) +{ + tcg_gen_insn_start(dcb->pc_next); +} + +static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs, + const CPUBreakpoint *bp) +{ + DisasContext *dc = container_of(dcb, DisasContext, base); + + gen_raise_exception_sync(dc, EXCP_DEBUG); + + /* + * The address covered by the breakpoint must be included in + * [tb->pc, tb->pc + tb->size) in order to for it to be + * properly cleared -- thus we increment the PC here so that + * the logic setting tb->size below does the right thing. + */ + dc->base.pc_next += 4; + return true; +} + +static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) +{ + DisasContext *dc = container_of(dcb, DisasContext, base); + CPUMBState *env = cs->env_ptr; + + /* TODO: This should raise an exception, not terminate qemu. */ + if (dc->base.pc_next & 3) { + cpu_abort(cs, "Microblaze: unaligned PC=%x\n", + (uint32_t)dc->base.pc_next); } - page_start = pc_start & TARGET_PAGE_MASK; - num_insns = 0; + dc->clear_imm = 1; + decode(dc, cpu_ldl_code(env, dc->base.pc_next)); + if (dc->clear_imm) { + dc->tb_flags &= ~IMM_FLAG; + } + dc->base.pc_next += 4; - gen_tb_start(tb); - do - { - tcg_gen_insn_start(dc->base.pc_next); - num_insns++; - - if (unlikely(cpu_breakpoint_test(cs, dc->base.pc_next, BP_ANY))) { - gen_raise_exception_sync(dc, EXCP_DEBUG); - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the logic setting tb->size below does the right thing. */ - dc->base.pc_next += 4; - break; + if (dc->delayed_branch && --dc->delayed_branch == 0) { + if (dc->tb_flags & DRTI_FLAG) { + do_rti(dc); } - - /* Pretty disas. */ - LOG_DIS("%8.8x:\t", (uint32_t)dc->base.pc_next); - - if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) { - gen_io_start(); + if (dc->tb_flags & DRTB_FLAG) { + do_rtb(dc); } - - dc->clear_imm = 1; - decode(dc, cpu_ldl_code(env, dc->base.pc_next)); - if (dc->clear_imm) - dc->tb_flags &= ~IMM_FLAG; - dc->base.pc_next += 4; - - if (dc->delayed_branch) { - dc->delayed_branch--; - if (!dc->delayed_branch) { - if (dc->tb_flags & DRTI_FLAG) - do_rti(dc); - if (dc->tb_flags & DRTB_FLAG) - do_rtb(dc); - if (dc->tb_flags & DRTE_FLAG) - do_rte(dc); - /* Clear the delay slot flag. */ - dc->tb_flags &= ~D_FLAG; - /* If it is a direct jump, try direct chaining. */ - if (dc->jmp == JMP_INDIRECT) { - TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next); - eval_cond_jmp(dc, cpu_btarget, tmp_pc); - tcg_temp_free_i32(tmp_pc); - dc->base.is_jmp = DISAS_JUMP; - } else if (dc->jmp == JMP_DIRECT) { - t_sync_flags(dc); - gen_goto_tb(dc, 0, dc->jmp_pc); - } else if (dc->jmp == JMP_DIRECT_CC) { - TCGLabel *l1 = gen_new_label(); - t_sync_flags(dc); - /* Conditional jmp. */ - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1); - gen_goto_tb(dc, 1, dc->base.pc_next); - gen_set_label(l1); - gen_goto_tb(dc, 0, dc->jmp_pc); - } - break; - } + if (dc->tb_flags & DRTE_FLAG) { + do_rte(dc); } - if (dc->base.singlestep_enabled) { - break; - } - } while (!dc->base.is_jmp && !dc->cpustate_changed - && !tcg_op_buf_full() - && !singlestep - && (dc->base.pc_next - page_start < TARGET_PAGE_SIZE) - && num_insns < max_insns); - - npc = dc->base.pc_next; - if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { - if (dc->tb_flags & D_FLAG) { - dc->base.is_jmp = DISAS_UPDATE; - tcg_gen_movi_i32(cpu_pc, npc); - sync_jmpstate(dc); - } else - npc = dc->jmp_pc; + /* Clear the delay slot flag. */ + dc->tb_flags &= ~D_FLAG; + dc->base.is_jmp = DISAS_JUMP; } - /* Force an update if the per-tb cpu state has changed. */ - if (dc->base.is_jmp == DISAS_NEXT - && (dc->cpustate_changed || org_flags != dc->tb_flags)) { + /* Force an exit if the per-tb cpu state has changed. */ + if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) { dc->base.is_jmp = DISAS_UPDATE; - tcg_gen_movi_i32(cpu_pc, npc); + tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); } - t_sync_flags(dc); +} + +static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) +{ + DisasContext *dc = container_of(dcb, DisasContext, base); + + assert(!dc->abort_at_next_insn); if (dc->base.is_jmp == DISAS_NORETURN) { - /* nothing more to generate */ - } else if (unlikely(cs->singlestep_enabled)) { - TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); - - if (dc->base.is_jmp != DISAS_JUMP) { - tcg_gen_movi_i32(cpu_pc, npc); - } - gen_helper_raise_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); - } else { - switch (dc->base.is_jmp) { - case DISAS_NEXT: - gen_goto_tb(dc, 1, npc); - break; - case DISAS_JUMP: - case DISAS_UPDATE: - /* indicate that the hash table must be used - to find the next TB */ - tcg_gen_exit_tb(NULL, 0); - break; - default: - g_assert_not_reached(); - } + /* We have already exited the TB. */ + return; } - gen_tb_end(tb, num_insns); - tb->size = dc->base.pc_next - pc_start; - tb->icount = num_insns; + t_sync_flags(dc); + if (dc->tb_flags & D_FLAG) { + sync_jmpstate(dc); + dc->jmp = JMP_NOJMP; + } + switch (dc->base.is_jmp) { + case DISAS_TOO_MANY: + assert(dc->jmp == JMP_NOJMP); + gen_goto_tb(dc, 0, dc->base.pc_next); + return; + + case DISAS_UPDATE: + assert(dc->jmp == JMP_NOJMP); + if (unlikely(cs->singlestep_enabled)) { + gen_raise_exception(dc, EXCP_DEBUG); + } else { + tcg_gen_exit_tb(NULL, 0); + } + return; + + case DISAS_JUMP: + switch (dc->jmp) { + case JMP_INDIRECT: + { + TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next); + eval_cond_jmp(dc, cpu_btarget, tmp_pc); + tcg_temp_free_i32(tmp_pc); + + if (unlikely(cs->singlestep_enabled)) { + gen_raise_exception(dc, EXCP_DEBUG); + } else { + tcg_gen_exit_tb(NULL, 0); + } + } + return; + + case JMP_DIRECT_CC: + { + TCGLabel *l1 = gen_new_label(); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1); + gen_goto_tb(dc, 1, dc->base.pc_next); + gen_set_label(l1); + } + /* fall through */ + + case JMP_DIRECT: + gen_goto_tb(dc, 0, dc->jmp_pc); + return; + } + /* fall through */ + + default: + g_assert_not_reached(); + } +} + +static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) +{ #ifdef DEBUG_DISAS #if !SIM_COMPAT - if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) - && qemu_log_in_addr_range(pc_start)) { - FILE *logfile = qemu_log_lock(); - qemu_log("--------------\n"); - log_target_disas(cs, pc_start, dc->base.pc_next - pc_start); - qemu_log_unlock(logfile); - } + qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first)); + log_target_disas(cs, dcb->pc_first, dcb->tb->size); #endif #endif - assert(!dc->abort_at_next_insn); +} + +static const TranslatorOps mb_tr_ops = { + .init_disas_context = mb_tr_init_disas_context, + .tb_start = mb_tr_tb_start, + .insn_start = mb_tr_insn_start, + .breakpoint_check = mb_tr_breakpoint_check, + .translate_insn = mb_tr_translate_insn, + .tb_stop = mb_tr_tb_stop, + .disas_log = mb_tr_disas_log, +}; + +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) +{ + DisasContext dc; + translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns); } void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) From 47393d564a6e59cacd64326a8348f7bd8417173e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 20:58:58 -0700 Subject: [PATCH 30/76] target/microblaze: Remove SIM_COMPAT Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 6a9710d76d..a90e56a17f 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -34,10 +34,9 @@ #include "exec/log.h" -#define SIM_COMPAT 0 #define DISAS_GNU 1 #define DISAS_MB 1 -#if DISAS_MB && !SIM_COMPAT +#if DISAS_MB # define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) #else # define LOG_DIS(...) do { } while (0) @@ -1749,11 +1748,9 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) { #ifdef DEBUG_DISAS -#if !SIM_COMPAT qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first)); log_target_disas(cs, dcb->pc_first, dcb->tb->size); #endif -#endif } static const TranslatorOps mb_tr_ops = { From ba0f357cae2d9f042f04da3b7d0e08fbbb5b0005 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 20:59:47 -0700 Subject: [PATCH 31/76] target/microblaze: Remove DISAS_GNU This is never used. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index a90e56a17f..6757720776 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -34,7 +34,6 @@ #include "exec/log.h" -#define DISAS_GNU 1 #define DISAS_MB 1 #if DISAS_MB # define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) From e3f8d192e089b6985b761d63ee2438aadb377a18 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 21:01:30 -0700 Subject: [PATCH 32/76] target/microblaze: Remove empty D macros This is never used in op_helper.c and translate.c. There are two trivial uses in helper.c which can be improved by always logging MMU_EXCP to CPU_LOG_INT. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/helper.c | 11 ++++------- target/microblaze/op_helper.c | 2 -- target/microblaze/translate.c | 2 -- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index 9a95456401..f8e2ca12a9 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -24,8 +24,6 @@ #include "qemu/host-utils.h" #include "exec/log.h" -#define D(x) - #if defined(CONFIG_USER_ONLY) void mb_cpu_do_interrupt(CPUState *cs) @@ -155,10 +153,13 @@ void mb_cpu_do_interrupt(CPUState *cs) case EXCP_MMU: env->regs[17] = env->pc; + qemu_log_mask(CPU_LOG_INT, + "MMU exception at pc=%x iflags=%x ear=%" PRIx64 "\n", + env->pc, env->iflags, env->ear); + env->esr &= ~(1 << 12); /* Exception breaks branch + dslot sequence? */ if (env->iflags & D_FLAG) { - D(qemu_log("D_FLAG set at exception bimm=%d\n", env->bimm)); env->esr |= 1 << 12 ; env->btr = env->btarget; @@ -166,14 +167,10 @@ void mb_cpu_do_interrupt(CPUState *cs) env->regs[17] -= 4; /* was the branch immprefixed?. */ if (env->bimm) { - qemu_log_mask(CPU_LOG_INT, - "bimm exception at pc=%x iflags=%x\n", - env->pc, env->iflags); env->regs[17] -= 4; log_cpu_state_mask(CPU_LOG_INT, cs, 0); } } else if (env->iflags & IMM_FLAG) { - D(qemu_log("IMM_FLAG set at exception\n")); env->regs[17] -= 4; } diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index d79202c3f8..decdca0fd8 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -26,8 +26,6 @@ #include "exec/cpu_ldst.h" #include "fpu/softfloat.h" -#define D(x) - void helper_put(uint32_t id, uint32_t ctrl, uint32_t data) { int test = ctrl & STREAM_TEST; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 6757720776..860859324a 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -41,8 +41,6 @@ # define LOG_DIS(...) do { } while (0) #endif -#define D(x) - #define EXTRACT_FIELD(src, start, end) \ (((src) >> start) & ((1 << (end - start + 1)) - 1)) From 11105d67497c94475a9c89df5850fb7a2d52323e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 21:08:40 -0700 Subject: [PATCH 33/76] target/microblaze: Remove LOG_DIS Also remove the related defines, DISAS_MB and DEBUG_DISAS. Rely on print_insn_microblaze. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 78 +---------------------------------- 1 file changed, 1 insertion(+), 77 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 860859324a..133ec24870 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -33,14 +33,6 @@ #include "trace-tcg.h" #include "exec/log.h" - -#define DISAS_MB 1 -#if DISAS_MB -# define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) -#else -# define LOG_DIS(...) do { } while (0) -#endif - #define EXTRACT_FIELD(src, start, end) \ (((src) >> start) & ((1 << (end - start + 1)) - 1)) @@ -205,10 +197,6 @@ static void dec_add(DisasContext *dc) k = dc->opcode & 4; c = dc->opcode & 2; - LOG_DIS("add%s%s%s r%d r%d r%d\n", - dc->type_b ? "i" : "", k ? "k" : "", c ? "c" : "", - dc->rd, dc->ra, dc->rb); - /* Take care of the easy cases first. */ if (k) { /* k - keep carry, no need to update MSR. */ @@ -252,7 +240,6 @@ static void dec_sub(DisasContext *dc) cmp = (dc->imm & 1) && (!dc->type_b) && k; if (cmp) { - LOG_DIS("cmp%s r%d, r%d ir=%x\n", u ? "u" : "", dc->rd, dc->ra, dc->ir); if (dc->rd) { if (u) gen_helper_cmpu(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); @@ -262,9 +249,6 @@ static void dec_sub(DisasContext *dc) return; } - LOG_DIS("sub%s%s r%d, r%d r%d\n", - k ? "k" : "", c ? "c" : "", dc->rd, dc->ra, dc->rb); - /* Take care of the easy cases first. */ if (k) { /* k - keep carry, no need to update MSR. */ @@ -314,19 +298,16 @@ static void dec_pattern(DisasContext *dc) switch (mode) { case 0: /* pcmpbf. */ - LOG_DIS("pcmpbf r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); if (dc->rd) gen_helper_pcmpbf(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); break; case 2: - LOG_DIS("pcmpeq r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); if (dc->rd) { tcg_gen_setcond_i32(TCG_COND_EQ, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); } break; case 3: - LOG_DIS("pcmpne r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); if (dc->rd) { tcg_gen_setcond_i32(TCG_COND_NE, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); @@ -349,7 +330,6 @@ static void dec_and(DisasContext *dc) } not = dc->opcode & (1 << 1); - LOG_DIS("and%s\n", not ? "n" : ""); if (!dc->rd) return; @@ -367,7 +347,6 @@ static void dec_or(DisasContext *dc) return; } - LOG_DIS("or r%d r%d r%d imm=%x\n", dc->rd, dc->ra, dc->rb, dc->imm); if (dc->rd) tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); } @@ -379,7 +358,6 @@ static void dec_xor(DisasContext *dc) return; } - LOG_DIS("xor r%d\n", dc->rd); if (dc->rd) tcg_gen_xor_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); } @@ -433,9 +411,6 @@ static void dec_msr(DisasContext *dc) if (clrset) { bool clr = extract32(dc->ir, 16, 1); - LOG_DIS("msr%s r%d imm=%x\n", clr ? "clr" : "set", - dc->rd, dc->imm); - if (!dc->cpu->cfg.use_msr_instr) { /* nop??? */ return; @@ -478,7 +453,6 @@ static void dec_msr(DisasContext *dc) sr &= 7; tmp_sr = tcg_const_i32(sr); - LOG_DIS("m%ss sr%d r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm); if (to) { gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]); } else { @@ -491,7 +465,6 @@ static void dec_msr(DisasContext *dc) #endif if (to) { - LOG_DIS("m%ss sr%x r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm); switch (sr) { case SR_PC: break; @@ -535,8 +508,6 @@ static void dec_msr(DisasContext *dc) break; } } else { - LOG_DIS("m%ss r%d sr%x imm=%x\n", to ? "t" : "f", dc->rd, sr, dc->imm); - switch (sr) { case SR_PC: tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); @@ -609,7 +580,6 @@ static void dec_mul(DisasContext *dc) subcode = dc->imm & 3; if (dc->type_b) { - LOG_DIS("muli r%d r%d %x\n", dc->rd, dc->ra, dc->imm); tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); return; } @@ -622,21 +592,17 @@ static void dec_mul(DisasContext *dc) tmp = tcg_temp_new_i32(); switch (subcode) { case 0: - LOG_DIS("mul r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); break; case 1: - LOG_DIS("mulh r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); tcg_gen_muls2_i32(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); break; case 2: - LOG_DIS("mulhsu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); tcg_gen_mulsu2_i32(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); break; case 3: - LOG_DIS("mulhu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); tcg_gen_mulu2_i32(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); break; default: @@ -652,7 +618,6 @@ static void dec_div(DisasContext *dc) unsigned int u; u = dc->imm & 2; - LOG_DIS("div\n"); if (trap_illegal(dc, !dc->cpu->cfg.use_div)) { return; @@ -688,10 +653,6 @@ static void dec_barrel(DisasContext *dc) imm_w = extract32(dc->imm, 6, 5); imm_s = extract32(dc->imm, 0, 5); - LOG_DIS("bs%s%s%s r%d r%d r%d\n", - e ? "e" : "", - s ? "l" : "r", t ? "a" : "l", dc->rd, dc->ra, dc->rb); - if (e) { if (imm_w + imm_s > 32 || imm_w == 0) { /* These inputs have an undefined behavior. */ @@ -742,7 +703,6 @@ static void dec_bit(DisasContext *dc) /* src. */ t0 = tcg_temp_new_i32(); - LOG_DIS("src r%d r%d\n", dc->rd, dc->ra); tcg_gen_shli_i32(t0, cpu_msr_c, 31); tcg_gen_andi_i32(cpu_msr_c, cpu_R[dc->ra], 1); if (dc->rd) { @@ -755,8 +715,6 @@ static void dec_bit(DisasContext *dc) case 0x1: case 0x41: /* srl. */ - LOG_DIS("srl r%d r%d\n", dc->rd, dc->ra); - tcg_gen_andi_i32(cpu_msr_c, cpu_R[dc->ra], 1); if (dc->rd) { if (op == 0x41) @@ -766,11 +724,9 @@ static void dec_bit(DisasContext *dc) } break; case 0x60: - LOG_DIS("ext8s r%d r%d\n", dc->rd, dc->ra); tcg_gen_ext8s_i32(cpu_R[dc->rd], cpu_R[dc->ra]); break; case 0x61: - LOG_DIS("ext16s r%d r%d\n", dc->rd, dc->ra); tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]); break; case 0x64: @@ -778,12 +734,10 @@ static void dec_bit(DisasContext *dc) case 0x74: case 0x76: /* wdc. */ - LOG_DIS("wdc r%d\n", dc->ra); trap_userspace(dc, true); break; case 0x68: /* wic. */ - LOG_DIS("wic r%d\n", dc->ra); trap_userspace(dc, true); break; case 0xe0: @@ -796,12 +750,10 @@ static void dec_bit(DisasContext *dc) break; case 0x1e0: /* swapb */ - LOG_DIS("swapb r%d r%d\n", dc->rd, dc->ra); tcg_gen_bswap32_i32(cpu_R[dc->rd], cpu_R[dc->ra]); break; case 0x1e2: /*swaph */ - LOG_DIS("swaph r%d r%d\n", dc->rd, dc->ra); tcg_gen_rotri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 16); break; default: @@ -824,7 +776,6 @@ static inline void sync_jmpstate(DisasContext *dc) static void dec_imm(DisasContext *dc) { - LOG_DIS("imm %x\n", dc->imm << 16); tcg_gen_movi_i32(cpu_imm, (dc->imm << 16)); dc->tb_flags |= IMM_FLAG; dc->clear_imm = 0; @@ -928,10 +879,6 @@ static void dec_load(DisasContext *dc) return; } - LOG_DIS("l%d%s%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "", - ex ? "x" : "", - ea ? "ea" : ""); - t_sync_flags(dc); addr = tcg_temp_new(); compute_ldst_addr(dc, ea, addr); @@ -1039,9 +986,6 @@ static void dec_store(DisasContext *dc) trap_userspace(dc, ea); - LOG_DIS("s%d%s%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "", - ex ? "x" : "", - ea ? "ea" : ""); t_sync_flags(dc); /* If we get a fault on a dslot, the jmpstate better be in sync. */ sync_jmpstate(dc); @@ -1184,7 +1128,6 @@ static void dec_bcc(DisasContext *dc) cc = EXTRACT_FIELD(dc->ir, 21, 23); dslot = dc->ir & (1 << 25); - LOG_DIS("bcc%s r%d %x\n", dslot ? "d" : "", dc->ra, dc->imm); dc->delayed_branch = 1; if (dslot) { @@ -1217,8 +1160,6 @@ static void dec_br(DisasContext *dc) if (mbar == 2 && dc->imm == 4) { uint16_t mbar_imm = dc->rd; - LOG_DIS("mbar %d\n", mbar_imm); - /* Data access memory barrier. */ if ((mbar_imm & 2) == 0) { tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); @@ -1228,8 +1169,6 @@ static void dec_br(DisasContext *dc) if (mbar_imm & 16) { TCGv_i32 tmp_1; - LOG_DIS("sleep\n"); - if (trap_userspace(dc, true)) { /* Sleep is a privileged instruction. */ return; @@ -1253,11 +1192,6 @@ static void dec_br(DisasContext *dc) return; } - LOG_DIS("br%s%s%s%s imm=%x\n", - abs ? "a" : "", link ? "l" : "", - dc->type_b ? "i" : "", dslot ? "d" : "", - dc->imm); - dc->delayed_branch = 1; if (dslot) { dec_setup_dslot(dc); @@ -1363,16 +1297,12 @@ static void dec_rts(DisasContext *dc) dec_setup_dslot(dc); if (i_bit) { - LOG_DIS("rtid ir=%x\n", dc->ir); dc->tb_flags |= DRTI_FLAG; } else if (b_bit) { - LOG_DIS("rtbd ir=%x\n", dc->ir); dc->tb_flags |= DRTB_FLAG; } else if (e_bit) { - LOG_DIS("rted ir=%x\n", dc->ir); dc->tb_flags |= DRTE_FLAG; - } else - LOG_DIS("rts ir=%x\n", dc->ir); + } dc->jmp = JMP_INDIRECT; tcg_gen_movi_i32(cpu_btaken, 1); @@ -1505,9 +1435,6 @@ static void dec_stream(DisasContext *dc) TCGv_i32 t_id, t_ctrl; int ctrl; - LOG_DIS("%s%s imm=%x\n", dc->rd ? "get" : "put", - dc->type_b ? "" : "d", dc->imm); - if (trap_userspace(dc, true)) { return; } @@ -1565,7 +1492,6 @@ static inline void decode(DisasContext *dc, uint32_t ir) int i; dc->ir = ir; - LOG_DIS("%8.8x\t", dc->ir); if (ir == 0) { trap_illegal(dc, dc->cpu->cfg.opcode_0_illegal); @@ -1744,10 +1670,8 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) { -#ifdef DEBUG_DISAS qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first)); log_target_disas(cs, dcb->pc_first, dcb->tb->size); -#endif } static const TranslatorOps mb_tr_ops = { From d7ecb757d1991ff0a58dcecf6c8990dbc19636bd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 21:52:15 -0700 Subject: [PATCH 34/76] target/microblaze: Ensure imm constant is always available Include the env->imm value in the TB values when IMM_FLAG is set. This means that we can always reconstruct the complete 32-bit imm. Discard env_imm when its contents can no longer be accessed. Fix user-mode checks for BRK/BRKI, which depend on IMM. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 2 +- target/microblaze/translate.c | 111 ++++++++++++++++++++-------------- 2 files changed, 67 insertions(+), 46 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 7066878ac7..013858b8e0 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -374,9 +374,9 @@ static inline void cpu_get_tb_cpu_state(CPUMBState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { *pc = env->pc; - *cs_base = 0; *flags = (env->iflags & IFLAGS_TB_MASK) | (env->msr & (MSR_UM | MSR_VM | MSR_EE)); + *cs_base = (*flags & IMM_FLAG ? env->imm : 0); } #if !defined(CONFIG_USER_ONLY) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 133ec24870..65ce8f3cd6 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -61,6 +61,7 @@ typedef struct DisasContext { /* Decoder. */ int type_b; uint32_t ir; + uint32_t ext_imm; uint8_t opcode; uint8_t rd, ra, rb; uint16_t imm; @@ -169,24 +170,23 @@ static bool trap_userspace(DisasContext *dc, bool cond) return cond_user; } -/* True if ALU operand b is a small immediate that may deserve - faster treatment. */ -static inline int dec_alu_op_b_is_small_imm(DisasContext *dc) +static int32_t dec_alu_typeb_imm(DisasContext *dc) { - /* Immediate insn without the imm prefix ? */ - return dc->type_b && !(dc->tb_flags & IMM_FLAG); + tcg_debug_assert(dc->type_b); + if (dc->tb_flags & IMM_FLAG) { + return dc->ext_imm | dc->imm; + } else { + return (int16_t)dc->imm; + } } static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc) { if (dc->type_b) { - if (dc->tb_flags & IMM_FLAG) - tcg_gen_ori_i32(cpu_imm, cpu_imm, dc->imm); - else - tcg_gen_movi_i32(cpu_imm, (int32_t)((int16_t)dc->imm)); + tcg_gen_movi_i32(cpu_imm, dec_alu_typeb_imm(dc)); return &cpu_imm; - } else - return &cpu_R[dc->rb]; + } + return &cpu_R[dc->rb]; } static void dec_add(DisasContext *dc) @@ -776,14 +776,14 @@ static inline void sync_jmpstate(DisasContext *dc) static void dec_imm(DisasContext *dc) { - tcg_gen_movi_i32(cpu_imm, (dc->imm << 16)); + dc->ext_imm = dc->imm << 16; + tcg_gen_movi_i32(cpu_imm, dc->ext_imm); dc->tb_flags |= IMM_FLAG; dc->clear_imm = 0; } static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t) { - bool extimm = dc->tb_flags & IMM_FLAG; /* Should be set to true if r1 is used by loadstores. */ bool stackprot = false; TCGv_i32 t32; @@ -836,11 +836,7 @@ static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t) } /* Immediate. */ t32 = tcg_temp_new_i32(); - if (!extimm) { - tcg_gen_addi_i32(t32, cpu_R[dc->ra], (int16_t)dc->imm); - } else { - tcg_gen_add_i32(t32, cpu_R[dc->ra], *(dec_alu_op_b(dc))); - } + tcg_gen_addi_i32(t32, cpu_R[dc->ra], dec_alu_typeb_imm(dc)); tcg_gen_extu_i32_tl(t, t32); tcg_temp_free_i32(t32); @@ -1134,15 +1130,13 @@ static void dec_bcc(DisasContext *dc) dec_setup_dslot(dc); } - if (dec_alu_op_b_is_small_imm(dc)) { - int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend. */ - - tcg_gen_movi_i32(cpu_btarget, dc->base.pc_next + offset); + if (dc->type_b) { dc->jmp = JMP_DIRECT_CC; - dc->jmp_pc = dc->base.pc_next + offset; + dc->jmp_pc = dc->base.pc_next + 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, *dec_alu_op_b(dc), dc->base.pc_next); + tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); } eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]); } @@ -1192,38 +1186,63 @@ 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; + } + } + } + dc->delayed_branch = 1; if (dslot) { dec_setup_dslot(dc); } - if (link && dc->rd) + if (link && dc->rd) { tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); + } - dc->jmp = JMP_INDIRECT; if (abs) { - tcg_gen_movi_i32(cpu_btaken, 1); - tcg_gen_mov_i32(cpu_btarget, *(dec_alu_op_b(dc))); - if (link && !dslot) { - if (!(dc->tb_flags & IMM_FLAG) && - (dc->imm == 8 || dc->imm == 0x18)) { + 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); } - if (dc->imm == 0) { - if (trap_userspace(dc, true)) { - return; - } - gen_raise_exception_sync(dc, EXCP_DEBUG); - } } + } else if (dc->type_b) { + dc->jmp = JMP_DIRECT; + dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); + tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); } else { - if (dec_alu_op_b_is_small_imm(dc)) { - dc->jmp = JMP_DIRECT; - dc->jmp_pc = dc->base.pc_next + (int32_t)((int16_t)dc->imm); - } else { - tcg_gen_movi_i32(cpu_btaken, 1); - tcg_gen_addi_i32(cpu_btarget, *dec_alu_op_b(dc), dc->base.pc_next); - } + dc->jmp = JMP_INDIRECT; + tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); } + tcg_gen_movi_i32(cpu_btaken, 1); } static inline void do_rti(DisasContext *dc) @@ -1529,6 +1548,7 @@ static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) dc->jmp = dc->delayed_branch ? JMP_INDIRECT : JMP_NOJMP; dc->cpustate_changed = 0; dc->abort_at_next_insn = 0; + dc->ext_imm = dc->base.tb->cs_base; bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; dc->base.max_insns = MIN(dc->base.max_insns, bound); @@ -1573,8 +1593,9 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) dc->clear_imm = 1; decode(dc, cpu_ldl_code(env, dc->base.pc_next)); - if (dc->clear_imm) { + if (dc->clear_imm && (dc->tb_flags & IMM_FLAG)) { dc->tb_flags &= ~IMM_FLAG; + tcg_gen_discard_i32(cpu_imm); } dc->base.pc_next += 4; From 44d1432ba25742624bdb9841b634d45b6711dcf8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 09:42:44 -0700 Subject: [PATCH 35/76] target/microblaze: Add decodetree infrastructure The new interface is a stub that recognizes no instructions. It falls back to the old decoder for all instructions. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 18 ++++++++++++++++++ target/microblaze/meson.build | 3 +++ target/microblaze/translate.c | 11 +++++++++-- 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 target/microblaze/insns.decode diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode new file mode 100644 index 0000000000..1ed9ca0731 --- /dev/null +++ b/target/microblaze/insns.decode @@ -0,0 +1,18 @@ +# +# MicroBlaze instruction decode definitions. +# +# Copyright (c) 2020 Richard Henderson +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see . +# diff --git a/target/microblaze/meson.build b/target/microblaze/meson.build index b8fe4afe61..639c3f73a8 100644 --- a/target/microblaze/meson.build +++ b/target/microblaze/meson.build @@ -1,4 +1,7 @@ +gen = decodetree.process('insns.decode') + microblaze_ss = ss.source_set() +microblaze_ss.add(gen) microblaze_ss.add(files( 'cpu.c', 'gdbstub.c', diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 65ce8f3cd6..e624093745 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -81,6 +81,9 @@ typedef struct DisasContext { int abort_at_next_insn; } DisasContext; +/* Include the auto-generated decoder. */ +#include "decode-insns.c.inc" + static inline void t_sync_flags(DisasContext *dc) { /* Synch the tb dependent flags between translator and runtime. */ @@ -1506,7 +1509,7 @@ static struct decoder_info { {{0, 0}, dec_null} }; -static inline void decode(DisasContext *dc, uint32_t ir) +static void old_decode(DisasContext *dc, uint32_t ir) { int i; @@ -1584,6 +1587,7 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) { DisasContext *dc = container_of(dcb, DisasContext, base); CPUMBState *env = cs->env_ptr; + uint32_t ir; /* TODO: This should raise an exception, not terminate qemu. */ if (dc->base.pc_next & 3) { @@ -1592,7 +1596,10 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) } dc->clear_imm = 1; - decode(dc, cpu_ldl_code(env, dc->base.pc_next)); + ir = cpu_ldl_code(env, dc->base.pc_next); + if (!decode(dc, ir)) { + old_decode(dc, ir); + } if (dc->clear_imm && (dc->tb_flags & IMM_FLAG)) { dc->tb_flags &= ~IMM_FLAG; tcg_gen_discard_i32(cpu_imm); From 20800179655d9262716ff20895c3c9d81ecb2d17 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 22:17:58 -0700 Subject: [PATCH 36/76] target/microblaze: Convert dec_add to decodetree Adds infrastrucure for translation of instructions, which could not be added before their first use. Cache a temporary which represents r0 as the immediate 0 value, or a sink. Move the special case of opcode_0_illegal from old_decode() into decodetree as well, lest this get interpreted as add. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 24 ++++ target/microblaze/translate.c | 197 ++++++++++++++++++++++++++------- 2 files changed, 178 insertions(+), 43 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index 1ed9ca0731..5f289a446c 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -16,3 +16,27 @@ # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, see . # + +&typea rd ra rb +&typeb rd ra imm + +# Include any IMM prefix in the value reported. +%extimm 0:s16 !function=typeb_imm + +@typea ...... rd:5 ra:5 rb:5 ... .... .... &typea +@typeb ...... rd:5 ra:5 ................ &typeb imm=%extimm + +### + +{ + zero 000000 00000 00000 00000 000 0000 0000 + add 000000 ..... ..... ..... 000 0000 0000 @typea +} +addc 000010 ..... ..... ..... 000 0000 0000 @typea +addk 000100 ..... ..... ..... 000 0000 0000 @typea +addkc 000110 ..... ..... ..... 000 0000 0000 @typea + +addi 001000 ..... ..... ................ @typeb +addic 001010 ..... ..... ................ @typeb +addik 001100 ..... ..... ................ @typeb +addikc 001110 ..... ..... ................ @typeb diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index e624093745..de822bd7b7 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -58,6 +58,9 @@ typedef struct DisasContext { DisasContextBase base; MicroBlazeCPU *cpu; + TCGv_i32 r0; + bool r0_set; + /* Decoder. */ int type_b; uint32_t ir; @@ -81,6 +84,14 @@ typedef struct DisasContext { int abort_at_next_insn; } DisasContext; +static int typeb_imm(DisasContext *dc, int x) +{ + if (dc->tb_flags & IMM_FLAG) { + return deposit32(dc->ext_imm, 0, 16, x); + } + return x; +} + /* Include the auto-generated decoder. */ #include "decode-insns.c.inc" @@ -176,11 +187,7 @@ static bool trap_userspace(DisasContext *dc, bool cond) static int32_t dec_alu_typeb_imm(DisasContext *dc) { tcg_debug_assert(dc->type_b); - if (dc->tb_flags & IMM_FLAG) { - return dc->ext_imm | dc->imm; - } else { - return (int16_t)dc->imm; - } + return typeb_imm(dc, (int16_t)dc->imm); } static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc) @@ -192,44 +199,146 @@ static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc) return &cpu_R[dc->rb]; } -static void dec_add(DisasContext *dc) +static TCGv_i32 reg_for_read(DisasContext *dc, int reg) { - unsigned int k, c; - TCGv_i32 cf; - - k = dc->opcode & 4; - c = dc->opcode & 2; - - /* Take care of the easy cases first. */ - if (k) { - /* k - keep carry, no need to update MSR. */ - /* If rd == r0, it's a nop. */ - if (dc->rd) { - tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); - - if (c) { - /* c - Add carry into the result. */ - tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cpu_msr_c); - } + if (likely(reg != 0)) { + return cpu_R[reg]; + } + if (!dc->r0_set) { + if (dc->r0 == NULL) { + dc->r0 = tcg_temp_new_i32(); } - return; + tcg_gen_movi_i32(dc->r0, 0); + dc->r0_set = true; + } + return dc->r0; +} + +static TCGv_i32 reg_for_write(DisasContext *dc, int reg) +{ + if (likely(reg != 0)) { + return cpu_R[reg]; + } + if (dc->r0 == NULL) { + dc->r0 = tcg_temp_new_i32(); + } + return dc->r0; +} + +static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects, + void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) +{ + TCGv_i32 rd, ra, rb; + + if (arg->rd == 0 && !side_effects) { + return true; } - /* From now on, we can assume k is zero. So we need to update MSR. */ - /* Extract carry. */ - cf = tcg_temp_new_i32(); - if (c) { - tcg_gen_mov_i32(cf, cpu_msr_c); - } else { - tcg_gen_movi_i32(cf, 0); + rd = reg_for_write(dc, arg->rd); + ra = reg_for_read(dc, arg->ra); + rb = reg_for_read(dc, arg->rb); + fn(rd, ra, rb); + return true; +} + +static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects, + void (*fni)(TCGv_i32, TCGv_i32, int32_t)) +{ + TCGv_i32 rd, ra; + + if (arg->rd == 0 && !side_effects) { + return true; } - gen_helper_carry(cpu_msr_c, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf); - if (dc->rd) { - tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); - tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf); + rd = reg_for_write(dc, arg->rd); + ra = reg_for_read(dc, arg->ra); + fni(rd, ra, arg->imm); + return true; +} + +static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, + void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) +{ + TCGv_i32 rd, ra, imm; + + if (arg->rd == 0 && !side_effects) { + return true; } - tcg_temp_free_i32(cf); + + rd = reg_for_write(dc, arg->rd); + ra = reg_for_read(dc, arg->ra); + imm = tcg_const_i32(arg->imm); + + fn(rd, ra, imm); + + tcg_temp_free_i32(imm); + return true; +} + +#define DO_TYPEA(NAME, SE, FN) \ + static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ + { return do_typea(dc, a, SE, FN); } + +#define DO_TYPEBI(NAME, SE, FNI) \ + static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ + { return do_typeb_imm(dc, a, SE, FNI); } + +#define DO_TYPEBV(NAME, SE, FN) \ + static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ + { return do_typeb_val(dc, a, SE, FN); } + +/* No input carry, but output carry. */ +static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + TCGv_i32 zero = tcg_const_i32(0); + + tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero); + + tcg_temp_free_i32(zero); +} + +/* Input and output carry. */ +static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); + tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); + + tcg_temp_free_i32(tmp); + tcg_temp_free_i32(zero); +} + +/* Input carry, but no output carry. */ +static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + tcg_gen_add_i32(out, ina, inb); + tcg_gen_add_i32(out, out, cpu_msr_c); +} + +DO_TYPEA(add, true, gen_add) +DO_TYPEA(addc, true, gen_addc) +DO_TYPEA(addk, false, tcg_gen_add_i32) +DO_TYPEA(addkc, true, gen_addkc) + +DO_TYPEBV(addi, true, gen_add) +DO_TYPEBV(addic, true, gen_addc) +DO_TYPEBI(addik, false, tcg_gen_addi_i32) +DO_TYPEBV(addikc, true, gen_addkc) + +static bool trans_zero(DisasContext *dc, arg_zero *arg) +{ + /* If opcode_0_illegal, trap. */ + if (dc->cpu->cfg.opcode_0_illegal) { + trap_illegal(dc, true); + return true; + } + /* + * Otherwise, this is "add r0, r0, r0". + * Continue to trans_add so that MSR[C] gets cleared. + */ + return false; } static void dec_sub(DisasContext *dc) @@ -1488,7 +1597,6 @@ static struct decoder_info { }; void (*dec)(DisasContext *dc); } decinfo[] = { - {DEC_ADD, dec_add}, {DEC_SUB, dec_sub}, {DEC_AND, dec_and}, {DEC_XOR, dec_xor}, @@ -1515,12 +1623,6 @@ static void old_decode(DisasContext *dc, uint32_t ir) dc->ir = ir; - if (ir == 0) { - trap_illegal(dc, dc->cpu->cfg.opcode_0_illegal); - /* Don't decode nop/zero instructions any further. */ - return; - } - /* bit 2 seems to indicate insn type. */ dc->type_b = ir & (1 << 29); @@ -1552,6 +1654,8 @@ static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) dc->cpustate_changed = 0; dc->abort_at_next_insn = 0; dc->ext_imm = dc->base.tb->cs_base; + dc->r0 = NULL; + dc->r0_set = false; bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; dc->base.max_insns = MIN(dc->base.max_insns, bound); @@ -1600,6 +1704,13 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) if (!decode(dc, ir)) { old_decode(dc, ir); } + + if (dc->r0) { + tcg_temp_free_i32(dc->r0); + dc->r0 = NULL; + dc->r0_set = false; + } + if (dc->clear_imm && (dc->tb_flags & IMM_FLAG)) { dc->tb_flags &= ~IMM_FLAG; tcg_gen_discard_i32(cpu_imm); From a2b0b90e7960c6dcf52be237149c1b9ff289d9a5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 11:29:24 -0700 Subject: [PATCH 37/76] target/microblaze: Convert dec_sub to decodetree Use tcg_gen_add2_i32 for computing carry. This removes the last use of helper_carry, so remove that. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/helper.h | 1 - target/microblaze/insns.decode | 13 ++++ target/microblaze/op_helper.c | 16 ----- target/microblaze/translate.c | 110 ++++++++++++++++----------------- 4 files changed, 65 insertions(+), 75 deletions(-) diff --git a/target/microblaze/helper.h b/target/microblaze/helper.h index 9309142f8d..988abf7661 100644 --- a/target/microblaze/helper.h +++ b/target/microblaze/helper.h @@ -1,5 +1,4 @@ DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32) -DEF_HELPER_FLAGS_3(carry, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_2(cmp, i32, i32, i32) DEF_HELPER_2(cmpu, i32, i32, i32) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index 5f289a446c..a611cc83a7 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -40,3 +40,16 @@ addi 001000 ..... ..... ................ @typeb addic 001010 ..... ..... ................ @typeb addik 001100 ..... ..... ................ @typeb addikc 001110 ..... ..... ................ @typeb + +cmp 000101 ..... ..... ..... 000 0000 0001 @typea +cmpu 000101 ..... ..... ..... 000 0000 0011 @typea + +rsub 000001 ..... ..... ..... 000 0000 0000 @typea +rsubc 000011 ..... ..... ..... 000 0000 0000 @typea +rsubk 000101 ..... ..... ..... 000 0000 0000 @typea +rsubkc 000111 ..... ..... ..... 000 0000 0000 @typea + +rsubi 001001 ..... ..... ................ @typeb +rsubic 001011 ..... ..... ................ @typeb +rsubik 001101 ..... ..... ................ @typeb +rsubikc 001111 ..... ..... ................ @typeb diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index decdca0fd8..9bb6a2ad76 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -69,17 +69,6 @@ void helper_raise_exception(CPUMBState *env, uint32_t index) cpu_loop_exit(cs); } -static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin) -{ - uint32_t cout = 0; - - if ((b == ~0) && cin) - cout = 1; - else if ((~0 - a) < (b + cin)) - cout = 1; - return cout; -} - uint32_t helper_cmp(uint32_t a, uint32_t b) { uint32_t t; @@ -100,11 +89,6 @@ uint32_t helper_cmpu(uint32_t a, uint32_t b) return t; } -uint32_t helper_carry(uint32_t a, uint32_t b, uint32_t cf) -{ - return compute_carry(a, b, cf); -} - static inline int div_prepare(CPUMBState *env, uint32_t a, uint32_t b) { MicroBlazeCPU *cpu = env_archcpu(env); diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index de822bd7b7..0e7d24ddca 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -327,6 +327,58 @@ DO_TYPEBV(addic, true, gen_addc) DO_TYPEBI(addik, false, tcg_gen_addi_i32) DO_TYPEBV(addikc, true, gen_addkc) +DO_TYPEA(cmp, false, gen_helper_cmp) +DO_TYPEA(cmpu, false, gen_helper_cmpu) + +/* No input carry, but output carry. */ +static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina); + tcg_gen_sub_i32(out, inb, ina); +} + +/* Input and output carry. */ +static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_not_i32(tmp, ina); + tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); + tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); + + tcg_temp_free_i32(zero); + tcg_temp_free_i32(tmp); +} + +/* No input or output carry. */ +static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + tcg_gen_sub_i32(out, inb, ina); +} + +/* Input carry, no output carry. */ +static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + TCGv_i32 nota = tcg_temp_new_i32(); + + tcg_gen_not_i32(nota, ina); + tcg_gen_add_i32(out, inb, nota); + tcg_gen_add_i32(out, out, cpu_msr_c); + + tcg_temp_free_i32(nota); +} + +DO_TYPEA(rsub, true, gen_rsub) +DO_TYPEA(rsubc, true, gen_rsubc) +DO_TYPEA(rsubk, false, gen_rsubk) +DO_TYPEA(rsubkc, true, gen_rsubkc) + +DO_TYPEBV(rsubi, true, gen_rsub) +DO_TYPEBV(rsubic, true, gen_rsubc) +DO_TYPEBV(rsubik, false, gen_rsubk) +DO_TYPEBV(rsubikc, true, gen_rsubkc) + static bool trans_zero(DisasContext *dc, arg_zero *arg) { /* If opcode_0_illegal, trap. */ @@ -341,63 +393,6 @@ static bool trans_zero(DisasContext *dc, arg_zero *arg) return false; } -static void dec_sub(DisasContext *dc) -{ - unsigned int u, cmp, k, c; - TCGv_i32 cf, na; - - u = dc->imm & 2; - k = dc->opcode & 4; - c = dc->opcode & 2; - cmp = (dc->imm & 1) && (!dc->type_b) && k; - - if (cmp) { - if (dc->rd) { - if (u) - gen_helper_cmpu(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); - else - gen_helper_cmp(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); - } - return; - } - - /* Take care of the easy cases first. */ - if (k) { - /* k - keep carry, no need to update MSR. */ - /* If rd == r0, it's a nop. */ - if (dc->rd) { - tcg_gen_sub_i32(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]); - - if (c) { - /* c - Add carry into the result. */ - tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cpu_msr_c); - } - } - return; - } - - /* From now on, we can assume k is zero. So we need to update MSR. */ - /* Extract carry. And complement a into na. */ - cf = tcg_temp_new_i32(); - na = tcg_temp_new_i32(); - if (c) { - tcg_gen_mov_i32(cf, cpu_msr_c); - } else { - tcg_gen_movi_i32(cf, 1); - } - - /* d = b + ~a + c. carry defaults to 1. */ - tcg_gen_not_i32(na, cpu_R[dc->ra]); - - gen_helper_carry(cpu_msr_c, na, *(dec_alu_op_b(dc)), cf); - if (dc->rd) { - tcg_gen_add_i32(cpu_R[dc->rd], na, *(dec_alu_op_b(dc))); - tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf); - } - tcg_temp_free_i32(cf); - tcg_temp_free_i32(na); -} - static void dec_pattern(DisasContext *dc) { unsigned int mode; @@ -1597,7 +1592,6 @@ static struct decoder_info { }; void (*dec)(DisasContext *dc); } decinfo[] = { - {DEC_SUB, dec_sub}, {DEC_AND, dec_and}, {DEC_XOR, dec_xor}, {DEC_OR, dec_or}, From 58b48b637db61e28a5e6c1ec9fce42b9f79c7b36 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Aug 2020 07:31:29 -0700 Subject: [PATCH 38/76] target/microblaze: Implement cmp and cmpu inline These are simple enough operations; we do not need to call an out-of-line helper. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/helper.h | 2 -- target/microblaze/op_helper.c | 20 -------------------- target/microblaze/translate.c | 24 ++++++++++++++++++++++-- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/target/microblaze/helper.h b/target/microblaze/helper.h index 988abf7661..6f7f96421f 100644 --- a/target/microblaze/helper.h +++ b/target/microblaze/helper.h @@ -1,6 +1,4 @@ DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32) -DEF_HELPER_2(cmp, i32, i32, i32) -DEF_HELPER_2(cmpu, i32, i32, i32) DEF_HELPER_3(divs, i32, env, i32, i32) DEF_HELPER_3(divu, i32, env, i32, i32) diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index 9bb6a2ad76..f976d112eb 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -69,26 +69,6 @@ void helper_raise_exception(CPUMBState *env, uint32_t index) cpu_loop_exit(cs); } -uint32_t helper_cmp(uint32_t a, uint32_t b) -{ - uint32_t t; - - t = b + ~a + 1; - if ((b & 0x80000000) ^ (a & 0x80000000)) - t = (t & 0x7fffffff) | (b & 0x80000000); - return t; -} - -uint32_t helper_cmpu(uint32_t a, uint32_t b) -{ - uint32_t t; - - t = b + ~a + 1; - if ((b & 0x80000000) ^ (a & 0x80000000)) - t = (t & 0x7fffffff) | (a & 0x80000000); - return t; -} - static inline int div_prepare(CPUMBState *env, uint32_t a, uint32_t b) { MicroBlazeCPU *cpu = env_archcpu(env); diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 0e7d24ddca..8da477457d 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -327,8 +327,28 @@ DO_TYPEBV(addic, true, gen_addc) DO_TYPEBI(addik, false, tcg_gen_addi_i32) DO_TYPEBV(addikc, true, gen_addkc) -DO_TYPEA(cmp, false, gen_helper_cmp) -DO_TYPEA(cmpu, false, gen_helper_cmpu) +static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + TCGv_i32 lt = tcg_temp_new_i32(); + + tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina); + tcg_gen_sub_i32(out, inb, ina); + tcg_gen_deposit_i32(out, out, lt, 31, 1); + tcg_temp_free_i32(lt); +} + +static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + TCGv_i32 lt = tcg_temp_new_i32(); + + tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina); + tcg_gen_sub_i32(out, inb, ina); + tcg_gen_deposit_i32(out, out, lt, 31, 1); + tcg_temp_free_i32(lt); +} + +DO_TYPEA(cmp, false, gen_cmp) +DO_TYPEA(cmpu, false, gen_cmpu) /* No input carry, but output carry. */ static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) From 607f576762948d1b0d47d74a42e3269beb4adf23 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 14:19:33 -0700 Subject: [PATCH 39/76] target/microblaze: Convert dec_pattern to decodetree Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 4 ++ target/microblaze/translate.c | 67 +++++++++------------------------- 2 files changed, 22 insertions(+), 49 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index a611cc83a7..16519f05dc 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -44,6 +44,10 @@ addikc 001110 ..... ..... ................ @typeb cmp 000101 ..... ..... ..... 000 0000 0001 @typea cmpu 000101 ..... ..... ..... 000 0000 0011 @typea +pcmpbf 100000 ..... ..... ..... 100 0000 0000 @typea +pcmpeq 100010 ..... ..... ..... 100 0000 0000 @typea +pcmpne 100011 ..... ..... ..... 100 0000 0000 @typea + rsub 000001 ..... ..... ..... 000 0000 0000 @typea rsubc 000011 ..... ..... ..... 000 0000 0000 @typea rsubk 000101 ..... ..... ..... 000 0000 0000 @typea diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 8da477457d..7ebf0e1e7d 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -279,6 +279,10 @@ static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ { return do_typea(dc, a, SE, FN); } +#define DO_TYPEA_CFG(NAME, CFG, SE, FN) \ + static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ + { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); } + #define DO_TYPEBI(NAME, SE, FNI) \ static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ { return do_typeb_imm(dc, a, SE, FNI); } @@ -350,6 +354,20 @@ static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) DO_TYPEA(cmp, false, gen_cmp) DO_TYPEA(cmpu, false, gen_cmpu) +static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb); +} + +static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb); +} + +DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf) +DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq) +DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne) + /* No input carry, but output carry. */ static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) { @@ -413,49 +431,10 @@ static bool trans_zero(DisasContext *dc, arg_zero *arg) return false; } -static void dec_pattern(DisasContext *dc) -{ - unsigned int mode; - - if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) { - return; - } - - mode = dc->opcode & 3; - switch (mode) { - case 0: - /* pcmpbf. */ - if (dc->rd) - gen_helper_pcmpbf(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); - break; - case 2: - if (dc->rd) { - tcg_gen_setcond_i32(TCG_COND_EQ, cpu_R[dc->rd], - cpu_R[dc->ra], cpu_R[dc->rb]); - } - break; - case 3: - if (dc->rd) { - tcg_gen_setcond_i32(TCG_COND_NE, cpu_R[dc->rd], - cpu_R[dc->ra], cpu_R[dc->rb]); - } - break; - default: - cpu_abort(CPU(dc->cpu), - "unsupported pattern insn opcode=%x\n", dc->opcode); - break; - } -} - static void dec_and(DisasContext *dc) { unsigned int not; - if (!dc->type_b && (dc->imm & (1 << 10))) { - dec_pattern(dc); - return; - } - not = dc->opcode & (1 << 1); if (!dc->rd) @@ -469,22 +448,12 @@ static void dec_and(DisasContext *dc) static void dec_or(DisasContext *dc) { - if (!dc->type_b && (dc->imm & (1 << 10))) { - dec_pattern(dc); - return; - } - if (dc->rd) tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); } static void dec_xor(DisasContext *dc) { - if (!dc->type_b && (dc->imm & (1 << 10))) { - dec_pattern(dc); - return; - } - if (dc->rd) tcg_gen_xor_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); } From cb0a0a4c8686792068860f339eddd695e1a485a1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 15:12:55 -0700 Subject: [PATCH 40/76] target/microblaze: Convert dec_and, dec_or, dec_xor to decodetree Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 12 +++++++++ target/microblaze/translate.c | 46 ++++++++++++---------------------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index 16519f05dc..93bd51c78b 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -41,9 +41,18 @@ addic 001010 ..... ..... ................ @typeb addik 001100 ..... ..... ................ @typeb addikc 001110 ..... ..... ................ @typeb +and 100001 ..... ..... ..... 000 0000 0000 @typea +andi 101001 ..... ..... ................ @typeb + +andn 100011 ..... ..... ..... 000 0000 0000 @typea +andni 101011 ..... ..... ................ @typeb + cmp 000101 ..... ..... ..... 000 0000 0001 @typea cmpu 000101 ..... ..... ..... 000 0000 0011 @typea +or 100000 ..... ..... ..... 000 0000 0000 @typea +ori 101000 ..... ..... ................ @typeb + pcmpbf 100000 ..... ..... ..... 100 0000 0000 @typea pcmpeq 100010 ..... ..... ..... 100 0000 0000 @typea pcmpne 100011 ..... ..... ..... 100 0000 0000 @typea @@ -57,3 +66,6 @@ rsubi 001001 ..... ..... ................ @typeb rsubic 001011 ..... ..... ................ @typeb rsubik 001101 ..... ..... ................ @typeb rsubikc 001111 ..... ..... ................ @typeb + +xor 100010 ..... ..... ..... 000 0000 0000 @typea +xori 101010 ..... ..... ................ @typeb diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 7ebf0e1e7d..a143f17e9d 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -331,6 +331,16 @@ DO_TYPEBV(addic, true, gen_addc) DO_TYPEBI(addik, false, tcg_gen_addi_i32) DO_TYPEBV(addikc, true, gen_addkc) +static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm) +{ + tcg_gen_andi_i32(out, ina, ~imm); +} + +DO_TYPEA(and, false, tcg_gen_and_i32) +DO_TYPEBI(andi, false, tcg_gen_andi_i32) +DO_TYPEA(andn, false, tcg_gen_andc_i32) +DO_TYPEBI(andni, false, gen_andni) + static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) { TCGv_i32 lt = tcg_temp_new_i32(); @@ -354,6 +364,9 @@ static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) DO_TYPEA(cmp, false, gen_cmp) DO_TYPEA(cmpu, false, gen_cmpu) +DO_TYPEA(or, false, tcg_gen_or_i32) +DO_TYPEBI(ori, false, tcg_gen_ori_i32) + static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) { tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb); @@ -417,6 +430,9 @@ DO_TYPEBV(rsubic, true, gen_rsubc) DO_TYPEBV(rsubik, false, gen_rsubk) DO_TYPEBV(rsubikc, true, gen_rsubkc) +DO_TYPEA(xor, false, tcg_gen_xor_i32) +DO_TYPEBI(xori, false, tcg_gen_xori_i32) + static bool trans_zero(DisasContext *dc, arg_zero *arg) { /* If opcode_0_illegal, trap. */ @@ -431,33 +447,6 @@ static bool trans_zero(DisasContext *dc, arg_zero *arg) return false; } -static void dec_and(DisasContext *dc) -{ - unsigned int not; - - not = dc->opcode & (1 << 1); - - if (!dc->rd) - return; - - if (not) { - tcg_gen_andc_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); - } else - tcg_gen_and_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); -} - -static void dec_or(DisasContext *dc) -{ - if (dc->rd) - tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); -} - -static void dec_xor(DisasContext *dc) -{ - if (dc->rd) - tcg_gen_xor_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); -} - static void msr_read(DisasContext *dc, TCGv_i32 d) { TCGv_i32 t; @@ -1581,9 +1570,6 @@ static struct decoder_info { }; void (*dec)(DisasContext *dc); } decinfo[] = { - {DEC_AND, dec_and}, - {DEC_XOR, dec_xor}, - {DEC_OR, dec_or}, {DEC_BIT, dec_bit}, {DEC_BARREL, dec_barrel}, {DEC_LD, dec_load}, From 97955ceb422421f48cbbab44cbe9a0998adde2cb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 22:49:20 -0700 Subject: [PATCH 41/76] target/microblaze: Convert dec_mul to decodetree Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 6 +++ target/microblaze/translate.c | 77 ++++++++++++++-------------------- 2 files changed, 37 insertions(+), 46 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index 93bd51c78b..1a2e22e44a 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -50,6 +50,12 @@ andni 101011 ..... ..... ................ @typeb cmp 000101 ..... ..... ..... 000 0000 0001 @typea cmpu 000101 ..... ..... ..... 000 0000 0011 @typea +mul 010000 ..... ..... ..... 000 0000 0000 @typea +mulh 010000 ..... ..... ..... 000 0000 0001 @typea +mulhu 010000 ..... ..... ..... 000 0000 0011 @typea +mulhsu 010000 ..... ..... ..... 000 0000 0010 @typea +muli 011000 ..... ..... ................ @typeb + or 100000 ..... ..... ..... 000 0000 0000 @typea ori 101000 ..... ..... ................ @typeb diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index a143f17e9d..617e208583 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -287,6 +287,10 @@ static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ { return do_typeb_imm(dc, a, SE, FNI); } +#define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \ + static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ + { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); } + #define DO_TYPEBV(NAME, SE, FN) \ static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ { return do_typeb_val(dc, a, SE, FN); } @@ -364,6 +368,33 @@ static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) DO_TYPEA(cmp, false, gen_cmp) DO_TYPEA(cmpu, false, gen_cmpu) +static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_muls2_i32(tmp, out, ina, inb); + tcg_temp_free_i32(tmp); +} + +static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_mulu2_i32(tmp, out, ina, inb); + tcg_temp_free_i32(tmp); +} + +static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_mulsu2_i32(tmp, out, ina, inb); + tcg_temp_free_i32(tmp); +} + +DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32) +DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh) +DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu) +DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu) +DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32) + DO_TYPEA(or, false, tcg_gen_or_i32) DO_TYPEBI(ori, false, tcg_gen_ori_i32) @@ -652,51 +683,6 @@ static void dec_msr(DisasContext *dc) } } -/* Multiplier unit. */ -static void dec_mul(DisasContext *dc) -{ - TCGv_i32 tmp; - unsigned int subcode; - - if (trap_illegal(dc, !dc->cpu->cfg.use_hw_mul)) { - return; - } - - subcode = dc->imm & 3; - - if (dc->type_b) { - tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); - return; - } - - /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2. */ - if (subcode >= 1 && subcode <= 3 && dc->cpu->cfg.use_hw_mul < 2) { - /* nop??? */ - } - - tmp = tcg_temp_new_i32(); - switch (subcode) { - case 0: - tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); - break; - case 1: - tcg_gen_muls2_i32(tmp, cpu_R[dc->rd], - cpu_R[dc->ra], cpu_R[dc->rb]); - break; - case 2: - tcg_gen_mulsu2_i32(tmp, cpu_R[dc->rd], - cpu_R[dc->ra], cpu_R[dc->rb]); - break; - case 3: - tcg_gen_mulu2_i32(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); - break; - default: - cpu_abort(CPU(dc->cpu), "unknown MUL insn %x\n", subcode); - break; - } - tcg_temp_free_i32(tmp); -} - /* Div unit. */ static void dec_div(DisasContext *dc) { @@ -1579,7 +1565,6 @@ static struct decoder_info { {DEC_BCC, dec_bcc}, {DEC_RTS, dec_rts}, {DEC_FPU, dec_fpu}, - {DEC_MUL, dec_mul}, {DEC_DIV, dec_div}, {DEC_MSR, dec_msr}, {DEC_STREAM, dec_stream}, From b1354342c1c7a01ef251160725db50ee8c40511a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 23:03:10 -0700 Subject: [PATCH 42/76] target/microblaze: Convert dec_div to decodetree Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 3 +++ target/microblaze/translate.c | 35 +++++++++++++--------------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index 1a2e22e44a..b2dcbdf784 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -50,6 +50,9 @@ andni 101011 ..... ..... ................ @typeb cmp 000101 ..... ..... ..... 000 0000 0001 @typea cmpu 000101 ..... ..... ..... 000 0000 0011 @typea +idiv 010010 ..... ..... ..... 000 0000 0000 @typea +idivu 010010 ..... ..... ..... 000 0000 0010 @typea + mul 010000 ..... ..... ..... 000 0000 0000 @typea mulh 010000 ..... ..... ..... 000 0000 0001 @typea mulhu 010000 ..... ..... ..... 000 0000 0011 @typea diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 617e208583..9763b9d77c 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -368,6 +368,19 @@ static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) DO_TYPEA(cmp, false, gen_cmp) DO_TYPEA(cmpu, false, gen_cmpu) +static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + gen_helper_divs(out, cpu_env, inb, ina); +} + +static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + gen_helper_divu(out, cpu_env, inb, ina); +} + +DO_TYPEA_CFG(idiv, use_div, true, gen_idiv) +DO_TYPEA_CFG(idivu, use_div, true, gen_idivu) + static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) { TCGv_i32 tmp = tcg_temp_new_i32(); @@ -683,27 +696,6 @@ static void dec_msr(DisasContext *dc) } } -/* Div unit. */ -static void dec_div(DisasContext *dc) -{ - unsigned int u; - - u = dc->imm & 2; - - if (trap_illegal(dc, !dc->cpu->cfg.use_div)) { - return; - } - - if (u) - gen_helper_divu(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)), - cpu_R[dc->ra]); - else - gen_helper_divs(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)), - cpu_R[dc->ra]); - if (!dc->rd) - tcg_gen_movi_i32(cpu_R[dc->rd], 0); -} - static void dec_barrel(DisasContext *dc) { TCGv_i32 t0; @@ -1565,7 +1557,6 @@ static struct decoder_info { {DEC_BCC, dec_bcc}, {DEC_RTS, dec_rts}, {DEC_FPU, dec_fpu}, - {DEC_DIV, dec_div}, {DEC_MSR, dec_msr}, {DEC_STREAM, dec_stream}, {{0, 0}, dec_null} From e98651d9ca475259a6721f6f1cff5da1ad4f0cc1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Aug 2020 23:12:14 -0700 Subject: [PATCH 43/76] target/microblaze: Unwind properly when raising divide-by-zero Restore the correct pc when raising divide-by-zero. Also, the MSR[DZO] bit is sticky -- it is not cleared with a successful divide. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/helper.h | 4 ++-- target/microblaze/op_helper.c | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/target/microblaze/helper.h b/target/microblaze/helper.h index 6f7f96421f..79e1e8ecc7 100644 --- a/target/microblaze/helper.h +++ b/target/microblaze/helper.h @@ -1,7 +1,7 @@ DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32) -DEF_HELPER_3(divs, i32, env, i32, i32) -DEF_HELPER_3(divu, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(divs, TCG_CALL_NO_WG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(divu, TCG_CALL_NO_WG, i32, env, i32, i32) DEF_HELPER_3(fadd, i32, env, i32, i32) DEF_HELPER_3(frsub, i32, env, i32, i32) diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index f976d112eb..d99d98051a 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -69,26 +69,27 @@ void helper_raise_exception(CPUMBState *env, uint32_t index) cpu_loop_exit(cs); } -static inline int div_prepare(CPUMBState *env, uint32_t a, uint32_t b) +static bool check_divz(CPUMBState *env, uint32_t a, uint32_t b, uintptr_t ra) { - MicroBlazeCPU *cpu = env_archcpu(env); - - if (b == 0) { + if (unlikely(b == 0)) { env->msr |= MSR_DZ; - if ((env->msr & MSR_EE) && cpu->cfg.div_zero_exception) { + if ((env->msr & MSR_EE) && + env_archcpu(env)->cfg.div_zero_exception) { + CPUState *cs = env_cpu(env); + env->esr = ESR_EC_DIVZERO; - helper_raise_exception(env, EXCP_HW_EXCP); + cs->exception_index = EXCP_HW_EXCP; + cpu_loop_exit_restore(cs, ra); } - return 0; + return false; } - env->msr &= ~MSR_DZ; - return 1; + return true; } uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b) { - if (!div_prepare(env, a, b)) { + if (!check_divz(env, a, b, GETPC())) { return 0; } return (int32_t)a / (int32_t)b; @@ -96,7 +97,7 @@ uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b) uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b) { - if (!div_prepare(env, a, b)) { + if (!check_divz(env, a, b, GETPC())) { return 0; } return a / b; From 39cf386458b4920ea14011af4cb5bb21c5e611fa Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Aug 2020 08:13:35 -0700 Subject: [PATCH 44/76] target/microblaze: Convert dec_bit to decodetree Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 20 +++++ target/microblaze/translate.c | 148 +++++++++++++++++---------------- 2 files changed, 95 insertions(+), 73 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index b2dcbdf784..d265e36044 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -17,6 +17,7 @@ # License along with this library; if not, see . # +&typea0 rd ra &typea rd ra rb &typeb rd ra imm @@ -26,6 +27,9 @@ @typea ...... rd:5 ra:5 rb:5 ... .... .... &typea @typeb ...... rd:5 ra:5 ................ &typeb imm=%extimm +# Officially typea, but with rb==0, which is not used. +@typea0 ...... rd:5 ra:5 ................ &typea0 + ### { @@ -47,6 +51,8 @@ andi 101001 ..... ..... ................ @typeb andn 100011 ..... ..... ..... 000 0000 0000 @typea andni 101011 ..... ..... ................ @typeb +clz 100100 ..... ..... 00000 000 1110 0000 @typea0 + cmp 000101 ..... ..... ..... 000 0000 0001 @typea cmpu 000101 ..... ..... ..... 000 0000 0011 @typea @@ -76,5 +82,19 @@ rsubic 001011 ..... ..... ................ @typeb rsubik 001101 ..... ..... ................ @typeb rsubikc 001111 ..... ..... ................ @typeb +sext8 100100 ..... ..... 00000 000 0110 0000 @typea0 +sext16 100100 ..... ..... 00000 000 0110 0001 @typea0 + +sra 100100 ..... ..... 00000 000 0000 0001 @typea0 +src 100100 ..... ..... 00000 000 0010 0001 @typea0 +srl 100100 ..... ..... 00000 000 0100 0001 @typea0 + +swapb 100100 ..... ..... 00000 001 1110 0000 @typea0 +swaph 100100 ..... ..... 00000 001 1110 0010 @typea0 + +# Cache operations have no effect in qemu: discard the arguments. +wdic 100100 00000 ----- ----- -00 -11- 01-0 # wdc +wdic 100100 00000 ----- ----- 000 0110 1000 # wic + xor 100010 ..... ..... ..... 000 0000 0000 @typea xori 101010 ..... ..... ................ @typeb diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 9763b9d77c..2d57f76548 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -241,6 +241,21 @@ static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects, return true; } +static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects, + void (*fn)(TCGv_i32, TCGv_i32)) +{ + TCGv_i32 rd, ra; + + if (arg->rd == 0 && !side_effects) { + return true; + } + + rd = reg_for_write(dc, arg->rd); + ra = reg_for_read(dc, arg->ra); + fn(rd, ra); + return true; +} + static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects, void (*fni)(TCGv_i32, TCGv_i32, int32_t)) { @@ -283,6 +298,14 @@ static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); } +#define DO_TYPEA0(NAME, SE, FN) \ + static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ + { return do_typea0(dc, a, SE, FN); } + +#define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \ + static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ + { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); } + #define DO_TYPEBI(NAME, SE, FNI) \ static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ { return do_typeb_imm(dc, a, SE, FNI); } @@ -345,6 +368,13 @@ DO_TYPEBI(andi, false, tcg_gen_andi_i32) DO_TYPEA(andn, false, tcg_gen_andc_i32) DO_TYPEBI(andni, false, gen_andni) +static void gen_clz(TCGv_i32 out, TCGv_i32 ina) +{ + tcg_gen_clzi_i32(out, ina, 32); +} + +DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz) + static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) { TCGv_i32 lt = tcg_temp_new_i32(); @@ -474,6 +504,51 @@ DO_TYPEBV(rsubic, true, gen_rsubc) DO_TYPEBV(rsubik, false, gen_rsubk) DO_TYPEBV(rsubikc, true, gen_rsubkc) +DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32) +DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32) + +static void gen_sra(TCGv_i32 out, TCGv_i32 ina) +{ + tcg_gen_andi_i32(cpu_msr_c, ina, 1); + tcg_gen_sari_i32(out, ina, 1); +} + +static void gen_src(TCGv_i32 out, TCGv_i32 ina) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_mov_i32(tmp, cpu_msr_c); + tcg_gen_andi_i32(cpu_msr_c, ina, 1); + tcg_gen_extract2_i32(out, ina, tmp, 1); + + tcg_temp_free_i32(tmp); +} + +static void gen_srl(TCGv_i32 out, TCGv_i32 ina) +{ + tcg_gen_andi_i32(cpu_msr_c, ina, 1); + tcg_gen_shri_i32(out, ina, 1); +} + +DO_TYPEA0(sra, false, gen_sra) +DO_TYPEA0(src, false, gen_src) +DO_TYPEA0(srl, false, gen_srl) + +static void gen_swaph(TCGv_i32 out, TCGv_i32 ina) +{ + tcg_gen_rotri_i32(out, ina, 16); +} + +DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32) +DO_TYPEA0(swaph, false, gen_swaph) + +static bool trans_wdic(DisasContext *dc, arg_wdic *a) +{ + /* Cache operations are nops: only check for supervisor mode. */ + trap_userspace(dc, true); + return true; +} + DO_TYPEA(xor, false, tcg_gen_xor_i32) DO_TYPEBI(xori, false, tcg_gen_xori_i32) @@ -754,78 +829,6 @@ static void dec_barrel(DisasContext *dc) } } -static void dec_bit(DisasContext *dc) -{ - CPUState *cs = CPU(dc->cpu); - TCGv_i32 t0; - unsigned int op; - - op = dc->ir & ((1 << 9) - 1); - switch (op) { - case 0x21: - /* src. */ - t0 = tcg_temp_new_i32(); - - tcg_gen_shli_i32(t0, cpu_msr_c, 31); - tcg_gen_andi_i32(cpu_msr_c, cpu_R[dc->ra], 1); - if (dc->rd) { - tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); - tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->rd], t0); - } - tcg_temp_free_i32(t0); - break; - - case 0x1: - case 0x41: - /* srl. */ - tcg_gen_andi_i32(cpu_msr_c, cpu_R[dc->ra], 1); - if (dc->rd) { - if (op == 0x41) - tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); - else - tcg_gen_sari_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); - } - break; - case 0x60: - tcg_gen_ext8s_i32(cpu_R[dc->rd], cpu_R[dc->ra]); - break; - case 0x61: - tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]); - break; - case 0x64: - case 0x66: - case 0x74: - case 0x76: - /* wdc. */ - trap_userspace(dc, true); - break; - case 0x68: - /* wic. */ - trap_userspace(dc, true); - break; - case 0xe0: - if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) { - return; - } - if (dc->cpu->cfg.use_pcmp_instr) { - tcg_gen_clzi_i32(cpu_R[dc->rd], cpu_R[dc->ra], 32); - } - break; - case 0x1e0: - /* swapb */ - tcg_gen_bswap32_i32(cpu_R[dc->rd], cpu_R[dc->ra]); - break; - case 0x1e2: - /*swaph */ - tcg_gen_rotri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 16); - break; - default: - cpu_abort(cs, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n", - (uint32_t)dc->base.pc_next, op, dc->rd, dc->ra, dc->rb); - break; - } -} - static inline void sync_jmpstate(DisasContext *dc) { if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { @@ -1548,7 +1551,6 @@ static struct decoder_info { }; void (*dec)(DisasContext *dc); } decinfo[] = { - {DEC_BIT, dec_bit}, {DEC_BARREL, dec_barrel}, {DEC_LD, dec_load}, {DEC_ST, dec_store}, From 081d8e02c352861af5deb20786160fa6860e5f8e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Aug 2020 08:47:38 -0700 Subject: [PATCH 45/76] target/microblaze: Convert dec_barrel to decodetree Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 20 ++++++ target/microblaze/translate.c | 125 +++++++++++++++++---------------- 2 files changed, 86 insertions(+), 59 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index d265e36044..4644defbfe 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -30,6 +30,15 @@ # Officially typea, but with rb==0, which is not used. @typea0 ...... rd:5 ra:5 ................ &typea0 +# Officially typeb, but any immediate extension is unused. +@typeb_bs ...... rd:5 ra:5 ..... ...... imm:5 &typeb + +# 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. +%ieimm 6:5 0:5 +@typeb_ie ...... rd:5 ra:5 ..... ..... . ..... &typeb imm=%ieimm + ### { @@ -51,6 +60,17 @@ andi 101001 ..... ..... ................ @typeb andn 100011 ..... ..... ..... 000 0000 0000 @typea andni 101011 ..... ..... ................ @typeb +bsrl 010001 ..... ..... ..... 000 0000 0000 @typea +bsra 010001 ..... ..... ..... 010 0000 0000 @typea +bsll 010001 ..... ..... ..... 100 0000 0000 @typea + +bsrli 011001 ..... ..... 00000 000000 ..... @typeb_bs +bsrai 011001 ..... ..... 00000 010000 ..... @typeb_bs +bslli 011001 ..... ..... 00000 100000 ..... @typeb_bs + +bsefi 011001 ..... ..... 01000 .....0 ..... @typeb_ie +bsifi 011001 ..... ..... 10000 .....0 ..... @typeb_ie + clz 100100 ..... ..... 00000 000 1110 0000 @typea0 cmp 000101 ..... ..... ..... 000 0000 0001 @typea diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 2d57f76548..964525f75e 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -368,6 +368,72 @@ DO_TYPEBI(andi, false, tcg_gen_andi_i32) DO_TYPEA(andn, false, tcg_gen_andc_i32) DO_TYPEBI(andni, false, gen_andni) +static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_andi_i32(tmp, inb, 31); + tcg_gen_sar_i32(out, ina, tmp); + tcg_temp_free_i32(tmp); +} + +static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_andi_i32(tmp, inb, 31); + tcg_gen_shr_i32(out, ina, tmp); + tcg_temp_free_i32(tmp); +} + +static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_andi_i32(tmp, inb, 31); + tcg_gen_shl_i32(out, ina, tmp); + tcg_temp_free_i32(tmp); +} + +static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) +{ + /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ + int imm_w = extract32(imm, 5, 5); + int imm_s = extract32(imm, 0, 5); + + if (imm_w + imm_s > 32 || imm_w == 0) { + /* These inputs have an undefined behavior. */ + qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", + imm_w, imm_s); + } else { + tcg_gen_extract_i32(out, ina, imm_s, imm_w); + } +} + +static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) +{ + /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ + int imm_w = extract32(imm, 5, 5); + int imm_s = extract32(imm, 0, 5); + int width = imm_w - imm_s + 1; + + if (imm_w < imm_s) { + /* These inputs have an undefined behavior. */ + qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", + imm_w, imm_s); + } else { + tcg_gen_deposit_i32(out, out, ina, imm_s, width); + } +} + +DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra) +DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl) +DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll) + +DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32) +DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32) +DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32) + +DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi) +DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi) + static void gen_clz(TCGv_i32 out, TCGv_i32 ina) { tcg_gen_clzi_i32(out, ina, 32); @@ -771,64 +837,6 @@ static void dec_msr(DisasContext *dc) } } -static void dec_barrel(DisasContext *dc) -{ - TCGv_i32 t0; - unsigned int imm_w, imm_s; - bool s, t, e = false, i = false; - - if (trap_illegal(dc, !dc->cpu->cfg.use_barrel)) { - return; - } - - if (dc->type_b) { - /* Insert and extract are only available in immediate mode. */ - i = extract32(dc->imm, 15, 1); - e = extract32(dc->imm, 14, 1); - } - s = extract32(dc->imm, 10, 1); - t = extract32(dc->imm, 9, 1); - imm_w = extract32(dc->imm, 6, 5); - imm_s = extract32(dc->imm, 0, 5); - - if (e) { - if (imm_w + imm_s > 32 || imm_w == 0) { - /* These inputs have an undefined behavior. */ - qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", - imm_w, imm_s); - } else { - tcg_gen_extract_i32(cpu_R[dc->rd], cpu_R[dc->ra], imm_s, imm_w); - } - } else if (i) { - int width = imm_w - imm_s + 1; - - if (imm_w < imm_s) { - /* These inputs have an undefined behavior. */ - qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", - imm_w, imm_s); - } else { - tcg_gen_deposit_i32(cpu_R[dc->rd], cpu_R[dc->rd], cpu_R[dc->ra], - imm_s, width); - } - } else { - t0 = tcg_temp_new_i32(); - - tcg_gen_mov_i32(t0, *(dec_alu_op_b(dc))); - tcg_gen_andi_i32(t0, t0, 31); - - if (s) { - tcg_gen_shl_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); - } else { - if (t) { - tcg_gen_sar_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); - } else { - tcg_gen_shr_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); - } - } - tcg_temp_free_i32(t0); - } -} - static inline void sync_jmpstate(DisasContext *dc) { if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { @@ -1551,7 +1559,6 @@ static struct decoder_info { }; void (*dec)(DisasContext *dc); } decinfo[] = { - {DEC_BARREL, dec_barrel}, {DEC_LD, dec_load}, {DEC_ST, dec_store}, {DEC_IMM, dec_imm}, From e64b2e5cfe1a6a158f134e5bfa6c246d23ad1d9d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Aug 2020 10:22:18 -0700 Subject: [PATCH 46/76] target/microblaze: Convert dec_imm to decodetree Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 2 ++ target/microblaze/translate.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index 4644defbfe..ad15c16f9b 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -79,6 +79,8 @@ cmpu 000101 ..... ..... ..... 000 0000 0011 @typea idiv 010010 ..... ..... ..... 000 0000 0000 @typea idivu 010010 ..... ..... ..... 000 0000 0010 @typea +imm 101100 00000 00000 imm:16 + mul 010000 ..... ..... ..... 000 0000 0000 @typea mulh 010000 ..... ..... ..... 000 0000 0001 @typea mulhu 010000 ..... ..... ..... 000 0000 0011 @typea diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 964525f75e..54de136a16 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -477,6 +477,15 @@ static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) DO_TYPEA_CFG(idiv, use_div, true, gen_idiv) DO_TYPEA_CFG(idivu, use_div, true, gen_idivu) +static bool trans_imm(DisasContext *dc, arg_imm *arg) +{ + dc->ext_imm = arg->imm << 16; + tcg_gen_movi_i32(cpu_imm, dc->ext_imm); + dc->tb_flags |= IMM_FLAG; + dc->clear_imm = 0; + return true; +} + static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) { TCGv_i32 tmp = tcg_temp_new_i32(); @@ -848,14 +857,6 @@ static inline void sync_jmpstate(DisasContext *dc) } } -static void dec_imm(DisasContext *dc) -{ - dc->ext_imm = dc->imm << 16; - tcg_gen_movi_i32(cpu_imm, dc->ext_imm); - dc->tb_flags |= IMM_FLAG; - dc->clear_imm = 0; -} - static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t) { /* Should be set to true if r1 is used by loadstores. */ @@ -1561,7 +1562,6 @@ static struct decoder_info { } decinfo[] = { {DEC_LD, dec_load}, {DEC_ST, dec_store}, - {DEC_IMM, dec_imm}, {DEC_BR, dec_br}, {DEC_BCC, dec_bcc}, {DEC_RTS, dec_rts}, From d5aead3df4369f56bf79bcd97a06cd63e4acfee6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 09:04:09 -0700 Subject: [PATCH 47/76] target/microblaze: Convert dec_fpu to decodetree The current dec_check_fpuv2 test, raising an FPU exception for an unimplemented instruction, appears to be contradictory to the manual. Drop that and merely check use_fpu == 2. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 19 +++++ target/microblaze/translate.c | 152 +++++++++------------------------ 2 files changed, 60 insertions(+), 111 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index ad15c16f9b..87e8f5679b 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -76,6 +76,25 @@ clz 100100 ..... ..... 00000 000 1110 0000 @typea0 cmp 000101 ..... ..... ..... 000 0000 0001 @typea cmpu 000101 ..... ..... ..... 000 0000 0011 @typea +fadd 010110 ..... ..... ..... 0000 000 0000 @typea +frsub 010110 ..... ..... ..... 0001 000 0000 @typea +fmul 010110 ..... ..... ..... 0010 000 0000 @typea +fdiv 010110 ..... ..... ..... 0011 000 0000 @typea +fcmp_un 010110 ..... ..... ..... 0100 000 0000 @typea +fcmp_lt 010110 ..... ..... ..... 0100 001 0000 @typea +fcmp_eq 010110 ..... ..... ..... 0100 010 0000 @typea +fcmp_le 010110 ..... ..... ..... 0100 011 0000 @typea +fcmp_gt 010110 ..... ..... ..... 0100 100 0000 @typea +fcmp_ne 010110 ..... ..... ..... 0100 101 0000 @typea +fcmp_ge 010110 ..... ..... ..... 0100 110 0000 @typea + +# Note that flt and fint, unlike fsqrt, are documented as having the RB +# operand which is unused. So allow the field to be non-zero but discard +# the value and treat as 2-operand insns. +flt 010110 ..... ..... ----- 0101 000 0000 @typea0 +fint 010110 ..... ..... ----- 0110 000 0000 @typea0 +fsqrt 010110 ..... ..... 00000 0111 000 0000 @typea0 + idiv 010010 ..... ..... ..... 000 0000 0000 @typea idivu 010010 ..... ..... ..... 000 0000 0010 @typea diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 54de136a16..72541905ec 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -318,6 +318,14 @@ static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ { return do_typeb_val(dc, a, SE, FN); } +#define ENV_WRAPPER2(NAME, HELPER) \ + static void NAME(TCGv_i32 out, TCGv_i32 ina) \ + { HELPER(out, cpu_env, ina); } + +#define ENV_WRAPPER3(NAME, HELPER) \ + static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \ + { HELPER(out, cpu_env, ina, inb); } + /* No input carry, but output carry. */ static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) { @@ -464,6 +472,39 @@ static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) DO_TYPEA(cmp, false, gen_cmp) DO_TYPEA(cmpu, false, gen_cmpu) +ENV_WRAPPER3(gen_fadd, gen_helper_fadd) +ENV_WRAPPER3(gen_frsub, gen_helper_frsub) +ENV_WRAPPER3(gen_fmul, gen_helper_fmul) +ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv) +ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un) +ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt) +ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq) +ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le) +ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt) +ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne) +ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge) + +DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd) +DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub) +DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul) +DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv) +DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un) +DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt) +DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq) +DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le) +DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt) +DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne) +DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge) + +ENV_WRAPPER2(gen_flt, gen_helper_flt) +ENV_WRAPPER2(gen_fint, gen_helper_fint) +ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt) + +DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt) +DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint) +DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt) + +/* Does not use ENV_WRAPPER3, because arguments are swapped as well. */ static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) { gen_helper_divs(out, cpu_env, inb, ina); @@ -1403,116 +1444,6 @@ static void dec_rts(DisasContext *dc) tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc)); } -static int dec_check_fpuv2(DisasContext *dc) -{ - if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) { - gen_raise_hw_excp(dc, ESR_EC_FPU); - } - return (dc->cpu->cfg.use_fpu == 2) ? PVR2_USE_FPU2_MASK : 0; -} - -static void dec_fpu(DisasContext *dc) -{ - unsigned int fpu_insn; - - if (trap_illegal(dc, !dc->cpu->cfg.use_fpu)) { - return; - } - - fpu_insn = (dc->ir >> 7) & 7; - - switch (fpu_insn) { - case 0: - gen_helper_fadd(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], - cpu_R[dc->rb]); - break; - - case 1: - gen_helper_frsub(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], - cpu_R[dc->rb]); - break; - - case 2: - gen_helper_fmul(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], - cpu_R[dc->rb]); - break; - - case 3: - gen_helper_fdiv(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], - cpu_R[dc->rb]); - break; - - case 4: - switch ((dc->ir >> 4) & 7) { - case 0: - gen_helper_fcmp_un(cpu_R[dc->rd], cpu_env, - cpu_R[dc->ra], cpu_R[dc->rb]); - break; - case 1: - gen_helper_fcmp_lt(cpu_R[dc->rd], cpu_env, - cpu_R[dc->ra], cpu_R[dc->rb]); - break; - case 2: - gen_helper_fcmp_eq(cpu_R[dc->rd], cpu_env, - cpu_R[dc->ra], cpu_R[dc->rb]); - break; - case 3: - gen_helper_fcmp_le(cpu_R[dc->rd], cpu_env, - cpu_R[dc->ra], cpu_R[dc->rb]); - break; - case 4: - gen_helper_fcmp_gt(cpu_R[dc->rd], cpu_env, - cpu_R[dc->ra], cpu_R[dc->rb]); - break; - case 5: - gen_helper_fcmp_ne(cpu_R[dc->rd], cpu_env, - cpu_R[dc->ra], cpu_R[dc->rb]); - break; - case 6: - gen_helper_fcmp_ge(cpu_R[dc->rd], cpu_env, - cpu_R[dc->ra], cpu_R[dc->rb]); - break; - default: - qemu_log_mask(LOG_UNIMP, - "unimplemented fcmp fpu_insn=%x pc=%x" - " opc=%x\n", - fpu_insn, (uint32_t)dc->base.pc_next, - dc->opcode); - dc->abort_at_next_insn = 1; - break; - } - break; - - case 5: - if (!dec_check_fpuv2(dc)) { - return; - } - gen_helper_flt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); - break; - - case 6: - if (!dec_check_fpuv2(dc)) { - return; - } - gen_helper_fint(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); - break; - - case 7: - if (!dec_check_fpuv2(dc)) { - return; - } - gen_helper_fsqrt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); - break; - - default: - qemu_log_mask(LOG_UNIMP, "unimplemented FPU insn fpu_insn=%x pc=%x" - " opc=%x\n", - fpu_insn, (uint32_t)dc->base.pc_next, dc->opcode); - dc->abort_at_next_insn = 1; - break; - } -} - static void dec_null(DisasContext *dc) { if (trap_illegal(dc, true)) { @@ -1565,7 +1496,6 @@ static struct decoder_info { {DEC_BR, dec_br}, {DEC_BCC, dec_bcc}, {DEC_RTS, dec_rts}, - {DEC_FPU, dec_fpu}, {DEC_MSR, dec_msr}, {DEC_STREAM, dec_stream}, {{0, 0}, dec_null} From 7bca6ddf901bba39f890fc80d22c26ed2606f4d5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 09:11:37 -0700 Subject: [PATCH 48/76] target/microblaze: Fix cpu unwind for fpu exceptions Restore the correct PC when an exception must be raised. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/op_helper.c | 37 +++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index d99d98051a..2c59d4492d 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -104,13 +104,16 @@ uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b) } /* raise FPU exception. */ -static void raise_fpu_exception(CPUMBState *env) +static void raise_fpu_exception(CPUMBState *env, uintptr_t ra) { + CPUState *cs = env_cpu(env); + env->esr = ESR_EC_FPU; - helper_raise_exception(env, EXCP_HW_EXCP); + cs->exception_index = EXCP_HW_EXCP; + cpu_loop_exit_restore(cs, ra); } -static void update_fpu_flags(CPUMBState *env, int flags) +static void update_fpu_flags(CPUMBState *env, int flags, uintptr_t ra) { int raise = 0; @@ -133,7 +136,7 @@ static void update_fpu_flags(CPUMBState *env, int flags) if (raise && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK) && (env->msr & MSR_EE)) { - raise_fpu_exception(env); + raise_fpu_exception(env, ra); } } @@ -148,7 +151,7 @@ uint32_t helper_fadd(CPUMBState *env, uint32_t a, uint32_t b) fd.f = float32_add(fa.f, fb.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); - update_fpu_flags(env, flags); + update_fpu_flags(env, flags, GETPC()); return fd.l; } @@ -162,7 +165,7 @@ uint32_t helper_frsub(CPUMBState *env, uint32_t a, uint32_t b) fb.l = b; fd.f = float32_sub(fb.f, fa.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); - update_fpu_flags(env, flags); + update_fpu_flags(env, flags, GETPC()); return fd.l; } @@ -176,7 +179,7 @@ uint32_t helper_fmul(CPUMBState *env, uint32_t a, uint32_t b) fb.l = b; fd.f = float32_mul(fa.f, fb.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); - update_fpu_flags(env, flags); + update_fpu_flags(env, flags, GETPC()); return fd.l; } @@ -191,7 +194,7 @@ uint32_t helper_fdiv(CPUMBState *env, uint32_t a, uint32_t b) fb.l = b; fd.f = float32_div(fb.f, fa.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); - update_fpu_flags(env, flags); + update_fpu_flags(env, flags, GETPC()); return fd.l; } @@ -206,7 +209,7 @@ uint32_t helper_fcmp_un(CPUMBState *env, uint32_t a, uint32_t b) if (float32_is_signaling_nan(fa.f, &env->fp_status) || float32_is_signaling_nan(fb.f, &env->fp_status)) { - update_fpu_flags(env, float_flag_invalid); + update_fpu_flags(env, float_flag_invalid, GETPC()); r = 1; } @@ -229,7 +232,7 @@ uint32_t helper_fcmp_lt(CPUMBState *env, uint32_t a, uint32_t b) fb.l = b; r = float32_lt(fb.f, fa.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); - update_fpu_flags(env, flags & float_flag_invalid); + update_fpu_flags(env, flags & float_flag_invalid, GETPC()); return r; } @@ -245,7 +248,7 @@ uint32_t helper_fcmp_eq(CPUMBState *env, uint32_t a, uint32_t b) fb.l = b; r = float32_eq_quiet(fa.f, fb.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); - update_fpu_flags(env, flags & float_flag_invalid); + update_fpu_flags(env, flags & float_flag_invalid, GETPC()); return r; } @@ -261,7 +264,7 @@ uint32_t helper_fcmp_le(CPUMBState *env, uint32_t a, uint32_t b) set_float_exception_flags(0, &env->fp_status); r = float32_le(fa.f, fb.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); - update_fpu_flags(env, flags & float_flag_invalid); + update_fpu_flags(env, flags & float_flag_invalid, GETPC()); return r; @@ -277,7 +280,7 @@ uint32_t helper_fcmp_gt(CPUMBState *env, uint32_t a, uint32_t b) set_float_exception_flags(0, &env->fp_status); r = float32_lt(fa.f, fb.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); - update_fpu_flags(env, flags & float_flag_invalid); + update_fpu_flags(env, flags & float_flag_invalid, GETPC()); return r; } @@ -291,7 +294,7 @@ uint32_t helper_fcmp_ne(CPUMBState *env, uint32_t a, uint32_t b) set_float_exception_flags(0, &env->fp_status); r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); - update_fpu_flags(env, flags & float_flag_invalid); + update_fpu_flags(env, flags & float_flag_invalid, GETPC()); return r; } @@ -306,7 +309,7 @@ uint32_t helper_fcmp_ge(CPUMBState *env, uint32_t a, uint32_t b) set_float_exception_flags(0, &env->fp_status); r = !float32_lt(fa.f, fb.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); - update_fpu_flags(env, flags & float_flag_invalid); + update_fpu_flags(env, flags & float_flag_invalid, GETPC()); return r; } @@ -330,7 +333,7 @@ uint32_t helper_fint(CPUMBState *env, uint32_t a) fa.l = a; r = float32_to_int32(fa.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); - update_fpu_flags(env, flags); + update_fpu_flags(env, flags, GETPC()); return r; } @@ -344,7 +347,7 @@ uint32_t helper_fsqrt(CPUMBState *env, uint32_t a) fa.l = a; fd.l = float32_sqrt(fa.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); - update_fpu_flags(env, flags); + update_fpu_flags(env, flags, GETPC()); return fd.l; } From 3986c650a25e645a2b39795e5004d7e0e1c7b8b1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Aug 2020 08:57:36 -0700 Subject: [PATCH 49/76] target/microblaze: Mark fpu helpers TCG_CALL_NO_WG Now that FSR is no longer a tcg global temp, we can say that the fpu helpers do not write to tcg temps. All temps are read implicitly by the fpu exception path. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/helper.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/target/microblaze/helper.h b/target/microblaze/helper.h index 79e1e8ecc7..64816c89e1 100644 --- a/target/microblaze/helper.h +++ b/target/microblaze/helper.h @@ -3,21 +3,21 @@ DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32) DEF_HELPER_FLAGS_3(divs, TCG_CALL_NO_WG, i32, env, i32, i32) DEF_HELPER_FLAGS_3(divu, TCG_CALL_NO_WG, i32, env, i32, i32) -DEF_HELPER_3(fadd, i32, env, i32, i32) -DEF_HELPER_3(frsub, i32, env, i32, i32) -DEF_HELPER_3(fmul, i32, env, i32, i32) -DEF_HELPER_3(fdiv, i32, env, i32, i32) -DEF_HELPER_2(flt, i32, env, i32) -DEF_HELPER_2(fint, i32, env, i32) -DEF_HELPER_2(fsqrt, i32, env, i32) +DEF_HELPER_FLAGS_3(fadd, TCG_CALL_NO_WG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(frsub, TCG_CALL_NO_WG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fmul, TCG_CALL_NO_WG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fdiv, TCG_CALL_NO_WG, i32, env, i32, i32) +DEF_HELPER_FLAGS_2(flt, TCG_CALL_NO_WG, i32, env, i32) +DEF_HELPER_FLAGS_2(fint, TCG_CALL_NO_WG, i32, env, i32) +DEF_HELPER_FLAGS_2(fsqrt, TCG_CALL_NO_WG, i32, env, i32) -DEF_HELPER_3(fcmp_un, i32, env, i32, i32) -DEF_HELPER_3(fcmp_lt, i32, env, i32, i32) -DEF_HELPER_3(fcmp_eq, i32, env, i32, i32) -DEF_HELPER_3(fcmp_le, i32, env, i32, i32) -DEF_HELPER_3(fcmp_gt, i32, env, i32, i32) -DEF_HELPER_3(fcmp_ne, i32, env, i32, i32) -DEF_HELPER_3(fcmp_ge, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fcmp_un, TCG_CALL_NO_WG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fcmp_lt, TCG_CALL_NO_WG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fcmp_eq, TCG_CALL_NO_WG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fcmp_le, TCG_CALL_NO_WG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fcmp_gt, TCG_CALL_NO_WG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fcmp_ne, TCG_CALL_NO_WG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fcmp_ge, TCG_CALL_NO_WG, i32, env, i32, i32) DEF_HELPER_FLAGS_2(pcmpbf, TCG_CALL_NO_RWG_SE, i32, i32, i32) #if !defined(CONFIG_USER_ONLY) From 2c32179f39278ebc975c3d08710bb22672911889 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 16:12:12 -0700 Subject: [PATCH 50/76] target/microblaze: Replace MSR_EE_FLAG with MSR_EE There's no reason to define MSR_EE_FLAG; we can just use the original MSR_EE define. Document the other flags copied into tb_flags with iflag to reserve those bits. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 4 +++- target/microblaze/translate.c | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 013858b8e0..594501e4e7 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -254,7 +254,9 @@ struct CPUMBState { /* Internal flags. */ #define IMM_FLAG 4 -#define MSR_EE_FLAG (1 << 8) +/* MSR_EE (1 << 8) */ +/* MSR_UM (1 << 11) */ +/* MSR_VM (1 << 13) */ #define DRTI_FLAG (1 << 16) #define DRTE_FLAG (1 << 17) #define DRTB_FLAG (1 << 18) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 72541905ec..1f6731e0af 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -162,7 +162,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) */ static bool trap_illegal(DisasContext *dc, bool cond) { - if (cond && (dc->tb_flags & MSR_EE_FLAG) + if (cond && (dc->tb_flags & MSR_EE) && dc->cpu->cfg.illegal_opcode_exception) { gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); } @@ -178,7 +178,7 @@ static bool trap_userspace(DisasContext *dc, bool cond) int mem_index = cpu_mmu_index(&dc->cpu->env, false); bool cond_user = cond && mem_index == MMU_USER_IDX; - if (cond_user && (dc->tb_flags & MSR_EE_FLAG)) { + if (cond_user && (dc->tb_flags & MSR_EE)) { gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); } return cond_user; From 287b1defeb44398d02669d97ebdc347d650f274d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 16:38:07 -0700 Subject: [PATCH 51/76] target/microblaze: Cache mem_index in DisasContext Ideally, nothing outside the top-level of translation even has access to env. Cache the value in init_disas_context. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 1f6731e0af..a55e110171 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -73,6 +73,7 @@ typedef struct DisasContext { unsigned int delayed_branch; unsigned int tb_flags, synced_flags; /* tb dependent flags. */ unsigned int clear_imm; + int mem_index; #define JMP_NOJMP 0 #define JMP_DIRECT 1 @@ -175,8 +176,7 @@ static bool trap_illegal(DisasContext *dc, bool cond) */ static bool trap_userspace(DisasContext *dc, bool cond) { - int mem_index = cpu_mmu_index(&dc->cpu->env, false); - bool cond_user = cond && mem_index == MMU_USER_IDX; + bool cond_user = cond && dc->mem_index == MMU_USER_IDX; if (cond_user && (dc->tb_flags & MSR_EE)) { gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); @@ -968,7 +968,7 @@ static void dec_load(DisasContext *dc) TCGv addr; unsigned int size; bool rev = false, ex = false, ea = false; - int mem_index = cpu_mmu_index(&dc->cpu->env, false); + int mem_index = dc->mem_index; MemOp mop; mop = dc->opcode & 3; @@ -1077,7 +1077,7 @@ static void dec_store(DisasContext *dc) TCGLabel *swx_skip = NULL; unsigned int size; bool rev = false, ex = false, ea = false; - int mem_index = cpu_mmu_index(&dc->cpu->env, false); + int mem_index = dc->mem_index; MemOp mop; mop = dc->opcode & 3; @@ -1540,6 +1540,7 @@ static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) dc->ext_imm = dc->base.tb->cs_base; dc->r0 = NULL; dc->r0_set = false; + dc->mem_index = cpu_mmu_index(&cpu->env, false); bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; dc->base.max_insns = MIN(dc->base.max_insns, bound); From 3f203194550108a72e8ee55d1b8bcb2333222b71 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Aug 2020 07:45:34 -0700 Subject: [PATCH 52/76] target/microblaze: Fix cpu unwind for stackprot Restore the correct PC when an exception must be raised. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/helper.h | 2 +- target/microblaze/op_helper.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/target/microblaze/helper.h b/target/microblaze/helper.h index 64816c89e1..a473c1867b 100644 --- a/target/microblaze/helper.h +++ b/target/microblaze/helper.h @@ -26,7 +26,7 @@ DEF_HELPER_4(mmu_write, void, env, i32, i32, i32) #endif DEF_HELPER_5(memalign, void, env, tl, i32, i32, i32) -DEF_HELPER_2(stackprot, void, env, tl) +DEF_HELPER_FLAGS_2(stackprot, TCG_CALL_NO_WG, void, env, tl) DEF_HELPER_2(get, i32, i32, i32) DEF_HELPER_3(put, void, i32, i32, i32) diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index 2c59d4492d..a99c467364 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -389,12 +389,16 @@ void helper_memalign(CPUMBState *env, target_ulong addr, void helper_stackprot(CPUMBState *env, target_ulong addr) { if (addr < env->slr || addr > env->shr) { + CPUState *cs = env_cpu(env); + qemu_log_mask(CPU_LOG_INT, "Stack protector violation at " TARGET_FMT_lx " %x %x\n", addr, env->slr, env->shr); + env->ear = addr; env->esr = ESR_EC_STACKPROT; - helper_raise_exception(env, EXCP_HW_EXCP); + cs->exception_index = EXCP_HW_EXCP; + cpu_loop_exit_restore(cs, GETPC()); } } From d8e59c4a6f888a8711af293d9ce2bb9609973748 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Aug 2020 17:38:44 -0700 Subject: [PATCH 53/76] target/microblaze: Convert dec_load and dec_store to decodetree Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 32 ++ target/microblaze/translate.c | 723 +++++++++++++++++++-------------- 2 files changed, 456 insertions(+), 299 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index 87e8f5679b..47b92b9cbc 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -100,6 +100,22 @@ idivu 010010 ..... ..... ..... 000 0000 0010 @typea imm 101100 00000 00000 imm:16 +lbu 110000 ..... ..... ..... 0000 000 0000 @typea +lbur 110000 ..... ..... ..... 0100 000 0000 @typea +lbuea 110000 ..... ..... ..... 0001 000 0000 @typea +lbui 111000 ..... ..... ................ @typeb + +lhu 110001 ..... ..... ..... 0000 000 0000 @typea +lhur 110001 ..... ..... ..... 0100 000 0000 @typea +lhuea 110001 ..... ..... ..... 0001 000 0000 @typea +lhui 111001 ..... ..... ................ @typeb + +lw 110010 ..... ..... ..... 0000 000 0000 @typea +lwr 110010 ..... ..... ..... 0100 000 0000 @typea +lwea 110010 ..... ..... ..... 0001 000 0000 @typea +lwx 110010 ..... ..... ..... 1000 000 0000 @typea +lwi 111010 ..... ..... ................ @typeb + mul 010000 ..... ..... ..... 000 0000 0000 @typea mulh 010000 ..... ..... ..... 000 0000 0001 @typea mulhu 010000 ..... ..... ..... 000 0000 0011 @typea @@ -123,6 +139,22 @@ rsubic 001011 ..... ..... ................ @typeb rsubik 001101 ..... ..... ................ @typeb rsubikc 001111 ..... ..... ................ @typeb +sb 110100 ..... ..... ..... 0000 000 0000 @typea +sbr 110100 ..... ..... ..... 0100 000 0000 @typea +sbea 110100 ..... ..... ..... 0001 000 0000 @typea +sbi 111100 ..... ..... ................ @typeb + +sh 110101 ..... ..... ..... 0000 000 0000 @typea +shr 110101 ..... ..... ..... 0100 000 0000 @typea +shea 110101 ..... ..... ..... 0001 000 0000 @typea +shi 111101 ..... ..... ................ @typeb + +sw 110110 ..... ..... ..... 0000 000 0000 @typea +swr 110110 ..... ..... ..... 0100 000 0000 @typea +swea 110110 ..... ..... ..... 0001 000 0000 @typea +swx 110110 ..... ..... ..... 1000 000 0000 @typea +swi 111110 ..... ..... ................ @typeb + sext8 100100 ..... ..... 00000 000 0110 0000 @typea0 sext16 100100 ..... ..... 00000 000 0110 0001 @typea0 diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index a55e110171..d2baa7db0e 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -105,6 +105,17 @@ static inline void t_sync_flags(DisasContext *dc) } } +static inline void sync_jmpstate(DisasContext *dc) +{ + if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { + if (dc->jmp == JMP_DIRECT) { + tcg_gen_movi_i32(cpu_btaken, 1); + } + dc->jmp = JMP_INDIRECT; + tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); + } +} + static void gen_raise_exception(DisasContext *dc, uint32_t index) { TCGv_i32 tmp = tcg_const_i32(index); @@ -668,6 +679,419 @@ static bool trans_wdic(DisasContext *dc, arg_wdic *a) DO_TYPEA(xor, false, tcg_gen_xor_i32) DO_TYPEBI(xori, false, tcg_gen_xori_i32) +static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb) +{ + TCGv ret = tcg_temp_new(); + + /* If any of the regs is r0, set t to the value of the other reg. */ + if (ra && rb) { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]); + tcg_gen_extu_i32_tl(ret, tmp); + tcg_temp_free_i32(tmp); + } else if (ra) { + tcg_gen_extu_i32_tl(ret, cpu_R[ra]); + } else if (rb) { + tcg_gen_extu_i32_tl(ret, cpu_R[rb]); + } else { + tcg_gen_movi_tl(ret, 0); + } + + if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) { + gen_helper_stackprot(cpu_env, ret); + } + return ret; +} + +static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) +{ + TCGv ret = tcg_temp_new(); + + /* If any of the regs is r0, set t to the value of the other reg. */ + if (ra) { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_addi_i32(tmp, cpu_R[ra], imm); + tcg_gen_extu_i32_tl(ret, tmp); + tcg_temp_free_i32(tmp); + } else { + tcg_gen_movi_tl(ret, (uint32_t)imm); + } + + if (ra == 1 && dc->cpu->cfg.stackprot) { + gen_helper_stackprot(cpu_env, ret); + } + return ret; +} + +static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) +{ + int addr_size = dc->cpu->cfg.addr_size; + TCGv ret = tcg_temp_new(); + + if (addr_size == 32 || ra == 0) { + if (rb) { + tcg_gen_extu_i32_tl(ret, cpu_R[rb]); + } else { + tcg_gen_movi_tl(ret, 0); + } + } else { + if (rb) { + tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]); + } else { + tcg_gen_extu_i32_tl(ret, cpu_R[ra]); + tcg_gen_shli_tl(ret, ret, 32); + } + if (addr_size < 64) { + /* Mask off out of range bits. */ + tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size)); + } + } + return ret; +} + +static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, + int mem_index, bool rev) +{ + TCGv_i32 v; + MemOp size = mop & MO_SIZE; + + /* + * When doing reverse accesses we need to do two things. + * + * 1. Reverse the address wrt endianness. + * 2. Byteswap the data lanes on the way back into the CPU core. + */ + if (rev) { + if (size > MO_8) { + mop ^= MO_BSWAP; + } + if (size < MO_32) { + tcg_gen_xori_tl(addr, addr, 3 - size); + } + } + + t_sync_flags(dc); + sync_jmpstate(dc); + + /* + * Microblaze gives MMU faults priority over faults due to + * unaligned addresses. That's why we speculatively do the load + * into v. If the load succeeds, we verify alignment of the + * address and if that succeeds we write into the destination reg. + */ + v = tcg_temp_new_i32(); + tcg_gen_qemu_ld_i32(v, addr, mem_index, mop); + + /* TODO: Convert to CPUClass::do_unaligned_access. */ + if (dc->cpu->cfg.unaligned_exceptions && size > MO_8) { + TCGv_i32 t0 = tcg_const_i32(0); + TCGv_i32 treg = tcg_const_i32(rd); + TCGv_i32 tsize = tcg_const_i32((1 << size) - 1); + + tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); + gen_helper_memalign(cpu_env, addr, treg, t0, tsize); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(treg); + tcg_temp_free_i32(tsize); + } + + if (rd) { + tcg_gen_mov_i32(cpu_R[rd], v); + } + + tcg_temp_free_i32(v); + tcg_temp_free(addr); + return true; +} + +static bool trans_lbu(DisasContext *dc, arg_typea *arg) +{ + TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); + return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); +} + +static bool trans_lbur(DisasContext *dc, arg_typea *arg) +{ + TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); + return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true); +} + +static bool trans_lbuea(DisasContext *dc, arg_typea *arg) +{ + if (trap_userspace(dc, true)) { + return true; + } + TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); + return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); +} + +static bool trans_lbui(DisasContext *dc, arg_typeb *arg) +{ + TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); + return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); +} + +static bool trans_lhu(DisasContext *dc, arg_typea *arg) +{ + TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); + return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); +} + +static bool trans_lhur(DisasContext *dc, arg_typea *arg) +{ + TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); + return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); +} + +static bool trans_lhuea(DisasContext *dc, arg_typea *arg) +{ + if (trap_userspace(dc, true)) { + return true; + } + TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); + return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); +} + +static bool trans_lhui(DisasContext *dc, arg_typeb *arg) +{ + TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); + return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); +} + +static bool trans_lw(DisasContext *dc, arg_typea *arg) +{ + TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); + return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); +} + +static bool trans_lwr(DisasContext *dc, arg_typea *arg) +{ + TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); + return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); +} + +static bool trans_lwea(DisasContext *dc, arg_typea *arg) +{ + if (trap_userspace(dc, true)) { + return true; + } + TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); + return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); +} + +static bool trans_lwi(DisasContext *dc, arg_typeb *arg) +{ + TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); + return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); +} + +static bool trans_lwx(DisasContext *dc, arg_typea *arg) +{ + TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); + + /* lwx does not throw unaligned access errors, so force alignment */ + tcg_gen_andi_tl(addr, addr, ~3); + + t_sync_flags(dc); + sync_jmpstate(dc); + + tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL); + tcg_gen_mov_tl(cpu_res_addr, addr); + tcg_temp_free(addr); + + if (arg->rd) { + tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val); + } + + /* No support for AXI exclusive so always clear C */ + tcg_gen_movi_i32(cpu_msr_c, 0); + return true; +} + +static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop, + int mem_index, bool rev) +{ + MemOp size = mop & MO_SIZE; + + /* + * When doing reverse accesses we need to do two things. + * + * 1. Reverse the address wrt endianness. + * 2. Byteswap the data lanes on the way back into the CPU core. + */ + if (rev) { + if (size > MO_8) { + mop ^= MO_BSWAP; + } + if (size < MO_32) { + tcg_gen_xori_tl(addr, addr, 3 - size); + } + } + + t_sync_flags(dc); + sync_jmpstate(dc); + + tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop); + + /* TODO: Convert to CPUClass::do_unaligned_access. */ + if (dc->cpu->cfg.unaligned_exceptions && size > MO_8) { + TCGv_i32 t1 = tcg_const_i32(1); + TCGv_i32 treg = tcg_const_i32(rd); + TCGv_i32 tsize = tcg_const_i32((1 << size) - 1); + + tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); + /* FIXME: if the alignment is wrong, we should restore the value + * in memory. One possible way to achieve this is to probe + * the MMU prior to the memaccess, thay way we could put + * the alignment checks in between the probe and the mem + * access. + */ + gen_helper_memalign(cpu_env, addr, treg, t1, tsize); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(treg); + tcg_temp_free_i32(tsize); + } + + tcg_temp_free(addr); + return true; +} + +static bool trans_sb(DisasContext *dc, arg_typea *arg) +{ + TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); + return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); +} + +static bool trans_sbr(DisasContext *dc, arg_typea *arg) +{ + TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); + return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true); +} + +static bool trans_sbea(DisasContext *dc, arg_typea *arg) +{ + if (trap_userspace(dc, true)) { + return true; + } + TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); + return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); +} + +static bool trans_sbi(DisasContext *dc, arg_typeb *arg) +{ + TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); + return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); +} + +static bool trans_sh(DisasContext *dc, arg_typea *arg) +{ + TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); + return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); +} + +static bool trans_shr(DisasContext *dc, arg_typea *arg) +{ + TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); + return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); +} + +static bool trans_shea(DisasContext *dc, arg_typea *arg) +{ + if (trap_userspace(dc, true)) { + return true; + } + TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); + return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); +} + +static bool trans_shi(DisasContext *dc, arg_typeb *arg) +{ + TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); + return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); +} + +static bool trans_sw(DisasContext *dc, arg_typea *arg) +{ + TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); + return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); +} + +static bool trans_swr(DisasContext *dc, arg_typea *arg) +{ + TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); + return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); +} + +static bool trans_swea(DisasContext *dc, arg_typea *arg) +{ + if (trap_userspace(dc, true)) { + return true; + } + TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); + return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); +} + +static bool trans_swi(DisasContext *dc, arg_typeb *arg) +{ + TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); + return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); +} + +static bool trans_swx(DisasContext *dc, arg_typea *arg) +{ + TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); + TCGLabel *swx_done = gen_new_label(); + TCGLabel *swx_fail = gen_new_label(); + TCGv_i32 tval; + + t_sync_flags(dc); + sync_jmpstate(dc); + + /* swx does not throw unaligned access errors, so force alignment */ + tcg_gen_andi_tl(addr, addr, ~3); + + /* + * Compare the address vs the one we used during lwx. + * On mismatch, the operation fails. On match, addr dies at the + * branch, but we know we can use the equal version in the global. + * In either case, addr is no longer needed. + */ + tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail); + tcg_temp_free(addr); + + /* + * Compare the value loaded during lwx with current contents of + * the reserved location. + */ + tval = tcg_temp_new_i32(); + + tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val, + reg_for_write(dc, arg->rd), + dc->mem_index, MO_TEUL); + + tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail); + tcg_temp_free_i32(tval); + + /* Success */ + tcg_gen_movi_i32(cpu_msr_c, 0); + tcg_gen_br(swx_done); + + /* Failure */ + gen_set_label(swx_fail); + tcg_gen_movi_i32(cpu_msr_c, 1); + + gen_set_label(swx_done); + + /* + * Prevent the saved address from working again without another ldx. + * Akin to the pseudocode setting reservation = 0. + */ + tcg_gen_movi_tl(cpu_res_addr, -1); + return true; +} + static bool trans_zero(DisasContext *dc, arg_zero *arg) { /* If opcode_0_illegal, trap. */ @@ -887,303 +1311,6 @@ static void dec_msr(DisasContext *dc) } } -static inline void sync_jmpstate(DisasContext *dc) -{ - if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { - if (dc->jmp == JMP_DIRECT) { - tcg_gen_movi_i32(cpu_btaken, 1); - } - dc->jmp = JMP_INDIRECT; - tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); - } -} - -static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t) -{ - /* Should be set to true if r1 is used by loadstores. */ - bool stackprot = false; - TCGv_i32 t32; - - /* All load/stores use ra. */ - if (dc->ra == 1 && dc->cpu->cfg.stackprot) { - stackprot = true; - } - - /* Treat the common cases first. */ - if (!dc->type_b) { - if (ea) { - int addr_size = dc->cpu->cfg.addr_size; - - if (addr_size == 32) { - tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]); - return; - } - - tcg_gen_concat_i32_i64(t, cpu_R[dc->rb], cpu_R[dc->ra]); - if (addr_size < 64) { - /* Mask off out of range bits. */ - tcg_gen_andi_i64(t, t, MAKE_64BIT_MASK(0, addr_size)); - } - return; - } - - /* If any of the regs is r0, set t to the value of the other reg. */ - if (dc->ra == 0) { - tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]); - return; - } else if (dc->rb == 0) { - tcg_gen_extu_i32_tl(t, cpu_R[dc->ra]); - return; - } - - if (dc->rb == 1 && dc->cpu->cfg.stackprot) { - stackprot = true; - } - - t32 = tcg_temp_new_i32(); - tcg_gen_add_i32(t32, cpu_R[dc->ra], cpu_R[dc->rb]); - tcg_gen_extu_i32_tl(t, t32); - tcg_temp_free_i32(t32); - - if (stackprot) { - gen_helper_stackprot(cpu_env, t); - } - return; - } - /* Immediate. */ - t32 = tcg_temp_new_i32(); - tcg_gen_addi_i32(t32, cpu_R[dc->ra], dec_alu_typeb_imm(dc)); - tcg_gen_extu_i32_tl(t, t32); - tcg_temp_free_i32(t32); - - if (stackprot) { - gen_helper_stackprot(cpu_env, t); - } - return; -} - -static void dec_load(DisasContext *dc) -{ - TCGv_i32 v; - TCGv addr; - unsigned int size; - bool rev = false, ex = false, ea = false; - int mem_index = dc->mem_index; - MemOp mop; - - mop = dc->opcode & 3; - size = 1 << mop; - if (!dc->type_b) { - ea = extract32(dc->ir, 7, 1); - rev = extract32(dc->ir, 9, 1); - ex = extract32(dc->ir, 10, 1); - } - mop |= MO_TE; - if (rev) { - mop ^= MO_BSWAP; - } - - if (trap_illegal(dc, size > 4)) { - return; - } - - if (trap_userspace(dc, ea)) { - return; - } - - t_sync_flags(dc); - addr = tcg_temp_new(); - compute_ldst_addr(dc, ea, addr); - /* Extended addressing bypasses the MMU. */ - mem_index = ea ? MMU_NOMMU_IDX : mem_index; - - /* - * When doing reverse accesses we need to do two things. - * - * 1. Reverse the address wrt endianness. - * 2. Byteswap the data lanes on the way back into the CPU core. - */ - if (rev && size != 4) { - /* Endian reverse the address. t is addr. */ - switch (size) { - case 1: - { - tcg_gen_xori_tl(addr, addr, 3); - break; - } - - case 2: - /* 00 -> 10 - 10 -> 00. */ - tcg_gen_xori_tl(addr, addr, 2); - break; - default: - cpu_abort(CPU(dc->cpu), "Invalid reverse size\n"); - break; - } - } - - /* lwx does not throw unaligned access errors, so force alignment */ - if (ex) { - tcg_gen_andi_tl(addr, addr, ~3); - } - - /* If we get a fault on a dslot, the jmpstate better be in sync. */ - sync_jmpstate(dc); - - /* Verify alignment if needed. */ - /* - * Microblaze gives MMU faults priority over faults due to - * unaligned addresses. That's why we speculatively do the load - * into v. If the load succeeds, we verify alignment of the - * address and if that succeeds we write into the destination reg. - */ - v = tcg_temp_new_i32(); - tcg_gen_qemu_ld_i32(v, addr, mem_index, mop); - - if (dc->cpu->cfg.unaligned_exceptions && size > 1) { - TCGv_i32 t0 = tcg_const_i32(0); - TCGv_i32 treg = tcg_const_i32(dc->rd); - TCGv_i32 tsize = tcg_const_i32(size - 1); - - tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); - gen_helper_memalign(cpu_env, addr, treg, t0, tsize); - - tcg_temp_free_i32(t0); - tcg_temp_free_i32(treg); - tcg_temp_free_i32(tsize); - } - - if (ex) { - tcg_gen_mov_tl(cpu_res_addr, addr); - tcg_gen_mov_i32(cpu_res_val, v); - } - if (dc->rd) { - tcg_gen_mov_i32(cpu_R[dc->rd], v); - } - tcg_temp_free_i32(v); - - if (ex) { /* lwx */ - /* no support for AXI exclusive so always clear C */ - tcg_gen_movi_i32(cpu_msr_c, 0); - } - - tcg_temp_free(addr); -} - -static void dec_store(DisasContext *dc) -{ - TCGv addr; - TCGLabel *swx_skip = NULL; - unsigned int size; - bool rev = false, ex = false, ea = false; - int mem_index = dc->mem_index; - MemOp mop; - - mop = dc->opcode & 3; - size = 1 << mop; - if (!dc->type_b) { - ea = extract32(dc->ir, 7, 1); - rev = extract32(dc->ir, 9, 1); - ex = extract32(dc->ir, 10, 1); - } - mop |= MO_TE; - if (rev) { - mop ^= MO_BSWAP; - } - - if (trap_illegal(dc, size > 4)) { - return; - } - - trap_userspace(dc, ea); - - t_sync_flags(dc); - /* If we get a fault on a dslot, the jmpstate better be in sync. */ - sync_jmpstate(dc); - /* SWX needs a temp_local. */ - addr = ex ? tcg_temp_local_new() : tcg_temp_new(); - compute_ldst_addr(dc, ea, addr); - /* Extended addressing bypasses the MMU. */ - mem_index = ea ? MMU_NOMMU_IDX : mem_index; - - if (ex) { /* swx */ - TCGv_i32 tval; - - /* swx does not throw unaligned access errors, so force alignment */ - tcg_gen_andi_tl(addr, addr, ~3); - - tcg_gen_movi_i32(cpu_msr_c, 1); - swx_skip = gen_new_label(); - tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_skip); - - /* - * Compare the value loaded at lwx with current contents of - * the reserved location. - */ - tval = tcg_temp_new_i32(); - - tcg_gen_atomic_cmpxchg_i32(tval, addr, cpu_res_val, - cpu_R[dc->rd], mem_index, - mop); - - tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_skip); - tcg_gen_movi_i32(cpu_msr_c, 0); - tcg_temp_free_i32(tval); - } - - if (rev && size != 4) { - /* Endian reverse the address. t is addr. */ - switch (size) { - case 1: - { - tcg_gen_xori_tl(addr, addr, 3); - break; - } - - case 2: - /* 00 -> 10 - 10 -> 00. */ - /* Force addr into the temp. */ - tcg_gen_xori_tl(addr, addr, 2); - break; - default: - cpu_abort(CPU(dc->cpu), "Invalid reverse size\n"); - break; - } - } - - if (!ex) { - tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop); - } - - /* Verify alignment if needed. */ - if (dc->cpu->cfg.unaligned_exceptions && size > 1) { - TCGv_i32 t1 = tcg_const_i32(1); - TCGv_i32 treg = tcg_const_i32(dc->rd); - TCGv_i32 tsize = tcg_const_i32(size - 1); - - tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); - /* FIXME: if the alignment is wrong, we should restore the value - * in memory. One possible way to achieve this is to probe - * the MMU prior to the memaccess, thay way we could put - * the alignment checks in between the probe and the mem - * access. - */ - gen_helper_memalign(cpu_env, addr, treg, t1, tsize); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(treg); - tcg_temp_free_i32(tsize); - } - - if (ex) { - gen_set_label(swx_skip); - } - - tcg_temp_free(addr); -} - static inline void eval_cc(DisasContext *dc, unsigned int cc, TCGv_i32 d, TCGv_i32 a) { @@ -1491,8 +1618,6 @@ static struct decoder_info { }; void (*dec)(DisasContext *dc); } decinfo[] = { - {DEC_LD, dec_load}, - {DEC_ST, dec_store}, {DEC_BR, dec_br}, {DEC_BCC, dec_bcc}, {DEC_RTS, dec_rts}, From 31f163d3da06f4f5e3cf1342b8970cf85e5a3b37 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Aug 2020 08:01:52 -0700 Subject: [PATCH 54/76] target/microblaze: Assert no overlap in flags making up tb_flags Create MSR_TB_MASK. Use it in cpu_get_tb_cpu_state, and check that IFLAGS_TB_MASK does not overlap. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 594501e4e7..2fc7cf26f1 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -261,8 +261,11 @@ struct CPUMBState { #define DRTE_FLAG (1 << 17) #define DRTB_FLAG (1 << 18) #define D_FLAG (1 << 19) /* Bit in ESR. */ + /* TB dependent CPUMBState. */ #define IFLAGS_TB_MASK (D_FLAG | IMM_FLAG | DRTI_FLAG | DRTE_FLAG | DRTB_FLAG) +#define MSR_TB_MASK (MSR_UM | MSR_VM | MSR_EE) + uint32_t iflags; #if !defined(CONFIG_USER_ONLY) @@ -372,12 +375,14 @@ typedef MicroBlazeCPU ArchCPU; #include "exec/cpu-all.h" +/* Ensure there is no overlap between the two masks. */ +QEMU_BUILD_BUG_ON(MSR_TB_MASK & IFLAGS_TB_MASK); + static inline void cpu_get_tb_cpu_state(CPUMBState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { *pc = env->pc; - *flags = (env->iflags & IFLAGS_TB_MASK) | - (env->msr & (MSR_UM | MSR_VM | MSR_EE)); + *flags = (env->iflags & IFLAGS_TB_MASK) | (env->msr & MSR_TB_MASK); *cs_base = (*flags & IMM_FLAG ? env->imm : 0); } From 7b34f45f9fe0c9fed16cfef74d0b39f890b87d4f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Aug 2020 08:08:19 -0700 Subject: [PATCH 55/76] target/microblaze: Move bimm to BIMM_FLAG It makes sense to keep BIMM with D_FLAG, as they can be written back to iflags at the same time. BIMM_FLAG does not need to be added to IFLAGS_TB_MASK because it does not affect the next TB, only the exception path out of the current TB. Renumber IMM_FLAG, as the value 4 holds no particular significance; pack these two flags at the bottom of the bitfield. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 4 ++-- target/microblaze/helper.c | 2 +- target/microblaze/translate.c | 12 +++++------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 2fc7cf26f1..a5df1fa28f 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -231,7 +231,6 @@ typedef struct CPUMBState CPUMBState; struct CPUMBState { uint32_t btaken; uint32_t btarget; - uint32_t bimm; uint32_t imm; uint32_t regs[32]; @@ -253,7 +252,8 @@ struct CPUMBState { uint32_t res_val; /* Internal flags. */ -#define IMM_FLAG 4 +#define IMM_FLAG (1 << 0) +#define BIMM_FLAG (1 << 1) /* MSR_EE (1 << 8) */ /* MSR_UM (1 << 11) */ /* MSR_VM (1 << 13) */ diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index f8e2ca12a9..06f4322e09 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -166,7 +166,7 @@ void mb_cpu_do_interrupt(CPUState *cs) /* Reexecute the branch. */ env->regs[17] -= 4; /* was the branch immprefixed?. */ - if (env->bimm) { + if (env->iflags & BIMM_FLAG) { env->regs[17] -= 4; log_cpu_state_mask(CPU_LOG_INT, cs, 0); } diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index d2baa7db0e..97a436c8d5 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1351,13 +1351,11 @@ static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false) static void dec_setup_dslot(DisasContext *dc) { - TCGv_i32 tmp = tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG)); - - dc->delayed_branch = 2; - dc->tb_flags |= D_FLAG; - - tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, bimm)); - tcg_temp_free_i32(tmp); + dc->delayed_branch = 2; + dc->tb_flags |= D_FLAG; + if (dc->type_b && (dc->tb_flags & IMM_FLAG)) { + dc->tb_flags |= BIMM_FLAG; + } } static void dec_bcc(DisasContext *dc) From 5318223d271865229c85e2cd2d32684b005c1d01 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 27 Aug 2020 15:01:30 -0700 Subject: [PATCH 56/76] target/microblaze: Fix no-op mb_cpu_transaction_failed Do not call cpu_restore_state when no exception will be delivered. This can lead to inconsistent cpu state. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Reported-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/op_helper.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index a99c467364..e6dcc79243 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -419,32 +419,33 @@ void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, int mmu_idx, MemTxAttrs attrs, MemTxResult response, uintptr_t retaddr) { - MicroBlazeCPU *cpu; - CPUMBState *env; + MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); + CPUMBState *env = &cpu->env; + qemu_log_mask(CPU_LOG_INT, "Transaction failed: vaddr 0x%" VADDR_PRIx " physaddr 0x" TARGET_FMT_plx " size %d access type %s\n", addr, physaddr, size, access_type == MMU_INST_FETCH ? "INST_FETCH" : (access_type == MMU_DATA_LOAD ? "DATA_LOAD" : "DATA_STORE")); - cpu = MICROBLAZE_CPU(cs); - env = &cpu->env; - cpu_restore_state(cs, retaddr, true); if (!(env->msr & MSR_EE)) { return; } - env->ear = addr; if (access_type == MMU_INST_FETCH) { - if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) { - env->esr = ESR_EC_INSN_BUS; - helper_raise_exception(env, EXCP_HW_EXCP); + if (!cpu->cfg.iopb_bus_exception) { + return; } + env->esr = ESR_EC_INSN_BUS; } else { - if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) { - env->esr = ESR_EC_DATA_BUS; - helper_raise_exception(env, EXCP_HW_EXCP); + if (!cpu->cfg.dopb_bus_exception) { + return; } + env->esr = ESR_EC_DATA_BUS; } + + env->ear = addr; + cs->exception_index = EXCP_HW_EXCP; + cpu_loop_exit_restore(cs, retaddr); } #endif From 683a247ed7a4993464e995106c20acbe237bdbfc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Aug 2020 08:44:20 -0700 Subject: [PATCH 57/76] target/microblaze: Store "current" iflags in insn_start This data is available during exception unwinding, thus we can restore it from there directly, rather than saving it during the TB. Thus we may remove the t_sync_flags() calls in the load/store operations. Note that these calls were missing from the other places where runtime exceptions may be raised, such as idiv and the floating point operations. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 2 ++ target/microblaze/translate.c | 24 +++++++++++++----------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index a5df1fa28f..83fadd36a5 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -228,6 +228,8 @@ typedef struct CPUMBState CPUMBState; #define STREAM_CONTROL (1 << 3) #define STREAM_NONBLOCK (1 << 4) +#define TARGET_INSN_START_EXTRA_WORDS 1 + struct CPUMBState { uint32_t btaken; uint32_t btarget; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 97a436c8d5..d2ee163294 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -58,6 +58,9 @@ typedef struct DisasContext { DisasContextBase base; MicroBlazeCPU *cpu; + /* TCG op of the current insn_start. */ + TCGOp *insn_start; + TCGv_i32 r0; bool r0_set; @@ -71,7 +74,7 @@ typedef struct DisasContext { unsigned int cpustate_changed; unsigned int delayed_branch; - unsigned int tb_flags, synced_flags; /* tb dependent flags. */ + unsigned int tb_flags; unsigned int clear_imm; int mem_index; @@ -96,12 +99,11 @@ static int typeb_imm(DisasContext *dc, int x) /* Include the auto-generated decoder. */ #include "decode-insns.c.inc" -static inline void t_sync_flags(DisasContext *dc) +static void t_sync_flags(DisasContext *dc) { /* Synch the tb dependent flags between translator and runtime. */ - if (dc->tb_flags != dc->synced_flags) { - tcg_gen_movi_i32(cpu_iflags, dc->tb_flags); - dc->synced_flags = dc->tb_flags; + if ((dc->tb_flags ^ dc->base.tb->flags) & ~MSR_TB_MASK) { + tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & ~MSR_TB_MASK); } } @@ -770,7 +772,6 @@ static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, } } - t_sync_flags(dc); sync_jmpstate(dc); /* @@ -893,7 +894,6 @@ static bool trans_lwx(DisasContext *dc, arg_typea *arg) /* lwx does not throw unaligned access errors, so force alignment */ tcg_gen_andi_tl(addr, addr, ~3); - t_sync_flags(dc); sync_jmpstate(dc); tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL); @@ -929,7 +929,6 @@ static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop, } } - t_sync_flags(dc); sync_jmpstate(dc); tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop); @@ -1046,7 +1045,6 @@ static bool trans_swx(DisasContext *dc, arg_typea *arg) TCGLabel *swx_fail = gen_new_label(); TCGv_i32 tval; - t_sync_flags(dc); sync_jmpstate(dc); /* swx does not throw unaligned access errors, so force alignment */ @@ -1655,7 +1653,7 @@ static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) int bound; dc->cpu = cpu; - dc->synced_flags = dc->tb_flags = dc->base.tb->flags; + dc->tb_flags = dc->base.tb->flags; dc->delayed_branch = !!(dc->tb_flags & D_FLAG); dc->jmp = dc->delayed_branch ? JMP_INDIRECT : JMP_NOJMP; dc->cpustate_changed = 0; @@ -1675,7 +1673,10 @@ static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) { - tcg_gen_insn_start(dcb->pc_next); + DisasContext *dc = container_of(dcb, DisasContext, base); + + tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK); + dc->insn_start = tcg_last_op(); } static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs, @@ -1917,4 +1918,5 @@ void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, target_ulong *data) { env->pc = data[0]; + env->iflags = data[1]; } From 2271a6ac0a075d859b71551626e3cae9817ba7da Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Aug 2020 19:27:53 -0700 Subject: [PATCH 58/76] tcg: Add tcg_get_insn_start_param MicroBlaze will shortly need to update a parameter in place. Add an interface to read to match that for write. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- include/tcg/tcg.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index d40c925d04..53ce94c2c5 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -777,11 +777,26 @@ static inline TCGv_i32 TCGV_HIGH(TCGv_i64 t) } #endif +static inline TCGArg tcg_get_insn_param(TCGOp *op, int arg) +{ + return op->args[arg]; +} + static inline void tcg_set_insn_param(TCGOp *op, int arg, TCGArg v) { op->args[arg] = v; } +static inline target_ulong tcg_get_insn_start_param(TCGOp *op, int arg) +{ +#if TARGET_LONG_BITS <= TCG_TARGET_REG_BITS + return tcg_get_insn_param(op, arg); +#else + return tcg_get_insn_param(op, arg * 2) | + ((uint64_t)tcg_get_insn_param(op, arg * 2 + 1) << 32); +#endif +} + static inline void tcg_set_insn_start_param(TCGOp *op, int arg, target_ulong v) { #if TARGET_LONG_BITS <= TCG_TARGET_REG_BITS From ab0c8d0f5b3377eba2c14116e199573583ea0089 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Aug 2020 20:29:01 -0700 Subject: [PATCH 59/76] target/microblaze: Use cc->do_unaligned_access This fixes the problem in which unaligned stores succeeded, but then we raised the exception after modifying memory. Store the ESS for the unaligned data access in the iflags for the insn, so that it can be found during unwind. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.c | 1 + target/microblaze/cpu.h | 10 ++++- target/microblaze/helper.c | 28 ++++++++++++++ target/microblaze/helper.h | 1 - target/microblaze/op_helper.c | 21 ---------- target/microblaze/translate.c | 72 +++++++++++++---------------------- 6 files changed, 64 insertions(+), 69 deletions(-) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 1eabf5cc3f..67017ecc33 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -317,6 +317,7 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data) cc->class_by_name = mb_cpu_class_by_name; cc->has_work = mb_cpu_has_work; cc->do_interrupt = mb_cpu_do_interrupt; + cc->do_unaligned_access = mb_cpu_do_unaligned_access; cc->cpu_exec_interrupt = mb_cpu_exec_interrupt; cc->dump_state = mb_cpu_dump_state; cc->set_pc = mb_cpu_set_pc; diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 83fadd36a5..63b8d93d41 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -79,10 +79,13 @@ typedef struct CPUMBState CPUMBState; /* Exception State Register (ESR) Fields */ #define ESR_DIZ (1<<11) /* Zone Protection */ +#define ESR_W (1<<11) /* Unaligned word access */ #define ESR_S (1<<10) /* Store instruction */ #define ESR_ESS_FSL_OFFSET 5 +#define ESR_ESS_MASK (0x7f << 5) + #define ESR_EC_FSL 0 #define ESR_EC_UNALIGNED_DATA 1 #define ESR_EC_ILLEGAL_OP 2 @@ -256,9 +259,11 @@ struct CPUMBState { /* Internal flags. */ #define IMM_FLAG (1 << 0) #define BIMM_FLAG (1 << 1) -/* MSR_EE (1 << 8) */ +#define ESR_ESS_FLAG (1 << 2) /* indicates ESR_ESS_MASK is present */ +/* MSR_EE (1 << 8) -- these 3 are not in iflags but tb_flags */ /* MSR_UM (1 << 11) */ /* MSR_VM (1 << 13) */ +/* ESR_ESS_MASK [11:5] -- unwind into iflags for unaligned excp */ #define DRTI_FLAG (1 << 16) #define DRTE_FLAG (1 << 17) #define DRTB_FLAG (1 << 18) @@ -330,6 +335,9 @@ struct MicroBlazeCPU { void mb_cpu_do_interrupt(CPUState *cs); bool mb_cpu_exec_interrupt(CPUState *cs, int int_req); +void mb_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, + MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr); void mb_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int mb_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index 06f4322e09..0e3be251a7 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -296,3 +296,31 @@ bool mb_cpu_exec_interrupt(CPUState *cs, int interrupt_request) } return false; } + +void mb_cpu_do_unaligned_access(CPUState *cs, vaddr addr, + MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr) +{ + MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); + uint32_t esr, iflags; + + /* Recover the pc and iflags from the corresponding insn_start. */ + cpu_restore_state(cs, retaddr, true); + iflags = cpu->env.iflags; + + qemu_log_mask(CPU_LOG_INT, + "Unaligned access addr=" TARGET_FMT_lx + " pc=%x iflags=%x\n", addr, cpu->env.pc, iflags); + + esr = ESR_EC_UNALIGNED_DATA; + if (likely(iflags & ESR_ESS_FLAG)) { + esr |= iflags & ESR_ESS_MASK; + } else { + qemu_log_mask(LOG_UNIMP, "Unaligned access without ESR_ESS_FLAG\n"); + } + + cpu->env.ear = addr; + cpu->env.esr = esr; + cs->exception_index = EXCP_HW_EXCP; + cpu_loop_exit(cs); +} diff --git a/target/microblaze/helper.h b/target/microblaze/helper.h index a473c1867b..3980fba797 100644 --- a/target/microblaze/helper.h +++ b/target/microblaze/helper.h @@ -25,7 +25,6 @@ DEF_HELPER_3(mmu_read, i32, env, i32, i32) DEF_HELPER_4(mmu_write, void, env, i32, i32, i32) #endif -DEF_HELPER_5(memalign, void, env, tl, i32, i32, i32) DEF_HELPER_FLAGS_2(stackprot, TCG_CALL_NO_WG, void, env, tl) DEF_HELPER_2(get, i32, i32, i32) diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index e6dcc79243..4614e99db3 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -365,27 +365,6 @@ uint32_t helper_pcmpbf(uint32_t a, uint32_t b) return 0; } -void helper_memalign(CPUMBState *env, target_ulong addr, - uint32_t dr, uint32_t wr, - uint32_t mask) -{ - if (addr & mask) { - qemu_log_mask(CPU_LOG_INT, - "unaligned access addr=" TARGET_FMT_lx - " mask=%x, wr=%d dr=r%d\n", - addr, mask, wr, dr); - env->ear = addr; - env->esr = ESR_EC_UNALIGNED_DATA | (wr << 10) | (dr & 31) << 5; - if (mask == 3) { - env->esr |= 1 << 11; - } - if (!(env->msr & MSR_EE)) { - return; - } - helper_raise_exception(env, EXCP_HW_EXCP); - } -} - void helper_stackprot(CPUMBState *env, target_ulong addr) { if (addr < env->slr || addr > env->shr) { diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index d2ee163294..597b96ffb3 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -751,10 +751,22 @@ static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) return ret; } +static void record_unaligned_ess(DisasContext *dc, int rd, + MemOp size, bool store) +{ + uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1); + + iflags |= ESR_ESS_FLAG; + iflags |= rd << 5; + iflags |= store * ESR_S; + iflags |= (size == MO_32) * ESR_W; + + tcg_set_insn_start_param(dc->insn_start, 1, iflags); +} + static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, int mem_index, bool rev) { - TCGv_i32 v; MemOp size = mop & MO_SIZE; /* @@ -774,34 +786,15 @@ static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, sync_jmpstate(dc); - /* - * Microblaze gives MMU faults priority over faults due to - * unaligned addresses. That's why we speculatively do the load - * into v. If the load succeeds, we verify alignment of the - * address and if that succeeds we write into the destination reg. - */ - v = tcg_temp_new_i32(); - tcg_gen_qemu_ld_i32(v, addr, mem_index, mop); - - /* TODO: Convert to CPUClass::do_unaligned_access. */ - if (dc->cpu->cfg.unaligned_exceptions && size > MO_8) { - TCGv_i32 t0 = tcg_const_i32(0); - TCGv_i32 treg = tcg_const_i32(rd); - TCGv_i32 tsize = tcg_const_i32((1 << size) - 1); - - tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); - gen_helper_memalign(cpu_env, addr, treg, t0, tsize); - - tcg_temp_free_i32(t0); - tcg_temp_free_i32(treg); - tcg_temp_free_i32(tsize); + if (size > MO_8 && + (dc->tb_flags & MSR_EE) && + dc->cpu->cfg.unaligned_exceptions) { + record_unaligned_ess(dc, rd, size, false); + mop |= MO_ALIGN; } - if (rd) { - tcg_gen_mov_i32(cpu_R[rd], v); - } + tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop); - tcg_temp_free_i32(v); tcg_temp_free(addr); return true; } @@ -931,28 +924,15 @@ static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop, sync_jmpstate(dc); - tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop); - - /* TODO: Convert to CPUClass::do_unaligned_access. */ - if (dc->cpu->cfg.unaligned_exceptions && size > MO_8) { - TCGv_i32 t1 = tcg_const_i32(1); - TCGv_i32 treg = tcg_const_i32(rd); - TCGv_i32 tsize = tcg_const_i32((1 << size) - 1); - - tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); - /* FIXME: if the alignment is wrong, we should restore the value - * in memory. One possible way to achieve this is to probe - * the MMU prior to the memaccess, thay way we could put - * the alignment checks in between the probe and the mem - * access. - */ - gen_helper_memalign(cpu_env, addr, treg, t1, tsize); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(treg); - tcg_temp_free_i32(tsize); + if (size > MO_8 && + (dc->tb_flags & MSR_EE) && + dc->cpu->cfg.unaligned_exceptions) { + record_unaligned_ess(dc, rd, size, true); + mop |= MO_ALIGN; } + tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop); + tcg_temp_free(addr); return true; } From 6f9642d7d799c4774e9e04f95679d370d52633c6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 22 Aug 2020 07:57:03 -0700 Subject: [PATCH 60/76] target/microblaze: Replace clear_imm with tb_flags_to_set This more general update variable will be able to handle delay slots as well. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 597b96ffb3..c0b586f467 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -75,7 +75,7 @@ typedef struct DisasContext { unsigned int cpustate_changed; unsigned int delayed_branch; unsigned int tb_flags; - unsigned int clear_imm; + unsigned int tb_flags_to_set; int mem_index; #define JMP_NOJMP 0 @@ -535,8 +535,7 @@ static bool trans_imm(DisasContext *dc, arg_imm *arg) { dc->ext_imm = arg->imm << 16; tcg_gen_movi_i32(cpu_imm, dc->ext_imm); - dc->tb_flags |= IMM_FLAG; - dc->clear_imm = 0; + dc->tb_flags_to_set = IMM_FLAG; return true; } @@ -1688,7 +1687,8 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) (uint32_t)dc->base.pc_next); } - dc->clear_imm = 1; + dc->tb_flags_to_set = 0; + ir = cpu_ldl_code(env, dc->base.pc_next); if (!decode(dc, ir)) { old_decode(dc, ir); @@ -1700,10 +1700,13 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) dc->r0_set = false; } - if (dc->clear_imm && (dc->tb_flags & IMM_FLAG)) { - dc->tb_flags &= ~IMM_FLAG; + /* Discard the imm global when its contents cannot be used. */ + if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) { tcg_gen_discard_i32(cpu_imm); } + + dc->tb_flags &= ~IMM_FLAG; + dc->tb_flags |= dc->tb_flags_to_set; dc->base.pc_next += 4; if (dc->delayed_branch && --dc->delayed_branch == 0) { From 1e521ce3b095ca9e324912cbd05391f00d37560a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 22 Aug 2020 08:25:39 -0700 Subject: [PATCH 61/76] target/microblaze: Replace delayed_branch with tb_flags_to_set The multi-stage counter can be replaced by clearing D_FLAG, the or'ing in tb_flags_to_set. The jump then happens when D_FLAG is finally cleared. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index c0b586f467..811c92d23b 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -73,7 +73,6 @@ typedef struct DisasContext { uint16_t imm; unsigned int cpustate_changed; - unsigned int delayed_branch; unsigned int tb_flags; unsigned int tb_flags_to_set; int mem_index; @@ -1328,10 +1327,9 @@ static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false) static void dec_setup_dslot(DisasContext *dc) { - dc->delayed_branch = 2; - dc->tb_flags |= D_FLAG; + dc->tb_flags_to_set |= D_FLAG; if (dc->type_b && (dc->tb_flags & IMM_FLAG)) { - dc->tb_flags |= BIMM_FLAG; + dc->tb_flags_to_set |= BIMM_FLAG; } } @@ -1343,7 +1341,6 @@ static void dec_bcc(DisasContext *dc) cc = EXTRACT_FIELD(dc->ir, 21, 23); dslot = dc->ir & (1 << 25); - dc->delayed_branch = 1; if (dslot) { dec_setup_dslot(dc); } @@ -1419,7 +1416,6 @@ static void dec_br(DisasContext *dc) } } - dc->delayed_branch = 1; if (dslot) { dec_setup_dslot(dc); } @@ -1633,8 +1629,7 @@ static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) dc->cpu = cpu; dc->tb_flags = dc->base.tb->flags; - dc->delayed_branch = !!(dc->tb_flags & D_FLAG); - dc->jmp = dc->delayed_branch ? JMP_INDIRECT : JMP_NOJMP; + dc->jmp = dc->tb_flags & D_FLAG ? JMP_INDIRECT : JMP_NOJMP; dc->cpustate_changed = 0; dc->abort_at_next_insn = 0; dc->ext_imm = dc->base.tb->cs_base; @@ -1705,11 +1700,11 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) tcg_gen_discard_i32(cpu_imm); } - dc->tb_flags &= ~IMM_FLAG; + dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG); dc->tb_flags |= dc->tb_flags_to_set; dc->base.pc_next += 4; - if (dc->delayed_branch && --dc->delayed_branch == 0) { + if (dc->jmp != JMP_NOJMP && !(dc->tb_flags & D_FLAG)) { if (dc->tb_flags & DRTI_FLAG) { do_rti(dc); } @@ -1719,8 +1714,6 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) if (dc->tb_flags & DRTE_FLAG) { do_rte(dc); } - /* Clear the delay slot flag. */ - dc->tb_flags &= ~D_FLAG; dc->base.is_jmp = DISAS_JUMP; } From 0c3da918de2ef8b1758d5e11b1c18c4f734c4401 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 22 Aug 2020 16:14:46 -0700 Subject: [PATCH 62/76] target/microblaze: Tidy mb_cpu_dump_state Using lookup_symbol is quite slow; remove that. Decode the various bits of iflags; only show imm, btaken, btarget when they are relevant to iflags. Improve formatting. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 67 +++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 811c92d23b..3b63fd79e5 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1818,41 +1818,56 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); CPUMBState *env = &cpu->env; + uint32_t iflags; int i; - if (!env) { - return; - } - - qemu_fprintf(f, "IN: PC=%x %s\n", - env->pc, lookup_symbol(env->pc)); - qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " " - "imm=%x iflags=%x fsr=%x rbtr=%x\n", - env->msr, env->esr, env->ear, - env->imm, env->iflags, env->fsr, env->btr); - qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", - env->btaken, env->btarget, + qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n", + env->pc, env->msr, (env->msr & MSR_UM) ? "user" : "kernel", (env->msr & MSR_UMS) ? "user" : "kernel", (bool)(env->msr & MSR_EIP), (bool)(env->msr & MSR_IE)); - for (i = 0; i < 12; i++) { - qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]); - if ((i + 1) % 4 == 0) { - qemu_fprintf(f, "\n"); - } + + iflags = env->iflags; + qemu_fprintf(f, "iflags: 0x%08x", iflags); + if (iflags & IMM_FLAG) { + qemu_fprintf(f, " IMM(0x%08x)", env->imm); + } + if (iflags & BIMM_FLAG) { + qemu_fprintf(f, " BIMM"); + } + if (iflags & D_FLAG) { + qemu_fprintf(f, " D(btaken=%d btarget=0x%08x)", + env->btaken, env->btarget); + } + if (iflags & DRTI_FLAG) { + qemu_fprintf(f, " DRTI"); + } + if (iflags & DRTE_FLAG) { + qemu_fprintf(f, " DRTE"); + } + if (iflags & DRTB_FLAG) { + qemu_fprintf(f, " DRTB"); + } + if (iflags & ESR_ESS_FLAG) { + qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK); + } + + qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n" + "ear=0x%016" PRIx64 " slr=0x%x shr=0x%x\n", + env->esr, env->fsr, env->btr, env->edr, + env->ear, env->slr, env->shr); + + for (i = 0; i < 12; i++) { + qemu_fprintf(f, "rpvr%-2d=%08x%c", + i, env->pvr.regs[i], i % 4 == 3 ? '\n' : ' '); } - /* Registers that aren't modeled are reported as 0 */ - qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 " - "rtlblo=0 rtlbhi=0\n", env->edr); - qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr); for (i = 0; i < 32; i++) { - qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); - if ((i + 1) % 4 == 0) - qemu_fprintf(f, "\n"); - } - qemu_fprintf(f, "\n\n"); + qemu_fprintf(f, "r%2.2d=%08x%c", + i, env->regs[i], i % 4 == 3 ? '\n' : ' '); + } + qemu_fprintf(f, "\n"); } void mb_tcg_init(void) From f523531471c9342020cda0ef5a2eccb7d77e7e34 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 23 Aug 2020 09:17:22 -0700 Subject: [PATCH 63/76] 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 Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- linux-user/microblaze/cpu_loop.c | 2 +- target/microblaze/cpu.h | 2 +- target/microblaze/helper.c | 10 +-- target/microblaze/insns.decode | 11 ++++ target/microblaze/translate.c | 107 ++++++++++++++++++------------- 5 files changed, 79 insertions(+), 53 deletions(-) diff --git a/linux-user/microblaze/cpu_loop.c b/linux-user/microblaze/cpu_loop.c index 3de99ea311..c3396a6e09 100644 --- a/linux-user/microblaze/cpu_loop.c +++ b/linux-user/microblaze/cpu_loop.c @@ -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]; 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); } From ee8c7f9f9ab0c06b26e22d869cc12893e0c73bce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 23 Aug 2020 09:38:15 -0700 Subject: [PATCH 64/76] target/microblaze: Convert mbar to decodetree Split this out of the normal branch instructions, as it requires special handling. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 2 + target/microblaze/translate.c | 85 +++++++++++++++++++--------------- 2 files changed, 49 insertions(+), 38 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index 9273a51d20..8eba47d90c 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -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 diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 1c772b95d9..832cf85c64 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -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); } From b9c58aabe62381fe736b6b4f9132986b90aa11cb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Aug 2020 09:58:14 -0700 Subject: [PATCH 65/76] target/microblaze: Reorganize branching Remove the btaken variable, and simplify things by always computing the full branch destination into btarget. This avoids all need for sync_jmpstate(). Retain the direct branch behaviour by remembering the jump destination in jmp_dest, discarding btarget. In the normal case, where the branch delay slot cannot trap (e.g. arithmetic), tcg will remove the computation into btarget, leaving us with just the tcg direct branching at the end. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 4 +- target/microblaze/translate.c | 192 ++++++++++++++-------------------- 2 files changed, 79 insertions(+), 117 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 1528749a0b..4298f242a6 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -234,8 +234,8 @@ typedef struct CPUMBState CPUMBState; #define TARGET_INSN_START_EXTRA_WORDS 1 struct CPUMBState { - uint32_t btaken; - uint32_t btarget; + uint32_t bvalue; /* TCG temporary, only valid during a TB */ + uint32_t btarget; /* Full resolved branch destination */ uint32_t imm; uint32_t regs[32]; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 832cf85c64..1545974669 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -45,7 +45,7 @@ static TCGv_i32 cpu_pc; static TCGv_i32 cpu_msr; static TCGv_i32 cpu_msr_c; static TCGv_i32 cpu_imm; -static TCGv_i32 cpu_btaken; +static TCGv_i32 cpu_bvalue; static TCGv_i32 cpu_btarget; static TCGv_i32 cpu_iflags; static TCGv cpu_res_addr; @@ -77,12 +77,11 @@ typedef struct DisasContext { unsigned int tb_flags_to_set; int mem_index; -#define JMP_NOJMP 0 -#define JMP_DIRECT 1 -#define JMP_DIRECT_CC 2 -#define JMP_INDIRECT 3 - unsigned int jmp; - uint32_t jmp_pc; + /* Condition under which to jump, including NEVER and ALWAYS. */ + TCGCond jmp_cond; + + /* Immediate branch-taken destination, or -1 for indirect. */ + uint32_t jmp_dest; int abort_at_next_insn; } DisasContext; @@ -106,17 +105,6 @@ static void t_sync_flags(DisasContext *dc) } } -static inline void sync_jmpstate(DisasContext *dc) -{ - if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { - if (dc->jmp == JMP_DIRECT) { - tcg_gen_movi_i32(cpu_btaken, 1); - } - dc->jmp = JMP_INDIRECT; - tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); - } -} - static void gen_raise_exception(DisasContext *dc, uint32_t index) { TCGv_i32 tmp = tcg_const_i32(index); @@ -782,8 +770,6 @@ static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, } } - sync_jmpstate(dc); - if (size > MO_8 && (dc->tb_flags & MSR_EE) && dc->cpu->cfg.unaligned_exceptions) { @@ -885,8 +871,6 @@ static bool trans_lwx(DisasContext *dc, arg_typea *arg) /* lwx does not throw unaligned access errors, so force alignment */ tcg_gen_andi_tl(addr, addr, ~3); - sync_jmpstate(dc); - tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL); tcg_gen_mov_tl(cpu_res_addr, addr); tcg_temp_free(addr); @@ -920,8 +904,6 @@ static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop, } } - sync_jmpstate(dc); - if (size > MO_8 && (dc->tb_flags & MSR_EE) && dc->cpu->cfg.unaligned_exceptions) { @@ -1023,8 +1005,6 @@ static bool trans_swx(DisasContext *dc, arg_typea *arg) TCGLabel *swx_fail = gen_new_label(); TCGv_i32 tval; - sync_jmpstate(dc); - /* swx does not throw unaligned access errors, so force alignment */ tcg_gen_andi_tl(addr, addr, ~3); @@ -1392,44 +1372,6 @@ static void dec_msr(DisasContext *dc) } } -static inline void eval_cc(DisasContext *dc, unsigned int cc, - TCGv_i32 d, TCGv_i32 a) -{ - static const int mb_to_tcg_cc[] = { - [CC_EQ] = TCG_COND_EQ, - [CC_NE] = TCG_COND_NE, - [CC_LT] = TCG_COND_LT, - [CC_LE] = TCG_COND_LE, - [CC_GE] = TCG_COND_GE, - [CC_GT] = TCG_COND_GT, - }; - - switch (cc) { - case CC_EQ: - case CC_NE: - case CC_LT: - case CC_LE: - case CC_GE: - case CC_GT: - tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0); - break; - default: - cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc); - break; - } -} - -static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false) -{ - TCGv_i32 zero = tcg_const_i32(0); - - tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc, - cpu_btaken, zero, - pc_true, pc_false); - - tcg_temp_free_i32(zero); -} - static void dec_setup_dslot(DisasContext *dc) { dc->tb_flags_to_set |= D_FLAG; @@ -1440,8 +1382,17 @@ static void dec_setup_dslot(DisasContext *dc) static void dec_bcc(DisasContext *dc) { + static const TCGCond mb_to_tcg_cc[] = { + [CC_EQ] = TCG_COND_EQ, + [CC_NE] = TCG_COND_NE, + [CC_LT] = TCG_COND_LT, + [CC_LE] = TCG_COND_LE, + [CC_GE] = TCG_COND_GE, + [CC_GT] = TCG_COND_GT, + }; unsigned int cc; unsigned int dslot; + TCGv_i32 zero, next; cc = EXTRACT_FIELD(dc->ir, 21, 23); dslot = dc->ir & (1 << 25); @@ -1450,15 +1401,29 @@ static void dec_bcc(DisasContext *dc) dec_setup_dslot(dc); } + dc->jmp_cond = mb_to_tcg_cc[cc]; + + /* Cache the condition register in cpu_bvalue across any delay slot. */ + tcg_gen_mov_i32(cpu_bvalue, cpu_R[dc->ra]); + + /* Store the branch taken destination into btarget. */ if (dc->type_b) { - dc->jmp = JMP_DIRECT_CC; - dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); - tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); + dc->jmp_dest = dc->base.pc_next + dec_alu_typeb_imm(dc); + tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); } else { - dc->jmp = JMP_INDIRECT; - tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); + dc->jmp_dest = -1; + tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, dc->rb), + dc->base.pc_next); } - eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]); + + /* Compute the final destination into btarget. */ + zero = tcg_const_i32(0); + next = tcg_const_i32(dc->base.pc_next + (dslot + 1) * 4); + tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget, + reg_for_read(dc, dc->ra), zero, + cpu_btarget, next); + tcg_temp_free_i32(zero); + tcg_temp_free_i32(next); } static void dec_br(DisasContext *dc) @@ -1479,14 +1444,13 @@ static void dec_br(DisasContext *dc) add_pc = abs ? 0 : dc->base.pc_next; if (dc->type_b) { - dc->jmp = JMP_DIRECT; - dc->jmp_pc = add_pc + dec_alu_typeb_imm(dc); - tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); + dc->jmp_dest = add_pc + dec_alu_typeb_imm(dc); + tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); } else { - dc->jmp = JMP_INDIRECT; + dc->jmp_dest = -1; tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], add_pc); } - tcg_gen_movi_i32(cpu_btaken, 1); + dc->jmp_cond = TCG_COND_ALWAYS; } static inline void do_rti(DisasContext *dc) @@ -1567,8 +1531,8 @@ static void dec_rts(DisasContext *dc) dc->tb_flags |= DRTE_FLAG; } - dc->jmp = JMP_INDIRECT; - tcg_gen_movi_i32(cpu_btaken, 1); + dc->jmp_cond = TCG_COND_ALWAYS; + dc->jmp_dest = -1; tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc)); } @@ -1659,13 +1623,14 @@ static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) dc->cpu = cpu; dc->tb_flags = dc->base.tb->flags; - dc->jmp = dc->tb_flags & D_FLAG ? JMP_INDIRECT : JMP_NOJMP; dc->cpustate_changed = 0; dc->abort_at_next_insn = 0; dc->ext_imm = dc->base.tb->cs_base; dc->r0 = NULL; dc->r0_set = false; dc->mem_index = cpu_mmu_index(&cpu->env, false); + dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER; + dc->jmp_dest = -1; bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; dc->base.max_insns = MIN(dc->base.max_insns, bound); @@ -1734,14 +1699,12 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) dc->tb_flags |= dc->tb_flags_to_set; dc->base.pc_next += 4; - if (dc->jmp != JMP_NOJMP && !(dc->tb_flags & D_FLAG)) { + if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) { if (dc->tb_flags & DRTI_FLAG) { do_rti(dc); - } - if (dc->tb_flags & DRTB_FLAG) { + } else if (dc->tb_flags & DRTB_FLAG) { do_rtb(dc); - } - if (dc->tb_flags & DRTE_FLAG) { + } else if (dc->tb_flags & DRTE_FLAG) { do_rte(dc); } dc->base.is_jmp = DISAS_JUMP; @@ -1766,19 +1729,13 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) } t_sync_flags(dc); - if (dc->tb_flags & D_FLAG) { - sync_jmpstate(dc); - dc->jmp = JMP_NOJMP; - } switch (dc->base.is_jmp) { case DISAS_TOO_MANY: - assert(dc->jmp == JMP_NOJMP); gen_goto_tb(dc, 0, dc->base.pc_next); return; case DISAS_UPDATE: - assert(dc->jmp == JMP_NOJMP); if (unlikely(cs->singlestep_enabled)) { gen_raise_exception(dc, EXCP_DEBUG); } else { @@ -1787,35 +1744,41 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) return; case DISAS_JUMP: - switch (dc->jmp) { - case JMP_INDIRECT: - { - TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next); - eval_cond_jmp(dc, cpu_btarget, tmp_pc); - tcg_temp_free_i32(tmp_pc); + if (dc->jmp_dest != -1 && !cs->singlestep_enabled) { + /* Direct jump. */ + tcg_gen_discard_i32(cpu_btarget); - if (unlikely(cs->singlestep_enabled)) { - gen_raise_exception(dc, EXCP_DEBUG); - } else { - tcg_gen_exit_tb(NULL, 0); - } - } - return; + if (dc->jmp_cond != TCG_COND_ALWAYS) { + /* Conditional direct jump. */ + TCGLabel *taken = gen_new_label(); + TCGv_i32 tmp = tcg_temp_new_i32(); - case JMP_DIRECT_CC: - { - TCGLabel *l1 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1); + /* + * Copy bvalue to a temp now, so we can discard bvalue. + * This can avoid writing bvalue to memory when the + * delay slot cannot raise an exception. + */ + tcg_gen_mov_i32(tmp, cpu_bvalue); + tcg_gen_discard_i32(cpu_bvalue); + + tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken); gen_goto_tb(dc, 1, dc->base.pc_next); - gen_set_label(l1); + gen_set_label(taken); } - /* fall through */ - - case JMP_DIRECT: - gen_goto_tb(dc, 0, dc->jmp_pc); + gen_goto_tb(dc, 0, dc->jmp_dest); return; } - /* fall through */ + + /* Indirect jump (or direct jump w/ singlestep) */ + tcg_gen_mov_i32(cpu_pc, cpu_btarget); + tcg_gen_discard_i32(cpu_btarget); + + if (unlikely(cs->singlestep_enabled)) { + gen_raise_exception(dc, EXCP_DEBUG); + } else { + tcg_gen_exit_tb(NULL, 0); + } + return; default: g_assert_not_reached(); @@ -1867,8 +1830,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, " BIMM"); } if (iflags & D_FLAG) { - qemu_fprintf(f, " D(btaken=%d btarget=0x%08x)", - env->btaken, env->btarget); + qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget); } if (iflags & DRTI_FLAG) { qemu_fprintf(f, " DRTI"); @@ -1918,7 +1880,7 @@ void mb_tcg_init(void) SP(msr_c), SP(imm), SP(iflags), - SP(btaken), + SP(bvalue), SP(btarget), SP(res_val), }; From 16bbbbc91ad0c2c8cfdc0e17a0cb7f60b690b534 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Aug 2020 17:38:04 -0700 Subject: [PATCH 66/76] target/microblaze: Convert dec_br to decodetree Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 14 ++++++ target/microblaze/translate.c | 87 +++++++++++++++++++--------------- 2 files changed, 63 insertions(+), 38 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index 8eba47d90c..340dd999b6 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -68,6 +68,20 @@ andi 101001 ..... ..... ................ @typeb andn 100011 ..... ..... ..... 000 0000 0000 @typea andni 101011 ..... ..... ................ @typeb +br 100110 ..... 00000 ..... 000 0000 0000 @typea_br +bra 100110 ..... 01000 ..... 000 0000 0000 @typea_br +brd 100110 ..... 10000 ..... 000 0000 0000 @typea_br +brad 100110 ..... 11000 ..... 000 0000 0000 @typea_br +brld 100110 ..... 10100 ..... 000 0000 0000 @typea_br +brald 100110 ..... 11100 ..... 000 0000 0000 @typea_br + +bri 101110 ..... 00000 ................ @typeb_br +brai 101110 ..... 01000 ................ @typeb_br +brid 101110 ..... 10000 ................ @typeb_br +braid 101110 ..... 11000 ................ @typeb_br +brlid 101110 ..... 10100 ................ @typeb_br +bralid 101110 ..... 11100 ................ @typeb_br + brk 100110 ..... 01100 ..... 000 0000 0000 @typea_br brki 101110 ..... 01100 ................ @typeb_br diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 1545974669..5c6e6e599e 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1048,6 +1048,53 @@ static bool trans_swx(DisasContext *dc, arg_typea *arg) return true; } +static void setup_dslot(DisasContext *dc, bool type_b) +{ + dc->tb_flags_to_set |= D_FLAG; + if (type_b && (dc->tb_flags & IMM_FLAG)) { + dc->tb_flags_to_set |= BIMM_FLAG; + } +} + +static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm, + bool delay, bool abs, int link) +{ + uint32_t add_pc; + + if (delay) { + setup_dslot(dc, dest_rb < 0); + } + + if (link) { + tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next); + } + + /* Store the branch taken destination into btarget. */ + add_pc = abs ? 0 : dc->base.pc_next; + if (dest_rb > 0) { + dc->jmp_dest = -1; + tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc); + } else { + dc->jmp_dest = add_pc + dest_imm; + tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); + } + dc->jmp_cond = TCG_COND_ALWAYS; + return true; +} + +#define DO_BR(NAME, NAMEI, DELAY, ABS, LINK) \ + static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg) \ + { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); } \ + static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg) \ + { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); } + +DO_BR(br, bri, false, false, false) +DO_BR(bra, brai, false, true, false) +DO_BR(brd, brid, true, false, false) +DO_BR(brad, braid, true, true, false) +DO_BR(brld, brlid, true, false, true) +DO_BR(brald, bralid, true, true, true) + static bool trans_brk(DisasContext *dc, arg_typea_br *arg) { if (trap_userspace(dc, true)) { @@ -1372,14 +1419,6 @@ static void dec_msr(DisasContext *dc) } } -static void dec_setup_dslot(DisasContext *dc) -{ - dc->tb_flags_to_set |= D_FLAG; - if (dc->type_b && (dc->tb_flags & IMM_FLAG)) { - dc->tb_flags_to_set |= BIMM_FLAG; - } -} - static void dec_bcc(DisasContext *dc) { static const TCGCond mb_to_tcg_cc[] = { @@ -1398,7 +1437,7 @@ static void dec_bcc(DisasContext *dc) dslot = dc->ir & (1 << 25); if (dslot) { - dec_setup_dslot(dc); + setup_dslot(dc, dc->type_b); } dc->jmp_cond = mb_to_tcg_cc[cc]; @@ -1426,33 +1465,6 @@ static void dec_bcc(DisasContext *dc) tcg_temp_free_i32(next); } -static void dec_br(DisasContext *dc) -{ - unsigned int dslot, link, abs; - uint32_t add_pc; - - dslot = dc->ir & (1 << 20); - abs = dc->ir & (1 << 19); - link = dc->ir & (1 << 18); - - if (dslot) { - dec_setup_dslot(dc); - } - if (link && dc->rd) { - tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); - } - - add_pc = abs ? 0 : dc->base.pc_next; - if (dc->type_b) { - dc->jmp_dest = add_pc + dec_alu_typeb_imm(dc); - tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); - } else { - dc->jmp_dest = -1; - tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], add_pc); - } - dc->jmp_cond = TCG_COND_ALWAYS; -} - static inline void do_rti(DisasContext *dc) { TCGv_i32 t0, t1; @@ -1521,7 +1533,7 @@ static void dec_rts(DisasContext *dc) return; } - dec_setup_dslot(dc); + setup_dslot(dc, true); if (i_bit) { dc->tb_flags |= DRTI_FLAG; @@ -1583,7 +1595,6 @@ static struct decoder_info { }; void (*dec)(DisasContext *dc); } decinfo[] = { - {DEC_BR, dec_br}, {DEC_BCC, dec_bcc}, {DEC_RTS, dec_rts}, {DEC_MSR, dec_msr}, From fd77911304ec3b6881e7e714d5b643693b0ff1ab Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Aug 2020 18:05:41 -0700 Subject: [PATCH 67/76] target/microblaze: Convert dec_bcc to decodetree Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 36 +++++++++++++ target/microblaze/translate.c | 99 ++++++++++++++++++---------------- 2 files changed, 88 insertions(+), 47 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index 340dd999b6..e6a61f147a 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -20,8 +20,10 @@ &typea0 rd ra &typea rd ra rb &typea_br rd rb +&typea_bc ra rb &typeb rd ra imm &typeb_br rd imm +&typeb_bc ra imm # Include any IMM prefix in the value reported. %extimm 0:s16 !function=typeb_imm @@ -35,12 +37,18 @@ # Officially typea, but with ra as opcode. @typea_br ...... rd:5 ..... rb:5 ........... &typea_br +# Officially typea, but with rd as opcode. +@typea_bc ...... ..... ra:5 rb:5 ........... &typea_bc + # 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 +# Officially typeb, but with rd as opcode. +@typeb_bc ...... ..... ra:5 ................ &typeb_bc 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. @@ -68,6 +76,34 @@ andi 101001 ..... ..... ................ @typeb andn 100011 ..... ..... ..... 000 0000 0000 @typea andni 101011 ..... ..... ................ @typeb +beq 100111 00000 ..... ..... 000 0000 0000 @typea_bc +bge 100111 00101 ..... ..... 000 0000 0000 @typea_bc +bgt 100111 00100 ..... ..... 000 0000 0000 @typea_bc +ble 100111 00011 ..... ..... 000 0000 0000 @typea_bc +blt 100111 00010 ..... ..... 000 0000 0000 @typea_bc +bne 100111 00001 ..... ..... 000 0000 0000 @typea_bc + +beqd 100111 10000 ..... ..... 000 0000 0000 @typea_bc +bged 100111 10101 ..... ..... 000 0000 0000 @typea_bc +bgtd 100111 10100 ..... ..... 000 0000 0000 @typea_bc +bled 100111 10011 ..... ..... 000 0000 0000 @typea_bc +bltd 100111 10010 ..... ..... 000 0000 0000 @typea_bc +bned 100111 10001 ..... ..... 000 0000 0000 @typea_bc + +beqi 101111 00000 ..... ................ @typeb_bc +bgei 101111 00101 ..... ................ @typeb_bc +bgti 101111 00100 ..... ................ @typeb_bc +blei 101111 00011 ..... ................ @typeb_bc +blti 101111 00010 ..... ................ @typeb_bc +bnei 101111 00001 ..... ................ @typeb_bc + +beqid 101111 10000 ..... ................ @typeb_bc +bgeid 101111 10101 ..... ................ @typeb_bc +bgtid 101111 10100 ..... ................ @typeb_bc +bleid 101111 10011 ..... ................ @typeb_bc +bltid 101111 10010 ..... ................ @typeb_bc +bneid 101111 10001 ..... ................ @typeb_bc + br 100110 ..... 00000 ..... 000 0000 0000 @typea_br bra 100110 ..... 01000 ..... 000 0000 0000 @typea_br brd 100110 ..... 10000 ..... 000 0000 0000 @typea_br diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 5c6e6e599e..b8dcef8f1c 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1095,6 +1095,58 @@ DO_BR(brad, braid, true, true, false) DO_BR(brld, brlid, true, false, true) DO_BR(brald, bralid, true, true, true) +static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm, + TCGCond cond, int ra, bool delay) +{ + TCGv_i32 zero, next; + + if (delay) { + setup_dslot(dc, dest_rb < 0); + } + + dc->jmp_cond = cond; + + /* Cache the condition register in cpu_bvalue across any delay slot. */ + tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra)); + + /* Store the branch taken destination into btarget. */ + if (dest_rb > 0) { + dc->jmp_dest = -1; + tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next); + } else { + dc->jmp_dest = dc->base.pc_next + dest_imm; + tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); + } + + /* Compute the final destination into btarget. */ + zero = tcg_const_i32(0); + next = tcg_const_i32(dc->base.pc_next + (delay + 1) * 4); + tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget, + reg_for_read(dc, ra), zero, + cpu_btarget, next); + tcg_temp_free_i32(zero); + tcg_temp_free_i32(next); + + return true; +} + +#define DO_BCC(NAME, COND) \ + static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg) \ + { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); } \ + static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg) \ + { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); } \ + static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg) \ + { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); } \ + static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg) \ + { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); } + +DO_BCC(beq, TCG_COND_EQ) +DO_BCC(bge, TCG_COND_GE) +DO_BCC(bgt, TCG_COND_GT) +DO_BCC(ble, TCG_COND_LE) +DO_BCC(blt, TCG_COND_LT) +DO_BCC(bne, TCG_COND_NE) + static bool trans_brk(DisasContext *dc, arg_typea_br *arg) { if (trap_userspace(dc, true)) { @@ -1419,52 +1471,6 @@ static void dec_msr(DisasContext *dc) } } -static void dec_bcc(DisasContext *dc) -{ - static const TCGCond mb_to_tcg_cc[] = { - [CC_EQ] = TCG_COND_EQ, - [CC_NE] = TCG_COND_NE, - [CC_LT] = TCG_COND_LT, - [CC_LE] = TCG_COND_LE, - [CC_GE] = TCG_COND_GE, - [CC_GT] = TCG_COND_GT, - }; - unsigned int cc; - unsigned int dslot; - TCGv_i32 zero, next; - - cc = EXTRACT_FIELD(dc->ir, 21, 23); - dslot = dc->ir & (1 << 25); - - if (dslot) { - setup_dslot(dc, dc->type_b); - } - - dc->jmp_cond = mb_to_tcg_cc[cc]; - - /* Cache the condition register in cpu_bvalue across any delay slot. */ - tcg_gen_mov_i32(cpu_bvalue, cpu_R[dc->ra]); - - /* Store the branch taken destination into btarget. */ - if (dc->type_b) { - dc->jmp_dest = dc->base.pc_next + dec_alu_typeb_imm(dc); - tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); - } else { - dc->jmp_dest = -1; - tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, dc->rb), - dc->base.pc_next); - } - - /* Compute the final destination into btarget. */ - zero = tcg_const_i32(0); - next = tcg_const_i32(dc->base.pc_next + (dslot + 1) * 4); - tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget, - reg_for_read(dc, dc->ra), zero, - cpu_btarget, next); - tcg_temp_free_i32(zero); - tcg_temp_free_i32(next); -} - static inline void do_rti(DisasContext *dc) { TCGv_i32 t0, t1; @@ -1595,7 +1601,6 @@ static struct decoder_info { }; void (*dec)(DisasContext *dc); } decinfo[] = { - {DEC_BCC, dec_bcc}, {DEC_RTS, dec_rts}, {DEC_MSR, dec_msr}, {DEC_STREAM, dec_stream}, From e6cb03548850f14d3236003ae8fd33ab8b95f4ca Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Aug 2020 18:25:25 -0700 Subject: [PATCH 68/76] target/microblaze: Convert dec_rts to decodetree Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 5 ++++ target/microblaze/translate.c | 51 +++++++++++++++------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index e6a61f147a..8906058a29 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -202,6 +202,11 @@ rsubic 001011 ..... ..... ................ @typeb rsubik 001101 ..... ..... ................ @typeb rsubikc 001111 ..... ..... ................ @typeb +rtbd 101101 10010 ..... ................ @typeb_bc +rtid 101101 10001 ..... ................ @typeb_bc +rted 101101 10100 ..... ................ @typeb_bc +rtsd 101101 10000 ..... ................ @typeb_bc + sb 110100 ..... ..... ..... 0000 000 0000 @typea sbr 110100 ..... ..... ..... 0100 000 0000 @typea sbea 110100 ..... ..... ..... 0001 000 0000 @typea diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index b8dcef8f1c..6c1855b29a 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1252,6 +1252,29 @@ static bool trans_mbar(DisasContext *dc, arg_mbar *arg) return true; } +static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set) +{ + if (trap_userspace(dc, to_set)) { + return true; + } + dc->tb_flags_to_set |= to_set; + setup_dslot(dc, true); + + dc->jmp_cond = TCG_COND_ALWAYS; + dc->jmp_dest = -1; + tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm); + return true; +} + +#define DO_RTS(NAME, IFLAG) \ + static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \ + { return do_rts(dc, arg, IFLAG); } + +DO_RTS(rtbd, DRTB_FLAG) +DO_RTS(rtid, DRTI_FLAG) +DO_RTS(rted, DRTE_FLAG) +DO_RTS(rtsd, 0) + static bool trans_zero(DisasContext *dc, arg_zero *arg) { /* If opcode_0_illegal, trap. */ @@ -1527,33 +1550,6 @@ static inline void do_rte(DisasContext *dc) dc->tb_flags &= ~DRTE_FLAG; } -static void dec_rts(DisasContext *dc) -{ - unsigned int b_bit, i_bit, e_bit; - - i_bit = dc->ir & (1 << 21); - b_bit = dc->ir & (1 << 22); - e_bit = dc->ir & (1 << 23); - - if (trap_userspace(dc, i_bit || b_bit || e_bit)) { - return; - } - - setup_dslot(dc, true); - - if (i_bit) { - dc->tb_flags |= DRTI_FLAG; - } else if (b_bit) { - dc->tb_flags |= DRTB_FLAG; - } else if (e_bit) { - dc->tb_flags |= DRTE_FLAG; - } - - dc->jmp_cond = TCG_COND_ALWAYS; - dc->jmp_dest = -1; - tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc)); -} - static void dec_null(DisasContext *dc) { if (trap_illegal(dc, true)) { @@ -1601,7 +1597,6 @@ static struct decoder_info { }; void (*dec)(DisasContext *dc); } decinfo[] = { - {DEC_RTS, dec_rts}, {DEC_MSR, dec_msr}, {DEC_STREAM, dec_stream}, {{0, 0}, dec_null} From 3fb394fd41420372233e9a49f0e287b3be227e49 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Aug 2020 18:34:06 -0700 Subject: [PATCH 69/76] target/microblaze: Tidy do_rti, do_rtb, do_rte Since cpu_msr is no longer a 64-bit quantity, we can simplify the arithmetic in these functions. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 65 ++++++++++++++--------------------- 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 6c1855b29a..0872795038 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1494,59 +1494,44 @@ static void dec_msr(DisasContext *dc) } } -static inline void do_rti(DisasContext *dc) +static void do_rti(DisasContext *dc) { - TCGv_i32 t0, t1; - t0 = tcg_temp_new_i32(); - t1 = tcg_temp_new_i32(); - tcg_gen_mov_i32(t1, cpu_msr); - tcg_gen_shri_i32(t0, t1, 1); - tcg_gen_ori_i32(t1, t1, MSR_IE); - tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); + TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); - tcg_gen_or_i32(t1, t1, t0); - msr_write(dc, t1); - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t0); + tcg_gen_shri_i32(tmp, cpu_msr, 1); + tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE); + tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM); + tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM)); + tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); + + tcg_temp_free_i32(tmp); dc->tb_flags &= ~DRTI_FLAG; } -static inline void do_rtb(DisasContext *dc) +static void do_rtb(DisasContext *dc) { - TCGv_i32 t0, t1; - t0 = tcg_temp_new_i32(); - t1 = tcg_temp_new_i32(); - tcg_gen_mov_i32(t1, cpu_msr); - tcg_gen_andi_i32(t1, t1, ~MSR_BIP); - tcg_gen_shri_i32(t0, t1, 1); - tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); + TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); - tcg_gen_or_i32(t1, t1, t0); - msr_write(dc, t1); - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t0); + tcg_gen_shri_i32(tmp, cpu_msr, 1); + tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP)); + tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM)); + tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); + + tcg_temp_free_i32(tmp); dc->tb_flags &= ~DRTB_FLAG; } -static inline void do_rte(DisasContext *dc) +static void do_rte(DisasContext *dc) { - TCGv_i32 t0, t1; - t0 = tcg_temp_new_i32(); - t1 = tcg_temp_new_i32(); + TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_mov_i32(t1, cpu_msr); - tcg_gen_ori_i32(t1, t1, MSR_EE); - tcg_gen_andi_i32(t1, t1, ~MSR_EIP); - tcg_gen_shri_i32(t0, t1, 1); - tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); + tcg_gen_shri_i32(tmp, cpu_msr, 1); + tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE); + tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM)); + tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP)); + tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); - tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); - tcg_gen_or_i32(t1, t1, t0); - msr_write(dc, t1); - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t0); + tcg_temp_free_i32(tmp); dc->tb_flags &= ~DRTE_FLAG; } From 536e340f464d7c2ef55cca47c7535d9409bf03c7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Aug 2020 19:05:32 -0700 Subject: [PATCH 70/76] target/microblaze: Convert msrclr, msrset to decodetree Split this out of dec_msr. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 6 +++ target/microblaze/translate.c | 85 +++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 37 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index 8906058a29..ed3312982f 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -24,6 +24,7 @@ &typeb rd ra imm &typeb_br rd imm &typeb_bc ra imm +&type_msr rd imm # Include any IMM prefix in the value reported. %extimm 0:s16 !function=typeb_imm @@ -55,6 +56,8 @@ %ieimm 6:5 0:5 @typeb_ie ...... rd:5 ra:5 ..... ..... . ..... &typeb imm=%ieimm +@type_msr ...... rd:5 ...... imm:15 &type_msr + ### { @@ -179,6 +182,9 @@ lwi 111010 ..... ..... ................ @typeb mbar 101110 imm:5 00010 0000 0000 0000 0100 +msrclr 100101 ..... 100010 ............... @type_msr +msrset 100101 ..... 100000 ............... @type_msr + mul 010000 ..... ..... ..... 000 0000 0000 @typea mulh 010000 ..... ..... ..... 000 0000 0001 @typea mulhu 010000 ..... ..... ..... 000 0000 0011 @typea diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 0872795038..9479dbc103 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1311,16 +1311,61 @@ static void msr_write(DisasContext *dc, TCGv_i32 v) tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR)); } +static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set) +{ + uint32_t imm = arg->imm; + + if (trap_userspace(dc, imm != MSR_C)) { + return true; + } + + if (arg->rd) { + msr_read(dc, cpu_R[arg->rd]); + } + + /* + * Handle the carry bit separately. + * This is the only bit that userspace can modify. + */ + if (imm & MSR_C) { + tcg_gen_movi_i32(cpu_msr_c, set); + } + + /* + * MSR_C and MSR_CC set above. + * MSR_PVR is not writable, and is always clear. + */ + imm &= ~(MSR_C | MSR_CC | MSR_PVR); + + if (imm != 0) { + if (set) { + tcg_gen_ori_i32(cpu_msr, cpu_msr, imm); + } else { + tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm); + } + dc->cpustate_changed = 1; + } + return true; +} + +static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg) +{ + return do_msrclrset(dc, arg, false); +} + +static bool trans_msrset(DisasContext *dc, arg_type_msr *arg) +{ + return do_msrclrset(dc, arg, true); +} + static void dec_msr(DisasContext *dc) { CPUState *cs = CPU(dc->cpu); - TCGv_i32 t0, t1; unsigned int sr, rn; - bool to, clrset, extended = false; + bool to, extended = false; sr = extract32(dc->imm, 0, 14); to = extract32(dc->imm, 14, 1); - clrset = extract32(dc->imm, 15, 1) == 0; dc->type_b = 1; if (to) { dc->cpustate_changed = 1; @@ -1334,40 +1379,6 @@ static void dec_msr(DisasContext *dc) extended = extract32(dc->imm, e_bit[to], 1); } - /* msrclr and msrset. */ - if (clrset) { - bool clr = extract32(dc->ir, 16, 1); - - if (!dc->cpu->cfg.use_msr_instr) { - /* nop??? */ - return; - } - - if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) { - return; - } - - if (dc->rd) - msr_read(dc, cpu_R[dc->rd]); - - t0 = tcg_temp_new_i32(); - t1 = tcg_temp_new_i32(); - msr_read(dc, t0); - tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc))); - - if (clr) { - tcg_gen_not_i32(t1, t1); - tcg_gen_and_i32(t0, t0, t1); - } else - tcg_gen_or_i32(t0, t0, t1); - msr_write(dc, t0); - tcg_temp_free_i32(t0); - tcg_temp_free_i32(t1); - tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); - dc->base.is_jmp = DISAS_UPDATE; - return; - } - if (trap_userspace(dc, to)) { return; } From 9df297a2d84a0c452567ae6c2be2b5c42b8a0931 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Aug 2020 19:59:57 -0700 Subject: [PATCH 71/76] target/microblaze: Convert dec_msr to decodetree Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 3 + target/microblaze/translate.c | 270 +++++++++++++++++---------------- 2 files changed, 139 insertions(+), 134 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index ed3312982f..43c9e16819 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -182,6 +182,9 @@ lwi 111010 ..... ..... ................ @typeb mbar 101110 imm:5 00010 0000 0000 0000 0100 +mfs 100101 rd:5 0 e:1 000 10 rs:14 +mts 100101 0 e:1 000 ra:5 11 rs:14 + msrclr 100101 ..... 100010 ............... @type_msr msrset 100101 ..... 100000 ............... @type_msr diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 9479dbc103..582f5a1577 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1300,6 +1300,7 @@ static void msr_read(DisasContext *dc, TCGv_i32 d) tcg_temp_free_i32(t); } +#ifndef CONFIG_USER_ONLY static void msr_write(DisasContext *dc, TCGv_i32 v) { dc->cpustate_changed = 1; @@ -1310,6 +1311,7 @@ static void msr_write(DisasContext *dc, TCGv_i32 v) /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */ tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR)); } +#endif static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set) { @@ -1358,151 +1360,152 @@ static bool trans_msrset(DisasContext *dc, arg_type_msr *arg) return do_msrclrset(dc, arg, true); } -static void dec_msr(DisasContext *dc) +static bool trans_mts(DisasContext *dc, arg_mts *arg) { - CPUState *cs = CPU(dc->cpu); - unsigned int sr, rn; - bool to, extended = false; - - sr = extract32(dc->imm, 0, 14); - to = extract32(dc->imm, 14, 1); - dc->type_b = 1; - if (to) { - dc->cpustate_changed = 1; + if (trap_userspace(dc, true)) { + return true; } - /* Extended MSRs are only available if addr_size > 32. */ - if (dc->cpu->cfg.addr_size > 32) { - /* The E-bit is encoded differently for To/From MSR. */ - static const unsigned int e_bit[] = { 19, 24 }; - - extended = extract32(dc->imm, e_bit[to], 1); +#ifdef CONFIG_USER_ONLY + g_assert_not_reached(); +#else + if (arg->e && arg->rs != 0x1003) { + qemu_log_mask(LOG_GUEST_ERROR, + "Invalid extended mts reg 0x%x\n", arg->rs); + return true; } - if (trap_userspace(dc, to)) { - return; - } + TCGv_i32 src = reg_for_read(dc, arg->ra); + switch (arg->rs) { + case SR_MSR: + msr_write(dc, src); + break; + case SR_FSR: + tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr)); + break; + case 0x800: + tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, slr)); + break; + case 0x802: + tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, shr)); + break; -#if !defined(CONFIG_USER_ONLY) - /* Catch read/writes to the mmu block. */ - if ((sr & ~0xff) == 0x1000) { - TCGv_i32 tmp_ext = tcg_const_i32(extended); - TCGv_i32 tmp_sr; + case 0x1000: /* PID */ + case 0x1001: /* ZPR */ + case 0x1002: /* TLBX */ + case 0x1003: /* TLBLO */ + case 0x1004: /* TLBHI */ + case 0x1005: /* TLBSX */ + { + TCGv_i32 tmp_ext = tcg_const_i32(arg->e); + TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7); - sr &= 7; - tmp_sr = tcg_const_i32(sr); - if (to) { - gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]); - } else { - gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr); + gen_helper_mmu_write(cpu_env, tmp_ext, tmp_reg, src); + tcg_temp_free_i32(tmp_reg); + tcg_temp_free_i32(tmp_ext); } - tcg_temp_free_i32(tmp_sr); - tcg_temp_free_i32(tmp_ext); - return; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs); + return true; } + dc->cpustate_changed = 1; + return true; +#endif +} + +static bool trans_mfs(DisasContext *dc, arg_mfs *arg) +{ + TCGv_i32 dest = reg_for_write(dc, arg->rd); + + if (arg->e) { + switch (arg->rs) { + case SR_EAR: + { + TCGv_i64 t64 = tcg_temp_new_i64(); + tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); + tcg_gen_extrh_i64_i32(dest, t64); + tcg_temp_free_i64(t64); + } + return true; +#ifndef CONFIG_USER_ONLY + case 0x1003: /* TLBLO */ + /* Handled below. */ + break; +#endif + case 0x2006 ... 0x2009: + /* High bits of PVR6-9 not implemented. */ + tcg_gen_movi_i32(dest, 0); + return true; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "Invalid extended mfs reg 0x%x\n", arg->rs); + return true; + } + } + + switch (arg->rs) { + case SR_PC: + tcg_gen_movi_i32(dest, dc->base.pc_next); + break; + case SR_MSR: + msr_read(dc, dest); + break; + case SR_EAR: + { + TCGv_i64 t64 = tcg_temp_new_i64(); + tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); + tcg_gen_extrl_i64_i32(dest, t64); + tcg_temp_free_i64(t64); + } + break; + case SR_ESR: + tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, esr)); + break; + case SR_FSR: + tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, fsr)); + break; + case SR_BTR: + tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, btr)); + break; + case SR_EDR: + tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, edr)); + break; + case 0x800: + tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, slr)); + break; + case 0x802: + tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, shr)); + break; + +#ifndef CONFIG_USER_ONLY + case 0x1000: /* PID */ + case 0x1001: /* ZPR */ + case 0x1002: /* TLBX */ + case 0x1003: /* TLBLO */ + case 0x1004: /* TLBHI */ + case 0x1005: /* TLBSX */ + { + TCGv_i32 tmp_ext = tcg_const_i32(arg->e); + TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7); + + gen_helper_mmu_read(dest, cpu_env, tmp_ext, tmp_reg); + tcg_temp_free_i32(tmp_reg); + tcg_temp_free_i32(tmp_ext); + } + break; #endif - if (to) { - switch (sr) { - case SR_PC: - break; - case SR_MSR: - msr_write(dc, cpu_R[dc->ra]); - break; - case SR_EAR: - { - TCGv_i64 t64 = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]); - tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear)); - tcg_temp_free_i64(t64); - } - break; - case SR_ESR: - tcg_gen_st_i32(cpu_R[dc->ra], - cpu_env, offsetof(CPUMBState, esr)); - break; - case SR_FSR: - tcg_gen_st_i32(cpu_R[dc->ra], - cpu_env, offsetof(CPUMBState, fsr)); - break; - case SR_BTR: - tcg_gen_st_i32(cpu_R[dc->ra], - cpu_env, offsetof(CPUMBState, btr)); - break; - case SR_EDR: - tcg_gen_st_i32(cpu_R[dc->ra], - cpu_env, offsetof(CPUMBState, edr)); - break; - case 0x800: - tcg_gen_st_i32(cpu_R[dc->ra], - cpu_env, offsetof(CPUMBState, slr)); - break; - case 0x802: - tcg_gen_st_i32(cpu_R[dc->ra], - cpu_env, offsetof(CPUMBState, shr)); - break; - default: - cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr); - break; - } - } else { - switch (sr) { - case SR_PC: - tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); - break; - case SR_MSR: - msr_read(dc, cpu_R[dc->rd]); - break; - case SR_EAR: - { - TCGv_i64 t64 = tcg_temp_new_i64(); - tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); - if (extended) { - tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64); - } else { - tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64); - } - tcg_temp_free_i64(t64); - } - break; - case SR_ESR: - tcg_gen_ld_i32(cpu_R[dc->rd], - cpu_env, offsetof(CPUMBState, esr)); - break; - case SR_FSR: - tcg_gen_ld_i32(cpu_R[dc->rd], - cpu_env, offsetof(CPUMBState, fsr)); - break; - case SR_BTR: - tcg_gen_ld_i32(cpu_R[dc->rd], - cpu_env, offsetof(CPUMBState, btr)); - break; - case SR_EDR: - tcg_gen_ld_i32(cpu_R[dc->rd], - cpu_env, offsetof(CPUMBState, edr)); - break; - case 0x800: - tcg_gen_ld_i32(cpu_R[dc->rd], - cpu_env, offsetof(CPUMBState, slr)); - break; - case 0x802: - tcg_gen_ld_i32(cpu_R[dc->rd], - cpu_env, offsetof(CPUMBState, shr)); - break; - case 0x2000 ... 0x200c: - rn = sr & 0xf; - tcg_gen_ld_i32(cpu_R[dc->rd], - cpu_env, offsetof(CPUMBState, pvr.regs[rn])); - break; - default: - cpu_abort(cs, "unknown mfs reg %x\n", sr); - break; - } - } - - if (dc->rd == 0) { - tcg_gen_movi_i32(cpu_R[0], 0); + case 0x2000 ... 0x200c: + tcg_gen_ld_i32(dest, cpu_env, + offsetof(CPUMBState, pvr.regs[arg->rs - 0x2000])); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs); + break; } + return true; } static void do_rti(DisasContext *dc) @@ -1593,7 +1596,6 @@ static struct decoder_info { }; void (*dec)(DisasContext *dc); } decinfo[] = { - {DEC_MSR, dec_msr}, {DEC_STREAM, dec_stream}, {{0, 0}, dec_null} }; From 52065d8f4689e88ac2e4b9f49b64399a3e80f40a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Aug 2020 20:13:45 -0700 Subject: [PATCH 72/76] target/microblaze: Convert dec_stream to decodetree Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/insns.decode | 6 ++++ target/microblaze/translate.c | 64 ++++++++++++++++++++++++++-------- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/target/microblaze/insns.decode b/target/microblaze/insns.decode index 43c9e16819..fb0f0e6838 100644 --- a/target/microblaze/insns.decode +++ b/target/microblaze/insns.decode @@ -159,6 +159,9 @@ flt 010110 ..... ..... ----- 0101 000 0000 @typea0 fint 010110 ..... ..... ----- 0110 000 0000 @typea0 fsqrt 010110 ..... ..... 00000 0111 000 0000 @typea0 +get 011011 rd:5 00000 0 ctrl:5 000000 imm:4 +getd 010011 rd:5 00000 rb:5 0 ctrl:5 00000 + idiv 010010 ..... ..... ..... 000 0000 0000 @typea idivu 010010 ..... ..... ..... 000 0000 0010 @typea @@ -201,6 +204,9 @@ pcmpbf 100000 ..... ..... ..... 100 0000 0000 @typea pcmpeq 100010 ..... ..... ..... 100 0000 0000 @typea pcmpne 100011 ..... ..... ..... 100 0000 0000 @typea +put 011011 00000 ra:5 1 ctrl:5 000000 imm:4 +putd 010011 00000 ra:5 rb:5 1 ctrl:5 00000 + rsub 000001 ..... ..... ..... 000 0000 0000 @typea rsubc 000011 ..... ..... ..... 000 0000 0000 @typea rsubk 000101 ..... ..... ..... 000 0000 0000 @typea diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 582f5a1577..2c87d671ae 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1560,33 +1560,68 @@ static void dec_null(DisasContext *dc) } /* Insns connected to FSL or AXI stream attached devices. */ -static void dec_stream(DisasContext *dc) +static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl) { TCGv_i32 t_id, t_ctrl; - int ctrl; if (trap_userspace(dc, true)) { - return; + return true; } t_id = tcg_temp_new_i32(); - if (dc->type_b) { - tcg_gen_movi_i32(t_id, dc->imm & 0xf); - ctrl = dc->imm >> 10; + if (rb) { + tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf); } else { - tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf); - ctrl = dc->imm >> 5; + tcg_gen_movi_i32(t_id, imm); } t_ctrl = tcg_const_i32(ctrl); - - if (dc->rd == 0) { - gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]); - } else { - gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl); - } + gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl); tcg_temp_free_i32(t_id); tcg_temp_free_i32(t_ctrl); + return true; +} + +static bool trans_get(DisasContext *dc, arg_get *arg) +{ + return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl); +} + +static bool trans_getd(DisasContext *dc, arg_getd *arg) +{ + return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl); +} + +static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl) +{ + TCGv_i32 t_id, t_ctrl; + + if (trap_userspace(dc, true)) { + return true; + } + + t_id = tcg_temp_new_i32(); + if (rb) { + tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf); + } else { + tcg_gen_movi_i32(t_id, imm); + } + + t_ctrl = tcg_const_i32(ctrl); + gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra)); + tcg_temp_free_i32(t_id); + tcg_temp_free_i32(t_ctrl); + return true; +} + +static bool trans_put(DisasContext *dc, arg_put *arg) +{ + return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl); +} + +static bool trans_putd(DisasContext *dc, arg_putd *arg) +{ + return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl); } static struct decoder_info { @@ -1596,7 +1631,6 @@ static struct decoder_info { }; void (*dec)(DisasContext *dc); } decinfo[] = { - {DEC_STREAM, dec_stream}, {{0, 0}, dec_null} }; From 921afa9daeb90f7d40e0abdec9e13d43c48268dc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Aug 2020 20:18:17 -0700 Subject: [PATCH 73/76] target/microblaze: Remove last of old decoder All instructions have been convered. Issue sigill if decodetree does not match. Remove argument decode from DisasContext. Remove microblaze-decode.h. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/microblaze-decode.h | 59 ---------------------- target/microblaze/translate.c | 73 +-------------------------- 2 files changed, 1 insertion(+), 131 deletions(-) delete mode 100644 target/microblaze/microblaze-decode.h diff --git a/target/microblaze/microblaze-decode.h b/target/microblaze/microblaze-decode.h deleted file mode 100644 index 17b2f29fff..0000000000 --- a/target/microblaze/microblaze-decode.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * MicroBlaze insn decoding macros. - * - * Copyright (c) 2009 Edgar E. Iglesias - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#ifndef TARGET_MICROBLAZE_MICROBLAZE_DECODE_H -#define TARGET_MICROBLAZE_MICROBLAZE_DECODE_H - -/* Convenient binary macros. */ -#define HEX__(n) 0x##n##LU -#define B8__(x) ((x&0x0000000FLU)?1:0) \ - + ((x&0x000000F0LU)?2:0) \ - + ((x&0x00000F00LU)?4:0) \ - + ((x&0x0000F000LU)?8:0) \ - + ((x&0x000F0000LU)?16:0) \ - + ((x&0x00F00000LU)?32:0) \ - + ((x&0x0F000000LU)?64:0) \ - + ((x&0xF0000000LU)?128:0) -#define B8(d) ((unsigned char)B8__(HEX__(d))) - -/* Decode logic, value and mask. */ -#define DEC_ADD {B8(00000000), B8(00110001)} -#define DEC_SUB {B8(00000001), B8(00110001)} -#define DEC_AND {B8(00100001), B8(00110101)} -#define DEC_XOR {B8(00100010), B8(00110111)} -#define DEC_OR {B8(00100000), B8(00110111)} -#define DEC_BIT {B8(00100100), B8(00111111)} -#define DEC_MSR {B8(00100101), B8(00111111)} - -#define DEC_BARREL {B8(00010001), B8(00110111)} -#define DEC_MUL {B8(00010000), B8(00110111)} -#define DEC_DIV {B8(00010010), B8(00110111)} -#define DEC_FPU {B8(00010110), B8(00111111)} - -#define DEC_LD {B8(00110000), B8(00110100)} -#define DEC_ST {B8(00110100), B8(00110100)} -#define DEC_IMM {B8(00101100), B8(00111111)} - -#define DEC_BR {B8(00100110), B8(00110111)} -#define DEC_BCC {B8(00100111), B8(00110111)} -#define DEC_RTS {B8(00101101), B8(00111111)} - -#define DEC_STREAM {B8(00010011), B8(00110111)} - -#endif diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 2c87d671ae..8f69ca50b2 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -24,7 +24,6 @@ #include "exec/exec-all.h" #include "tcg/tcg-op.h" #include "exec/helper-proto.h" -#include "microblaze-decode.h" #include "exec/cpu_ldst.h" #include "exec/helper-gen.h" #include "exec/translator.h" @@ -65,13 +64,7 @@ typedef struct DisasContext { bool r0_set; /* Decoder. */ - int type_b; - uint32_t ir; uint32_t ext_imm; - uint8_t opcode; - uint8_t rd, ra, rb; - uint16_t imm; - unsigned int cpustate_changed; unsigned int tb_flags; unsigned int tb_flags_to_set; @@ -82,8 +75,6 @@ typedef struct DisasContext { /* Immediate branch-taken destination, or -1 for indirect. */ uint32_t jmp_dest; - - int abort_at_next_insn; } DisasContext; static int typeb_imm(DisasContext *dc, int x) @@ -184,21 +175,6 @@ static bool trap_userspace(DisasContext *dc, bool cond) return cond_user; } -static int32_t dec_alu_typeb_imm(DisasContext *dc) -{ - tcg_debug_assert(dc->type_b); - return typeb_imm(dc, (int16_t)dc->imm); -} - -static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc) -{ - if (dc->type_b) { - tcg_gen_movi_i32(cpu_imm, dec_alu_typeb_imm(dc)); - return &cpu_imm; - } - return &cpu_R[dc->rb]; -} - static TCGv_i32 reg_for_read(DisasContext *dc, int reg) { if (likely(reg != 0)) { @@ -1549,16 +1525,6 @@ static void do_rte(DisasContext *dc) dc->tb_flags &= ~DRTE_FLAG; } -static void dec_null(DisasContext *dc) -{ - if (trap_illegal(dc, true)) { - return; - } - qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", - (uint32_t)dc->base.pc_next, dc->opcode); - dc->abort_at_next_insn = 1; -} - /* Insns connected to FSL or AXI stream attached devices. */ static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl) { @@ -1624,40 +1590,6 @@ static bool trans_putd(DisasContext *dc, arg_putd *arg) return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl); } -static struct decoder_info { - struct { - uint32_t bits; - uint32_t mask; - }; - void (*dec)(DisasContext *dc); -} decinfo[] = { - {{0, 0}, dec_null} -}; - -static void old_decode(DisasContext *dc, uint32_t ir) -{ - int i; - - dc->ir = ir; - - /* bit 2 seems to indicate insn type. */ - dc->type_b = ir & (1 << 29); - - dc->opcode = EXTRACT_FIELD(ir, 26, 31); - dc->rd = EXTRACT_FIELD(ir, 21, 25); - dc->ra = EXTRACT_FIELD(ir, 16, 20); - dc->rb = EXTRACT_FIELD(ir, 11, 15); - dc->imm = EXTRACT_FIELD(ir, 0, 15); - - /* Large switch for all insns. */ - for (i = 0; i < ARRAY_SIZE(decinfo); i++) { - if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) { - decinfo[i].dec(dc); - break; - } - } -} - static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) { DisasContext *dc = container_of(dcb, DisasContext, base); @@ -1667,7 +1599,6 @@ static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) dc->cpu = cpu; dc->tb_flags = dc->base.tb->flags; dc->cpustate_changed = 0; - dc->abort_at_next_insn = 0; dc->ext_imm = dc->base.tb->cs_base; dc->r0 = NULL; dc->r0_set = false; @@ -1724,7 +1655,7 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) ir = cpu_ldl_code(env, dc->base.pc_next); if (!decode(dc, ir)) { - old_decode(dc, ir); + trap_illegal(dc, true); } if (dc->r0) { @@ -1764,8 +1695,6 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) { DisasContext *dc = container_of(dcb, DisasContext, base); - assert(!dc->abort_at_next_insn); - if (dc->base.is_jmp == DISAS_NORETURN) { /* We have already exited the TB. */ return; From e47c22319921e3eeca08d9fe54de940902942576 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Aug 2020 20:30:51 -0700 Subject: [PATCH 74/76] target/microblaze: Remove cpu_R[0] Do not initialize cpu_R[0], as this should be totally unused. The cpu_for_read and cpu_for_write functions use a local temp. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 8f69ca50b2..8c287457a9 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1842,7 +1842,13 @@ void mb_tcg_init(void) static const struct { TCGv_i32 *var; int ofs; char name[8]; } i32s[] = { - R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), + /* + * Note that r0 is handled specially in reg_for_read + * and reg_for_write. Nothing should touch cpu_R[0]. + * Leave that element NULL, which will assert quickly + * inside the tcg generator functions. + */ + R(1), R(2), R(3), R(4), R(5), R(6), R(7), R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), From e269b4bdf228f57f6671b7692c08f7304179a4c4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Aug 2020 07:40:14 -0700 Subject: [PATCH 75/76] target/microblaze: Add flags markup to some helpers The mmu_read, mmu_write, get, and put helpers do not touch the general registers, or any of the other variables managed by tcg. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/helper.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target/microblaze/helper.h b/target/microblaze/helper.h index 3980fba797..f740835fcb 100644 --- a/target/microblaze/helper.h +++ b/target/microblaze/helper.h @@ -21,11 +21,11 @@ DEF_HELPER_FLAGS_3(fcmp_ge, TCG_CALL_NO_WG, i32, env, i32, i32) DEF_HELPER_FLAGS_2(pcmpbf, TCG_CALL_NO_RWG_SE, i32, i32, i32) #if !defined(CONFIG_USER_ONLY) -DEF_HELPER_3(mmu_read, i32, env, i32, i32) -DEF_HELPER_4(mmu_write, void, env, i32, i32, i32) +DEF_HELPER_FLAGS_3(mmu_read, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_4(mmu_write, TCG_CALL_NO_RWG, void, env, i32, i32, i32) #endif DEF_HELPER_FLAGS_2(stackprot, TCG_CALL_NO_WG, void, env, tl) -DEF_HELPER_2(get, i32, i32, i32) -DEF_HELPER_3(put, void, i32, i32, i32) +DEF_HELPER_FLAGS_2(get, TCG_CALL_NO_RWG, i32, i32, i32) +DEF_HELPER_FLAGS_3(put, TCG_CALL_NO_RWG, void, i32, i32, i32) From 19f27b6c2493472fe2790cf08d7b0140d57bdad5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Aug 2020 12:37:12 -0700 Subject: [PATCH 76/76] target/microblaze: Reduce linux-user address space to 32-bit User-space programs cannot use the 64-bit lwea/swea instructions. We can improve code generation and runtime by restricting the user-only address space to 32-bit. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu-param.h | 15 +++++++++++++++ target/microblaze/cpu.h | 2 +- target/microblaze/helper.c | 4 ++-- target/microblaze/translate.c | 28 +++++++++++++++++++++++++++- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/target/microblaze/cpu-param.h b/target/microblaze/cpu-param.h index 4abbc62d50..4d8297fa94 100644 --- a/target/microblaze/cpu-param.h +++ b/target/microblaze/cpu-param.h @@ -8,9 +8,24 @@ #ifndef MICROBLAZE_CPU_PARAM_H #define MICROBLAZE_CPU_PARAM_H 1 +/* + * While system mode can address up to 64 bits of address space, + * this is done via the lea/sea instructions, which are system-only + * (as they also bypass the mmu). + * + * We can improve the user-only experience by only exposing 32 bits + * of address space. + */ +#ifdef CONFIG_USER_ONLY +#define TARGET_LONG_BITS 32 +#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#define TARGET_VIRT_ADDR_SPACE_BITS 32 +#else #define TARGET_LONG_BITS 64 #define TARGET_PHYS_ADDR_SPACE_BITS 64 #define TARGET_VIRT_ADDR_SPACE_BITS 64 +#endif + /* FIXME: MB uses variable pages down to 1K but linux only uses 4k. */ #define TARGET_PAGE_BITS 12 #define NB_MMU_MODES 3 diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 4298f242a6..d11b6fa995 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -242,7 +242,7 @@ struct CPUMBState { uint32_t pc; uint32_t msr; /* All bits of MSR except MSR[C] and MSR[CC] */ uint32_t msr_c; /* MSR[C], in low bit; other bits must be 0 */ - uint64_t ear; + target_ulong ear; uint32_t esr; uint32_t fsr; uint32_t btr; diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index 1667822fb7..48547385b0 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -303,8 +303,8 @@ void mb_cpu_do_unaligned_access(CPUState *cs, vaddr addr, iflags = cpu->env.iflags; qemu_log_mask(CPU_LOG_INT, - "Unaligned access addr=" TARGET_FMT_lx - " pc=%x iflags=%x\n", addr, cpu->env.pc, iflags); + "Unaligned access addr=" TARGET_FMT_lx " pc=%x iflags=%x\n", + (target_ulong)addr, cpu->env.pc, iflags); esr = ESR_EC_UNALIGNED_DATA; if (likely(iflags & ESR_ESS_FLAG)) { diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 8c287457a9..a377818b5e 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -687,6 +687,7 @@ static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) return ret; } +#ifndef CONFIG_USER_ONLY static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) { int addr_size = dc->cpu->cfg.addr_size; @@ -712,6 +713,7 @@ static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) } return ret; } +#endif static void record_unaligned_ess(DisasContext *dc, int rd, MemOp size, bool store) @@ -776,8 +778,12 @@ static bool trans_lbuea(DisasContext *dc, arg_typea *arg) if (trap_userspace(dc, true)) { return true; } +#ifdef CONFIG_USER_ONLY + return true; +#else TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); +#endif } static bool trans_lbui(DisasContext *dc, arg_typeb *arg) @@ -803,8 +809,12 @@ static bool trans_lhuea(DisasContext *dc, arg_typea *arg) if (trap_userspace(dc, true)) { return true; } +#ifdef CONFIG_USER_ONLY + return true; +#else TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); +#endif } static bool trans_lhui(DisasContext *dc, arg_typeb *arg) @@ -830,8 +840,12 @@ static bool trans_lwea(DisasContext *dc, arg_typea *arg) if (trap_userspace(dc, true)) { return true; } +#ifdef CONFIG_USER_ONLY + return true; +#else TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); +#endif } static bool trans_lwi(DisasContext *dc, arg_typeb *arg) @@ -910,8 +924,12 @@ static bool trans_sbea(DisasContext *dc, arg_typea *arg) if (trap_userspace(dc, true)) { return true; } +#ifdef CONFIG_USER_ONLY + return true; +#else TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); +#endif } static bool trans_sbi(DisasContext *dc, arg_typeb *arg) @@ -937,8 +955,12 @@ static bool trans_shea(DisasContext *dc, arg_typea *arg) if (trap_userspace(dc, true)) { return true; } +#ifdef CONFIG_USER_ONLY + return true; +#else TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); +#endif } static bool trans_shi(DisasContext *dc, arg_typeb *arg) @@ -964,8 +986,12 @@ static bool trans_swea(DisasContext *dc, arg_typea *arg) if (trap_userspace(dc, true)) { return true; } +#ifdef CONFIG_USER_ONLY + return true; +#else TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); +#endif } static bool trans_swi(DisasContext *dc, arg_typeb *arg) @@ -1818,7 +1844,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) } qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n" - "ear=0x%016" PRIx64 " slr=0x%x shr=0x%x\n", + "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n", env->esr, env->fsr, env->btr, env->edr, env->ear, env->slr, env->shr);