From 4a09d0bb34ab030e09e87173b2e3ec0fd7616cff Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Feb 2017 15:06:54 -0800 Subject: [PATCH 01/24] target/openrisc: Rename the cpu from or32 to or1k This is in keeping with the toolchain and or1ksim. Signed-off-by: Richard Henderson --- configure | 6 +++--- default-configs/or1k-linux-user.mak | 1 + default-configs/or1k-softmmu.mak | 4 ++++ default-configs/or32-linux-user.mak | 1 - default-configs/or32-softmmu.mak | 4 ---- hw/openrisc/openrisc_sim.c | 4 ++-- target/openrisc/cpu.h | 2 +- tests/tcg/openrisc/Makefile | 4 ++-- 8 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 default-configs/or1k-linux-user.mak create mode 100644 default-configs/or1k-softmmu.mak delete mode 100644 default-configs/or32-linux-user.mak delete mode 100644 default-configs/or32-softmmu.mak diff --git a/configure b/configure index 63253398a2..1c9655e639 100755 --- a/configure +++ b/configure @@ -5843,7 +5843,7 @@ target_name=$(echo $target | cut -d '-' -f 1) target_bigendian="no" case "$target_name" in - armeb|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or32|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) + armeb|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or1k|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) target_bigendian=yes ;; esac @@ -5937,7 +5937,7 @@ case "$target_name" in ;; nios2) ;; - or32) + or1k) TARGET_ARCH=openrisc TARGET_BASE_ARCH=openrisc ;; @@ -6145,7 +6145,7 @@ for i in $ARCH $TARGET_BASE_ARCH ; do nios2) disas_config "NIOS2" ;; - or32) + or1k) disas_config "OPENRISC" ;; ppc*) diff --git a/default-configs/or1k-linux-user.mak b/default-configs/or1k-linux-user.mak new file mode 100644 index 0000000000..20e03c1317 --- /dev/null +++ b/default-configs/or1k-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for or1k-linux-user diff --git a/default-configs/or1k-softmmu.mak b/default-configs/or1k-softmmu.mak new file mode 100644 index 0000000000..10bfa7abb8 --- /dev/null +++ b/default-configs/or1k-softmmu.mak @@ -0,0 +1,4 @@ +# Default configuration for or1k-softmmu + +CONFIG_SERIAL=y +CONFIG_OPENCORES_ETH=y diff --git a/default-configs/or32-linux-user.mak b/default-configs/or32-linux-user.mak deleted file mode 100644 index 808c1f9b83..0000000000 --- a/default-configs/or32-linux-user.mak +++ /dev/null @@ -1 +0,0 @@ -# Default configuration for or32-linux-user diff --git a/default-configs/or32-softmmu.mak b/default-configs/or32-softmmu.mak deleted file mode 100644 index cce474672a..0000000000 --- a/default-configs/or32-softmmu.mak +++ /dev/null @@ -1,4 +0,0 @@ -# Default configuration for or32-softmmu - -CONFIG_SERIAL=y -CONFIG_OPENCORES_ETH=y diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 6d06d5be01..fc0d0967b7 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -139,10 +139,10 @@ static void openrisc_sim_init(MachineState *machine) static void openrisc_sim_machine_init(MachineClass *mc) { - mc->desc = "or32 simulation"; + mc->desc = "or1k simulation"; mc->init = openrisc_sim_init; mc->max_cpus = 1; mc->is_default = 1; } -DEFINE_MACHINE("or32-sim", openrisc_sim_machine_init) +DEFINE_MACHINE("or1k-sim", openrisc_sim_machine_init) diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index 508ef568b4..231c163617 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -32,7 +32,7 @@ struct OpenRISCCPU; #include "fpu/softfloat.h" #include "qom/cpu.h" -#define TYPE_OPENRISC_CPU "or32-cpu" +#define TYPE_OPENRISC_CPU "or1k-cpu" #define OPENRISC_CPU_CLASS(klass) \ OBJECT_CLASS_CHECK(OpenRISCCPUClass, (klass), TYPE_OPENRISC_CPU) diff --git a/tests/tcg/openrisc/Makefile b/tests/tcg/openrisc/Makefile index 7e65888761..fb5ceda512 100644 --- a/tests/tcg/openrisc/Makefile +++ b/tests/tcg/openrisc/Makefile @@ -1,8 +1,8 @@ -include ../../config-host.mak -CROSS = or32-linux- +CROSS = or1k-linux- -SIM = qemu-or32 +SIM = qemu-or1k CC = $(CROSS)gcc From ab9023385576389e68b937d744de8ef8a0a4dc7a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 28 Jan 2017 12:54:20 -0800 Subject: [PATCH 02/24] linux-user: Add MMAP_SHIFT for openrisc The page size on openrisc is 8k. Sync the shift required for the mmap2 syscall. Signed-off-by: Richard Henderson --- linux-user/openrisc/target_syscall.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/openrisc/target_syscall.h b/linux-user/openrisc/target_syscall.h index 9d3380f9a8..03104f80af 100644 --- a/linux-user/openrisc/target_syscall.h +++ b/linux-user/openrisc/target_syscall.h @@ -31,4 +31,6 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define MMAP_SHIFT TARGET_PAGE_BITS + #endif /* OPENRISC_TARGET_SYSCALL_H */ From a0adc417a0b22e9b33a529133e04822753067f33 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Feb 2017 21:30:13 -0800 Subject: [PATCH 03/24] linux-user: Fix openrisc cpu_loop We need to handle EXCP_DEBUG and EXCP_INTERRUPT. We need to send signals to the guest using queue_signal. Signed-off-by: Richard Henderson --- linux-user/main.c | 95 ++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 54 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index e588f58f2a..001f71c6cc 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2574,52 +2574,17 @@ kuser_fail: void cpu_loop(CPUOpenRISCState *env) { CPUState *cs = CPU(openrisc_env_get_cpu(env)); - int trapnr, gdbsig; + int trapnr; abi_long ret; + target_siginfo_t info; for (;;) { cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); process_queued_cpu_work(cs); - gdbsig = 0; switch (trapnr) { - case EXCP_RESET: - qemu_log_mask(CPU_LOG_INT, "\nReset request, exit, pc is %#x\n", env->pc); - exit(EXIT_FAILURE); - break; - case EXCP_BUSERR: - qemu_log_mask(CPU_LOG_INT, "\nBus error, exit, pc is %#x\n", env->pc); - gdbsig = TARGET_SIGBUS; - break; - case EXCP_DPF: - case EXCP_IPF: - cpu_dump_state(cs, stderr, fprintf, 0); - gdbsig = TARGET_SIGSEGV; - break; - case EXCP_TICK: - qemu_log_mask(CPU_LOG_INT, "\nTick time interrupt pc is %#x\n", env->pc); - break; - case EXCP_ALIGN: - qemu_log_mask(CPU_LOG_INT, "\nAlignment pc is %#x\n", env->pc); - gdbsig = TARGET_SIGBUS; - break; - case EXCP_ILLEGAL: - qemu_log_mask(CPU_LOG_INT, "\nIllegal instructionpc is %#x\n", env->pc); - gdbsig = TARGET_SIGILL; - break; - case EXCP_INT: - qemu_log_mask(CPU_LOG_INT, "\nExternal interruptpc is %#x\n", env->pc); - break; - case EXCP_DTLBMISS: - case EXCP_ITLBMISS: - qemu_log_mask(CPU_LOG_INT, "\nTLB miss\n"); - break; - case EXCP_RANGE: - qemu_log_mask(CPU_LOG_INT, "\nRange\n"); - gdbsig = TARGET_SIGSEGV; - break; case EXCP_SYSCALL: env->pc += 4; /* 0xc00; */ ret = do_syscall(env, @@ -2636,32 +2601,54 @@ void cpu_loop(CPUOpenRISCState *env) env->gpr[11] = ret; } break; + case EXCP_DPF: + case EXCP_IPF: + case EXCP_RANGE: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + break; + case EXCP_ALIGN: + info.si_signo = TARGET_SIGBUS; + info.si_errno = 0; + info.si_code = TARGET_BUS_ADRALN; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + break; + case EXCP_ILLEGAL: + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPC; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + break; case EXCP_FPE: - qemu_log_mask(CPU_LOG_INT, "\nFloating point error\n"); + info.si_signo = TARGET_SIGFPE; + info.si_errno = 0; + info.si_code = 0; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; - case EXCP_TRAP: - qemu_log_mask(CPU_LOG_INT, "\nTrap\n"); - gdbsig = TARGET_SIGTRAP; + case EXCP_INTERRUPT: + /* We processed the pending cpu work above. */ break; - case EXCP_NR: - qemu_log_mask(CPU_LOG_INT, "\nNR\n"); + case EXCP_DEBUG: + trapnr = gdb_handlesig(cs, TARGET_SIGTRAP); + if (trapnr) { + info.si_signo = trapnr; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + } break; case EXCP_ATOMIC: cpu_exec_step_atomic(cs); break; default: - EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n", - trapnr); - gdbsig = TARGET_SIGILL; - break; + g_assert_not_reached(); } - if (gdbsig) { - gdb_handlesig(cs, gdbsig); - if (gdbsig != TARGET_SIGTRAP) { - exit(EXIT_FAILURE); - } - } - process_pending_signals(env); } } From c40413a65eeb98d6f9eeb92544ab782c812ccc51 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Feb 2017 06:56:34 +1000 Subject: [PATCH 04/24] linux-user: Honor CLONE_SETTLS for openrisc Threads work much better when you set the TLS register. This was fixed in the upstream kernel for Linux 4.9. Signed-off-by: Richard Henderson --- linux-user/openrisc/target_cpu.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/linux-user/openrisc/target_cpu.h b/linux-user/openrisc/target_cpu.h index a21ed1aff8..f283d96a93 100644 --- a/linux-user/openrisc/target_cpu.h +++ b/linux-user/openrisc/target_cpu.h @@ -30,9 +30,7 @@ static inline void cpu_clone_regs(CPUOpenRISCState *env, target_ulong newsp) static inline void cpu_set_tls(CPUOpenRISCState *env, target_ulong newtls) { - /* Linux kernel 3.10 does not pay any attention to CLONE_SETTLS - * in copy_thread(), so QEMU need not do so either. - */ + env->gpr[10] = newtls; } #endif From c56e3b86701501364a4756201b6a9db9454463ab Mon Sep 17 00:00:00 2001 From: Stafford Horne Date: Sat, 14 Jan 2017 07:00:28 +0900 Subject: [PATCH 05/24] target/openrisc: Fix exception handling status registers I am working on testing instruction emulation patches for the linux kernel. During testing I found these 2 issues: - sets DSX (delay slot exception) but never clears it - EEAR for illegal insns should point to the bad exception (as per openrisc spec) but its not This patch fixes these two issues by clearing the DSX flag when not in a delay slot and by setting EEAR to exception PC when handling illegal instruction exceptions. After this patch the openrisc kernel with latest patches boots great on qemu and instruction emulation works. Cc: qemu-trivial@nongnu.org Cc: openrisc@lists.librecores.org Signed-off-by: Stafford Horne Message-Id: <20170113220028.29687-1-shorne@gmail.com> Signed-off-by: Richard Henderson --- target/openrisc/interrupt.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index e43fc84ef7..a243eb2751 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -38,10 +38,17 @@ void openrisc_cpu_do_interrupt(CPUState *cs) env->flags &= ~D_FLAG; env->sr |= SR_DSX; env->epcr -= 4; + } else { + env->sr &= ~SR_DSX; } if (cs->exception_index == EXCP_SYSCALL) { env->epcr += 4; } + /* When we have an illegal instruction the error effective address + shall be set to the illegal instruction address. */ + if (cs->exception_index == EXCP_ILLEGAL) { + env->eear = env->pc; + } /* For machine-state changed between user-mode and supervisor mode, we need flush TLB when we enter&exit EXCP. */ From 930c3d0074ad0a5e26560f2133f82d803369bec3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 18 Feb 2015 22:19:18 -0800 Subject: [PATCH 06/24] target/openrisc: Implement lwa, swa Signed-off-by: Richard Henderson --- target/openrisc/cpu.c | 1 + target/openrisc/cpu.h | 3 ++ target/openrisc/interrupt.c | 1 + target/openrisc/interrupt_helper.c | 1 + target/openrisc/machine.c | 24 ++++++++----- target/openrisc/mmu.c | 1 + target/openrisc/translate.c | 58 ++++++++++++++++++++++++++++++ 7 files changed, 81 insertions(+), 8 deletions(-) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 422139d29f..7fd2b9a216 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -48,6 +48,7 @@ static void openrisc_cpu_reset(CPUState *s) cpu->env.pc = 0x100; cpu->env.sr = SR_FO | SR_SM; + cpu->env.lock_addr = -1; s->exception_index = -1; cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP; diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index 231c163617..06d0e897d8 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -296,6 +296,9 @@ typedef struct CPUOpenRISCState { uint32_t fpcsr; /* Float register */ float_status fp_status; + target_ulong lock_addr; + target_ulong lock_value; + uint32_t flags; /* cpu_flags, we only use it for exception in solt so far. */ uint32_t btaken; /* the SR_F bit */ diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index a243eb2751..a98163832e 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -62,6 +62,7 @@ void openrisc_cpu_do_interrupt(CPUState *cs) env->sr &= ~SR_TEE; env->tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu; env->tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu; + env->lock_addr = -1; if (cs->exception_index > 0 && cs->exception_index < EXCP_NR) { env->pc = (cs->exception_index << 8); diff --git a/target/openrisc/interrupt_helper.c b/target/openrisc/interrupt_helper.c index 0ed5146e8d..a6d4df3ce2 100644 --- a/target/openrisc/interrupt_helper.c +++ b/target/openrisc/interrupt_helper.c @@ -34,6 +34,7 @@ void HELPER(rfe)(CPUOpenRISCState *env) cpu->env.pc = cpu->env.epcr; cpu->env.npc = cpu->env.epcr; cpu->env.sr = cpu->env.esr; + cpu->env.lock_addr = -1; #ifndef CONFIG_USER_ONLY if (cpu->env.sr & SR_DME) { diff --git a/target/openrisc/machine.c b/target/openrisc/machine.c index 17b0c77d6c..d0b47ef1d9 100644 --- a/target/openrisc/machine.c +++ b/target/openrisc/machine.c @@ -26,18 +26,26 @@ static const VMStateDescription vmstate_env = { .name = "env", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(gpr, CPUOpenRISCState, 32), + VMSTATE_UINTTL_ARRAY(gpr, CPUOpenRISCState, 32), + VMSTATE_UINTTL(pc, CPUOpenRISCState), + VMSTATE_UINTTL(npc, CPUOpenRISCState), + VMSTATE_UINTTL(ppc, CPUOpenRISCState), + VMSTATE_UINTTL(jmp_pc, CPUOpenRISCState), + VMSTATE_UINTTL(lock_addr, CPUOpenRISCState), + VMSTATE_UINTTL(lock_value, CPUOpenRISCState), + VMSTATE_UINTTL(epcr, CPUOpenRISCState), + VMSTATE_UINTTL(eear, CPUOpenRISCState), VMSTATE_UINT32(sr, CPUOpenRISCState), - VMSTATE_UINT32(epcr, CPUOpenRISCState), - VMSTATE_UINT32(eear, CPUOpenRISCState), + VMSTATE_UINT32(vr, CPUOpenRISCState), + VMSTATE_UINT32(upr, CPUOpenRISCState), + VMSTATE_UINT32(cpucfgr, CPUOpenRISCState), + VMSTATE_UINT32(dmmucfgr, CPUOpenRISCState), + VMSTATE_UINT32(immucfgr, CPUOpenRISCState), VMSTATE_UINT32(esr, CPUOpenRISCState), VMSTATE_UINT32(fpcsr, CPUOpenRISCState), - VMSTATE_UINT32(pc, CPUOpenRISCState), - VMSTATE_UINT32(npc, CPUOpenRISCState), - VMSTATE_UINT32(ppc, CPUOpenRISCState), VMSTATE_END_OF_LIST() } }; diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c index 505dcdcdc8..56b11d3d68 100644 --- a/target/openrisc/mmu.c +++ b/target/openrisc/mmu.c @@ -174,6 +174,7 @@ static void cpu_openrisc_raise_mmu_exception(OpenRISCCPU *cpu, cs->exception_index = exception; cpu->env.eear = address; + cpu->env.lock_addr = -1; } #ifndef CONFIG_USER_ONLY diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 03fa7db570..c207875fe6 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -61,6 +61,8 @@ static TCGv jmp_pc; /* l.jr/l.jalr temp pc */ static TCGv cpu_npc; static TCGv cpu_ppc; static TCGv_i32 env_btaken; /* bf/bnf , F flag taken */ +static TCGv cpu_lock_addr; +static TCGv cpu_lock_value; static TCGv_i32 fpcsr; static TCGv machi, maclo; static TCGv fpmaddhi, fpmaddlo; @@ -95,6 +97,12 @@ void openrisc_translate_init(void) env_btaken = tcg_global_mem_new_i32(cpu_env, offsetof(CPUOpenRISCState, btaken), "btaken"); + cpu_lock_addr = tcg_global_mem_new(cpu_env, + offsetof(CPUOpenRISCState, lock_addr), + "lock_addr"); + cpu_lock_value = tcg_global_mem_new(cpu_env, + offsetof(CPUOpenRISCState, lock_value), + "lock_value"); fpcsr = tcg_global_mem_new_i32(cpu_env, offsetof(CPUOpenRISCState, fpcsr), "fpcsr"); @@ -265,6 +273,46 @@ static void gen_jump(DisasContext *dc, uint32_t imm, uint32_t reg, uint32_t op0) } +static void gen_lwa(DisasContext *dc, TCGv rd, TCGv ra, int32_t ofs) +{ + TCGv ea = tcg_temp_new(); + + tcg_gen_addi_tl(ea, ra, ofs); + tcg_gen_qemu_ld_tl(rd, ea, dc->mem_idx, MO_TEUL); + tcg_gen_mov_tl(cpu_lock_addr, ea); + tcg_gen_mov_tl(cpu_lock_value, rd); + tcg_temp_free(ea); +} + +static void gen_swa(DisasContext *dc, TCGv rb, TCGv ra, int32_t ofs) +{ + TCGv ea, val; + TCGLabel *lab_fail, *lab_done; + + ea = tcg_temp_new(); + tcg_gen_addi_tl(ea, ra, ofs); + + lab_fail = gen_new_label(); + lab_done = gen_new_label(); + tcg_gen_brcond_tl(TCG_COND_NE, ea, cpu_lock_addr, lab_fail); + tcg_temp_free(ea); + + val = tcg_temp_new(); + tcg_gen_atomic_cmpxchg_tl(val, cpu_lock_addr, cpu_lock_value, + rb, dc->mem_idx, MO_TEUL); + tcg_gen_setcond_tl(TCG_COND_EQ, env_btaken, val, cpu_lock_value); + tcg_temp_free(val); + + tcg_gen_br(lab_done); + + gen_set_label(lab_fail); + tcg_gen_movi_tl(env_btaken, 0); + + gen_set_label(lab_done); + tcg_gen_movi_tl(cpu_lock_addr, -1); + wb_SR_F(); +} + static void dec_calc(DisasContext *dc, uint32_t insn) { uint32_t op0, op1, op2; @@ -819,6 +867,11 @@ static void dec_misc(DisasContext *dc, uint32_t insn) } break; + case 0x1b: /* l.lwa */ + LOG_DIS("l.lwa r%d, r%d, %d\n", rd, ra, I16); + gen_lwa(dc, cpu_R[rd], cpu_R[ra], I16); + break; + case 0x1c: /* l.cust1 */ LOG_DIS("l.cust1\n"); break; @@ -1029,6 +1082,11 @@ static void dec_misc(DisasContext *dc, uint32_t insn) } break; + case 0x33: /* l.swa */ + LOG_DIS("l.swa %d, r%d, r%d, %d\n", I5, ra, rb, I11); + gen_swa(dc, cpu_R[rb], cpu_R[ra], sign_extend(tmp, 16)); + break; + /* not used yet, open it when we need or64. */ /*#ifdef TARGET_OPENRISC64 case 0x34: l.sd From 111ece5133e1f301c43545e9400cbb2f121c0cc3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 18 Feb 2015 16:27:45 -0800 Subject: [PATCH 07/24] target/openrisc: Tidy insn dumping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoids warnings from unused variables etc. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Bastian Koppelmann Signed-off-by: Richard Henderson --- target/openrisc/translate.c | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index c207875fe6..ac0c409607 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -34,14 +34,8 @@ #include "trace-tcg.h" #include "exec/log.h" - -#define OPENRISC_DISAS - -#ifdef OPENRISC_DISAS -# define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) -#else -# define LOG_DIS(...) do { } while (0) -#endif +#define LOG_DIS(str, ...) \ + qemu_log_mask(CPU_LOG_TB_IN_ASM, "%08x: " str, dc->pc, ## __VA_ARGS__) typedef struct DisasContext { TranslationBlock *tb; @@ -766,9 +760,7 @@ static void dec_misc(DisasContext *dc, uint32_t insn) { uint32_t op0, op1; uint32_t ra, rb, rd; -#ifdef OPENRISC_DISAS uint32_t L6, K5; -#endif uint32_t I16, I5, I11, N26, tmp; TCGMemOp mop; @@ -777,10 +769,8 @@ static void dec_misc(DisasContext *dc, uint32_t insn) ra = extract32(insn, 16, 5); rb = extract32(insn, 11, 5); rd = extract32(insn, 21, 5); -#ifdef OPENRISC_DISAS L6 = extract32(insn, 5, 6); K5 = extract32(insn, 0, 5); -#endif I16 = extract32(insn, 0, 16); I5 = extract32(insn, 21, 5); I11 = extract32(insn, 0, 11); @@ -1387,13 +1377,10 @@ static void dec_compi(DisasContext *dc, uint32_t insn) static void dec_sys(DisasContext *dc, uint32_t insn) { uint32_t op0; -#ifdef OPENRISC_DISAS uint32_t K16; -#endif + op0 = extract32(insn, 16, 10); -#ifdef OPENRISC_DISAS K16 = extract32(insn, 0, 16); -#endif switch (op0) { case 0x000: /* l.sys */ @@ -1723,6 +1710,13 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb) max_insns = TCG_MAX_INSNS; } + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) + && qemu_log_in_addr_range(pc_start)) { + qemu_log_lock(); + qemu_log("----------------\n"); + qemu_log("IN: %s\n", lookup_symbol(pc_start)); + } + gen_tb_start(tb); do { @@ -1807,18 +1801,12 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb) tb->size = dc->pc - pc_start; tb->icount = num_insns; -#ifdef DEBUG_DISAS if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) && qemu_log_in_addr_range(pc_start)) { - qemu_log_lock(); - qemu_log("----------------\n"); - qemu_log("IN: %s\n", lookup_symbol(pc_start)); - log_target_disas(cs, pc_start, dc->pc - pc_start, 0); - qemu_log("\nisize=%d osize=%d\n", - dc->pc - pc_start, tcg_op_buf_count()); + log_target_disas(cs, pc_start, tb->size, 0); + qemu_log("\n"); qemu_log_unlock(); } -#endif } void openrisc_cpu_dump_state(CPUState *cs, FILE *f, From 6da544a6c4572ed11931218e940f45d00b1fe3a7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 26 Jan 2017 17:35:09 -0800 Subject: [PATCH 08/24] target/openrisc: Rationalize immediate extraction The architecture manual is consistent in using "I" for signed fields and "K" for unsigned fields. Mirror that. Reviewed-by: Bastian Koppelmann Signed-off-by: Richard Henderson --- target/openrisc/translate.c | 98 +++++++++++++++---------------------- 1 file changed, 40 insertions(+), 58 deletions(-) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index ac0c409607..d999d2f478 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -129,23 +129,6 @@ static inline void wb_SR_F(void) gen_set_label(label); } -static inline int zero_extend(unsigned int val, int width) -{ - return val & ((1 << width) - 1); -} - -static inline int sign_extend(unsigned int val, int width) -{ - int sval; - - /* LSL */ - val <<= TARGET_LONG_BITS - width; - sval = val; - /* ASR. */ - sval >>= TARGET_LONG_BITS - width; - return sval; -} - static inline void gen_sync_flags(DisasContext *dc) { /* Sync the tb dependent flag between translate and runtime. */ @@ -221,11 +204,9 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) } } -static void gen_jump(DisasContext *dc, uint32_t imm, uint32_t reg, uint32_t op0) +static void gen_jump(DisasContext *dc, int32_t n26, uint32_t reg, uint32_t op0) { - target_ulong tmp_pc; - /* N26, 26bits imm */ - tmp_pc = sign_extend((imm<<2), 26) + dc->pc; + target_ulong tmp_pc = dc->pc + n26 * 4; switch (op0) { case 0x00: /* l.j */ @@ -760,8 +741,8 @@ static void dec_misc(DisasContext *dc, uint32_t insn) { uint32_t op0, op1; uint32_t ra, rb, rd; - uint32_t L6, K5; - uint32_t I16, I5, I11, N26, tmp; + uint32_t L6, K5, K16, K5_11; + int32_t I16, I5_11, N26; TCGMemOp mop; op0 = extract32(insn, 26, 6); @@ -771,11 +752,11 @@ static void dec_misc(DisasContext *dc, uint32_t insn) rd = extract32(insn, 21, 5); L6 = extract32(insn, 5, 6); K5 = extract32(insn, 0, 5); - I16 = extract32(insn, 0, 16); - I5 = extract32(insn, 21, 5); - I11 = extract32(insn, 0, 11); - N26 = extract32(insn, 0, 26); - tmp = (I5<<11) + I11; + K16 = extract32(insn, 0, 16); + I16 = (int16_t)K16; + N26 = sextract32(insn, 0, 26); + K5_11 = (extract32(insn, 21, 5) << 11) | extract32(insn, 0, 11); + I5_11 = (int16_t)K5_11; switch (op0) { case 0x00: /* l.j */ @@ -821,12 +802,12 @@ static void dec_misc(DisasContext *dc, uint32_t insn) break; case 0x13: /* l.maci */ - LOG_DIS("l.maci %d, r%d, %d\n", I5, ra, I11); + LOG_DIS("l.maci r%d, %d\n", ra, I16); { TCGv_i64 t1 = tcg_temp_new_i64(); TCGv_i64 t2 = tcg_temp_new_i64(); TCGv_i32 dst = tcg_temp_new_i32(); - TCGv ttmp = tcg_const_tl(tmp); + TCGv ttmp = tcg_const_tl(I16); tcg_gen_mul_tl(dst, cpu_R[ra], ttmp); tcg_gen_ext_i32_i64(t1, dst); tcg_gen_concat_i32_i64(t2, maclo, machi); @@ -936,7 +917,7 @@ static void dec_misc(DisasContext *dc, uint32_t insn) do_load: { TCGv t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16)); + tcg_gen_addi_tl(t0, cpu_R[ra], I16); tcg_gen_qemu_ld_tl(cpu_R[rd], t0, dc->mem_idx, mop); tcg_temp_free(t0); } @@ -954,7 +935,7 @@ static void dec_misc(DisasContext *dc, uint32_t insn) TCGv_i32 res = tcg_temp_local_new_i32(); TCGv_i32 sr_ove = tcg_temp_local_new_i32(); tcg_gen_extu_i32_i64(ta, cpu_R[ra]); - tcg_gen_addi_i64(td, ta, sign_extend(I16, 16)); + tcg_gen_addi_i64(td, ta, I16); tcg_gen_extrl_i64_i32(res, td); tcg_gen_shri_i64(td, td, 32); tcg_gen_andi_i64(td, td, 0x3); @@ -989,7 +970,7 @@ static void dec_misc(DisasContext *dc, uint32_t insn) tcg_gen_andi_i32(sr_cy, cpu_sr, SR_CY); tcg_gen_shri_i32(sr_cy, sr_cy, 10); tcg_gen_extu_i32_i64(tcy, sr_cy); - tcg_gen_addi_i64(td, ta, sign_extend(I16, 16)); + tcg_gen_addi_i64(td, ta, I16); tcg_gen_add_i64(td, td, tcy); tcg_gen_extrl_i64_i32(res, td); tcg_gen_shri_i64(td, td, 32); @@ -1013,18 +994,18 @@ static void dec_misc(DisasContext *dc, uint32_t insn) break; case 0x29: /* l.andi */ - LOG_DIS("l.andi r%d, r%d, %d\n", rd, ra, I16); - tcg_gen_andi_tl(cpu_R[rd], cpu_R[ra], zero_extend(I16, 16)); + LOG_DIS("l.andi r%d, r%d, %d\n", rd, ra, K16); + tcg_gen_andi_tl(cpu_R[rd], cpu_R[ra], K16); break; case 0x2a: /* l.ori */ - LOG_DIS("l.ori r%d, r%d, %d\n", rd, ra, I16); - tcg_gen_ori_tl(cpu_R[rd], cpu_R[ra], zero_extend(I16, 16)); + LOG_DIS("l.ori r%d, r%d, %d\n", rd, ra, K16); + tcg_gen_ori_tl(cpu_R[rd], cpu_R[ra], K16); break; case 0x2b: /* l.xori */ LOG_DIS("l.xori r%d, r%d, %d\n", rd, ra, I16); - tcg_gen_xori_tl(cpu_R[rd], cpu_R[ra], sign_extend(I16, 16)); + tcg_gen_xori_tl(cpu_R[rd], cpu_R[ra], I16); break; case 0x2c: /* l.muli */ @@ -1039,12 +1020,12 @@ static void dec_misc(DisasContext *dc, uint32_t insn) break; case 0x2d: /* l.mfspr */ - LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16); + LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, K16); { #if defined(CONFIG_USER_ONLY) return; #else - TCGv_i32 ti = tcg_const_i32(I16); + TCGv_i32 ti = tcg_const_i32(K16); if (dc->mem_idx == MMU_USER_IDX) { gen_illegal_exception(dc); return; @@ -1056,12 +1037,12 @@ static void dec_misc(DisasContext *dc, uint32_t insn) break; case 0x30: /* l.mtspr */ - LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11); + LOG_DIS("l.mtspr r%d, r%d, %d\n", ra, rb, K5_11); { #if defined(CONFIG_USER_ONLY) return; #else - TCGv_i32 im = tcg_const_i32(tmp); + TCGv_i32 im = tcg_const_i32(K5_11); if (dc->mem_idx == MMU_USER_IDX) { gen_illegal_exception(dc); return; @@ -1073,38 +1054,38 @@ static void dec_misc(DisasContext *dc, uint32_t insn) break; case 0x33: /* l.swa */ - LOG_DIS("l.swa %d, r%d, r%d, %d\n", I5, ra, rb, I11); - gen_swa(dc, cpu_R[rb], cpu_R[ra], sign_extend(tmp, 16)); + LOG_DIS("l.swa r%d, r%d, %d\n", ra, rb, I5_11); + gen_swa(dc, cpu_R[rb], cpu_R[ra], I5_11); break; /* not used yet, open it when we need or64. */ /*#ifdef TARGET_OPENRISC64 case 0x34: l.sd - LOG_DIS("l.sd %d, r%d, r%d, %d\n", I5, ra, rb, I11); + LOG_DIS("l.sd r%d, r%d, %d\n", ra, rb, I5_11); check_ob64s(dc); mop = MO_TEQ; goto do_store; #endif*/ case 0x35: /* l.sw */ - LOG_DIS("l.sw %d, r%d, r%d, %d\n", I5, ra, rb, I11); + LOG_DIS("l.sw r%d, r%d, %d\n", ra, rb, I5_11); mop = MO_TEUL; goto do_store; case 0x36: /* l.sb */ - LOG_DIS("l.sb %d, r%d, r%d, %d\n", I5, ra, rb, I11); + LOG_DIS("l.sb r%d, r%d, %d\n", ra, rb, I5_11); mop = MO_UB; goto do_store; case 0x37: /* l.sh */ - LOG_DIS("l.sh %d, r%d, r%d, %d\n", I5, ra, rb, I11); + LOG_DIS("l.sh r%d, r%d, %d\n", ra, rb, I5_11); mop = MO_TEUW; goto do_store; do_store: { TCGv t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(tmp, 16)); + tcg_gen_addi_tl(t0, cpu_R[ra], I5_11); tcg_gen_qemu_st_tl(cpu_R[rb], t0, dc->mem_idx, mop); tcg_temp_free(t0); } @@ -1172,30 +1153,32 @@ static void dec_mac(DisasContext *dc, uint32_t insn) static void dec_logic(DisasContext *dc, uint32_t insn) { uint32_t op0; - uint32_t rd, ra, L6; + uint32_t rd, ra, L6, S6; op0 = extract32(insn, 6, 2); rd = extract32(insn, 21, 5); ra = extract32(insn, 16, 5); L6 = extract32(insn, 0, 6); + S6 = L6 & (TARGET_LONG_BITS - 1); switch (op0) { case 0x00: /* l.slli */ LOG_DIS("l.slli r%d, r%d, %d\n", rd, ra, L6); - tcg_gen_shli_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f)); + tcg_gen_shli_tl(cpu_R[rd], cpu_R[ra], S6); break; case 0x01: /* l.srli */ LOG_DIS("l.srli r%d, r%d, %d\n", rd, ra, L6); - tcg_gen_shri_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f)); + tcg_gen_shri_tl(cpu_R[rd], cpu_R[ra], S6); break; case 0x02: /* l.srai */ LOG_DIS("l.srai r%d, r%d, %d\n", rd, ra, L6); - tcg_gen_sari_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f)); break; + tcg_gen_sari_tl(cpu_R[rd], cpu_R[ra], S6); + break; case 0x03: /* l.rori */ LOG_DIS("l.rori r%d, r%d, %d\n", rd, ra, L6); - tcg_gen_rotri_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f)); + tcg_gen_rotri_tl(cpu_R[rd], cpu_R[ra], S6); break; default: @@ -1306,15 +1289,14 @@ static void dec_comp(DisasContext *dc, uint32_t insn) static void dec_compi(DisasContext *dc, uint32_t insn) { - uint32_t op0; - uint32_t ra, I16; + uint32_t op0, ra; + int32_t I16; op0 = extract32(insn, 21, 5); ra = extract32(insn, 16, 5); - I16 = extract32(insn, 0, 16); + I16 = sextract32(insn, 0, 16); tcg_gen_movi_i32(env_btaken, 0x0); - I16 = sign_extend(I16, 16); switch (op0) { case 0x0: /* l.sfeqi */ From 9ecaa27e7123211f45ca723a736ffae14f6c1f42 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Apr 2015 13:31:50 -0700 Subject: [PATCH 09/24] target/openrisc: Streamline arithmetic and OVE Fix incorrect overflow calculation. Move overflow exception check to a helper function, to eliminate inline branches. Remove some incorrect special casing of R0. Implement multiply inline. Reviewed-by: Bastian Koppelmann Signed-off-by: Richard Henderson --- target/openrisc/Makefile.objs | 2 +- target/openrisc/exception_helper.c | 12 + target/openrisc/helper.h | 4 +- target/openrisc/int_helper.c | 61 ----- target/openrisc/translate.c | 426 ++++++++++++----------------- 5 files changed, 191 insertions(+), 314 deletions(-) delete mode 100644 target/openrisc/int_helper.c diff --git a/target/openrisc/Makefile.objs b/target/openrisc/Makefile.objs index 397d01650e..918b1c6e9c 100644 --- a/target/openrisc/Makefile.objs +++ b/target/openrisc/Makefile.objs @@ -1,5 +1,5 @@ obj-$(CONFIG_SOFTMMU) += machine.o obj-y += cpu.o exception.o interrupt.o mmu.o translate.o -obj-y += exception_helper.o fpu_helper.o int_helper.o \ +obj-y += exception_helper.o fpu_helper.o \ interrupt_helper.o mmu_helper.o sys_helper.o obj-y += gdbstub.o diff --git a/target/openrisc/exception_helper.c b/target/openrisc/exception_helper.c index 329a9e400b..7e54c978be 100644 --- a/target/openrisc/exception_helper.c +++ b/target/openrisc/exception_helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" +#include "exec/exec-all.h" #include "exception.h" void HELPER(exception)(CPUOpenRISCState *env, uint32_t excp) @@ -28,3 +29,14 @@ void HELPER(exception)(CPUOpenRISCState *env, uint32_t excp) raise_exception(cpu, excp); } + +void HELPER(ove)(CPUOpenRISCState *env, target_ulong test) +{ + if (unlikely(test) && (env->sr & SR_OVE)) { + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); + CPUState *cs = CPU(cpu); + + cs->exception_index = EXCP_RANGE; + cpu_loop_exit_restore(cs, GETPC()); + } +} diff --git a/target/openrisc/helper.h b/target/openrisc/helper.h index bcc7245fc3..c2c8098243 100644 --- a/target/openrisc/helper.h +++ b/target/openrisc/helper.h @@ -19,6 +19,7 @@ /* exception */ DEF_HELPER_FLAGS_2(exception, 0, void, env, i32) +DEF_HELPER_FLAGS_2(ove, TCG_CALL_NO_WG, void, env, tl) /* float */ DEF_HELPER_FLAGS_2(itofd, 0, i64, env, i64) @@ -53,9 +54,6 @@ FOP_CMP(gt) FOP_CMP(ge) #undef FOP_CMP -/* int */ -DEF_HELPER_FLAGS_3(mul32, 0, i32, env, i32, i32) - /* interrupt */ DEF_HELPER_FLAGS_1(rfe, 0, void, env) diff --git a/target/openrisc/int_helper.c b/target/openrisc/int_helper.c deleted file mode 100644 index ba0fd277cd..0000000000 --- a/target/openrisc/int_helper.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * OpenRISC int helper routines - * - * Copyright (c) 2011-2012 Jia Liu - * Feng Gao - * - * 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 . - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" -#include "exception.h" -#include "qemu/host-utils.h" - -uint32_t HELPER(mul32)(CPUOpenRISCState *env, - uint32_t ra, uint32_t rb) -{ - uint64_t result; - uint32_t high, cy; - - OpenRISCCPU *cpu = openrisc_env_get_cpu(env); - - result = (uint64_t)ra * rb; - /* regisiers in or32 is 32bit, so 32 is NOT a magic number. - or64 is not handled in this function, and not implement yet, - TARGET_LONG_BITS for or64 is 64, it will break this function, - so, we didn't use TARGET_LONG_BITS here. */ - high = result >> 32; - cy = result >> (32 - 1); - - if ((cy & 0x1) == 0x0) { - if (high == 0x0) { - return result; - } - } - - if ((cy & 0x1) == 0x1) { - if (high == 0xffffffff) { - return result; - } - } - - cpu->env.sr |= (SR_OV | SR_CY); - if (cpu->env.sr & SR_OVE) { - raise_exception(cpu, EXCP_RANGE); - } - - return result; -} diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index d999d2f478..7c6cd1c1db 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -247,6 +247,166 @@ static void gen_jump(DisasContext *dc, int32_t n26, uint32_t reg, uint32_t op0) gen_sync_flags(dc); } +static void gen_ove_cy(DisasContext *dc, TCGv cy) +{ + gen_helper_ove(cpu_env, cy); +} + +static void gen_ove_ov(DisasContext *dc, TCGv ov) +{ + gen_helper_ove(cpu_env, ov); +} + +static void gen_ove_cyov(DisasContext *dc, TCGv cy, TCGv ov) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_or_tl(t0, cy, ov); + gen_helper_ove(cpu_env, t0); + tcg_temp_free(t0); +} + +static void gen_add(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) +{ + TCGv t0 = tcg_const_tl(0); + TCGv res = tcg_temp_new(); + TCGv sr_cy = tcg_temp_new(); + TCGv sr_ov = tcg_temp_new(); + + tcg_gen_add2_tl(res, sr_cy, srca, t0, srcb, t0); + tcg_gen_xor_tl(sr_ov, srca, srcb); + tcg_gen_xor_tl(t0, res, srcb); + tcg_gen_andc_tl(sr_ov, t0, sr_ov); + tcg_temp_free(t0); + + tcg_gen_mov_tl(dest, res); + tcg_temp_free(res); + + tcg_gen_shri_tl(sr_ov, sr_ov, TARGET_LONG_BITS - 1); + tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_cy, ctz32(SR_CY), 1); + tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_ov, ctz32(SR_OV), 1); + + gen_ove_cyov(dc, sr_ov, sr_cy); + tcg_temp_free(sr_ov); + tcg_temp_free(sr_cy); +} + +static void gen_addc(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) +{ + TCGv t0 = tcg_const_tl(0); + TCGv res = tcg_temp_new(); + TCGv sr_cy = tcg_temp_new(); + TCGv sr_ov = tcg_temp_new(); + + tcg_gen_shri_tl(sr_cy, cpu_sr, ctz32(SR_CY)); + tcg_gen_andi_tl(sr_cy, sr_cy, 1); + + tcg_gen_add2_tl(res, sr_cy, srca, t0, sr_cy, t0); + tcg_gen_add2_tl(res, sr_cy, res, sr_cy, srcb, t0); + tcg_gen_xor_tl(sr_ov, srca, srcb); + tcg_gen_xor_tl(t0, res, srcb); + tcg_gen_andc_tl(sr_ov, t0, sr_ov); + tcg_temp_free(t0); + + tcg_gen_mov_tl(dest, res); + tcg_temp_free(res); + + tcg_gen_shri_tl(sr_ov, sr_ov, TARGET_LONG_BITS - 1); + tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_cy, ctz32(SR_CY), 1); + tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_ov, ctz32(SR_OV), 1); + + gen_ove_cyov(dc, sr_ov, sr_cy); + tcg_temp_free(sr_ov); + tcg_temp_free(sr_cy); +} + +static void gen_sub(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) +{ + TCGv res = tcg_temp_new(); + TCGv sr_cy = tcg_temp_new(); + TCGv sr_ov = tcg_temp_new(); + + tcg_gen_sub_tl(res, srca, srcb); + tcg_gen_xor_tl(sr_cy, srca, srcb); + tcg_gen_xor_tl(sr_ov, res, srcb); + tcg_gen_and_tl(sr_ov, sr_ov, sr_cy); + tcg_gen_setcond_tl(TCG_COND_LTU, sr_cy, srca, srcb); + + tcg_gen_mov_tl(dest, res); + tcg_temp_free(res); + + tcg_gen_shri_tl(sr_ov, sr_ov, TARGET_LONG_BITS - 1); + tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_cy, ctz32(SR_CY), 1); + tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_ov, ctz32(SR_OV), 1); + + gen_ove_cyov(dc, sr_ov, sr_cy); + tcg_temp_free(sr_ov); + tcg_temp_free(sr_cy); +} + +static void gen_mul(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) +{ + TCGv sr_ov = tcg_temp_new(); + TCGv t0 = tcg_temp_new(); + + tcg_gen_muls2_tl(dest, sr_ov, srca, srcb); + tcg_gen_sari_tl(t0, dest, TARGET_LONG_BITS - 1); + tcg_gen_setcond_tl(TCG_COND_NE, sr_ov, sr_ov, t0); + tcg_temp_free(t0); + + tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_ov, ctz32(SR_OV), 1); + + gen_ove_ov(dc, sr_ov); + tcg_temp_free(sr_ov); +} + +static void gen_mulu(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) +{ + TCGv sr_cy = tcg_temp_new(); + + tcg_gen_muls2_tl(dest, sr_cy, srca, srcb); + tcg_gen_setcondi_tl(TCG_COND_NE, sr_cy, sr_cy, 0); + + tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_cy, ctz32(SR_CY), 1); + + gen_ove_cy(dc, sr_cy); + tcg_temp_free(sr_cy); +} + +static void gen_div(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) +{ + TCGv sr_ov = tcg_temp_new(); + TCGv t0 = tcg_temp_new(); + + tcg_gen_setcondi_tl(TCG_COND_EQ, sr_ov, srcb, 0); + /* The result of divide-by-zero is undefined. + Supress the host-side exception by dividing by 1. */ + tcg_gen_or_tl(t0, srcb, sr_ov); + tcg_gen_div_tl(dest, srca, t0); + tcg_temp_free(t0); + + tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_ov, ctz32(SR_OV), 1); + + gen_ove_ov(dc, sr_ov); + tcg_temp_free(sr_ov); +} + +static void gen_divu(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) +{ + TCGv sr_cy = tcg_temp_new(); + TCGv t0 = tcg_temp_new(); + + tcg_gen_setcondi_tl(TCG_COND_EQ, sr_cy, srcb, 0); + /* The result of divide-by-zero is undefined. + Supress the host-side exception by dividing by 1. */ + tcg_gen_or_tl(t0, srcb, sr_cy); + tcg_gen_divu_tl(dest, srca, t0); + tcg_temp_free(t0); + + tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_cy, ctz32(SR_CY), 1); + + gen_ove_cy(dc, sr_cy); + tcg_temp_free(sr_cy); +} static void gen_lwa(DisasContext *dc, TCGv rd, TCGv ra, int32_t ofs) { @@ -304,34 +464,7 @@ static void dec_calc(DisasContext *dc, uint32_t insn) switch (op1) { case 0x00: /* l.add */ LOG_DIS("l.add r%d, r%d, r%d\n", rd, ra, rb); - { - TCGLabel *lab = gen_new_label(); - TCGv_i64 ta = tcg_temp_new_i64(); - TCGv_i64 tb = tcg_temp_new_i64(); - TCGv_i64 td = tcg_temp_local_new_i64(); - TCGv_i32 res = tcg_temp_local_new_i32(); - TCGv_i32 sr_ove = tcg_temp_local_new_i32(); - tcg_gen_extu_i32_i64(ta, cpu_R[ra]); - tcg_gen_extu_i32_i64(tb, cpu_R[rb]); - tcg_gen_add_i64(td, ta, tb); - tcg_gen_extrl_i64_i32(res, td); - tcg_gen_shri_i64(td, td, 31); - tcg_gen_andi_i64(td, td, 0x3); - /* Jump to lab when no overflow. */ - tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); - tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); - tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); - tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); - tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); - gen_exception(dc, EXCP_RANGE); - gen_set_label(lab); - tcg_gen_mov_i32(cpu_R[rd], res); - tcg_temp_free_i64(ta); - tcg_temp_free_i64(tb); - tcg_temp_free_i64(td); - tcg_temp_free_i32(res); - tcg_temp_free_i32(sr_ove); - } + gen_add(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; default: gen_illegal_exception(dc); @@ -343,42 +476,7 @@ static void dec_calc(DisasContext *dc, uint32_t insn) switch (op1) { case 0x00: LOG_DIS("l.addc r%d, r%d, r%d\n", rd, ra, rb); - { - TCGLabel *lab = gen_new_label(); - TCGv_i64 ta = tcg_temp_new_i64(); - TCGv_i64 tb = tcg_temp_new_i64(); - TCGv_i64 tcy = tcg_temp_local_new_i64(); - TCGv_i64 td = tcg_temp_local_new_i64(); - TCGv_i32 res = tcg_temp_local_new_i32(); - TCGv_i32 sr_cy = tcg_temp_local_new_i32(); - TCGv_i32 sr_ove = tcg_temp_local_new_i32(); - tcg_gen_extu_i32_i64(ta, cpu_R[ra]); - tcg_gen_extu_i32_i64(tb, cpu_R[rb]); - tcg_gen_andi_i32(sr_cy, cpu_sr, SR_CY); - tcg_gen_extu_i32_i64(tcy, sr_cy); - tcg_gen_shri_i64(tcy, tcy, 10); - tcg_gen_add_i64(td, ta, tb); - tcg_gen_add_i64(td, td, tcy); - tcg_gen_extrl_i64_i32(res, td); - tcg_gen_shri_i64(td, td, 32); - tcg_gen_andi_i64(td, td, 0x3); - /* Jump to lab when no overflow. */ - tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); - tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); - tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); - tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); - tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); - gen_exception(dc, EXCP_RANGE); - gen_set_label(lab); - tcg_gen_mov_i32(cpu_R[rd], res); - tcg_temp_free_i64(ta); - tcg_temp_free_i64(tb); - tcg_temp_free_i64(tcy); - tcg_temp_free_i64(td); - tcg_temp_free_i32(res); - tcg_temp_free_i32(sr_cy); - tcg_temp_free_i32(sr_ove); - } + gen_addc(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; default: gen_illegal_exception(dc); @@ -390,35 +488,7 @@ static void dec_calc(DisasContext *dc, uint32_t insn) switch (op1) { case 0x00: LOG_DIS("l.sub r%d, r%d, r%d\n", rd, ra, rb); - { - TCGLabel *lab = gen_new_label(); - TCGv_i64 ta = tcg_temp_new_i64(); - TCGv_i64 tb = tcg_temp_new_i64(); - TCGv_i64 td = tcg_temp_local_new_i64(); - TCGv_i32 res = tcg_temp_local_new_i32(); - TCGv_i32 sr_ove = tcg_temp_local_new_i32(); - - tcg_gen_extu_i32_i64(ta, cpu_R[ra]); - tcg_gen_extu_i32_i64(tb, cpu_R[rb]); - tcg_gen_sub_i64(td, ta, tb); - tcg_gen_extrl_i64_i32(res, td); - tcg_gen_shri_i64(td, td, 31); - tcg_gen_andi_i64(td, td, 0x3); - /* Jump to lab when no overflow. */ - tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); - tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); - tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); - tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); - tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); - gen_exception(dc, EXCP_RANGE); - gen_set_label(lab); - tcg_gen_mov_i32(cpu_R[rd], res); - tcg_temp_free_i64(ta); - tcg_temp_free_i64(tb); - tcg_temp_free_i64(td); - tcg_temp_free_i32(res); - tcg_temp_free_i32(sr_ove); - } + gen_sub(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; default: gen_illegal_exception(dc); @@ -466,11 +536,7 @@ static void dec_calc(DisasContext *dc, uint32_t insn) switch (op1) { case 0x03: /* l.mul */ LOG_DIS("l.mul r%d, r%d, r%d\n", rd, ra, rb); - if (ra != 0 && rb != 0) { - gen_helper_mul32(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); - } else { - tcg_gen_movi_tl(cpu_R[rd], 0x0); - } + gen_mul(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; default: gen_illegal_exception(dc); @@ -482,36 +548,7 @@ static void dec_calc(DisasContext *dc, uint32_t insn) switch (op1) { case 0x03: /* l.div */ LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb); - { - TCGLabel *lab0 = gen_new_label(); - TCGLabel *lab1 = gen_new_label(); - TCGLabel *lab2 = gen_new_label(); - TCGLabel *lab3 = gen_new_label(); - TCGv_i32 sr_ove = tcg_temp_local_new_i32(); - if (rb == 0) { - tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); - tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); - tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab0); - gen_exception(dc, EXCP_RANGE); - gen_set_label(lab0); - } else { - tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_R[rb], - 0x00000000, lab1); - tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[ra], - 0x80000000, lab2); - tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[rb], - 0xffffffff, lab2); - gen_set_label(lab1); - tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); - tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); - tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab3); - gen_exception(dc, EXCP_RANGE); - gen_set_label(lab2); - tcg_gen_div_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); - gen_set_label(lab3); - } - tcg_temp_free_i32(sr_ove); - } + gen_div(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; default: @@ -524,30 +561,7 @@ static void dec_calc(DisasContext *dc, uint32_t insn) switch (op1) { case 0x03: /* l.divu */ LOG_DIS("l.divu r%d, r%d, r%d\n", rd, ra, rb); - { - TCGLabel *lab0 = gen_new_label(); - TCGLabel *lab1 = gen_new_label(); - TCGLabel *lab2 = gen_new_label(); - TCGv_i32 sr_ove = tcg_temp_local_new_i32(); - if (rb == 0) { - tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); - tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); - tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab0); - gen_exception(dc, EXCP_RANGE); - gen_set_label(lab0); - } else { - tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[rb], - 0x00000000, lab1); - tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); - tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); - tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab2); - gen_exception(dc, EXCP_RANGE); - gen_set_label(lab1); - tcg_gen_divu_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); - gen_set_label(lab2); - } - tcg_temp_free_i32(sr_ove); - } + gen_divu(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; default: @@ -560,34 +574,7 @@ static void dec_calc(DisasContext *dc, uint32_t insn) switch (op1) { case 0x03: /* l.mulu */ LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb); - if (rb != 0 && ra != 0) { - TCGv_i64 result = tcg_temp_local_new_i64(); - TCGv_i64 tra = tcg_temp_local_new_i64(); - TCGv_i64 trb = tcg_temp_local_new_i64(); - TCGv_i64 high = tcg_temp_new_i64(); - TCGv_i32 sr_ove = tcg_temp_local_new_i32(); - TCGLabel *lab = gen_new_label(); - /* Calculate each result. */ - tcg_gen_extu_i32_i64(tra, cpu_R[ra]); - tcg_gen_extu_i32_i64(trb, cpu_R[rb]); - tcg_gen_mul_i64(result, tra, trb); - tcg_temp_free_i64(tra); - tcg_temp_free_i64(trb); - tcg_gen_shri_i64(high, result, TARGET_LONG_BITS); - /* Overflow or not. */ - tcg_gen_brcondi_i64(TCG_COND_EQ, high, 0x00000000, lab); - tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY)); - tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE); - tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab); - gen_exception(dc, EXCP_RANGE); - gen_set_label(lab); - tcg_temp_free_i64(high); - tcg_gen_trunc_i64_tl(cpu_R[rd], result); - tcg_temp_free_i64(result); - tcg_temp_free_i32(sr_ove); - } else { - tcg_gen_movi_tl(cpu_R[rd], 0); - } + gen_mulu(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; default: @@ -744,6 +731,7 @@ static void dec_misc(DisasContext *dc, uint32_t insn) uint32_t L6, K5, K16, K5_11; int32_t I16, I5_11, N26; TCGMemOp mop; + TCGv t0; op0 = extract32(insn, 26, 6); op1 = extract32(insn, 24, 2); @@ -925,72 +913,16 @@ static void dec_misc(DisasContext *dc, uint32_t insn) case 0x27: /* l.addi */ LOG_DIS("l.addi r%d, r%d, %d\n", rd, ra, I16); - { - if (I16 == 0) { - tcg_gen_mov_tl(cpu_R[rd], cpu_R[ra]); - } else { - TCGLabel *lab = gen_new_label(); - TCGv_i64 ta = tcg_temp_new_i64(); - TCGv_i64 td = tcg_temp_local_new_i64(); - TCGv_i32 res = tcg_temp_local_new_i32(); - TCGv_i32 sr_ove = tcg_temp_local_new_i32(); - tcg_gen_extu_i32_i64(ta, cpu_R[ra]); - tcg_gen_addi_i64(td, ta, I16); - tcg_gen_extrl_i64_i32(res, td); - tcg_gen_shri_i64(td, td, 32); - tcg_gen_andi_i64(td, td, 0x3); - /* Jump to lab when no overflow. */ - tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); - tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); - tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); - tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); - tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); - gen_exception(dc, EXCP_RANGE); - gen_set_label(lab); - tcg_gen_mov_i32(cpu_R[rd], res); - tcg_temp_free_i64(ta); - tcg_temp_free_i64(td); - tcg_temp_free_i32(res); - tcg_temp_free_i32(sr_ove); - } - } + t0 = tcg_const_tl(I16); + gen_add(dc, cpu_R[rd], cpu_R[ra], t0); + tcg_temp_free(t0); break; case 0x28: /* l.addic */ LOG_DIS("l.addic r%d, r%d, %d\n", rd, ra, I16); - { - TCGLabel *lab = gen_new_label(); - TCGv_i64 ta = tcg_temp_new_i64(); - TCGv_i64 td = tcg_temp_local_new_i64(); - TCGv_i64 tcy = tcg_temp_local_new_i64(); - TCGv_i32 res = tcg_temp_local_new_i32(); - TCGv_i32 sr_cy = tcg_temp_local_new_i32(); - TCGv_i32 sr_ove = tcg_temp_local_new_i32(); - tcg_gen_extu_i32_i64(ta, cpu_R[ra]); - tcg_gen_andi_i32(sr_cy, cpu_sr, SR_CY); - tcg_gen_shri_i32(sr_cy, sr_cy, 10); - tcg_gen_extu_i32_i64(tcy, sr_cy); - tcg_gen_addi_i64(td, ta, I16); - tcg_gen_add_i64(td, td, tcy); - tcg_gen_extrl_i64_i32(res, td); - tcg_gen_shri_i64(td, td, 32); - tcg_gen_andi_i64(td, td, 0x3); - /* Jump to lab when no overflow. */ - tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); - tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); - tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); - tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); - tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); - gen_exception(dc, EXCP_RANGE); - gen_set_label(lab); - tcg_gen_mov_i32(cpu_R[rd], res); - tcg_temp_free_i64(ta); - tcg_temp_free_i64(td); - tcg_temp_free_i64(tcy); - tcg_temp_free_i32(res); - tcg_temp_free_i32(sr_cy); - tcg_temp_free_i32(sr_ove); - } + t0 = tcg_const_tl(I16); + gen_addc(dc, cpu_R[rd], cpu_R[ra], t0); + tcg_temp_free(t0); break; case 0x29: /* l.andi */ @@ -1010,13 +942,9 @@ static void dec_misc(DisasContext *dc, uint32_t insn) case 0x2c: /* l.muli */ LOG_DIS("l.muli r%d, r%d, %d\n", rd, ra, I16); - if (ra != 0 && I16 != 0) { - TCGv_i32 im = tcg_const_i32(I16); - gen_helper_mul32(cpu_R[rd], cpu_env, cpu_R[ra], im); - tcg_temp_free_i32(im); - } else { - tcg_gen_movi_tl(cpu_R[rd], 0x0); - } + t0 = tcg_const_tl(I16); + gen_mul(dc, cpu_R[rd], cpu_R[ra], t0); + tcg_temp_free(t0); break; case 0x2d: /* l.mfspr */ From 0c53d7342b4e8412f3b81eed67f053304813dc5d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 18 Feb 2015 12:34:56 -0800 Subject: [PATCH 10/24] target/openrisc: Put SR[OVE] in TB flags Removes a call at execution time for overflow exceptions. Signed-off-by: Richard Henderson --- target/openrisc/cpu.h | 4 ++-- target/openrisc/exception_helper.c | 2 +- target/openrisc/translate.c | 24 +++++++++++++++--------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index 06d0e897d8..ef90e49a4d 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -400,8 +400,8 @@ static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env, { *pc = env->pc; *cs_base = 0; - /* D_FLAG -- branch instruction exception */ - *flags = (env->flags & D_FLAG); + /* D_FLAG -- branch instruction exception, OVE overflow trap enable. */ + *flags = (env->flags & D_FLAG) | (env->sr & SR_OVE); } static inline int cpu_mmu_index(CPUOpenRISCState *env, bool ifetch) diff --git a/target/openrisc/exception_helper.c b/target/openrisc/exception_helper.c index 7e54c978be..5147da68c4 100644 --- a/target/openrisc/exception_helper.c +++ b/target/openrisc/exception_helper.c @@ -32,7 +32,7 @@ void HELPER(exception)(CPUOpenRISCState *env, uint32_t excp) void HELPER(ove)(CPUOpenRISCState *env, target_ulong test) { - if (unlikely(test) && (env->sr & SR_OVE)) { + if (unlikely(test)) { OpenRISCCPU *cpu = openrisc_env_get_cpu(env); CPUState *cs = CPU(cpu); diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 7c6cd1c1db..b8116bae86 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -132,8 +132,8 @@ static inline void wb_SR_F(void) static inline void gen_sync_flags(DisasContext *dc) { /* Sync the tb dependent flag between translate and runtime. */ - if (dc->tb_flags != dc->synced_flags) { - tcg_gen_movi_tl(env_flags, dc->tb_flags); + if ((dc->tb_flags ^ dc->synced_flags) & D_FLAG) { + tcg_gen_movi_tl(env_flags, dc->tb_flags & D_FLAG); dc->synced_flags = dc->tb_flags; } } @@ -249,20 +249,26 @@ static void gen_jump(DisasContext *dc, int32_t n26, uint32_t reg, uint32_t op0) static void gen_ove_cy(DisasContext *dc, TCGv cy) { - gen_helper_ove(cpu_env, cy); + if (dc->tb_flags & SR_OVE) { + gen_helper_ove(cpu_env, cy); + } } static void gen_ove_ov(DisasContext *dc, TCGv ov) { - gen_helper_ove(cpu_env, ov); + if (dc->tb_flags & SR_OVE) { + gen_helper_ove(cpu_env, ov); + } } static void gen_ove_cyov(DisasContext *dc, TCGv cy, TCGv ov) { - TCGv t0 = tcg_temp_new(); - tcg_gen_or_tl(t0, cy, ov); - gen_helper_ove(cpu_env, t0); - tcg_temp_free(t0); + if (dc->tb_flags & SR_OVE) { + TCGv t0 = tcg_temp_new(); + tcg_gen_or_tl(t0, cy, ov); + gen_helper_ove(cpu_env, t0); + tcg_temp_free(t0); + } } static void gen_add(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) @@ -1606,7 +1612,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb) dc->flags = cpu->env.cpucfgr; dc->mem_idx = cpu_mmu_index(&cpu->env, false); dc->synced_flags = dc->tb_flags = tb->flags; - dc->delayed_branch = !!(dc->tb_flags & D_FLAG); + dc->delayed_branch = (dc->tb_flags & D_FLAG) != 0; dc->singlestep_enabled = cs->singlestep_enabled; next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; From cf2ae4428f320f3d8027a50c1cd45f4b5a6c93bb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 18 Feb 2015 17:41:52 -0800 Subject: [PATCH 11/24] target/openrisc: Invert the decoding in dec_calc Decoding the opcodes in the right order reduces by 100+ lines. Also, it happens to put the opcodes in the same order as Chapter 17. Reviewed-by: Bastian Koppelmann Signed-off-by: Richard Henderson --- target/openrisc/translate.c | 304 ++++++++++++------------------------ 1 file changed, 96 insertions(+), 208 deletions(-) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index b8116bae86..1f3f22c79a 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -465,133 +465,95 @@ static void dec_calc(DisasContext *dc, uint32_t insn) rb = extract32(insn, 11, 5); rd = extract32(insn, 21, 5); - switch (op0) { - case 0x0000: - switch (op1) { - case 0x00: /* l.add */ + switch (op1) { + case 0: + switch (op0) { + case 0x0: /* l.add */ LOG_DIS("l.add r%d, r%d, r%d\n", rd, ra, rb); gen_add(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); - break; - default: - gen_illegal_exception(dc); - break; - } - break; + return; - case 0x0001: /* l.addc */ - switch (op1) { - case 0x00: + case 0x1: /* l.addc */ LOG_DIS("l.addc r%d, r%d, r%d\n", rd, ra, rb); gen_addc(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); - break; - default: - gen_illegal_exception(dc); - break; - } - break; + return; - case 0x0002: /* l.sub */ - switch (op1) { - case 0x00: + case 0x2: /* l.sub */ LOG_DIS("l.sub r%d, r%d, r%d\n", rd, ra, rb); gen_sub(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); - break; - default: - gen_illegal_exception(dc); - break; - } - break; + return; - case 0x0003: /* l.and */ - switch (op1) { - case 0x00: + case 0x3: /* l.and */ LOG_DIS("l.and r%d, r%d, r%d\n", rd, ra, rb); tcg_gen_and_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); - break; - default: - gen_illegal_exception(dc); - break; - } - break; + return; - case 0x0004: /* l.or */ - switch (op1) { - case 0x00: + case 0x4: /* l.or */ LOG_DIS("l.or r%d, r%d, r%d\n", rd, ra, rb); tcg_gen_or_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); - break; - default: - gen_illegal_exception(dc); - break; - } - break; + return; - case 0x0005: - switch (op1) { - case 0x00: /* l.xor */ + case 0x5: /* l.xor */ LOG_DIS("l.xor r%d, r%d, r%d\n", rd, ra, rb); tcg_gen_xor_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); - break; - default: - gen_illegal_exception(dc); - break; - } - break; + return; - case 0x0006: - switch (op1) { - case 0x03: /* l.mul */ - LOG_DIS("l.mul r%d, r%d, r%d\n", rd, ra, rb); - gen_mul(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); - break; - default: - gen_illegal_exception(dc); - break; - } - break; - - case 0x0009: - switch (op1) { - case 0x03: /* l.div */ - LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb); - gen_div(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); + case 0x8: + switch (op2) { + case 0: /* l.sll */ + LOG_DIS("l.sll r%d, r%d, r%d\n", rd, ra, rb); + tcg_gen_shl_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); + return; + case 1: /* l.srl */ + LOG_DIS("l.srl r%d, r%d, r%d\n", rd, ra, rb); + tcg_gen_shr_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); + return; + case 2: /* l.sra */ + LOG_DIS("l.sra r%d, r%d, r%d\n", rd, ra, rb); + tcg_gen_sar_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); + return; + case 3: /* l.ror */ + LOG_DIS("l.ror r%d, r%d, r%d\n", rd, ra, rb); + tcg_gen_rotr_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); + return; + } break; - default: - gen_illegal_exception(dc); - break; - } - break; - - case 0x000a: - switch (op1) { - case 0x03: /* l.divu */ - LOG_DIS("l.divu r%d, r%d, r%d\n", rd, ra, rb); - gen_divu(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); + case 0xc: + switch (op2) { + case 0: /* l.exths */ + LOG_DIS("l.exths r%d, r%d\n", rd, ra); + tcg_gen_ext16s_tl(cpu_R[rd], cpu_R[ra]); + return; + case 1: /* l.extbs */ + LOG_DIS("l.extbs r%d, r%d\n", rd, ra); + tcg_gen_ext8s_tl(cpu_R[rd], cpu_R[ra]); + return; + case 2: /* l.exthz */ + LOG_DIS("l.exthz r%d, r%d\n", rd, ra); + tcg_gen_ext16u_tl(cpu_R[rd], cpu_R[ra]); + return; + case 3: /* l.extbz */ + LOG_DIS("l.extbz r%d, r%d\n", rd, ra); + tcg_gen_ext8u_tl(cpu_R[rd], cpu_R[ra]); + return; + } break; - default: - gen_illegal_exception(dc); - break; - } - break; - - case 0x000b: - switch (op1) { - case 0x03: /* l.mulu */ - LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb); - gen_mulu(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); + case 0xd: + switch (op2) { + case 0: /* l.extws */ + LOG_DIS("l.extws r%d, r%d\n", rd, ra); + tcg_gen_ext32s_tl(cpu_R[rd], cpu_R[ra]); + return; + case 1: /* l.extwz */ + LOG_DIS("l.extwz r%d, r%d\n", rd, ra); + tcg_gen_ext32u_tl(cpu_R[rd], cpu_R[ra]); + return; + } break; - default: - gen_illegal_exception(dc); - break; - } - break; - - case 0x000e: - switch (op1) { - case 0x00: /* l.cmov */ + case 0xe: /* l.cmov */ LOG_DIS("l.cmov r%d, r%d, r%d\n", rd, ra, rb); { TCGLabel *lab = gen_new_label(); @@ -606,128 +568,54 @@ static void dec_calc(DisasContext *dc, uint32_t insn) tcg_temp_free(sr_f); tcg_temp_free(res); } - break; + return; - default: - gen_illegal_exception(dc); - break; - } - break; - - case 0x000f: - switch (op1) { - case 0x00: /* l.ff1 */ + case 0xf: /* l.ff1 */ LOG_DIS("l.ff1 r%d, r%d, r%d\n", rd, ra, rb); tcg_gen_ctzi_tl(cpu_R[rd], cpu_R[ra], -1); tcg_gen_addi_tl(cpu_R[rd], cpu_R[rd], 1); - break; - case 0x01: /* l.fl1 */ + return; + } + break; + + case 1: + switch (op0) { + case 0xf: /* l.fl1 */ LOG_DIS("l.fl1 r%d, r%d, r%d\n", rd, ra, rb); tcg_gen_clzi_tl(cpu_R[rd], cpu_R[ra], TARGET_LONG_BITS); tcg_gen_subfi_tl(cpu_R[rd], TARGET_LONG_BITS, cpu_R[rd]); - break; - - default: - gen_illegal_exception(dc); - break; + return; } break; - case 0x0008: - switch (op1) { - case 0x00: - switch (op2) { - case 0x00: /* l.sll */ - LOG_DIS("l.sll r%d, r%d, r%d\n", rd, ra, rb); - tcg_gen_shl_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); - break; - case 0x01: /* l.srl */ - LOG_DIS("l.srl r%d, r%d, r%d\n", rd, ra, rb); - tcg_gen_shr_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); - break; - case 0x02: /* l.sra */ - LOG_DIS("l.sra r%d, r%d, r%d\n", rd, ra, rb); - tcg_gen_sar_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); - break; - case 0x03: /* l.ror */ - LOG_DIS("l.ror r%d, r%d, r%d\n", rd, ra, rb); - tcg_gen_rotr_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]); - break; - - default: - gen_illegal_exception(dc); - break; - } - break; - - default: - gen_illegal_exception(dc); - break; - } + case 2: break; - case 0x000c: - switch (op1) { - case 0x00: - switch (op2) { - case 0x00: /* l.exths */ - LOG_DIS("l.exths r%d, r%d\n", rd, ra); - tcg_gen_ext16s_tl(cpu_R[rd], cpu_R[ra]); - break; - case 0x01: /* l.extbs */ - LOG_DIS("l.extbs r%d, r%d\n", rd, ra); - tcg_gen_ext8s_tl(cpu_R[rd], cpu_R[ra]); - break; - case 0x02: /* l.exthz */ - LOG_DIS("l.exthz r%d, r%d\n", rd, ra); - tcg_gen_ext16u_tl(cpu_R[rd], cpu_R[ra]); - break; - case 0x03: /* l.extbz */ - LOG_DIS("l.extbz r%d, r%d\n", rd, ra); - tcg_gen_ext8u_tl(cpu_R[rd], cpu_R[ra]); - break; + case 3: + switch (op0) { + case 0x6: /* l.mul */ + LOG_DIS("l.mul r%d, r%d, r%d\n", rd, ra, rb); + gen_mul(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); + return; - default: - gen_illegal_exception(dc); - break; - } - break; + case 0x9: /* l.div */ + LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb); + gen_div(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); + return; - default: - gen_illegal_exception(dc); - break; + case 0xa: /* l.divu */ + LOG_DIS("l.divu r%d, r%d, r%d\n", rd, ra, rb); + gen_divu(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); + return; + + case 0xb: /* l.mulu */ + LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb); + gen_mulu(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); + return; } break; - - case 0x000d: - switch (op1) { - case 0x00: - switch (op2) { - case 0x00: /* l.extws */ - LOG_DIS("l.extws r%d, r%d\n", rd, ra); - tcg_gen_ext32s_tl(cpu_R[rd], cpu_R[ra]); - break; - case 0x01: /* l.extwz */ - LOG_DIS("l.extwz r%d, r%d\n", rd, ra); - tcg_gen_ext32u_tl(cpu_R[rd], cpu_R[ra]); - break; - - default: - gen_illegal_exception(dc); - break; - } - break; - - default: - gen_illegal_exception(dc); - break; - } - break; - - default: - gen_illegal_exception(dc); - break; } + gen_illegal_exception(dc); } static void dec_misc(DisasContext *dc, uint32_t insn) From 84775c43f390d4f5dd9adf8732e7e0b6deed8f61 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 18 Feb 2015 11:45:54 -0800 Subject: [PATCH 12/24] target/openrisc: Keep SR_F in a separate variable This avoids having to keep merging and extracting the flag from SR. Reviewed-by: Bastian Koppelmann Signed-off-by: Richard Henderson --- linux-user/elfload.c | 3 +- linux-user/main.c | 3 +- target/openrisc/cpu.h | 15 ++++- target/openrisc/gdbstub.c | 4 +- target/openrisc/interrupt.c | 2 +- target/openrisc/interrupt_helper.c | 2 +- target/openrisc/machine.c | 38 ++++++++++- target/openrisc/sys_helper.c | 5 +- target/openrisc/translate.c | 104 +++++++++++------------------ 9 files changed, 98 insertions(+), 78 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index c66cbbe84b..8271227339 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1054,9 +1054,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, for (i = 0; i < 32; i++) { (*regs)[i] = tswapreg(env->gpr[i]); } - (*regs)[32] = tswapreg(env->pc); - (*regs)[33] = tswapreg(env->sr); + (*regs)[33] = tswapreg(cpu_get_sr(env)); } #define ELF_HWCAP 0 #define ELF_PLATFORM NULL diff --git a/linux-user/main.c b/linux-user/main.c index 001f71c6cc..4fd49ce6b6 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -4765,9 +4765,8 @@ int main(int argc, char **argv, char **envp) for (i = 0; i < 32; i++) { env->gpr[i] = regs->gpr[i]; } - - env->sr = regs->sr; env->pc = regs->pc; + cpu_set_sr(env, regs->sr); } #elif defined(TARGET_SH4) { diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index ef90e49a4d..bb5d3636f1 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -286,7 +286,8 @@ typedef struct CPUOpenRISCState { target_ulong epcr; /* Exception PC register */ target_ulong eear; /* Exception EA register */ - uint32_t sr; /* Supervisor register */ + target_ulong sr_f; /* the SR_F bit, values 0, 1. */ + uint32_t sr; /* Supervisor register, without SR_F */ uint32_t vr; /* Version register */ uint32_t upr; /* Unit presence register */ uint32_t cpucfgr; /* CPU configure register */ @@ -301,7 +302,6 @@ typedef struct CPUOpenRISCState { uint32_t flags; /* cpu_flags, we only use it for exception in solt so far. */ - uint32_t btaken; /* the SR_F bit */ /* Fields up to this point are cleared by a CPU reset */ struct {} end_reset_fields; @@ -412,6 +412,17 @@ static inline int cpu_mmu_index(CPUOpenRISCState *env, bool ifetch) return (env->sr & SR_SM) == 0 ? MMU_USER_IDX : MMU_SUPERVISOR_IDX; } +static inline uint32_t cpu_get_sr(const CPUOpenRISCState *env) +{ + return env->sr + env->sr_f * SR_F; +} + +static inline void cpu_set_sr(CPUOpenRISCState *env, uint32_t val) +{ + env->sr_f = (val & SR_F) != 0; + env->sr = (val & ~SR_F) | SR_FO; +} + #define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_INT_0 #endif /* OPENRISC_CPU_H */ diff --git a/target/openrisc/gdbstub.c b/target/openrisc/gdbstub.c index cb16e76358..31ea013d8c 100644 --- a/target/openrisc/gdbstub.c +++ b/target/openrisc/gdbstub.c @@ -38,7 +38,7 @@ int openrisc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) return gdb_get_reg32(mem_buf, env->npc); case 34: /* SR */ - return gdb_get_reg32(mem_buf, env->sr); + return gdb_get_reg32(mem_buf, cpu_get_sr(env)); default: break; @@ -73,7 +73,7 @@ int openrisc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) break; case 34: /* SR */ - env->sr = tmp; + cpu_set_sr(env, tmp); break; default: diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index a98163832e..042506f014 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -54,7 +54,7 @@ void openrisc_cpu_do_interrupt(CPUState *cs) we need flush TLB when we enter&exit EXCP. */ tlb_flush(cs); - env->esr = env->sr; + env->esr = cpu_get_sr(env); env->sr &= ~SR_DME; env->sr &= ~SR_IME; env->sr |= SR_SM; diff --git a/target/openrisc/interrupt_helper.c b/target/openrisc/interrupt_helper.c index a6d4df3ce2..c7fa97a565 100644 --- a/target/openrisc/interrupt_helper.c +++ b/target/openrisc/interrupt_helper.c @@ -33,7 +33,7 @@ void HELPER(rfe)(CPUOpenRISCState *env) #endif cpu->env.pc = cpu->env.epcr; cpu->env.npc = cpu->env.epcr; - cpu->env.sr = cpu->env.esr; + cpu_set_sr(&cpu->env, cpu->env.esr); cpu->env.lock_addr = -1; #ifndef CONFIG_USER_ONLY diff --git a/target/openrisc/machine.c b/target/openrisc/machine.c index d0b47ef1d9..b723138567 100644 --- a/target/openrisc/machine.c +++ b/target/openrisc/machine.c @@ -24,6 +24,27 @@ #include "hw/boards.h" #include "migration/cpu.h" +static int get_sr(QEMUFile *f, void *opaque, size_t size, VMStateField *field) +{ + CPUOpenRISCState *env = opaque; + cpu_set_sr(env, qemu_get_be32(f)); + return 0; +} + +static int put_sr(QEMUFile *f, void *opaque, size_t size, + VMStateField *field, QJSON *vmdesc) +{ + CPUOpenRISCState *env = opaque; + qemu_put_be32(f, cpu_get_sr(env)); + return 0; +} + +static const VMStateInfo vmstate_sr = { + .name = "sr", + .get = get_sr, + .put = put_sr, +}; + static const VMStateDescription vmstate_env = { .name = "env", .version_id = 2, @@ -38,7 +59,22 @@ static const VMStateDescription vmstate_env = { VMSTATE_UINTTL(lock_value, CPUOpenRISCState), VMSTATE_UINTTL(epcr, CPUOpenRISCState), VMSTATE_UINTTL(eear, CPUOpenRISCState), - VMSTATE_UINT32(sr, CPUOpenRISCState), + + /* Save the architecture value of the SR, not the internally + expanded version. Since this architecture value does not + exist in memory to be stored, this requires a but of hoop + jumping. We want OFFSET=0 so that we effectively pass ENV + to the helper functions, and we need to fill in the name by + hand since there's no field of that name. */ + { + .name = "sr", + .version_id = 0, + .size = sizeof(uint32_t), + .info = &vmstate_sr, + .flags = VMS_SINGLE, + .offset = 0 + }, + VMSTATE_UINT32(vr, CPUOpenRISCState), VMSTATE_UINT32(upr, CPUOpenRISCState), VMSTATE_UINT32(cpucfgr, CPUOpenRISCState), diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index daea902856..4a59728964 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -49,8 +49,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, (rb & (SR_IME | SR_DME | SR_SM))) { tlb_flush(cs); } - env->sr = rb; - env->sr |= SR_FO; /* FO is const equal to 1 */ + cpu_set_sr(env, rb); if (env->sr & SR_DME) { env->tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_data; @@ -200,7 +199,7 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, return env->npc; case TO_SPR(0, 17): /* SR */ - return env->sr; + return cpu_get_sr(env); case TO_SPR(0, 18): /* PPC */ return env->ppc; diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 1f3f22c79a..405a1a0792 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -54,7 +54,7 @@ static TCGv cpu_pc; static TCGv jmp_pc; /* l.jr/l.jalr temp pc */ static TCGv cpu_npc; static TCGv cpu_ppc; -static TCGv_i32 env_btaken; /* bf/bnf , F flag taken */ +static TCGv cpu_sr_f; /* bf/bnf, F flag taken */ static TCGv cpu_lock_addr; static TCGv cpu_lock_value; static TCGv_i32 fpcsr; @@ -88,9 +88,8 @@ void openrisc_translate_init(void) offsetof(CPUOpenRISCState, ppc), "ppc"); jmp_pc = tcg_global_mem_new(cpu_env, offsetof(CPUOpenRISCState, jmp_pc), "jmp_pc"); - env_btaken = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUOpenRISCState, btaken), - "btaken"); + cpu_sr_f = tcg_global_mem_new(cpu_env, + offsetof(CPUOpenRISCState, sr_f), "sr_f"); cpu_lock_addr = tcg_global_mem_new(cpu_env, offsetof(CPUOpenRISCState, lock_addr), "lock_addr"); @@ -119,16 +118,6 @@ void openrisc_translate_init(void) } } -/* Writeback SR_F translation space to execution space. */ -static inline void wb_SR_F(void) -{ - TCGLabel *label = gen_new_label(); - tcg_gen_andi_tl(cpu_sr, cpu_sr, ~SR_F); - tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, label); - tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_F); - gen_set_label(label); -} - static inline void gen_sync_flags(DisasContext *dc) { /* Sync the tb dependent flag between translate and runtime. */ @@ -220,14 +209,11 @@ static void gen_jump(DisasContext *dc, int32_t n26, uint32_t reg, uint32_t op0) case 0x04: /* l.bf */ { TCGLabel *lab = gen_new_label(); - TCGv sr_f = tcg_temp_new(); tcg_gen_movi_tl(jmp_pc, dc->pc+8); - tcg_gen_andi_tl(sr_f, cpu_sr, SR_F); - tcg_gen_brcondi_i32(op0 == 0x03 ? TCG_COND_EQ : TCG_COND_NE, - sr_f, SR_F, lab); + tcg_gen_brcondi_tl(op0 == 0x03 ? TCG_COND_NE : TCG_COND_EQ, + cpu_sr_f, 0, lab); tcg_gen_movi_tl(jmp_pc, tmp_pc); gen_set_label(lab); - tcg_temp_free(sr_f); } break; case 0x11: /* l.jr */ @@ -441,17 +427,16 @@ static void gen_swa(DisasContext *dc, TCGv rb, TCGv ra, int32_t ofs) val = tcg_temp_new(); tcg_gen_atomic_cmpxchg_tl(val, cpu_lock_addr, cpu_lock_value, rb, dc->mem_idx, MO_TEUL); - tcg_gen_setcond_tl(TCG_COND_EQ, env_btaken, val, cpu_lock_value); + tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, val, cpu_lock_value); tcg_temp_free(val); tcg_gen_br(lab_done); gen_set_label(lab_fail); - tcg_gen_movi_tl(env_btaken, 0); + tcg_gen_movi_tl(cpu_sr_f, 0); gen_set_label(lab_done); tcg_gen_movi_tl(cpu_lock_addr, -1); - wb_SR_F(); } static void dec_calc(DisasContext *dc, uint32_t insn) @@ -558,14 +543,11 @@ static void dec_calc(DisasContext *dc, uint32_t insn) { TCGLabel *lab = gen_new_label(); TCGv res = tcg_temp_local_new(); - TCGv sr_f = tcg_temp_new(); - tcg_gen_andi_tl(sr_f, cpu_sr, SR_F); tcg_gen_mov_tl(res, cpu_R[rb]); - tcg_gen_brcondi_tl(TCG_COND_NE, sr_f, SR_F, lab); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_sr_f, 0, lab); tcg_gen_mov_tl(res, cpu_R[ra]); gen_set_label(lab); tcg_gen_mov_tl(cpu_R[rd], res); - tcg_temp_free(sr_f); tcg_temp_free(res); } return; @@ -1046,7 +1028,6 @@ static void dec_comp(DisasContext *dc, uint32_t insn) ra = extract32(insn, 16, 5); rb = extract32(insn, 11, 5); - tcg_gen_movi_i32(env_btaken, 0x0); /* unsigned integers */ tcg_gen_ext32u_tl(cpu_R[ra], cpu_R[ra]); tcg_gen_ext32u_tl(cpu_R[rb], cpu_R[rb]); @@ -1054,59 +1035,58 @@ static void dec_comp(DisasContext *dc, uint32_t insn) switch (op0) { case 0x0: /* l.sfeq */ LOG_DIS("l.sfeq r%d, r%d\n", ra, rb); - tcg_gen_setcond_tl(TCG_COND_EQ, env_btaken, cpu_R[ra], cpu_R[rb]); + tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, cpu_R[ra], cpu_R[rb]); break; case 0x1: /* l.sfne */ LOG_DIS("l.sfne r%d, r%d\n", ra, rb); - tcg_gen_setcond_tl(TCG_COND_NE, env_btaken, cpu_R[ra], cpu_R[rb]); + tcg_gen_setcond_tl(TCG_COND_NE, cpu_sr_f, cpu_R[ra], cpu_R[rb]); break; case 0x2: /* l.sfgtu */ LOG_DIS("l.sfgtu r%d, r%d\n", ra, rb); - tcg_gen_setcond_tl(TCG_COND_GTU, env_btaken, cpu_R[ra], cpu_R[rb]); + tcg_gen_setcond_tl(TCG_COND_GTU, cpu_sr_f, cpu_R[ra], cpu_R[rb]); break; case 0x3: /* l.sfgeu */ LOG_DIS("l.sfgeu r%d, r%d\n", ra, rb); - tcg_gen_setcond_tl(TCG_COND_GEU, env_btaken, cpu_R[ra], cpu_R[rb]); + tcg_gen_setcond_tl(TCG_COND_GEU, cpu_sr_f, cpu_R[ra], cpu_R[rb]); break; case 0x4: /* l.sfltu */ LOG_DIS("l.sfltu r%d, r%d\n", ra, rb); - tcg_gen_setcond_tl(TCG_COND_LTU, env_btaken, cpu_R[ra], cpu_R[rb]); + tcg_gen_setcond_tl(TCG_COND_LTU, cpu_sr_f, cpu_R[ra], cpu_R[rb]); break; case 0x5: /* l.sfleu */ LOG_DIS("l.sfleu r%d, r%d\n", ra, rb); - tcg_gen_setcond_tl(TCG_COND_LEU, env_btaken, cpu_R[ra], cpu_R[rb]); + tcg_gen_setcond_tl(TCG_COND_LEU, cpu_sr_f, cpu_R[ra], cpu_R[rb]); break; case 0xa: /* l.sfgts */ LOG_DIS("l.sfgts r%d, r%d\n", ra, rb); - tcg_gen_setcond_tl(TCG_COND_GT, env_btaken, cpu_R[ra], cpu_R[rb]); + tcg_gen_setcond_tl(TCG_COND_GT, cpu_sr_f, cpu_R[ra], cpu_R[rb]); break; case 0xb: /* l.sfges */ LOG_DIS("l.sfges r%d, r%d\n", ra, rb); - tcg_gen_setcond_tl(TCG_COND_GE, env_btaken, cpu_R[ra], cpu_R[rb]); + tcg_gen_setcond_tl(TCG_COND_GE, cpu_sr_f, cpu_R[ra], cpu_R[rb]); break; case 0xc: /* l.sflts */ LOG_DIS("l.sflts r%d, r%d\n", ra, rb); - tcg_gen_setcond_tl(TCG_COND_LT, env_btaken, cpu_R[ra], cpu_R[rb]); + tcg_gen_setcond_tl(TCG_COND_LT, cpu_sr_f, cpu_R[ra], cpu_R[rb]); break; case 0xd: /* l.sfles */ LOG_DIS("l.sfles r%d, r%d\n", ra, rb); - tcg_gen_setcond_tl(TCG_COND_LE, env_btaken, cpu_R[ra], cpu_R[rb]); + tcg_gen_setcond_tl(TCG_COND_LE, cpu_sr_f, cpu_R[ra], cpu_R[rb]); break; default: gen_illegal_exception(dc); break; } - wb_SR_F(); } static void dec_compi(DisasContext *dc, uint32_t insn) @@ -1118,64 +1098,61 @@ static void dec_compi(DisasContext *dc, uint32_t insn) ra = extract32(insn, 16, 5); I16 = sextract32(insn, 0, 16); - tcg_gen_movi_i32(env_btaken, 0x0); - switch (op0) { case 0x0: /* l.sfeqi */ LOG_DIS("l.sfeqi r%d, %d\n", ra, I16); - tcg_gen_setcondi_tl(TCG_COND_EQ, env_btaken, cpu_R[ra], I16); + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_f, cpu_R[ra], I16); break; case 0x1: /* l.sfnei */ LOG_DIS("l.sfnei r%d, %d\n", ra, I16); - tcg_gen_setcondi_tl(TCG_COND_NE, env_btaken, cpu_R[ra], I16); + tcg_gen_setcondi_tl(TCG_COND_NE, cpu_sr_f, cpu_R[ra], I16); break; case 0x2: /* l.sfgtui */ LOG_DIS("l.sfgtui r%d, %d\n", ra, I16); - tcg_gen_setcondi_tl(TCG_COND_GTU, env_btaken, cpu_R[ra], I16); + tcg_gen_setcondi_tl(TCG_COND_GTU, cpu_sr_f, cpu_R[ra], I16); break; case 0x3: /* l.sfgeui */ LOG_DIS("l.sfgeui r%d, %d\n", ra, I16); - tcg_gen_setcondi_tl(TCG_COND_GEU, env_btaken, cpu_R[ra], I16); + tcg_gen_setcondi_tl(TCG_COND_GEU, cpu_sr_f, cpu_R[ra], I16); break; case 0x4: /* l.sfltui */ LOG_DIS("l.sfltui r%d, %d\n", ra, I16); - tcg_gen_setcondi_tl(TCG_COND_LTU, env_btaken, cpu_R[ra], I16); + tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_sr_f, cpu_R[ra], I16); break; case 0x5: /* l.sfleui */ LOG_DIS("l.sfleui r%d, %d\n", ra, I16); - tcg_gen_setcondi_tl(TCG_COND_LEU, env_btaken, cpu_R[ra], I16); + tcg_gen_setcondi_tl(TCG_COND_LEU, cpu_sr_f, cpu_R[ra], I16); break; case 0xa: /* l.sfgtsi */ LOG_DIS("l.sfgtsi r%d, %d\n", ra, I16); - tcg_gen_setcondi_tl(TCG_COND_GT, env_btaken, cpu_R[ra], I16); + tcg_gen_setcondi_tl(TCG_COND_GT, cpu_sr_f, cpu_R[ra], I16); break; case 0xb: /* l.sfgesi */ LOG_DIS("l.sfgesi r%d, %d\n", ra, I16); - tcg_gen_setcondi_tl(TCG_COND_GE, env_btaken, cpu_R[ra], I16); + tcg_gen_setcondi_tl(TCG_COND_GE, cpu_sr_f, cpu_R[ra], I16); break; case 0xc: /* l.sfltsi */ LOG_DIS("l.sfltsi r%d, %d\n", ra, I16); - tcg_gen_setcondi_tl(TCG_COND_LT, env_btaken, cpu_R[ra], I16); + tcg_gen_setcondi_tl(TCG_COND_LT, cpu_sr_f, cpu_R[ra], I16); break; case 0xd: /* l.sflesi */ LOG_DIS("l.sflesi r%d, %d\n", ra, I16); - tcg_gen_setcondi_tl(TCG_COND_LE, env_btaken, cpu_R[ra], I16); + tcg_gen_setcondi_tl(TCG_COND_LE, cpu_sr_f, cpu_R[ra], I16); break; default: gen_illegal_exception(dc); break; } - wb_SR_F(); } static void dec_sys(DisasContext *dc, uint32_t insn) @@ -1308,32 +1285,32 @@ static void dec_float(DisasContext *dc, uint32_t insn) case 0x08: /* lf.sfeq.s */ LOG_DIS("lf.sfeq.s r%d, r%d\n", ra, rb); - gen_helper_float_eq_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + gen_helper_float_eq_s(cpu_sr_f, cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x09: /* lf.sfne.s */ LOG_DIS("lf.sfne.s r%d, r%d\n", ra, rb); - gen_helper_float_ne_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + gen_helper_float_ne_s(cpu_sr_f, cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x0a: /* lf.sfgt.s */ LOG_DIS("lf.sfgt.s r%d, r%d\n", ra, rb); - gen_helper_float_gt_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + gen_helper_float_gt_s(cpu_sr_f, cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x0b: /* lf.sfge.s */ LOG_DIS("lf.sfge.s r%d, r%d\n", ra, rb); - gen_helper_float_ge_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + gen_helper_float_ge_s(cpu_sr_f, cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x0c: /* lf.sflt.s */ LOG_DIS("lf.sflt.s r%d, r%d\n", ra, rb); - gen_helper_float_lt_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + gen_helper_float_lt_s(cpu_sr_f, cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x0d: /* lf.sfle.s */ LOG_DIS("lf.sfle.s r%d, r%d\n", ra, rb); - gen_helper_float_le_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + gen_helper_float_le_s(cpu_sr_f, cpu_env, cpu_R[ra], cpu_R[rb]); break; /* not used yet, open it when we need or64. */ @@ -1394,37 +1371,37 @@ static void dec_float(DisasContext *dc, uint32_t insn) case 0x18: lf.sfeq.d LOG_DIS("lf.sfeq.d r%d, r%d\n", ra, rb); check_of64s(dc); - gen_helper_float_eq_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + gen_helper_float_eq_d(cpu_sr_f, cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x1a: lf.sfgt.d LOG_DIS("lf.sfgt.d r%d, r%d\n", ra, rb); check_of64s(dc); - gen_helper_float_gt_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + gen_helper_float_gt_d(cpu_sr_f, cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x1b: lf.sfge.d LOG_DIS("lf.sfge.d r%d, r%d\n", ra, rb); check_of64s(dc); - gen_helper_float_ge_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + gen_helper_float_ge_d(cpu_sr_f, cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x19: lf.sfne.d LOG_DIS("lf.sfne.d r%d, r%d\n", ra, rb); check_of64s(dc); - gen_helper_float_ne_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + gen_helper_float_ne_d(cpu_sr_f, cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x1c: lf.sflt.d LOG_DIS("lf.sflt.d r%d, r%d\n", ra, rb); check_of64s(dc); - gen_helper_float_lt_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + gen_helper_float_lt_d(cpu_sr_f, cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x1d: lf.sfle.d LOG_DIS("lf.sfle.d r%d, r%d\n", ra, rb); check_of64s(dc); - gen_helper_float_le_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]); + gen_helper_float_le_d(cpu_sr_f, cpu_env, cpu_R[ra], cpu_R[rb]); break; #endif*/ @@ -1432,7 +1409,6 @@ static void dec_float(DisasContext *dc, uint32_t insn) gen_illegal_exception(dc); break; } - wb_SR_F(); } static void disas_openrisc_insn(DisasContext *dc, OpenRISCCPU *cpu) From 9745807191a81c45970f780166f44a7f93b18653 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 18 Feb 2015 13:26:26 -0800 Subject: [PATCH 13/24] target/openrisc: Keep SR_CY and SR_OV in a separate variables This significantly streamlines carry and overflow production. Signed-off-by: Richard Henderson --- target/openrisc/cpu.h | 13 +++- target/openrisc/exception_helper.c | 31 ++++++-- target/openrisc/helper.h | 4 +- target/openrisc/translate.c | 119 ++++++++++------------------- 4 files changed, 78 insertions(+), 89 deletions(-) diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index bb5d3636f1..e693461118 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -287,7 +287,9 @@ typedef struct CPUOpenRISCState { target_ulong eear; /* Exception EA register */ target_ulong sr_f; /* the SR_F bit, values 0, 1. */ - uint32_t sr; /* Supervisor register, without SR_F */ + target_ulong sr_cy; /* the SR_CY bit, values 0, 1. */ + target_long sr_ov; /* the SR_OV bit (in the sign bit only) */ + uint32_t sr; /* Supervisor register, without SR_{F,CY,OV} */ uint32_t vr; /* Version register */ uint32_t upr; /* Unit presence register */ uint32_t cpucfgr; /* CPU configure register */ @@ -414,13 +416,18 @@ static inline int cpu_mmu_index(CPUOpenRISCState *env, bool ifetch) static inline uint32_t cpu_get_sr(const CPUOpenRISCState *env) { - return env->sr + env->sr_f * SR_F; + return (env->sr + + env->sr_f * SR_F + + env->sr_cy * SR_CY + + (env->sr_ov < 0) * SR_OV); } static inline void cpu_set_sr(CPUOpenRISCState *env, uint32_t val) { env->sr_f = (val & SR_F) != 0; - env->sr = (val & ~SR_F) | SR_FO; + env->sr_cy = (val & SR_CY) != 0; + env->sr_ov = (val & SR_OV ? -1 : 0); + env->sr = (val & ~(SR_F | SR_CY | SR_OV)) | SR_FO; } #define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_INT_0 diff --git a/target/openrisc/exception_helper.c b/target/openrisc/exception_helper.c index 5147da68c4..1536053856 100644 --- a/target/openrisc/exception_helper.c +++ b/target/openrisc/exception_helper.c @@ -30,13 +30,32 @@ void HELPER(exception)(CPUOpenRISCState *env, uint32_t excp) raise_exception(cpu, excp); } -void HELPER(ove)(CPUOpenRISCState *env, target_ulong test) +static void QEMU_NORETURN do_range(CPUOpenRISCState *env, uintptr_t pc) { - if (unlikely(test)) { - OpenRISCCPU *cpu = openrisc_env_get_cpu(env); - CPUState *cs = CPU(cpu); + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); + CPUState *cs = CPU(cpu); - cs->exception_index = EXCP_RANGE; - cpu_loop_exit_restore(cs, GETPC()); + cs->exception_index = EXCP_RANGE; + cpu_loop_exit_restore(cs, pc); +} + +void HELPER(ove_cy)(CPUOpenRISCState *env) +{ + if (env->sr_cy) { + do_range(env, GETPC()); + } +} + +void HELPER(ove_ov)(CPUOpenRISCState *env) +{ + if (env->sr_ov < 0) { + do_range(env, GETPC()); + } +} + +void HELPER(ove_cyov)(CPUOpenRISCState *env) +{ + if (env->sr_cy || env->sr_ov < 0) { + do_range(env, GETPC()); } } diff --git a/target/openrisc/helper.h b/target/openrisc/helper.h index c2c8098243..f4d97a2d59 100644 --- a/target/openrisc/helper.h +++ b/target/openrisc/helper.h @@ -19,7 +19,9 @@ /* exception */ DEF_HELPER_FLAGS_2(exception, 0, void, env, i32) -DEF_HELPER_FLAGS_2(ove, TCG_CALL_NO_WG, void, env, tl) +DEF_HELPER_FLAGS_1(ove_cy, TCG_CALL_NO_WG, void, env) +DEF_HELPER_FLAGS_1(ove_ov, TCG_CALL_NO_WG, void, env) +DEF_HELPER_FLAGS_1(ove_cyov, TCG_CALL_NO_WG, void, env) /* float */ DEF_HELPER_FLAGS_2(itofd, 0, i64, env, i64) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 405a1a0792..6c745d3fd0 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -55,6 +55,8 @@ static TCGv jmp_pc; /* l.jr/l.jalr temp pc */ static TCGv cpu_npc; static TCGv cpu_ppc; static TCGv cpu_sr_f; /* bf/bnf, F flag taken */ +static TCGv cpu_sr_cy; /* carry (unsigned overflow) */ +static TCGv cpu_sr_ov; /* signed overflow */ static TCGv cpu_lock_addr; static TCGv cpu_lock_value; static TCGv_i32 fpcsr; @@ -90,6 +92,10 @@ void openrisc_translate_init(void) offsetof(CPUOpenRISCState, jmp_pc), "jmp_pc"); cpu_sr_f = tcg_global_mem_new(cpu_env, offsetof(CPUOpenRISCState, sr_f), "sr_f"); + cpu_sr_cy = tcg_global_mem_new(cpu_env, + offsetof(CPUOpenRISCState, sr_cy), "sr_cy"); + cpu_sr_ov = tcg_global_mem_new(cpu_env, + offsetof(CPUOpenRISCState, sr_ov), "sr_ov"); cpu_lock_addr = tcg_global_mem_new(cpu_env, offsetof(CPUOpenRISCState, lock_addr), "lock_addr"); @@ -233,27 +239,24 @@ static void gen_jump(DisasContext *dc, int32_t n26, uint32_t reg, uint32_t op0) gen_sync_flags(dc); } -static void gen_ove_cy(DisasContext *dc, TCGv cy) +static void gen_ove_cy(DisasContext *dc) { if (dc->tb_flags & SR_OVE) { - gen_helper_ove(cpu_env, cy); + gen_helper_ove_cy(cpu_env); } } -static void gen_ove_ov(DisasContext *dc, TCGv ov) +static void gen_ove_ov(DisasContext *dc) { if (dc->tb_flags & SR_OVE) { - gen_helper_ove(cpu_env, ov); + gen_helper_ove_ov(cpu_env); } } -static void gen_ove_cyov(DisasContext *dc, TCGv cy, TCGv ov) +static void gen_ove_cyov(DisasContext *dc) { if (dc->tb_flags & SR_OVE) { - TCGv t0 = tcg_temp_new(); - tcg_gen_or_tl(t0, cy, ov); - gen_helper_ove(cpu_env, t0); - tcg_temp_free(t0); + gen_helper_ove_cyov(cpu_env); } } @@ -261,143 +264,101 @@ static void gen_add(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) { TCGv t0 = tcg_const_tl(0); TCGv res = tcg_temp_new(); - TCGv sr_cy = tcg_temp_new(); - TCGv sr_ov = tcg_temp_new(); - tcg_gen_add2_tl(res, sr_cy, srca, t0, srcb, t0); - tcg_gen_xor_tl(sr_ov, srca, srcb); + tcg_gen_add2_tl(res, cpu_sr_cy, srca, t0, srcb, t0); + tcg_gen_xor_tl(cpu_sr_ov, srca, srcb); tcg_gen_xor_tl(t0, res, srcb); - tcg_gen_andc_tl(sr_ov, t0, sr_ov); + tcg_gen_andc_tl(cpu_sr_ov, t0, cpu_sr_ov); tcg_temp_free(t0); tcg_gen_mov_tl(dest, res); tcg_temp_free(res); - tcg_gen_shri_tl(sr_ov, sr_ov, TARGET_LONG_BITS - 1); - tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_cy, ctz32(SR_CY), 1); - tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_ov, ctz32(SR_OV), 1); - - gen_ove_cyov(dc, sr_ov, sr_cy); - tcg_temp_free(sr_ov); - tcg_temp_free(sr_cy); + gen_ove_cyov(dc); } static void gen_addc(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) { TCGv t0 = tcg_const_tl(0); TCGv res = tcg_temp_new(); - TCGv sr_cy = tcg_temp_new(); - TCGv sr_ov = tcg_temp_new(); - tcg_gen_shri_tl(sr_cy, cpu_sr, ctz32(SR_CY)); - tcg_gen_andi_tl(sr_cy, sr_cy, 1); - - tcg_gen_add2_tl(res, sr_cy, srca, t0, sr_cy, t0); - tcg_gen_add2_tl(res, sr_cy, res, sr_cy, srcb, t0); - tcg_gen_xor_tl(sr_ov, srca, srcb); + tcg_gen_add2_tl(res, cpu_sr_cy, srca, t0, cpu_sr_cy, t0); + tcg_gen_add2_tl(res, cpu_sr_cy, res, cpu_sr_cy, srcb, t0); + tcg_gen_xor_tl(cpu_sr_ov, srca, srcb); tcg_gen_xor_tl(t0, res, srcb); - tcg_gen_andc_tl(sr_ov, t0, sr_ov); + tcg_gen_andc_tl(cpu_sr_ov, t0, cpu_sr_ov); tcg_temp_free(t0); tcg_gen_mov_tl(dest, res); tcg_temp_free(res); - tcg_gen_shri_tl(sr_ov, sr_ov, TARGET_LONG_BITS - 1); - tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_cy, ctz32(SR_CY), 1); - tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_ov, ctz32(SR_OV), 1); - - gen_ove_cyov(dc, sr_ov, sr_cy); - tcg_temp_free(sr_ov); - tcg_temp_free(sr_cy); + gen_ove_cyov(dc); } static void gen_sub(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) { TCGv res = tcg_temp_new(); - TCGv sr_cy = tcg_temp_new(); - TCGv sr_ov = tcg_temp_new(); tcg_gen_sub_tl(res, srca, srcb); - tcg_gen_xor_tl(sr_cy, srca, srcb); - tcg_gen_xor_tl(sr_ov, res, srcb); - tcg_gen_and_tl(sr_ov, sr_ov, sr_cy); - tcg_gen_setcond_tl(TCG_COND_LTU, sr_cy, srca, srcb); + tcg_gen_xor_tl(cpu_sr_cy, srca, srcb); + tcg_gen_xor_tl(cpu_sr_ov, res, srcb); + tcg_gen_and_tl(cpu_sr_ov, cpu_sr_ov, cpu_sr_cy); + tcg_gen_setcond_tl(TCG_COND_LTU, cpu_sr_cy, srca, srcb); tcg_gen_mov_tl(dest, res); tcg_temp_free(res); - tcg_gen_shri_tl(sr_ov, sr_ov, TARGET_LONG_BITS - 1); - tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_cy, ctz32(SR_CY), 1); - tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_ov, ctz32(SR_OV), 1); - - gen_ove_cyov(dc, sr_ov, sr_cy); - tcg_temp_free(sr_ov); - tcg_temp_free(sr_cy); + gen_ove_cyov(dc); } static void gen_mul(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) { - TCGv sr_ov = tcg_temp_new(); TCGv t0 = tcg_temp_new(); - tcg_gen_muls2_tl(dest, sr_ov, srca, srcb); + tcg_gen_muls2_tl(dest, cpu_sr_ov, srca, srcb); tcg_gen_sari_tl(t0, dest, TARGET_LONG_BITS - 1); - tcg_gen_setcond_tl(TCG_COND_NE, sr_ov, sr_ov, t0); + tcg_gen_setcond_tl(TCG_COND_NE, cpu_sr_ov, cpu_sr_ov, t0); tcg_temp_free(t0); - tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_ov, ctz32(SR_OV), 1); - - gen_ove_ov(dc, sr_ov); - tcg_temp_free(sr_ov); + tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov); + gen_ove_ov(dc); } static void gen_mulu(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) { - TCGv sr_cy = tcg_temp_new(); + tcg_gen_muls2_tl(dest, cpu_sr_cy, srca, srcb); + tcg_gen_setcondi_tl(TCG_COND_NE, cpu_sr_cy, cpu_sr_cy, 0); - tcg_gen_muls2_tl(dest, sr_cy, srca, srcb); - tcg_gen_setcondi_tl(TCG_COND_NE, sr_cy, sr_cy, 0); - - tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_cy, ctz32(SR_CY), 1); - - gen_ove_cy(dc, sr_cy); - tcg_temp_free(sr_cy); + gen_ove_cy(dc); } static void gen_div(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) { - TCGv sr_ov = tcg_temp_new(); TCGv t0 = tcg_temp_new(); - tcg_gen_setcondi_tl(TCG_COND_EQ, sr_ov, srcb, 0); + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_ov, srcb, 0); /* The result of divide-by-zero is undefined. Supress the host-side exception by dividing by 1. */ - tcg_gen_or_tl(t0, srcb, sr_ov); + tcg_gen_or_tl(t0, srcb, cpu_sr_ov); tcg_gen_div_tl(dest, srca, t0); tcg_temp_free(t0); - tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_ov, ctz32(SR_OV), 1); - - gen_ove_ov(dc, sr_ov); - tcg_temp_free(sr_ov); + tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov); + gen_ove_ov(dc); } static void gen_divu(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) { - TCGv sr_cy = tcg_temp_new(); TCGv t0 = tcg_temp_new(); - tcg_gen_setcondi_tl(TCG_COND_EQ, sr_cy, srcb, 0); + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_cy, srcb, 0); /* The result of divide-by-zero is undefined. Supress the host-side exception by dividing by 1. */ - tcg_gen_or_tl(t0, srcb, sr_cy); + tcg_gen_or_tl(t0, srcb, cpu_sr_cy); tcg_gen_divu_tl(dest, srca, t0); tcg_temp_free(t0); - tcg_gen_deposit_tl(cpu_sr, cpu_sr, sr_cy, ctz32(SR_CY), 1); - - gen_ove_cy(dc, sr_cy); - tcg_temp_free(sr_cy); + gen_ove_cy(dc); } static void gen_lwa(DisasContext *dc, TCGv rd, TCGv ra, int32_t ofs) From 784696d119d2c6709920e8f4c8c9b445a43a8e8c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 18 Feb 2015 11:51:10 -0800 Subject: [PATCH 14/24] target/openrisc: Use movcond where appropriate Reviewed-by: Bastian Koppelmann Signed-off-by: Richard Henderson --- target/openrisc/translate.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 6c745d3fd0..f91ab6a557 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -214,12 +214,16 @@ static void gen_jump(DisasContext *dc, int32_t n26, uint32_t reg, uint32_t op0) case 0x03: /* l.bnf */ case 0x04: /* l.bf */ { - TCGLabel *lab = gen_new_label(); - tcg_gen_movi_tl(jmp_pc, dc->pc+8); - tcg_gen_brcondi_tl(op0 == 0x03 ? TCG_COND_NE : TCG_COND_EQ, - cpu_sr_f, 0, lab); - tcg_gen_movi_tl(jmp_pc, tmp_pc); - gen_set_label(lab); + TCGv t_next = tcg_const_tl(dc->pc + 8); + TCGv t_true = tcg_const_tl(tmp_pc); + TCGv t_zero = tcg_const_tl(0); + + tcg_gen_movcond_tl(op0 == 0x03 ? TCG_COND_EQ : TCG_COND_NE, + jmp_pc, cpu_sr_f, t_zero, t_true, t_next); + + tcg_temp_free(t_next); + tcg_temp_free(t_true); + tcg_temp_free(t_zero); } break; case 0x11: /* l.jr */ @@ -502,14 +506,10 @@ static void dec_calc(DisasContext *dc, uint32_t insn) case 0xe: /* l.cmov */ LOG_DIS("l.cmov r%d, r%d, r%d\n", rd, ra, rb); { - TCGLabel *lab = gen_new_label(); - TCGv res = tcg_temp_local_new(); - tcg_gen_mov_tl(res, cpu_R[rb]); - tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_sr_f, 0, lab); - tcg_gen_mov_tl(res, cpu_R[ra]); - gen_set_label(lab); - tcg_gen_mov_tl(cpu_R[rd], res); - tcg_temp_free(res); + TCGv zero = tcg_const_tl(0); + tcg_gen_movcond_tl(TCG_COND_NE, cpu_R[rd], cpu_sr_f, zero, + cpu_R[ra], cpu_R[rb]); + tcg_temp_free(zero); } return; From 9fba702bd4be03f1df156d4d60178c4badc8ff2d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 18 Feb 2015 13:38:33 -0800 Subject: [PATCH 15/24] target/openrisc: Set flags on helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Bastian Koppelmann Signed-off-by: Richard Henderson --- target/openrisc/helper.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/target/openrisc/helper.h b/target/openrisc/helper.h index f4d97a2d59..78a123d442 100644 --- a/target/openrisc/helper.h +++ b/target/openrisc/helper.h @@ -18,26 +18,26 @@ */ /* exception */ -DEF_HELPER_FLAGS_2(exception, 0, void, env, i32) +DEF_HELPER_FLAGS_2(exception, TCG_CALL_NO_WG, void, env, i32) DEF_HELPER_FLAGS_1(ove_cy, TCG_CALL_NO_WG, void, env) DEF_HELPER_FLAGS_1(ove_ov, TCG_CALL_NO_WG, void, env) DEF_HELPER_FLAGS_1(ove_cyov, TCG_CALL_NO_WG, void, env) /* float */ -DEF_HELPER_FLAGS_2(itofd, 0, i64, env, i64) -DEF_HELPER_FLAGS_2(itofs, 0, i32, env, i32) -DEF_HELPER_FLAGS_2(ftoid, 0, i64, env, i64) -DEF_HELPER_FLAGS_2(ftois, 0, i32, env, i32) +DEF_HELPER_FLAGS_2(itofd, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(itofs, TCG_CALL_NO_WG, i32, env, i32) +DEF_HELPER_FLAGS_2(ftoid, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(ftois, TCG_CALL_NO_WG, i32, env, i32) #define FOP_MADD(op) \ -DEF_HELPER_FLAGS_3(float_ ## op ## _s, 0, i32, env, i32, i32) \ -DEF_HELPER_FLAGS_3(float_ ## op ## _d, 0, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(float_ ## op ## _s, TCG_CALL_NO_WG, i32, env, i32, i32) \ +DEF_HELPER_FLAGS_3(float_ ## op ## _d, TCG_CALL_NO_WG, i64, env, i64, i64) FOP_MADD(muladd) #undef FOP_MADD #define FOP_CALC(op) \ -DEF_HELPER_FLAGS_3(float_ ## op ## _s, 0, i32, env, i32, i32) \ -DEF_HELPER_FLAGS_3(float_ ## op ## _d, 0, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(float_ ## op ## _s, TCG_CALL_NO_WG, i32, env, i32, i32) \ +DEF_HELPER_FLAGS_3(float_ ## op ## _d, TCG_CALL_NO_WG, i64, env, i64, i64) FOP_CALC(add) FOP_CALC(sub) FOP_CALC(mul) @@ -46,8 +46,8 @@ FOP_CALC(rem) #undef FOP_CALC #define FOP_CMP(op) \ -DEF_HELPER_FLAGS_3(float_ ## op ## _s, 0, i32, env, i32, i32) \ -DEF_HELPER_FLAGS_3(float_ ## op ## _d, 0, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(float_ ## op ## _s, TCG_CALL_NO_WG, i32, env, i32, i32) \ +DEF_HELPER_FLAGS_3(float_ ## op ## _d, TCG_CALL_NO_WG, i64, env, i64, i64) FOP_CMP(eq) FOP_CMP(lt) FOP_CMP(le) @@ -61,4 +61,4 @@ DEF_HELPER_FLAGS_1(rfe, 0, void, env) /* sys */ DEF_HELPER_FLAGS_4(mtspr, 0, void, env, tl, tl, tl) -DEF_HELPER_FLAGS_4(mfspr, 0, tl, env, tl, tl, tl) +DEF_HELPER_FLAGS_4(mfspr, TCG_CALL_NO_WG, tl, env, tl, tl, tl) From 20dc52a37c81b672a5239b20527335508bcea02e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 18 Feb 2015 16:26:01 -0800 Subject: [PATCH 16/24] target/openrisc: Enable trap, csync, msync, psync for user mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not documented as disabled for user mode. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Bastian Koppelmann Signed-off-by: Richard Henderson --- target/openrisc/translate.c | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index f91ab6a557..6c8f05ce35 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -1134,52 +1134,20 @@ static void dec_sys(DisasContext *dc, uint32_t insn) case 0x100: /* l.trap */ LOG_DIS("l.trap %d\n", K16); -#if defined(CONFIG_USER_ONLY) - return; -#else - if (dc->mem_idx == MMU_USER_IDX) { - gen_illegal_exception(dc); - return; - } tcg_gen_movi_tl(cpu_pc, dc->pc); gen_exception(dc, EXCP_TRAP); -#endif break; case 0x300: /* l.csync */ LOG_DIS("l.csync\n"); -#if defined(CONFIG_USER_ONLY) - return; -#else - if (dc->mem_idx == MMU_USER_IDX) { - gen_illegal_exception(dc); - return; - } -#endif break; case 0x200: /* l.msync */ LOG_DIS("l.msync\n"); -#if defined(CONFIG_USER_ONLY) - return; -#else - if (dc->mem_idx == MMU_USER_IDX) { - gen_illegal_exception(dc); - return; - } -#endif break; case 0x270: /* l.psync */ LOG_DIS("l.psync\n"); -#if defined(CONFIG_USER_ONLY) - return; -#else - if (dc->mem_idx == MMU_USER_IDX) { - gen_illegal_exception(dc); - return; - } -#endif break; default: From 24fc5c0feb0d8ed3367c6628c14ac3ba6ebcbb89 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 23 Jan 2017 19:07:40 -0800 Subject: [PATCH 17/24] target/openrisc: Implement msync Signed-off-by: Richard Henderson --- target/openrisc/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 6c8f05ce35..dd4ba8c8ee 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -1144,6 +1144,7 @@ static void dec_sys(DisasContext *dc, uint32_t insn) case 0x200: /* l.msync */ LOG_DIS("l.msync\n"); + tcg_gen_mb(TCG_MO_ALL); break; case 0x270: /* l.psync */ From 6f7332ba713bc4d36f1078990c5a48618933d6c3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 18 Feb 2015 15:05:05 -0800 Subject: [PATCH 18/24] target/openrisc: Represent MACHI:MACLO as a single unit Significantly simplifies the implementation of the use of MAC. Reviewed-by: Bastian Koppelmann Signed-off-by: Richard Henderson --- target/openrisc/cpu.h | 3 +- target/openrisc/machine.c | 5 +- target/openrisc/sys_helper.c | 13 ++++ target/openrisc/translate.c | 120 ++++++++++++++++++----------------- 4 files changed, 80 insertions(+), 61 deletions(-) diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index e693461118..9528277c87 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -277,8 +277,7 @@ typedef struct CPUOpenRISCState { target_ulong ppc; /* Prev PC */ target_ulong jmp_pc; /* Jump PC */ - target_ulong machi; /* Multiply register MACHI */ - target_ulong maclo; /* Multiply register MACLO */ + uint64_t mac; /* Multiply registers MACHI:MACLO */ target_ulong fpmaddhi; /* Multiply and add float register FPMADDHI */ target_ulong fpmaddlo; /* Multiply and add float register FPMADDLO */ diff --git a/target/openrisc/machine.c b/target/openrisc/machine.c index b723138567..4100957138 100644 --- a/target/openrisc/machine.c +++ b/target/openrisc/machine.c @@ -47,8 +47,8 @@ static const VMStateInfo vmstate_sr = { static const VMStateDescription vmstate_env = { .name = "env", - .version_id = 2, - .minimum_version_id = 2, + .version_id = 3, + .minimum_version_id = 3, .fields = (VMStateField[]) { VMSTATE_UINTTL_ARRAY(gpr, CPUOpenRISCState, 32), VMSTATE_UINTTL(pc, CPUOpenRISCState), @@ -82,6 +82,7 @@ static const VMStateDescription vmstate_env = { VMSTATE_UINT32(immucfgr, CPUOpenRISCState), VMSTATE_UINT32(esr, CPUOpenRISCState), VMSTATE_UINT32(fpcsr, CPUOpenRISCState), + VMSTATE_UINT64(mac, CPUOpenRISCState), VMSTATE_END_OF_LIST() } }; diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 4a59728964..9841a5bb27 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -120,6 +120,12 @@ void HELPER(mtspr)(CPUOpenRISCState *env, case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */ case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */ break; + case TO_SPR(5, 1): /* MACLO */ + env->mac = deposit64(env->mac, 0, 32, rb); + break; + case TO_SPR(5, 2): /* MACHI */ + env->mac = deposit64(env->mac, 32, 32, rb); + break; case TO_SPR(9, 0): /* PICMR */ env->picmr |= rb; break; @@ -245,6 +251,13 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */ break; + case TO_SPR(5, 1): /* MACLO */ + return (uint32_t)env->mac; + break; + case TO_SPR(5, 2): /* MACHI */ + return env->mac >> 32; + break; + case TO_SPR(9, 0): /* PICMR */ return env->picmr; diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index dd4ba8c8ee..82b8bec150 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -60,7 +60,7 @@ static TCGv cpu_sr_ov; /* signed overflow */ static TCGv cpu_lock_addr; static TCGv cpu_lock_value; static TCGv_i32 fpcsr; -static TCGv machi, maclo; +static TCGv_i64 cpu_mac; /* MACHI:MACLO */ static TCGv fpmaddhi, fpmaddlo; static TCGv_i32 env_flags; #include "exec/gen-icount.h" @@ -105,12 +105,9 @@ void openrisc_translate_init(void) fpcsr = tcg_global_mem_new_i32(cpu_env, offsetof(CPUOpenRISCState, fpcsr), "fpcsr"); - machi = tcg_global_mem_new(cpu_env, - offsetof(CPUOpenRISCState, machi), - "machi"); - maclo = tcg_global_mem_new(cpu_env, - offsetof(CPUOpenRISCState, maclo), - "maclo"); + cpu_mac = tcg_global_mem_new_i64(cpu_env, + offsetof(CPUOpenRISCState, mac), + "mac"); fpmaddhi = tcg_global_mem_new(cpu_env, offsetof(CPUOpenRISCState, fpmaddhi), "fpmaddhi"); @@ -365,6 +362,58 @@ static void gen_divu(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) gen_ove_cy(dc); } +static void gen_mac(DisasContext *dc, TCGv srca, TCGv srcb) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_ext_tl_i64(t1, srca); + tcg_gen_ext_tl_i64(t2, srcb); + tcg_gen_mul_i64(t1, t1, t2); + + /* Note that overflow is only computed during addition stage. */ + tcg_gen_xor_i64(t2, cpu_mac, t1); + tcg_gen_add_i64(cpu_mac, cpu_mac, t1); + tcg_gen_xor_i64(t1, t1, cpu_mac); + tcg_gen_andc_i64(t1, t1, t2); + tcg_temp_free_i64(t2); + +#if TARGET_LONG_BITS == 32 + tcg_gen_extrh_i64_i32(cpu_sr_ov, t1); +#else + tcg_gen_mov_i64(cpu_sr_ov, t1); +#endif + tcg_temp_free_i64(t1); + + gen_ove_ov(dc); +} + +static void gen_msb(DisasContext *dc, TCGv srca, TCGv srcb) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_ext_tl_i64(t1, srca); + tcg_gen_ext_tl_i64(t2, srcb); + tcg_gen_mul_i64(t1, t1, t2); + + /* Note that overflow is only computed during subtraction stage. */ + tcg_gen_xor_i64(t2, cpu_mac, t1); + tcg_gen_sub_i64(cpu_mac, cpu_mac, t1); + tcg_gen_xor_i64(t1, t1, cpu_mac); + tcg_gen_and_i64(t1, t1, t2); + tcg_temp_free_i64(t2); + +#if TARGET_LONG_BITS == 32 + tcg_gen_extrh_i64_i32(cpu_sr_ov, t1); +#else + tcg_gen_mov_i64(cpu_sr_ov, t1); +#endif + tcg_temp_free_i64(t1); + + gen_ove_ov(dc); +} + static void gen_lwa(DisasContext *dc, TCGv rd, TCGv ra, int32_t ofs) { TCGv ea = tcg_temp_new(); @@ -628,23 +677,9 @@ static void dec_misc(DisasContext *dc, uint32_t insn) case 0x13: /* l.maci */ LOG_DIS("l.maci r%d, %d\n", ra, I16); - { - TCGv_i64 t1 = tcg_temp_new_i64(); - TCGv_i64 t2 = tcg_temp_new_i64(); - TCGv_i32 dst = tcg_temp_new_i32(); - TCGv ttmp = tcg_const_tl(I16); - tcg_gen_mul_tl(dst, cpu_R[ra], ttmp); - tcg_gen_ext_i32_i64(t1, dst); - tcg_gen_concat_i32_i64(t2, maclo, machi); - tcg_gen_add_i64(t2, t2, t1); - tcg_gen_extrl_i64_i32(maclo, t2); - tcg_gen_shri_i64(t2, t2, 32); - tcg_gen_extrl_i64_i32(machi, t2); - tcg_temp_free_i32(dst); - tcg_temp_free(ttmp); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t2); - } + t0 = tcg_const_tl(I16); + gen_mac(dc, cpu_R[ra], t0); + tcg_temp_free(t0); break; case 0x09: /* l.rfe */ @@ -873,40 +908,12 @@ static void dec_mac(DisasContext *dc, uint32_t insn) switch (op0) { case 0x0001: /* l.mac */ LOG_DIS("l.mac r%d, r%d\n", ra, rb); - { - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i64 t1 = tcg_temp_new_i64(); - TCGv_i64 t2 = tcg_temp_new_i64(); - tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]); - tcg_gen_ext_i32_i64(t1, t0); - tcg_gen_concat_i32_i64(t2, maclo, machi); - tcg_gen_add_i64(t2, t2, t1); - tcg_gen_extrl_i64_i32(maclo, t2); - tcg_gen_shri_i64(t2, t2, 32); - tcg_gen_extrl_i64_i32(machi, t2); - tcg_temp_free_i32(t0); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t2); - } + gen_mac(dc, cpu_R[ra], cpu_R[rb]); break; case 0x0002: /* l.msb */ LOG_DIS("l.msb r%d, r%d\n", ra, rb); - { - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i64 t1 = tcg_temp_new_i64(); - TCGv_i64 t2 = tcg_temp_new_i64(); - tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]); - tcg_gen_ext_i32_i64(t1, t0); - tcg_gen_concat_i32_i64(t2, maclo, machi); - tcg_gen_sub_i64(t2, t2, t1); - tcg_gen_extrl_i64_i32(maclo, t2); - tcg_gen_shri_i64(t2, t2, 32); - tcg_gen_extrl_i64_i32(machi, t2); - tcg_temp_free_i32(t0); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t2); - } + gen_msb(dc, cpu_R[ra], cpu_R[rb]); break; default: @@ -969,9 +976,8 @@ static void dec_M(DisasContext *dc, uint32_t insn) case 0x1: /* l.macrc */ LOG_DIS("l.macrc r%d\n", rd); - tcg_gen_mov_tl(cpu_R[rd], maclo); - tcg_gen_movi_tl(maclo, 0x0); - tcg_gen_movi_tl(machi, 0x0); + tcg_gen_trunc_i64_tl(cpu_R[rd], cpu_mac); + tcg_gen_movi_i64(cpu_mac, 0); break; default: From cc5de49ebe5b2881b88b22c13410f13657b472e0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 18 Feb 2015 17:03:40 -0800 Subject: [PATCH 19/24] target/openrisc: Implement muld, muldu, macu, msbu Reviewed-by: Bastian Koppelmann Signed-off-by: Richard Henderson --- target/openrisc/translate.c | 108 ++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 82b8bec150..ce9672e7b7 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -362,6 +362,56 @@ static void gen_divu(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) gen_ove_cy(dc); } +static void gen_muld(DisasContext *dc, TCGv srca, TCGv srcb) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_ext_tl_i64(t1, srca); + tcg_gen_ext_tl_i64(t2, srcb); + if (TARGET_LONG_BITS == 32) { + tcg_gen_mul_i64(cpu_mac, t1, t2); + tcg_gen_movi_tl(cpu_sr_ov, 0); + } else { + TCGv_i64 high = tcg_temp_new_i64(); + + tcg_gen_muls2_i64(cpu_mac, high, t1, t2); + tcg_gen_sari_i64(t1, cpu_mac, 63); + tcg_gen_setcond_i64(TCG_COND_NE, t1, t1, high); + tcg_temp_free_i64(high); + tcg_gen_trunc_i64_tl(cpu_sr_ov, t1); + tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov); + + gen_ove_ov(dc); + } + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); +} + +static void gen_muldu(DisasContext *dc, TCGv srca, TCGv srcb) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_extu_tl_i64(t1, srca); + tcg_gen_extu_tl_i64(t2, srcb); + if (TARGET_LONG_BITS == 32) { + tcg_gen_mul_i64(cpu_mac, t1, t2); + tcg_gen_movi_tl(cpu_sr_cy, 0); + } else { + TCGv_i64 high = tcg_temp_new_i64(); + + tcg_gen_mulu2_i64(cpu_mac, high, t1, t2); + tcg_gen_setcondi_i64(TCG_COND_NE, high, high, 0); + tcg_gen_trunc_i64_tl(cpu_sr_cy, high); + tcg_temp_free_i64(high); + + gen_ove_cy(dc); + } + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); +} + static void gen_mac(DisasContext *dc, TCGv srca, TCGv srcb) { TCGv_i64 t1 = tcg_temp_new_i64(); @@ -388,6 +438,25 @@ static void gen_mac(DisasContext *dc, TCGv srca, TCGv srcb) gen_ove_ov(dc); } +static void gen_macu(DisasContext *dc, TCGv srca, TCGv srcb) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_extu_tl_i64(t1, srca); + tcg_gen_extu_tl_i64(t2, srcb); + tcg_gen_mul_i64(t1, t1, t2); + tcg_temp_free_i64(t2); + + /* Note that overflow is only computed during addition stage. */ + tcg_gen_add_i64(cpu_mac, cpu_mac, t1); + tcg_gen_setcond_i64(TCG_COND_LTU, t1, cpu_mac, t1); + tcg_gen_trunc_i64_tl(cpu_sr_cy, t1); + tcg_temp_free_i64(t1); + + gen_ove_cy(dc); +} + static void gen_msb(DisasContext *dc, TCGv srca, TCGv srcb) { TCGv_i64 t1 = tcg_temp_new_i64(); @@ -414,6 +483,25 @@ static void gen_msb(DisasContext *dc, TCGv srca, TCGv srcb) gen_ove_ov(dc); } +static void gen_msbu(DisasContext *dc, TCGv srca, TCGv srcb) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_extu_tl_i64(t1, srca); + tcg_gen_extu_tl_i64(t2, srcb); + tcg_gen_mul_i64(t1, t1, t2); + + /* Note that overflow is only computed during subtraction stage. */ + tcg_gen_setcond_i64(TCG_COND_LTU, t2, cpu_mac, t1); + tcg_gen_sub_i64(cpu_mac, cpu_mac, t1); + tcg_gen_trunc_i64_tl(cpu_sr_cy, t2); + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t1); + + gen_ove_cy(dc); +} + static void gen_lwa(DisasContext *dc, TCGv rd, TCGv ra, int32_t ofs) { TCGv ea = tcg_temp_new(); @@ -590,6 +678,11 @@ static void dec_calc(DisasContext *dc, uint32_t insn) gen_mul(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); return; + case 0x7: /* l.muld */ + LOG_DIS("l.muld r%d, r%d\n", ra, rb); + gen_muld(dc, cpu_R[ra], cpu_R[rb]); + break; + case 0x9: /* l.div */ LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb); gen_div(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); @@ -604,6 +697,11 @@ static void dec_calc(DisasContext *dc, uint32_t insn) LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb); gen_mulu(dc, cpu_R[rd], cpu_R[ra], cpu_R[rb]); return; + + case 0xc: /* l.muldu */ + LOG_DIS("l.muldu r%d, r%d\n", ra, rb); + gen_muldu(dc, cpu_R[ra], cpu_R[rb]); + return; } break; } @@ -916,6 +1014,16 @@ static void dec_mac(DisasContext *dc, uint32_t insn) gen_msb(dc, cpu_R[ra], cpu_R[rb]); break; + case 0x0003: /* l.macu */ + LOG_DIS("l.macu r%d, r%d\n", ra, rb); + gen_macu(dc, cpu_R[ra], cpu_R[rb]); + break; + + case 0x0004: /* l.msbu */ + LOG_DIS("l.msbu r%d, r%d\n", ra, rb); + gen_msbu(dc, cpu_R[ra], cpu_R[rb]); + break; + default: gen_illegal_exception(dc); break; From 762e22edcd021035e1dbcf0dbc31b4794c5c1027 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 18 Feb 2015 18:47:35 -0800 Subject: [PATCH 20/24] target/openrisc: Fix madd Note that the specification for lf.madd.s is confused. It's the only mention of supposed FPMADDHI/FPMADDLO special registers. On the other hand, or1ksim implements a somewhat normal non-fused multiply and add. Mirror that. Reviewed-by: Bastian Koppelmann Signed-off-by: Richard Henderson --- target/openrisc/cpu.h | 3 -- target/openrisc/fpu_helper.c | 68 +++++++++++++----------------------- target/openrisc/helper.h | 7 ++-- target/openrisc/translate.c | 13 +++---- 4 files changed, 30 insertions(+), 61 deletions(-) diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index 9528277c87..069403884b 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -279,9 +279,6 @@ typedef struct CPUOpenRISCState { uint64_t mac; /* Multiply registers MACHI:MACLO */ - target_ulong fpmaddhi; /* Multiply and add float register FPMADDHI */ - target_ulong fpmaddlo; /* Multiply and add float register FPMADDLO */ - target_ulong epcr; /* Exception PC register */ target_ulong eear; /* Exception EA register */ diff --git a/target/openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c index c54404b80d..1375cea948 100644 --- a/target/openrisc/fpu_helper.c +++ b/target/openrisc/fpu_helper.c @@ -146,52 +146,32 @@ FLOAT_CALC(div) FLOAT_CALC(rem) #undef FLOAT_CALC -#define FLOAT_TERNOP(name1, name2) \ -uint64_t helper_float_ ## name1 ## name2 ## _d(CPUOpenRISCState *env, \ - uint64_t fdt0, \ - uint64_t fdt1) \ -{ \ - uint64_t result, temp, hi, lo; \ - uint32_t val1, val2; \ - OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ - hi = env->fpmaddhi; \ - lo = env->fpmaddlo; \ - set_float_exception_flags(0, &cpu->env.fp_status); \ - result = float64_ ## name1(fdt0, fdt1, &cpu->env.fp_status); \ - lo &= 0xffffffff; \ - hi &= 0xffffffff; \ - temp = (hi << 32) | lo; \ - result = float64_ ## name2(result, temp, &cpu->env.fp_status); \ - val1 = result >> 32; \ - val2 = (uint32_t) (result & 0xffffffff); \ - update_fpcsr(cpu); \ - cpu->env.fpmaddlo = val2; \ - cpu->env.fpmaddhi = val1; \ - return 0; \ -} \ - \ -uint32_t helper_float_ ## name1 ## name2 ## _s(CPUOpenRISCState *env, \ - uint32_t fdt0, uint32_t fdt1) \ -{ \ - uint64_t result, temp, hi, lo; \ - uint32_t val1, val2; \ - OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ - hi = cpu->env.fpmaddhi; \ - lo = cpu->env.fpmaddlo; \ - set_float_exception_flags(0, &cpu->env.fp_status); \ - result = float64_ ## name1(fdt0, fdt1, &cpu->env.fp_status); \ - temp = (hi << 32) | lo; \ - result = float64_ ## name2(result, temp, &cpu->env.fp_status); \ - val1 = result >> 32; \ - val2 = (uint32_t) (result & 0xffffffff); \ - update_fpcsr(cpu); \ - cpu->env.fpmaddlo = val2; \ - cpu->env.fpmaddhi = val1; \ - return 0; \ + +uint64_t helper_float_madd_d(CPUOpenRISCState *env, uint64_t a, + uint64_t b, uint64_t c) +{ + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); + uint64_t result; + set_float_exception_flags(0, &cpu->env.fp_status); + /* Note that or1ksim doesn't use merged operation. */ + result = float64_mul(b, c, &cpu->env.fp_status); + result = float64_add(result, a, &cpu->env.fp_status); + update_fpcsr(cpu); + return result; } -FLOAT_TERNOP(mul, add) -#undef FLOAT_TERNOP +uint32_t helper_float_madd_s(CPUOpenRISCState *env, uint32_t a, + uint32_t b, uint32_t c) +{ + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); + uint32_t result; + set_float_exception_flags(0, &cpu->env.fp_status); + /* Note that or1ksim doesn't use merged operation. */ + result = float32_mul(b, c, &cpu->env.fp_status); + result = float32_add(result, a, &cpu->env.fp_status); + update_fpcsr(cpu); + return result; +} #define FLOAT_CMP(name) \ diff --git a/target/openrisc/helper.h b/target/openrisc/helper.h index 78a123d442..4fd1a6bb8e 100644 --- a/target/openrisc/helper.h +++ b/target/openrisc/helper.h @@ -29,11 +29,8 @@ DEF_HELPER_FLAGS_2(itofs, TCG_CALL_NO_WG, i32, env, i32) DEF_HELPER_FLAGS_2(ftoid, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_2(ftois, TCG_CALL_NO_WG, i32, env, i32) -#define FOP_MADD(op) \ -DEF_HELPER_FLAGS_3(float_ ## op ## _s, TCG_CALL_NO_WG, i32, env, i32, i32) \ -DEF_HELPER_FLAGS_3(float_ ## op ## _d, TCG_CALL_NO_WG, i64, env, i64, i64) -FOP_MADD(muladd) -#undef FOP_MADD +DEF_HELPER_FLAGS_4(float_madd_s, TCG_CALL_NO_WG, i32, env, i32, i32, i32) +DEF_HELPER_FLAGS_4(float_madd_d, TCG_CALL_NO_WG, i64, env, i64, i64, i64) #define FOP_CALC(op) \ DEF_HELPER_FLAGS_3(float_ ## op ## _s, TCG_CALL_NO_WG, i32, env, i32, i32) \ diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index ce9672e7b7..66064e1829 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -61,7 +61,6 @@ static TCGv cpu_lock_addr; static TCGv cpu_lock_value; static TCGv_i32 fpcsr; static TCGv_i64 cpu_mac; /* MACHI:MACLO */ -static TCGv fpmaddhi, fpmaddlo; static TCGv_i32 env_flags; #include "exec/gen-icount.h" @@ -108,12 +107,6 @@ void openrisc_translate_init(void) cpu_mac = tcg_global_mem_new_i64(cpu_env, offsetof(CPUOpenRISCState, mac), "mac"); - fpmaddhi = tcg_global_mem_new(cpu_env, - offsetof(CPUOpenRISCState, fpmaddhi), - "fpmaddhi"); - fpmaddlo = tcg_global_mem_new(cpu_env, - offsetof(CPUOpenRISCState, fpmaddlo), - "fpmaddlo"); for (i = 0; i < 32; i++) { cpu_R[i] = tcg_global_mem_new(cpu_env, offsetof(CPUOpenRISCState, gpr[i]), @@ -1324,7 +1317,8 @@ static void dec_float(DisasContext *dc, uint32_t insn) case 0x07: /* lf.madd.s */ LOG_DIS("lf.madd.s r%d, r%d, r%d\n", rd, ra, rb); - gen_helper_float_muladd_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + gen_helper_float_madd_s(cpu_R[rd], cpu_env, cpu_R[rd], + cpu_R[ra], cpu_R[rb]); break; case 0x08: /* lf.sfeq.s */ @@ -1409,7 +1403,8 @@ static void dec_float(DisasContext *dc, uint32_t insn) case 0x17: lf.madd.d LOG_DIS("lf.madd.d r%d, r%d, r%d\n", rd, ra, rb); check_of64s(dc); - gen_helper_float_muladd_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); + gen_helper_float_madd_d(cpu_R[rd], cpu_env, cpu_R[rd], + cpu_R[ra], cpu_R[rb]); break; case 0x18: lf.sfeq.d From a8000cb480c8cfb612b039bf0382c41b9d6c7d45 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 5 Apr 2016 11:50:16 -0700 Subject: [PATCH 21/24] target/openrisc: Optimize l.jal to next MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows the tcg optimizer to see, and fold, all of the constants involved in a GOT base register load sequence. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/openrisc/translate.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 66064e1829..cda84b61cb 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -198,7 +198,11 @@ static void gen_jump(DisasContext *dc, int32_t n26, uint32_t reg, uint32_t op0) tcg_gen_movi_tl(jmp_pc, tmp_pc); break; case 0x01: /* l.jal */ - tcg_gen_movi_tl(cpu_R[9], (dc->pc + 8)); + tcg_gen_movi_tl(cpu_R[9], dc->pc + 8); + /* Optimize jal being used to load the PC for PIC. */ + if (tmp_pc == dc->pc + 8) { + return; + } tcg_gen_movi_tl(jmp_pc, tmp_pc); break; case 0x03: /* l.bnf */ From 24c328521b19aff2559118809ddf0522d6dfaaea Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 5 Apr 2016 11:41:48 -0700 Subject: [PATCH 22/24] target/openrisc: Tidy ppc/npc implementation The NPC SPR is really only supposed to be used for FPGA debugging. It contains the same contents as PC, unless one plays games. Follow the or1ksim implementation in flushing delayed branch state when it is changed. The PPC SPR need not be updated every instruction, merely when we exit the TB or attempt to read its contents. Signed-off-by: Richard Henderson --- target/openrisc/cpu.h | 2 +- target/openrisc/gdbstub.c | 13 ++++++--- target/openrisc/interrupt_helper.c | 1 - target/openrisc/machine.c | 5 ++-- target/openrisc/sys_helper.c | 44 +++++++++++------------------- target/openrisc/translate.c | 29 ++++++++------------ 6 files changed, 39 insertions(+), 55 deletions(-) diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index 069403884b..82946369dc 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -58,6 +58,7 @@ typedef struct OpenRISCCPUClass { } OpenRISCCPUClass; #define NB_MMU_MODES 3 +#define TARGET_INSN_START_EXTRA_WORDS 1 enum { MMU_NOMMU_IDX = 0, @@ -273,7 +274,6 @@ typedef struct CPUOpenRISCTLBContext { typedef struct CPUOpenRISCState { target_ulong gpr[32]; /* General registers */ target_ulong pc; /* Program counter */ - target_ulong npc; /* Next PC */ target_ulong ppc; /* Prev PC */ target_ulong jmp_pc; /* Jump PC */ diff --git a/target/openrisc/gdbstub.c b/target/openrisc/gdbstub.c index 31ea013d8c..2a4821fe9b 100644 --- a/target/openrisc/gdbstub.c +++ b/target/openrisc/gdbstub.c @@ -34,8 +34,8 @@ int openrisc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) case 32: /* PPC */ return gdb_get_reg32(mem_buf, env->ppc); - case 33: /* NPC */ - return gdb_get_reg32(mem_buf, env->npc); + case 33: /* NPC (equals PC) */ + return gdb_get_reg32(mem_buf, env->pc); case 34: /* SR */ return gdb_get_reg32(mem_buf, cpu_get_sr(env)); @@ -68,8 +68,13 @@ int openrisc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->ppc = tmp; break; - case 33: /* NPC */ - env->npc = tmp; + case 33: /* NPC (equals PC) */ + /* If setting PC to something different, + also clear delayed branch status. */ + if (env->pc != tmp) { + env->pc = tmp; + env->flags = 0; + } break; case 34: /* SR */ diff --git a/target/openrisc/interrupt_helper.c b/target/openrisc/interrupt_helper.c index c7fa97a565..56620e0571 100644 --- a/target/openrisc/interrupt_helper.c +++ b/target/openrisc/interrupt_helper.c @@ -32,7 +32,6 @@ void HELPER(rfe)(CPUOpenRISCState *env) (cpu->env.esr & (SR_SM | SR_IME | SR_DME)); #endif cpu->env.pc = cpu->env.epcr; - cpu->env.npc = cpu->env.epcr; cpu_set_sr(&cpu->env, cpu->env.esr); cpu->env.lock_addr = -1; diff --git a/target/openrisc/machine.c b/target/openrisc/machine.c index 4100957138..686eaa30c9 100644 --- a/target/openrisc/machine.c +++ b/target/openrisc/machine.c @@ -47,12 +47,11 @@ static const VMStateInfo vmstate_sr = { static const VMStateDescription vmstate_env = { .name = "env", - .version_id = 3, - .minimum_version_id = 3, + .version_id = 4, + .minimum_version_id = 4, .fields = (VMStateField[]) { VMSTATE_UINTTL_ARRAY(gpr, CPUOpenRISCState, 32), VMSTATE_UINTTL(pc, CPUOpenRISCState), - VMSTATE_UINTTL(npc, CPUOpenRISCState), VMSTATE_UINTTL(ppc, CPUOpenRISCState), VMSTATE_UINTTL(jmp_pc, CPUOpenRISCState), VMSTATE_UINTTL(lock_addr, CPUOpenRISCState), diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 9841a5bb27..0968901426 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -29,11 +29,10 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong ra, target_ulong rb, target_ulong offset) { #ifndef CONFIG_USER_ONLY - int spr = (ra | offset); - int idx; - OpenRISCCPU *cpu = openrisc_env_get_cpu(env); CPUState *cs = CPU(cpu); + int spr = (ra | offset); + int idx; switch (spr) { case TO_SPR(0, 0): /* VR */ @@ -41,7 +40,14 @@ void HELPER(mtspr)(CPUOpenRISCState *env, break; case TO_SPR(0, 16): /* NPC */ - env->npc = rb; + cpu_restore_state(cs, GETPC()); + /* ??? Mirror or1ksim in not trashing delayed branch state + when "jumping" to the current instruction. */ + if (env->pc != rb) { + env->pc = rb; + env->flags = 0; + cpu_loop_exit(cs); + } break; case TO_SPR(0, 17): /* SR */ @@ -170,7 +176,6 @@ void HELPER(mtspr)(CPUOpenRISCState *env, cpu_openrisc_timer_update(cpu); break; default: - break; } #endif @@ -180,11 +185,11 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, target_ulong ra, uint32_t offset) { #ifndef CONFIG_USER_ONLY + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); + CPUState *cs = CPU(cpu); int spr = (ra | offset); int idx; - OpenRISCCPU *cpu = openrisc_env_get_cpu(env); - switch (spr) { case TO_SPR(0, 0): /* VR */ return env->vr & SPR_VR; @@ -201,13 +206,15 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, case TO_SPR(0, 4): /* IMMUCFGR */ return env->immucfgr; - case TO_SPR(0, 16): /* NPC */ - return env->npc; + case TO_SPR(0, 16): /* NPC (equals PC) */ + cpu_restore_state(cs, GETPC()); + return env->pc; case TO_SPR(0, 17): /* SR */ return cpu_get_sr(env); case TO_SPR(0, 18): /* PPC */ + cpu_restore_state(cs, GETPC()); return env->ppc; case TO_SPR(0, 32): /* EPCR */ @@ -276,25 +283,6 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, } #endif -/*If we later need to add tracepoints (or debug printfs) for the return -value, it may be useful to structure the code like this: - -target_ulong ret = 0; - -switch() { -case x: - ret = y; - break; -case z: - ret = 42; - break; -... -} - -later something like trace_spr_read(ret); - -return ret;*/ - /* for rd is passed in, if rd unchanged, just keep it back. */ return rd; } diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index cda84b61cb..10f0633e91 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -39,7 +39,7 @@ typedef struct DisasContext { TranslationBlock *tb; - target_ulong pc, ppc, npc; + target_ulong pc; uint32_t tb_flags, synced_flags, flags; uint32_t is_jmp; uint32_t mem_idx; @@ -52,7 +52,6 @@ static TCGv cpu_sr; static TCGv cpu_R[32]; static TCGv cpu_pc; static TCGv jmp_pc; /* l.jr/l.jalr temp pc */ -static TCGv cpu_npc; static TCGv cpu_ppc; static TCGv cpu_sr_f; /* bf/bnf, F flag taken */ static TCGv cpu_sr_cy; /* carry (unsigned overflow) */ @@ -83,8 +82,6 @@ void openrisc_translate_init(void) "flags"); cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPUOpenRISCState, pc), "pc"); - cpu_npc = tcg_global_mem_new(cpu_env, - offsetof(CPUOpenRISCState, npc), "npc"); cpu_ppc = tcg_global_mem_new(cpu_env, offsetof(CPUOpenRISCState, ppc), "ppc"); jmp_pc = tcg_global_mem_new(cpu_env, @@ -1514,7 +1511,6 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb) dc->tb = tb; dc->is_jmp = DISAS_NEXT; - dc->ppc = pc_start; dc->pc = pc_start; dc->flags = cpu->env.cpucfgr; dc->mem_idx = cpu_mmu_index(&cpu->env, false); @@ -1543,7 +1539,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb) gen_tb_start(tb); do { - tcg_gen_insn_start(dc->pc); + tcg_gen_insn_start(dc->pc, num_insns != 0); num_insns++; if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { @@ -1561,12 +1557,9 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb) if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { gen_io_start(); } - dc->ppc = dc->pc - 4; - dc->npc = dc->pc + 4; - tcg_gen_movi_tl(cpu_ppc, dc->ppc); - tcg_gen_movi_tl(cpu_npc, dc->npc); disas_openrisc_insn(dc, cpu); - dc->pc = dc->npc; + dc->pc = dc->pc + 4; + /* delay slot */ if (dc->delayed_branch) { dc->delayed_branch--; @@ -1574,10 +1567,8 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb) dc->tb_flags &= ~D_FLAG; gen_sync_flags(dc); tcg_gen_mov_tl(cpu_pc, jmp_pc); - tcg_gen_mov_tl(cpu_npc, jmp_pc); - tcg_gen_movi_tl(jmp_pc, 0); - tcg_gen_exit_tb(0); - dc->is_jmp = DISAS_JUMP; + tcg_gen_discard_tl(jmp_pc); + dc->is_jmp = DISAS_UPDATE; break; } } @@ -1591,14 +1582,13 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb) if (tb->cflags & CF_LAST_IO) { gen_io_end(); } + + tcg_gen_movi_tl(cpu_ppc, dc->pc - 4); if (dc->is_jmp == DISAS_NEXT) { dc->is_jmp = DISAS_UPDATE; tcg_gen_movi_tl(cpu_pc, dc->pc); } if (unlikely(cs->singlestep_enabled)) { - if (dc->is_jmp == DISAS_NEXT) { - tcg_gen_movi_tl(cpu_pc, dc->pc); - } gen_exception(dc, EXCP_DEBUG); } else { switch (dc->is_jmp) { @@ -1651,4 +1641,7 @@ void restore_state_to_opc(CPUOpenRISCState *env, TranslationBlock *tb, target_ulong *data) { env->pc = data[0]; + if (data[1]) { + env->ppc = env->pc - 4; + } } From a01deb36a685365b4a3117112da3cc4f0f79e955 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 5 Apr 2016 18:00:33 -0700 Subject: [PATCH 23/24] target/openrisc: Tidy handling of delayed branches Signed-off-by: Richard Henderson --- target/openrisc/cpu.h | 12 +++++------ target/openrisc/gdbstub.c | 2 +- target/openrisc/interrupt.c | 4 ++-- target/openrisc/sys_helper.c | 2 +- target/openrisc/translate.c | 40 +++++++++++++++--------------------- 5 files changed, 25 insertions(+), 35 deletions(-) diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index 82946369dc..50a36ba8ef 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -83,9 +83,6 @@ enum { /* Version Register */ #define SPR_VR 0xFFFF003F -/* Internal flags, delay slot flag */ -#define D_FLAG 1 - /* Interrupt */ #define NR_IRQS 32 @@ -298,8 +295,7 @@ typedef struct CPUOpenRISCState { target_ulong lock_addr; target_ulong lock_value; - uint32_t flags; /* cpu_flags, we only use it for exception - in solt so far. */ + uint32_t dflag; /* In delay slot (boolean) */ /* Fields up to this point are cleared by a CPU reset */ struct {} end_reset_fields; @@ -392,14 +388,16 @@ int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu, #include "exec/cpu-all.h" +#define TB_FLAGS_DFLAG 1 +#define TB_FLAGS_OVE SR_OVE + static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { *pc = env->pc; *cs_base = 0; - /* D_FLAG -- branch instruction exception, OVE overflow trap enable. */ - *flags = (env->flags & D_FLAG) | (env->sr & SR_OVE); + *flags = env->dflag | (env->sr & SR_OVE); } static inline int cpu_mmu_index(CPUOpenRISCState *env, bool ifetch) diff --git a/target/openrisc/gdbstub.c b/target/openrisc/gdbstub.c index 2a4821fe9b..b18c7e9f05 100644 --- a/target/openrisc/gdbstub.c +++ b/target/openrisc/gdbstub.c @@ -73,7 +73,7 @@ int openrisc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) also clear delayed branch status. */ if (env->pc != tmp) { env->pc = tmp; - env->flags = 0; + env->dflag = 0; } break; diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index 042506f014..a2eec6fb32 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -34,8 +34,8 @@ void openrisc_cpu_do_interrupt(CPUState *cs) CPUOpenRISCState *env = &cpu->env; env->epcr = env->pc; - if (env->flags & D_FLAG) { - env->flags &= ~D_FLAG; + if (env->dflag) { + env->dflag = 0; env->sr |= SR_DSX; env->epcr -= 4; } else { diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 0968901426..60c3193656 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -45,7 +45,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, when "jumping" to the current instruction. */ if (env->pc != rb) { env->pc = rb; - env->flags = 0; + env->dflag = 0; cpu_loop_exit(cs); } break; diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 10f0633e91..313dae2a2c 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -40,11 +40,11 @@ typedef struct DisasContext { TranslationBlock *tb; target_ulong pc; - uint32_t tb_flags, synced_flags, flags; uint32_t is_jmp; uint32_t mem_idx; - int singlestep_enabled; + uint32_t tb_flags; uint32_t delayed_branch; + bool singlestep_enabled; } DisasContext; static TCGv_env cpu_env; @@ -60,7 +60,7 @@ static TCGv cpu_lock_addr; static TCGv cpu_lock_value; static TCGv_i32 fpcsr; static TCGv_i64 cpu_mac; /* MACHI:MACLO */ -static TCGv_i32 env_flags; +static TCGv_i32 cpu_dflag; #include "exec/gen-icount.h" void openrisc_translate_init(void) @@ -77,9 +77,9 @@ void openrisc_translate_init(void) tcg_ctx.tcg_env = cpu_env; cpu_sr = tcg_global_mem_new(cpu_env, offsetof(CPUOpenRISCState, sr), "sr"); - env_flags = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUOpenRISCState, flags), - "flags"); + cpu_dflag = tcg_global_mem_new_i32(cpu_env, + offsetof(CPUOpenRISCState, dflag), + "dflag"); cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPUOpenRISCState, pc), "pc"); cpu_ppc = tcg_global_mem_new(cpu_env, @@ -111,15 +111,6 @@ void openrisc_translate_init(void) } } -static inline void gen_sync_flags(DisasContext *dc) -{ - /* Sync the tb dependent flag between translate and runtime. */ - if ((dc->tb_flags ^ dc->synced_flags) & D_FLAG) { - tcg_gen_movi_tl(env_flags, dc->tb_flags & D_FLAG); - dc->synced_flags = dc->tb_flags; - } -} - static void gen_exception(DisasContext *dc, unsigned int excp) { TCGv_i32 tmp = tcg_const_i32(excp); @@ -230,8 +221,6 @@ static void gen_jump(DisasContext *dc, int32_t n26, uint32_t reg, uint32_t op0) } dc->delayed_branch = 2; - dc->tb_flags |= D_FLAG; - gen_sync_flags(dc); } static void gen_ove_cy(DisasContext *dc) @@ -1512,10 +1501,9 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb) dc->is_jmp = DISAS_NEXT; dc->pc = pc_start; - dc->flags = cpu->env.cpucfgr; dc->mem_idx = cpu_mmu_index(&cpu->env, false); - dc->synced_flags = dc->tb_flags = tb->flags; - dc->delayed_branch = (dc->tb_flags & D_FLAG) != 0; + dc->tb_flags = tb->flags; + dc->delayed_branch = (dc->tb_flags & TB_FLAGS_DFLAG) != 0; dc->singlestep_enabled = cs->singlestep_enabled; next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; @@ -1539,7 +1527,8 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb) gen_tb_start(tb); do { - tcg_gen_insn_start(dc->pc, num_insns != 0); + tcg_gen_insn_start(dc->pc, (dc->delayed_branch ? 1 : 0) + | (num_insns ? 2 : 0)); num_insns++; if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { @@ -1564,8 +1553,6 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb) if (dc->delayed_branch) { dc->delayed_branch--; if (!dc->delayed_branch) { - dc->tb_flags &= ~D_FLAG; - gen_sync_flags(dc); tcg_gen_mov_tl(cpu_pc, jmp_pc); tcg_gen_discard_tl(jmp_pc); dc->is_jmp = DISAS_UPDATE; @@ -1583,6 +1570,10 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb) gen_io_end(); } + if ((dc->tb_flags & TB_FLAGS_DFLAG ? 1 : 0) != (dc->delayed_branch != 0)) { + tcg_gen_movi_i32(cpu_dflag, dc->delayed_branch != 0); + } + tcg_gen_movi_tl(cpu_ppc, dc->pc - 4); if (dc->is_jmp == DISAS_NEXT) { dc->is_jmp = DISAS_UPDATE; @@ -1641,7 +1632,8 @@ void restore_state_to_opc(CPUOpenRISCState *env, TranslationBlock *tb, target_ulong *data) { env->pc = data[0]; - if (data[1]) { + env->dflag = data[1] & 1; + if (data[1] & 2) { env->ppc = env->pc - 4; } } From 6597c28d618a3d16d468770b7c30a0237a8c8ea9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 5 Apr 2016 19:43:40 -0700 Subject: [PATCH 24/24] target/openrisc: Optimize for r0 being zero The HW does not special-case r0, but the ABI specifies that r0 should contain 0. If we expose this fact to the optimizer, we can simplify a lot of the generated code. We must of course verify that r0==0, but that is trivial to do with a TB flag. Signed-off-by: Richard Henderson --- target/openrisc/cpu.h | 5 +- target/openrisc/exception_helper.c | 1 + target/openrisc/translate.c | 83 ++++++++++++++++++++++-------- 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index 50a36ba8ef..418a0e6960 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -389,6 +389,7 @@ int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu, #include "exec/cpu-all.h" #define TB_FLAGS_DFLAG 1 +#define TB_FLAGS_R0_0 2 #define TB_FLAGS_OVE SR_OVE static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env, @@ -397,7 +398,9 @@ static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env, { *pc = env->pc; *cs_base = 0; - *flags = env->dflag | (env->sr & SR_OVE); + *flags = (env->dflag + | (env->gpr[0] == 0 ? TB_FLAGS_R0_0 : 0) + | (env->sr & SR_OVE)); } static inline int cpu_mmu_index(CPUOpenRISCState *env, bool ifetch) diff --git a/target/openrisc/exception_helper.c b/target/openrisc/exception_helper.c index 1536053856..a8a5f69b05 100644 --- a/target/openrisc/exception_helper.c +++ b/target/openrisc/exception_helper.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" #include "exception.h" diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 313dae2a2c..7c4cbf205f 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -50,6 +50,7 @@ typedef struct DisasContext { static TCGv_env cpu_env; static TCGv cpu_sr; static TCGv cpu_R[32]; +static TCGv cpu_R0; static TCGv cpu_pc; static TCGv jmp_pc; /* l.jr/l.jalr temp pc */ static TCGv cpu_ppc; @@ -109,6 +110,7 @@ void openrisc_translate_init(void) offsetof(CPUOpenRISCState, gpr[i]), regnames[i]); } + cpu_R0 = cpu_R[0]; } static void gen_exception(DisasContext *dc, unsigned int excp) @@ -149,6 +151,15 @@ static void check_ov64s(DisasContext *dc) } #endif*/ +/* We're about to write to REG. On the off-chance that the user is + writing to R0, re-instate the architectural register. */ +#define check_r0_write(reg) \ + do { \ + if (unlikely(reg == 0)) { \ + cpu_R[0] = cpu_R0; \ + } \ + } while (0) + static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) { if (unlikely(dc->singlestep_enabled)) { @@ -496,7 +507,7 @@ static void gen_lwa(DisasContext *dc, TCGv rd, TCGv ra, int32_t ofs) tcg_temp_free(ea); } -static void gen_swa(DisasContext *dc, TCGv rb, TCGv ra, int32_t ofs) +static void gen_swa(DisasContext *dc, int b, TCGv ra, int32_t ofs) { TCGv ea, val; TCGLabel *lab_fail, *lab_done; @@ -504,6 +515,12 @@ static void gen_swa(DisasContext *dc, TCGv rb, TCGv ra, int32_t ofs) ea = tcg_temp_new(); tcg_gen_addi_tl(ea, ra, ofs); + /* For TB_FLAGS_R0_0, the branch below invalidates the temporary assigned + to cpu_R[0]. Since l.swa is quite often immediately followed by a + branch, don't bother reallocating; finish the TB using the "real" R0. + This also takes care of RB input across the branch. */ + cpu_R[0] = cpu_R0; + lab_fail = gen_new_label(); lab_done = gen_new_label(); tcg_gen_brcond_tl(TCG_COND_NE, ea, cpu_lock_addr, lab_fail); @@ -511,7 +528,7 @@ static void gen_swa(DisasContext *dc, TCGv rb, TCGv ra, int32_t ofs) val = tcg_temp_new(); tcg_gen_atomic_cmpxchg_tl(val, cpu_lock_addr, cpu_lock_value, - rb, dc->mem_idx, MO_TEUL); + cpu_R[b], dc->mem_idx, MO_TEUL); tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, val, cpu_lock_value); tcg_temp_free(val); @@ -781,6 +798,7 @@ static void dec_misc(DisasContext *dc, uint32_t insn) case 0x1b: /* l.lwa */ LOG_DIS("l.lwa r%d, r%d, %d\n", rd, ra, I16); + check_r0_write(rd); gen_lwa(dc, cpu_R[rd], cpu_R[ra], I16); break; @@ -856,16 +874,16 @@ static void dec_misc(DisasContext *dc, uint32_t insn) goto do_load; do_load: - { - TCGv t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[ra], I16); - tcg_gen_qemu_ld_tl(cpu_R[rd], t0, dc->mem_idx, mop); - tcg_temp_free(t0); - } + check_r0_write(rd); + t0 = tcg_temp_new(); + tcg_gen_addi_tl(t0, cpu_R[ra], I16); + tcg_gen_qemu_ld_tl(cpu_R[rd], t0, dc->mem_idx, mop); + tcg_temp_free(t0); break; case 0x27: /* l.addi */ LOG_DIS("l.addi r%d, r%d, %d\n", rd, ra, I16); + check_r0_write(rd); t0 = tcg_const_tl(I16); gen_add(dc, cpu_R[rd], cpu_R[ra], t0); tcg_temp_free(t0); @@ -873,6 +891,7 @@ static void dec_misc(DisasContext *dc, uint32_t insn) case 0x28: /* l.addic */ LOG_DIS("l.addic r%d, r%d, %d\n", rd, ra, I16); + check_r0_write(rd); t0 = tcg_const_tl(I16); gen_addc(dc, cpu_R[rd], cpu_R[ra], t0); tcg_temp_free(t0); @@ -880,21 +899,25 @@ static void dec_misc(DisasContext *dc, uint32_t insn) case 0x29: /* l.andi */ LOG_DIS("l.andi r%d, r%d, %d\n", rd, ra, K16); + check_r0_write(rd); tcg_gen_andi_tl(cpu_R[rd], cpu_R[ra], K16); break; case 0x2a: /* l.ori */ LOG_DIS("l.ori r%d, r%d, %d\n", rd, ra, K16); + check_r0_write(rd); tcg_gen_ori_tl(cpu_R[rd], cpu_R[ra], K16); break; case 0x2b: /* l.xori */ LOG_DIS("l.xori r%d, r%d, %d\n", rd, ra, I16); + check_r0_write(rd); tcg_gen_xori_tl(cpu_R[rd], cpu_R[ra], I16); break; case 0x2c: /* l.muli */ LOG_DIS("l.muli r%d, r%d, %d\n", rd, ra, I16); + check_r0_write(rd); t0 = tcg_const_tl(I16); gen_mul(dc, cpu_R[rd], cpu_R[ra], t0); tcg_temp_free(t0); @@ -902,6 +925,7 @@ static void dec_misc(DisasContext *dc, uint32_t insn) case 0x2d: /* l.mfspr */ LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, K16); + check_r0_write(rd); { #if defined(CONFIG_USER_ONLY) return; @@ -936,7 +960,7 @@ static void dec_misc(DisasContext *dc, uint32_t insn) case 0x33: /* l.swa */ LOG_DIS("l.swa r%d, r%d, %d\n", ra, rb, I5_11); - gen_swa(dc, cpu_R[rb], cpu_R[ra], I5_11); + gen_swa(dc, rb, cpu_R[ra], I5_11); break; /* not used yet, open it when we need or64. */ @@ -1023,6 +1047,7 @@ static void dec_logic(DisasContext *dc, uint32_t insn) L6 = extract32(insn, 0, 6); S6 = L6 & (TARGET_LONG_BITS - 1); + check_r0_write(rd); switch (op0) { case 0x00: /* l.slli */ LOG_DIS("l.slli r%d, r%d, %d\n", rd, ra, L6); @@ -1059,6 +1084,7 @@ static void dec_M(DisasContext *dc, uint32_t insn) rd = extract32(insn, 21, 5); K16 = extract32(insn, 0, 16); + check_r0_write(rd); switch (op0) { case 0x0: /* l.movhi */ LOG_DIS("l.movhi r%d, %d\n", rd, K16); @@ -1266,47 +1292,49 @@ static void dec_float(DisasContext *dc, uint32_t insn) switch (op0) { case 0x00: /* lf.add.s */ LOG_DIS("lf.add.s r%d, r%d, r%d\n", rd, ra, rb); + check_r0_write(rd); gen_helper_float_add_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x01: /* lf.sub.s */ LOG_DIS("lf.sub.s r%d, r%d, r%d\n", rd, ra, rb); + check_r0_write(rd); gen_helper_float_sub_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); break; - case 0x02: /* lf.mul.s */ LOG_DIS("lf.mul.s r%d, r%d, r%d\n", rd, ra, rb); - if (ra != 0 && rb != 0) { - gen_helper_float_mul_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); - } else { - tcg_gen_ori_tl(fpcsr, fpcsr, FPCSR_ZF); - tcg_gen_movi_i32(cpu_R[rd], 0x0); - } + check_r0_write(rd); + gen_helper_float_mul_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x03: /* lf.div.s */ LOG_DIS("lf.div.s r%d, r%d, r%d\n", rd, ra, rb); + check_r0_write(rd); gen_helper_float_div_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x04: /* lf.itof.s */ LOG_DIS("lf.itof r%d, r%d\n", rd, ra); + check_r0_write(rd); gen_helper_itofs(cpu_R[rd], cpu_env, cpu_R[ra]); break; case 0x05: /* lf.ftoi.s */ LOG_DIS("lf.ftoi r%d, r%d\n", rd, ra); + check_r0_write(rd); gen_helper_ftois(cpu_R[rd], cpu_env, cpu_R[ra]); break; case 0x06: /* lf.rem.s */ LOG_DIS("lf.rem.s r%d, r%d, r%d\n", rd, ra, rb); + check_r0_write(rd); gen_helper_float_rem_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x07: /* lf.madd.s */ LOG_DIS("lf.madd.s r%d, r%d, r%d\n", rd, ra, rb); + check_r0_write(rd); gen_helper_float_madd_s(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; @@ -1346,53 +1374,56 @@ static void dec_float(DisasContext *dc, uint32_t insn) case 0x10: lf.add.d LOG_DIS("lf.add.d r%d, r%d, r%d\n", rd, ra, rb); check_of64s(dc); + check_r0_write(rd); gen_helper_float_add_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x11: lf.sub.d LOG_DIS("lf.sub.d r%d, r%d, r%d\n", rd, ra, rb); check_of64s(dc); + check_r0_write(rd); gen_helper_float_sub_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x12: lf.mul.d LOG_DIS("lf.mul.d r%d, r%d, r%d\n", rd, ra, rb); check_of64s(dc); - if (ra != 0 && rb != 0) { - gen_helper_float_mul_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); - } else { - tcg_gen_ori_tl(fpcsr, fpcsr, FPCSR_ZF); - tcg_gen_movi_i64(cpu_R[rd], 0x0); - } + check_r0_write(rd); + gen_helper_float_mul_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x13: lf.div.d LOG_DIS("lf.div.d r%d, r%d, r%d\n", rd, ra, rb); check_of64s(dc); + check_r0_write(rd); gen_helper_float_div_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x14: lf.itof.d LOG_DIS("lf.itof r%d, r%d\n", rd, ra); check_of64s(dc); + check_r0_write(rd); gen_helper_itofd(cpu_R[rd], cpu_env, cpu_R[ra]); break; case 0x15: lf.ftoi.d LOG_DIS("lf.ftoi r%d, r%d\n", rd, ra); check_of64s(dc); + check_r0_write(rd); gen_helper_ftoid(cpu_R[rd], cpu_env, cpu_R[ra]); break; case 0x16: lf.rem.d LOG_DIS("lf.rem.d r%d, r%d, r%d\n", rd, ra, rb); check_of64s(dc); + check_r0_write(rd); gen_helper_float_rem_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]); break; case 0x17: lf.madd.d LOG_DIS("lf.madd.d r%d, r%d, r%d\n", rd, ra, rb); check_of64s(dc); + check_r0_write(rd); gen_helper_float_madd_d(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], cpu_R[rb]); break; @@ -1526,6 +1557,14 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb) gen_tb_start(tb); + /* Allow the TCG optimizer to see that R0 == 0, + when it's true, which is the common case. */ + if (dc->tb_flags & TB_FLAGS_R0_0) { + cpu_R[0] = tcg_const_tl(0); + } else { + cpu_R[0] = cpu_R0; + } + do { tcg_gen_insn_start(dc->pc, (dc->delayed_branch ? 1 : 0) | (num_insns ? 2 : 0));