diff options
Diffstat (limited to 'cpu-exec.c')
-rw-r--r-- | cpu-exec.c | 93 |
1 files changed, 63 insertions, 30 deletions
diff --git a/cpu-exec.c b/cpu-exec.c index 9d00cffb5e..08e10f4322 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -82,15 +82,40 @@ void cpu_resume_from_signal(CPUState *env1, void *puc) longjmp(env->jmp_env, 1); } +/* Execute the code without caching the generated code. An interpreter + could be used if available. */ +static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb) +{ + unsigned long next_tb; + TranslationBlock *tb; + + /* Should never happen. + We only end up here when an existing TB is too long. */ + if (max_cycles > CF_COUNT_MASK) + max_cycles = CF_COUNT_MASK; + + tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags, + max_cycles); + env->current_tb = tb; + /* execute the generated code */ + next_tb = tcg_qemu_tb_exec(tb->tc_ptr); + + if ((next_tb & 3) == 2) { + /* Restore PC. This may happen if async event occurs before + the TB starts executing. */ + CPU_PC_FROM_TB(env, tb); + } + tb_phys_invalidate(tb, -1); + tb_free(tb); +} + static TranslationBlock *tb_find_slow(target_ulong pc, target_ulong cs_base, uint64_t flags) { TranslationBlock *tb, **ptb1; - int code_gen_size; unsigned int h; target_ulong phys_pc, phys_page1, phys_page2, virt_page2; - uint8_t *tc_ptr; tb_invalidated_flag = 0; @@ -124,30 +149,8 @@ static TranslationBlock *tb_find_slow(target_ulong pc, ptb1 = &tb->phys_hash_next; } not_found: - /* if no translated code available, then translate it now */ - tb = tb_alloc(pc); - if (!tb) { - /* flush must be done */ - tb_flush(env); - /* cannot fail at this point */ - tb = tb_alloc(pc); - /* don't forget to invalidate previous TB info */ - tb_invalidated_flag = 1; - } - tc_ptr = code_gen_ptr; - tb->tc_ptr = tc_ptr; - tb->cs_base = cs_base; - tb->flags = flags; - cpu_gen_code(env, tb, &code_gen_size); - code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); - - /* check next page if needed */ - virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; - phys_page2 = -1; - if ((pc & TARGET_PAGE_MASK) != virt_page2) { - phys_page2 = get_phys_addr_code(env, virt_page2); - } - tb_link_phys(tb, phys_pc, phys_page2); + /* if no translated code available, then translate it now */ + tb = tb_gen_code(env, pc, cs_base, flags, 0); found: /* we add the TB in the virtual pc hash table */ @@ -583,6 +586,7 @@ int cpu_exec(CPUState *env1) of memory exceptions while generating the code, we must recompute the hash index here */ next_tb = 0; + tb_invalidated_flag = 0; } #ifdef DEBUG_EXEC if ((loglevel & CPU_LOG_EXEC)) { @@ -604,16 +608,45 @@ int cpu_exec(CPUState *env1) } } spin_unlock(&tb_lock); - tc_ptr = tb->tc_ptr; env->current_tb = tb; + while (env->current_tb) { + tc_ptr = tb->tc_ptr; /* execute the generated code */ #if defined(__sparc__) && !defined(HOST_SOLARIS) #undef env - env = cpu_single_env; + env = cpu_single_env; #define env cpu_single_env #endif - next_tb = tcg_qemu_tb_exec(tc_ptr); - env->current_tb = NULL; + next_tb = tcg_qemu_tb_exec(tc_ptr); + env->current_tb = NULL; + if ((next_tb & 3) == 2) { + /* Instruction counter exired. */ + int insns_left; + tb = (TranslationBlock *)(long)(next_tb & ~3); + /* Restore PC. */ + CPU_PC_FROM_TB(env, tb); + insns_left = env->icount_decr.u32; + if (env->icount_extra && insns_left >= 0) { + /* Refill decrementer and continue execution. */ + env->icount_extra += insns_left; + if (env->icount_extra > 0xffff) { + insns_left = 0xffff; + } else { + insns_left = env->icount_extra; + } + env->icount_extra -= insns_left; + env->icount_decr.u16.low = insns_left; + } else { + if (insns_left > 0) { + /* Execute remaining instructions. */ + cpu_exec_nocache(insns_left, tb); + } + env->exception_index = EXCP_INTERRUPT; + next_tb = 0; + cpu_loop_exit(); + } + } + } /* reset soft MMU for next block (it can currently only be set by a memory fault) */ #if defined(USE_KQEMU) |