summaryrefslogtreecommitdiff
path: root/cpu-exec.c
diff options
context:
space:
mode:
authorpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2008-06-29 01:03:05 +0000
committerpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2008-06-29 01:03:05 +0000
commit2e70f6efa8b960d3b5401373ad6fa98747bb9578 (patch)
tree4864a691a4d52324fe4626261e202525dd3a8659 /cpu-exec.c
parentf6e5889e7f581d286cd2153a71c386795a7070ac (diff)
downloadqemu-2e70f6efa8b960d3b5401373ad6fa98747bb9578.tar.gz
Add instruction counter.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4799 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'cpu-exec.c')
-rw-r--r--cpu-exec.c93
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)