Add instruction counter.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4799 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
pbrook
2008-06-29 01:03:05 +00:00
parent f6e5889e7f
commit 2e70f6efa8
29 changed files with 830 additions and 117 deletions
+2
View File
@@ -782,6 +782,8 @@ void cpu_abort(CPUState *env, const char *fmt, ...)
__attribute__ ((__noreturn__)); __attribute__ ((__noreturn__));
extern CPUState *first_cpu; extern CPUState *first_cpu;
extern CPUState *cpu_single_env; extern CPUState *cpu_single_env;
extern int64_t qemu_icount;
extern int use_icount;
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */ #define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ #define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
+28 -6
View File
@@ -130,17 +130,29 @@ typedef struct CPUTLBEntry {
sizeof(target_phys_addr_t))]; sizeof(target_phys_addr_t))];
} CPUTLBEntry; } CPUTLBEntry;
#ifdef WORDS_BIGENDIAN
typedef struct icount_decr_u16 {
uint16_t high;
uint16_t low;
} icount_decr_u16;
#else
typedef struct icount_decr_u16 {
uint16_t low;
uint16_t high;
} icount_decr_u16;
#endif
#define CPU_TEMP_BUF_NLONGS 128 #define CPU_TEMP_BUF_NLONGS 128
#define CPU_COMMON \ #define CPU_COMMON \
struct TranslationBlock *current_tb; /* currently executing TB */ \ struct TranslationBlock *current_tb; /* currently executing TB */ \
/* soft mmu support */ \ /* soft mmu support */ \
/* in order to avoid passing too many arguments to the memory \ /* in order to avoid passing too many arguments to the MMIO \
write helpers, we store some rarely used information in the CPU \ helpers, we store some rarely used information in the CPU \
context) */ \ context) */ \
unsigned long mem_write_pc; /* host pc at which the memory was \ unsigned long mem_io_pc; /* host pc at which the memory was \
written */ \ accessed */ \
target_ulong mem_write_vaddr; /* target virtual addr at which the \ target_ulong mem_io_vaddr; /* target virtual addr at which the \
memory was written */ \ memory was accessed */ \
int halted; /* TRUE if the CPU is in suspend state */ \ int halted; /* TRUE if the CPU is in suspend state */ \
/* The meaning of the MMU modes is defined in the target code. */ \ /* The meaning of the MMU modes is defined in the target code. */ \
CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \ CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \
@@ -149,6 +161,16 @@ typedef struct CPUTLBEntry {
/* buffer for temporaries in the code generator */ \ /* buffer for temporaries in the code generator */ \
long temp_buf[CPU_TEMP_BUF_NLONGS]; \ long temp_buf[CPU_TEMP_BUF_NLONGS]; \
\ \
int64_t icount_extra; /* Instructions until next timer event. */ \
/* Number of cycles left, with interrupt flag in high bit. \
This allows a single read-compare-cbranch-write sequence to test \
for both decrementer underflow and exceptions. */ \
union { \
uint32_t u32; \
icount_decr_u16 u16; \
} icount_decr; \
uint32_t can_do_io; /* nonzero if memory mapped IO is safe. */ \
\
/* from this point: preserved by CPU reset */ \ /* from this point: preserved by CPU reset */ \
/* ice debug support */ \ /* ice debug support */ \
target_ulong breakpoints[MAX_BREAKPOINTS]; \ target_ulong breakpoints[MAX_BREAKPOINTS]; \
+63 -30
View File
@@ -82,15 +82,40 @@ void cpu_resume_from_signal(CPUState *env1, void *puc)
longjmp(env->jmp_env, 1); 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, static TranslationBlock *tb_find_slow(target_ulong pc,
target_ulong cs_base, target_ulong cs_base,
uint64_t flags) uint64_t flags)
{ {
TranslationBlock *tb, **ptb1; TranslationBlock *tb, **ptb1;
int code_gen_size;
unsigned int h; unsigned int h;
target_ulong phys_pc, phys_page1, phys_page2, virt_page2; target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
uint8_t *tc_ptr;
tb_invalidated_flag = 0; tb_invalidated_flag = 0;
@@ -124,30 +149,8 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
ptb1 = &tb->phys_hash_next; ptb1 = &tb->phys_hash_next;
} }
not_found: not_found:
/* if no translated code available, then translate it now */ /* if no translated code available, then translate it now */
tb = tb_alloc(pc); tb = tb_gen_code(env, pc, cs_base, flags, 0);
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);
found: found:
/* we add the TB in the virtual pc hash table */ /* 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 of memory exceptions while generating the code, we
must recompute the hash index here */ must recompute the hash index here */
next_tb = 0; next_tb = 0;
tb_invalidated_flag = 0;
} }
#ifdef DEBUG_EXEC #ifdef DEBUG_EXEC
if ((loglevel & CPU_LOG_EXEC)) { if ((loglevel & CPU_LOG_EXEC)) {
@@ -604,16 +608,45 @@ int cpu_exec(CPUState *env1)
} }
} }
spin_unlock(&tb_lock); spin_unlock(&tb_lock);
tc_ptr = tb->tc_ptr;
env->current_tb = tb; env->current_tb = tb;
while (env->current_tb) {
tc_ptr = tb->tc_ptr;
/* execute the generated code */ /* execute the generated code */
#if defined(__sparc__) && !defined(HOST_SOLARIS) #if defined(__sparc__) && !defined(HOST_SOLARIS)
#undef env #undef env
env = cpu_single_env; env = cpu_single_env;
#define env cpu_single_env #define env cpu_single_env
#endif #endif
next_tb = tcg_qemu_tb_exec(tc_ptr); next_tb = tcg_qemu_tb_exec(tc_ptr);
env->current_tb = NULL; 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 /* reset soft MMU for next block (it can currently
only be set by a memory fault) */ only be set by a memory fault) */
#if defined(USE_KQEMU) #if defined(USE_KQEMU)
+27 -6
View File
@@ -27,7 +27,7 @@
#define DISAS_UPDATE 2 /* cpu state was modified dynamically */ #define DISAS_UPDATE 2 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP 3 /* only pc was modified statically */ #define DISAS_TB_JUMP 3 /* only pc was modified statically */
struct TranslationBlock; typedef struct TranslationBlock TranslationBlock;
/* XXX: make safe guess about sizes */ /* XXX: make safe guess about sizes */
#define MAX_OP_PER_INSTR 64 #define MAX_OP_PER_INSTR 64
@@ -48,6 +48,7 @@ extern target_ulong gen_opc_pc[OPC_BUF_SIZE];
extern target_ulong gen_opc_npc[OPC_BUF_SIZE]; extern target_ulong gen_opc_npc[OPC_BUF_SIZE];
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
extern uint16_t gen_opc_icount[OPC_BUF_SIZE];
extern target_ulong gen_opc_jump_pc[2]; extern target_ulong gen_opc_jump_pc[2];
extern uint32_t gen_opc_hflags[OPC_BUF_SIZE]; extern uint32_t gen_opc_hflags[OPC_BUF_SIZE];
@@ -75,6 +76,10 @@ int cpu_restore_state_copy(struct TranslationBlock *tb,
CPUState *env, unsigned long searched_pc, CPUState *env, unsigned long searched_pc,
void *puc); void *puc);
void cpu_resume_from_signal(CPUState *env1, void *puc); void cpu_resume_from_signal(CPUState *env1, void *puc);
void cpu_io_recompile(CPUState *env, void *retaddr);
TranslationBlock *tb_gen_code(CPUState *env,
target_ulong pc, target_ulong cs_base, int flags,
int cflags);
void cpu_exec_init(CPUState *env); void cpu_exec_init(CPUState *env);
int page_unprotect(target_ulong address, unsigned long pc, void *puc); int page_unprotect(target_ulong address, unsigned long pc, void *puc);
void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end, void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
@@ -117,16 +122,15 @@ static inline int tlb_set_page(CPUState *env1, target_ulong vaddr,
#define USE_DIRECT_JUMP #define USE_DIRECT_JUMP
#endif #endif
typedef struct TranslationBlock { struct TranslationBlock {
target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */
target_ulong cs_base; /* CS base for this block */ target_ulong cs_base; /* CS base for this block */
uint64_t flags; /* flags defining in which context the code was generated */ uint64_t flags; /* flags defining in which context the code was generated */
uint16_t size; /* size of target code for this block (1 <= uint16_t size; /* size of target code for this block (1 <=
size <= TARGET_PAGE_SIZE) */ size <= TARGET_PAGE_SIZE) */
uint16_t cflags; /* compile flags */ uint16_t cflags; /* compile flags */
#define CF_TB_FP_USED 0x0002 /* fp ops are used in the TB */ #define CF_COUNT_MASK 0x7fff
#define CF_FP_USED 0x0004 /* fp ops are used in the TB or in a chained TB */ #define CF_LAST_IO 0x8000 /* Last insn may be an IO access. */
#define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */
uint8_t *tc_ptr; /* pointer to the translated code */ uint8_t *tc_ptr; /* pointer to the translated code */
/* next matching tb for physical address. */ /* next matching tb for physical address. */
@@ -150,7 +154,8 @@ typedef struct TranslationBlock {
jmp_first */ jmp_first */
struct TranslationBlock *jmp_next[2]; struct TranslationBlock *jmp_next[2];
struct TranslationBlock *jmp_first; struct TranslationBlock *jmp_first;
} TranslationBlock; uint32_t icount;
};
static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc) static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc)
{ {
@@ -173,9 +178,11 @@ static inline unsigned int tb_phys_hash_func(unsigned long pc)
} }
TranslationBlock *tb_alloc(target_ulong pc); TranslationBlock *tb_alloc(target_ulong pc);
void tb_free(TranslationBlock *tb);
void tb_flush(CPUState *env); void tb_flush(CPUState *env);
void tb_link_phys(TranslationBlock *tb, void tb_link_phys(TranslationBlock *tb,
target_ulong phys_pc, target_ulong phys_page2); target_ulong phys_pc, target_ulong phys_page2);
void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr);
extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
extern uint8_t *code_gen_ptr; extern uint8_t *code_gen_ptr;
@@ -364,6 +371,20 @@ static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr)
} }
return addr + env1->tlb_table[mmu_idx][page_index].addend - (unsigned long)phys_ram_base; return addr + env1->tlb_table[mmu_idx][page_index].addend - (unsigned long)phys_ram_base;
} }
/* Deterministic execution requires that IO only be performaed on the last
instruction of a TB so that interrupts take effect immediately. */
static inline int can_do_io(CPUState *env)
{
if (!use_icount)
return 1;
/* If not executing code then assume we are ok. */
if (!env->current_tb)
return 1;
return env->can_do_io != 0;
}
#endif #endif
#ifdef USE_KQEMU #ifdef USE_KQEMU
+118 -29
View File
@@ -107,6 +107,13 @@ CPUState *first_cpu;
/* current CPU in the current thread. It is only valid inside /* current CPU in the current thread. It is only valid inside
cpu_exec() */ cpu_exec() */
CPUState *cpu_single_env; CPUState *cpu_single_env;
/* 0 = Do not count executed instructions.
1 = Precice instruction counting.
2 = Adaptive rate instruction counting. */
int use_icount = 0;
/* Current instruction counter. While executing translated code this may
include some instructions that have not yet been executed. */
int64_t qemu_icount;
typedef struct PageDesc { typedef struct PageDesc {
/* list of TBs intersecting this ram page */ /* list of TBs intersecting this ram page */
@@ -633,7 +640,7 @@ static inline void tb_reset_jump(TranslationBlock *tb, int n)
tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n])); tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
} }
static inline void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr) void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
{ {
CPUState *env; CPUState *env;
PageDesc *p; PageDesc *p;
@@ -746,11 +753,9 @@ static void build_page_bitmap(PageDesc *p)
} }
} }
#ifdef TARGET_HAS_PRECISE_SMC TranslationBlock *tb_gen_code(CPUState *env,
target_ulong pc, target_ulong cs_base,
static void tb_gen_code(CPUState *env, int flags, int cflags)
target_ulong pc, target_ulong cs_base, int flags,
int cflags)
{ {
TranslationBlock *tb; TranslationBlock *tb;
uint8_t *tc_ptr; uint8_t *tc_ptr;
@@ -764,6 +769,8 @@ static void tb_gen_code(CPUState *env,
tb_flush(env); tb_flush(env);
/* cannot fail at this point */ /* cannot fail at this point */
tb = tb_alloc(pc); tb = tb_alloc(pc);
/* Don't forget to invalidate previous TB info. */
tb_invalidated_flag = 1;
} }
tc_ptr = code_gen_ptr; tc_ptr = code_gen_ptr;
tb->tc_ptr = tc_ptr; tb->tc_ptr = tc_ptr;
@@ -780,8 +787,8 @@ static void tb_gen_code(CPUState *env,
phys_page2 = get_phys_addr_code(env, virt_page2); phys_page2 = get_phys_addr_code(env, virt_page2);
} }
tb_link_phys(tb, phys_pc, phys_page2); tb_link_phys(tb, phys_pc, phys_page2);
return tb;
} }
#endif
/* invalidate all TBs which intersect with the target physical page /* invalidate all TBs which intersect with the target physical page
starting in range [start;end[. NOTE: start and end must refer to starting in range [start;end[. NOTE: start and end must refer to
@@ -836,13 +843,13 @@ void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t
if (current_tb_not_found) { if (current_tb_not_found) {
current_tb_not_found = 0; current_tb_not_found = 0;
current_tb = NULL; current_tb = NULL;
if (env->mem_write_pc) { if (env->mem_io_pc) {
/* now we have a real cpu fault */ /* now we have a real cpu fault */
current_tb = tb_find_pc(env->mem_write_pc); current_tb = tb_find_pc(env->mem_io_pc);
} }
} }
if (current_tb == tb && if (current_tb == tb &&
!(current_tb->cflags & CF_SINGLE_INSN)) { (current_tb->cflags & CF_COUNT_MASK) != 1) {
/* If we are modifying the current TB, we must stop /* If we are modifying the current TB, we must stop
its execution. We could be more precise by checking its execution. We could be more precise by checking
that the modification is after the current PC, but it that the modification is after the current PC, but it
@@ -851,7 +858,7 @@ void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t
current_tb_modified = 1; current_tb_modified = 1;
cpu_restore_state(current_tb, env, cpu_restore_state(current_tb, env,
env->mem_write_pc, NULL); env->mem_io_pc, NULL);
#if defined(TARGET_I386) #if defined(TARGET_I386)
current_flags = env->hflags; current_flags = env->hflags;
current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
@@ -883,7 +890,7 @@ void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t
if (!p->first_tb) { if (!p->first_tb) {
invalidate_page_bitmap(p); invalidate_page_bitmap(p);
if (is_cpu_write_access) { if (is_cpu_write_access) {
tlb_unprotect_code_phys(env, start, env->mem_write_vaddr); tlb_unprotect_code_phys(env, start, env->mem_io_vaddr);
} }
} }
#endif #endif
@@ -893,8 +900,7 @@ void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t
modifying the memory. It will ensure that it cannot modify modifying the memory. It will ensure that it cannot modify
itself */ itself */
env->current_tb = NULL; env->current_tb = NULL;
tb_gen_code(env, current_pc, current_cs_base, current_flags, tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
CF_SINGLE_INSN);
cpu_resume_from_signal(env, NULL); cpu_resume_from_signal(env, NULL);
} }
#endif #endif
@@ -909,7 +915,7 @@ static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int le
if (1) { if (1) {
if (loglevel) { if (loglevel) {
fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n", fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
cpu_single_env->mem_write_vaddr, len, cpu_single_env->mem_io_vaddr, len,
cpu_single_env->eip, cpu_single_env->eip,
cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base); cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
} }
@@ -961,7 +967,7 @@ static void tb_invalidate_phys_page(target_phys_addr_t addr,
tb = (TranslationBlock *)((long)tb & ~3); tb = (TranslationBlock *)((long)tb & ~3);
#ifdef TARGET_HAS_PRECISE_SMC #ifdef TARGET_HAS_PRECISE_SMC
if (current_tb == tb && if (current_tb == tb &&
!(current_tb->cflags & CF_SINGLE_INSN)) { (current_tb->cflags & CF_COUNT_MASK) != 1) {
/* If we are modifying the current TB, we must stop /* If we are modifying the current TB, we must stop
its execution. We could be more precise by checking its execution. We could be more precise by checking
that the modification is after the current PC, but it that the modification is after the current PC, but it
@@ -990,8 +996,7 @@ static void tb_invalidate_phys_page(target_phys_addr_t addr,
modifying the memory. It will ensure that it cannot modify modifying the memory. It will ensure that it cannot modify
itself */ itself */
env->current_tb = NULL; env->current_tb = NULL;
tb_gen_code(env, current_pc, current_cs_base, current_flags, tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
CF_SINGLE_INSN);
cpu_resume_from_signal(env, puc); cpu_resume_from_signal(env, puc);
} }
#endif #endif
@@ -1068,6 +1073,17 @@ TranslationBlock *tb_alloc(target_ulong pc)
return tb; return tb;
} }
void tb_free(TranslationBlock *tb)
{
/* In practice this is mostly used for single use temorary TB
Ignore the hard cases and just back up if this TB happens to
be the last one generated. */
if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) {
code_gen_ptr = tb->tc_ptr;
nb_tbs--;
}
}
/* add a new TB and link it to the physical page tables. phys_page2 is /* add a new TB and link it to the physical page tables. phys_page2 is
(-1) to indicate that only one page contains the TB. */ (-1) to indicate that only one page contains the TB. */
void tb_link_phys(TranslationBlock *tb, void tb_link_phys(TranslationBlock *tb,
@@ -1369,7 +1385,9 @@ void cpu_interrupt(CPUState *env, int mask)
TranslationBlock *tb; TranslationBlock *tb;
static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED; static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
#endif #endif
int old_mask;
old_mask = env->interrupt_request;
/* FIXME: This is probably not threadsafe. A different thread could /* FIXME: This is probably not threadsafe. A different thread could
be in the mittle of a read-modify-write operation. */ be in the mittle of a read-modify-write operation. */
env->interrupt_request |= mask; env->interrupt_request |= mask;
@@ -1379,13 +1397,25 @@ void cpu_interrupt(CPUState *env, int mask)
emulation this often isn't actually as bad as it sounds. Often emulation this often isn't actually as bad as it sounds. Often
signals are used primarily to interrupt blocking syscalls. */ signals are used primarily to interrupt blocking syscalls. */
#else #else
/* if the cpu is currently executing code, we must unlink it and if (use_icount) {
all the potentially executing TB */ env->icount_decr.u16.high = 0x8000;
tb = env->current_tb; #ifndef CONFIG_USER_ONLY
if (tb && !testandset(&interrupt_lock)) { /* CPU_INTERRUPT_EXIT isn't a real interrupt. It just means
env->current_tb = NULL; an async event happened and we need to process it. */
tb_reset_jump_recursive(tb); if (!can_do_io(env)
resetlock(&interrupt_lock); && (mask & ~(old_mask | CPU_INTERRUPT_EXIT)) != 0) {
cpu_abort(env, "Raised interrupt while not in I/O function");
}
#endif
} else {
tb = env->current_tb;
/* if the cpu is currently executing code, we must unlink it and
all the potentially executing TB */
if (tb && !testandset(&interrupt_lock)) {
env->current_tb = NULL;
tb_reset_jump_recursive(tb);
resetlock(&interrupt_lock);
}
} }
#endif #endif
} }
@@ -2227,7 +2257,7 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
/* we remove the notdirty callback only if the code has been /* we remove the notdirty callback only if the code has been
flushed */ flushed */
if (dirty_flags == 0xff) if (dirty_flags == 0xff)
tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr); tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
} }
static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr, static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
@@ -2252,7 +2282,7 @@ static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
/* we remove the notdirty callback only if the code has been /* we remove the notdirty callback only if the code has been
flushed */ flushed */
if (dirty_flags == 0xff) if (dirty_flags == 0xff)
tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr); tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
} }
static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr, static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
@@ -2277,7 +2307,7 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
/* we remove the notdirty callback only if the code has been /* we remove the notdirty callback only if the code has been
flushed */ flushed */
if (dirty_flags == 0xff) if (dirty_flags == 0xff)
tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr); tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
} }
static CPUReadMemoryFunc *error_mem_read[3] = { static CPUReadMemoryFunc *error_mem_read[3] = {
@@ -2299,7 +2329,7 @@ static void check_watchpoint(int offset, int flags)
target_ulong vaddr; target_ulong vaddr;
int i; int i;
vaddr = (env->mem_write_vaddr & TARGET_PAGE_MASK) + offset; vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
for (i = 0; i < env->nb_watchpoints; i++) { for (i = 0; i < env->nb_watchpoints; i++) {
if (vaddr == env->watchpoint[i].vaddr if (vaddr == env->watchpoint[i].vaddr
&& (env->watchpoint[i].type & flags)) { && (env->watchpoint[i].type & flags)) {
@@ -2967,6 +2997,65 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
return 0; return 0;
} }
/* in deterministic execution mode, instructions doing device I/Os
must be at the end of the TB */
void cpu_io_recompile(CPUState *env, void *retaddr)
{
TranslationBlock *tb;
uint32_t n, cflags;
target_ulong pc, cs_base;
uint64_t flags;
tb = tb_find_pc((unsigned long)retaddr);
if (!tb) {
cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
retaddr);
}
n = env->icount_decr.u16.low + tb->icount;
cpu_restore_state(tb, env, (unsigned long)retaddr, NULL);
/* Calculate how many instructions had been executed before the fault
occured. */
n = n - env->icount_decr.u16.low;
/* Generate a new TB ending on the I/O insn. */
n++;
/* On MIPS and SH, delay slot instructions can only be restarted if
they were already the first instruction in the TB. If this is not
the first instruction in a TB then re-execute the preceeding
branch. */
#if defined(TARGET_MIPS)
if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) {
env->active_tc.PC -= 4;
env->icount_decr.u16.low++;
env->hflags &= ~MIPS_HFLAG_BMASK;
}
#elif defined(TARGET_SH4)
if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
&& n > 1) {
env->pc -= 2;
env->icount_decr.u16.low++;
env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
}
#endif
/* This should never happen. */
if (n > CF_COUNT_MASK)
cpu_abort(env, "TB too big during recompile");
cflags = n | CF_LAST_IO;
pc = tb->pc;
cs_base = tb->cs_base;
flags = tb->flags;
tb_phys_invalidate(tb, -1);
/* FIXME: In theory this could raise an exception. In practice
we have already translated the block once so it's probably ok. */
tb_gen_code(env, pc, cs_base, flags, cflags);
/* TODO: If env->pc != tb->pc (i.e. the failuting instruction was not
the first in the TB) then we end up generating a whole new TB and
repeating the fault, which is horribly inefficient.
Better would be to execute just this insn uncached, or generate a
second new TB. */
cpu_resume_from_signal(env, NULL);
}
void dump_exec_info(FILE *f, void dump_exec_info(FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
{ {
+5
View File
@@ -91,7 +91,12 @@ static void mips_timer_cb (void *opaque)
if (env->CP0_Cause & (1 << CP0Ca_DC)) if (env->CP0_Cause & (1 << CP0Ca_DC))
return; return;
/* ??? This callback should occur when the counter is exactly equal to
the comparator value. Offset the count by one to avoid immediately
retriggering the callback before any virtual time has passed. */
env->CP0_Count++;
cpu_mips_timer_update(env); cpu_mips_timer_update(env);
env->CP0_Count--;
if (env->insn_flags & ISA_MIPS32R2) if (env->insn_flags & ISA_MIPS32R2)
env->CP0_Cause |= 1 << CP0Ca_TI; env->CP0_Cause |= 1 << CP0Ca_TI;
qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
+11
View File
@@ -965,6 +965,17 @@ On M68K this implements the "ColdFire GDB" interface used by libgloss.
Note that this allows guest direct access to the host filesystem, Note that this allows guest direct access to the host filesystem,
so should only be used with trusted guest OS. so should only be used with trusted guest OS.
@item -icount [N|auto]
Enable virtual instruction counter. The virtual cpu will execute one
instruction every 2^N ns of virtual time. If @code{auto} is specified
then the virtual cpu speed will be automatically adjusted to keep virtual
time within a few seconds of real time.
Note that while this option can give deterministic behavior, it does not
provide cycle accurate emulation. Modern CPUs contain superscalar out of
order cores with complex cache heirachies. The number of instructions
executed often has little or no correlation with actual performance.
@end table @end table
@c man end @c man end
+17 -5
View File
@@ -51,12 +51,18 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
int mmu_idx, int mmu_idx,
void *retaddr); void *retaddr);
static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
target_ulong addr) target_ulong addr,
void *retaddr)
{ {
DATA_TYPE res; DATA_TYPE res;
int index; int index;
index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
physaddr = (physaddr & TARGET_PAGE_MASK) + addr; physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
env->mem_io_pc = (unsigned long)retaddr;
if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT)
&& !can_do_io(env)) {
cpu_io_recompile(env, retaddr);
}
#if SHIFT <= 2 #if SHIFT <= 2
res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr); res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr);
@@ -95,8 +101,9 @@ DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
/* IO access */ /* IO access */
if ((addr & (DATA_SIZE - 1)) != 0) if ((addr & (DATA_SIZE - 1)) != 0)
goto do_unaligned_access; goto do_unaligned_access;
retaddr = GETPC();
addend = env->iotlb[mmu_idx][index]; addend = env->iotlb[mmu_idx][index];
res = glue(io_read, SUFFIX)(addend, addr); res = glue(io_read, SUFFIX)(addend, addr, retaddr);
} else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
/* slow unaligned access (it spans two pages or IO) */ /* slow unaligned access (it spans two pages or IO) */
do_unaligned_access: do_unaligned_access:
@@ -148,8 +155,9 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
/* IO access */ /* IO access */
if ((addr & (DATA_SIZE - 1)) != 0) if ((addr & (DATA_SIZE - 1)) != 0)
goto do_unaligned_access; goto do_unaligned_access;
retaddr = GETPC();
addend = env->iotlb[mmu_idx][index]; addend = env->iotlb[mmu_idx][index];
res = glue(io_read, SUFFIX)(addend, addr); res = glue(io_read, SUFFIX)(addend, addr, retaddr);
} else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
do_unaligned_access: do_unaligned_access:
/* slow unaligned access (it spans two pages) */ /* slow unaligned access (it spans two pages) */
@@ -194,9 +202,13 @@ static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr,
int index; int index;
index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
physaddr = (physaddr & TARGET_PAGE_MASK) + addr; physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT)
&& !can_do_io(env)) {
cpu_io_recompile(env, retaddr);
}
env->mem_write_vaddr = addr; env->mem_io_vaddr = addr;
env->mem_write_pc = (unsigned long)retaddr; env->mem_io_pc = (unsigned long)retaddr;
#if SHIFT <= 2 #if SHIFT <= 2
io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val); io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val);
#else #else
+2
View File
@@ -415,4 +415,6 @@ void cpu_loop_exit (void);
void pal_init (CPUState *env); void pal_init (CPUState *env);
void call_pal (CPUState *env, int palcode); void call_pal (CPUState *env, int palcode);
#define CPU_PC_FROM_TB(env, tb) env->pc = tb->pc
#endif /* !defined (__CPU_ALPHA_H__) */ #endif /* !defined (__CPU_ALPHA_H__) */
+32 -1
View File
@@ -43,6 +43,19 @@ struct DisasContext {
uint32_t amask; uint32_t amask;
}; };
TCGv cpu_env;
#include "gen-icount.h"
void alpha_translate_init()
{
static int done_init = 0;
if (done_init)
return;
cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env");
done_init = 1;
}
static always_inline void gen_op_nop (void) static always_inline void gen_op_nop (void)
{ {
#if defined(GENERATE_NOP) #if defined(GENERATE_NOP)
@@ -1970,6 +1983,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
uint16_t *gen_opc_end; uint16_t *gen_opc_end;
int j, lj = -1; int j, lj = -1;
int ret; int ret;
int num_insns;
int max_insns;
pc_start = tb->pc; pc_start = tb->pc;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
@@ -1981,6 +1996,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
ctx.mem_idx = ((env->ps >> 3) & 3); ctx.mem_idx = ((env->ps >> 3) & 3);
ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1; ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1;
#endif #endif
num_insns = 0;
max_insns = tb->cflags & CF_COUNT_MASK;
if (max_insns == 0)
max_insns = CF_COUNT_MASK;
gen_icount_start();
for (ret = 0; ret == 0;) { for (ret = 0; ret == 0;) {
if (env->nb_breakpoints > 0) { if (env->nb_breakpoints > 0) {
for(j = 0; j < env->nb_breakpoints; j++) { for(j = 0; j < env->nb_breakpoints; j++) {
@@ -1998,8 +2019,11 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
gen_opc_instr_start[lj++] = 0; gen_opc_instr_start[lj++] = 0;
gen_opc_pc[lj] = ctx.pc; gen_opc_pc[lj] = ctx.pc;
gen_opc_instr_start[lj] = 1; gen_opc_instr_start[lj] = 1;
gen_opc_icount[lj] = num_insns;
} }
} }
if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
gen_io_start();
#if defined ALPHA_DEBUG_DISAS #if defined ALPHA_DEBUG_DISAS
insn_count++; insn_count++;
if (logfile != NULL) { if (logfile != NULL) {
@@ -2014,6 +2038,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
fprintf(logfile, "opcode %08x %d\n", insn, insn_count); fprintf(logfile, "opcode %08x %d\n", insn, insn_count);
} }
#endif #endif
num_insns++;
ctx.pc += 4; ctx.pc += 4;
ret = translate_one(ctxp, insn); ret = translate_one(ctxp, insn);
if (ret != 0) if (ret != 0)
@@ -2022,7 +2047,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
* generation * generation
*/ */
if (((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) || if (((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) ||
(env->singlestep_enabled)) { (env->singlestep_enabled) ||
num_insns >= max_insns) {
break; break;
} }
#if defined (DO_SINGLE_STEP) #if defined (DO_SINGLE_STEP)
@@ -2035,8 +2061,11 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
#if defined (DO_TB_FLUSH) #if defined (DO_TB_FLUSH)
gen_op_tb_flush(); gen_op_tb_flush();
#endif #endif
if (tb->cflags & CF_LAST_IO)
gen_io_end();
/* Generate the return instruction */ /* Generate the return instruction */
tcg_gen_exit_tb(0); tcg_gen_exit_tb(0);
gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end; *gen_opc_ptr = INDEX_op_end;
if (search_pc) { if (search_pc) {
j = gen_opc_ptr - gen_opc_buf; j = gen_opc_ptr - gen_opc_buf;
@@ -2045,6 +2074,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
gen_opc_instr_start[lj++] = 0; gen_opc_instr_start[lj++] = 0;
} else { } else {
tb->size = ctx.pc - pc_start; tb->size = ctx.pc - pc_start;
tb->icount = num_insns;
} }
#if defined ALPHA_DEBUG_DISAS #if defined ALPHA_DEBUG_DISAS
if (loglevel & CPU_LOG_TB_CPU) { if (loglevel & CPU_LOG_TB_CPU) {
@@ -2079,6 +2109,7 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
if (!env) if (!env)
return NULL; return NULL;
cpu_exec_init(env); cpu_exec_init(env);
alpha_translate_init();
tlb_flush(env, 1); tlb_flush(env, 1);
/* XXX: should not be hardcoded */ /* XXX: should not be hardcoded */
env->implver = IMPLVER_2106x; env->implver = IMPLVER_2106x;
+2
View File
@@ -417,6 +417,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
} }
#endif #endif
#define CPU_PC_FROM_TB(env, tb) env->regs[15] = tb->pc
#include "cpu-all.h" #include "cpu-all.h"
#endif #endif
+30 -1
View File
@@ -84,6 +84,9 @@ static TCGv cpu_V0, cpu_V1, cpu_M0;
static TCGv cpu_T[2]; static TCGv cpu_T[2];
static TCGv cpu_F0s, cpu_F1s, cpu_F0d, cpu_F1d; static TCGv cpu_F0s, cpu_F1s, cpu_F0d, cpu_F1d;
#define ICOUNT_TEMP cpu_T[0]
#include "gen-icount.h"
/* initialize TCG globals. */ /* initialize TCG globals. */
void arm_translate_init(void) void arm_translate_init(void)
{ {
@@ -8539,6 +8542,8 @@ static inline int gen_intermediate_code_internal(CPUState *env,
int j, lj; int j, lj;
target_ulong pc_start; target_ulong pc_start;
uint32_t next_page_start; uint32_t next_page_start;
int num_insns;
int max_insns;
/* generate intermediate code */ /* generate intermediate code */
num_temps = 0; num_temps = 0;
@@ -8575,6 +8580,12 @@ static inline int gen_intermediate_code_internal(CPUState *env,
cpu_M0 = tcg_temp_new(TCG_TYPE_I64); cpu_M0 = tcg_temp_new(TCG_TYPE_I64);
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
lj = -1; lj = -1;
num_insns = 0;
max_insns = tb->cflags & CF_COUNT_MASK;
if (max_insns == 0)
max_insns = CF_COUNT_MASK;
gen_icount_start();
/* Reset the conditional execution bits immediately. This avoids /* Reset the conditional execution bits immediately. This avoids
complications trying to do it at the end of the block. */ complications trying to do it at the end of the block. */
if (env->condexec_bits) if (env->condexec_bits)
@@ -8625,8 +8636,12 @@ static inline int gen_intermediate_code_internal(CPUState *env,
} }
gen_opc_pc[lj] = dc->pc; gen_opc_pc[lj] = dc->pc;
gen_opc_instr_start[lj] = 1; gen_opc_instr_start[lj] = 1;
gen_opc_icount[lj] = num_insns;
} }
if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
gen_io_start();
if (env->thumb) { if (env->thumb) {
disas_thumb_insn(env, dc); disas_thumb_insn(env, dc);
if (dc->condexec_mask) { if (dc->condexec_mask) {
@@ -8659,9 +8674,20 @@ static inline int gen_intermediate_code_internal(CPUState *env,
* Otherwise the subsequent code could get translated several times. * Otherwise the subsequent code could get translated several times.
* Also stop translation when a page boundary is reached. This * Also stop translation when a page boundary is reached. This
* ensures prefech aborts occur at the right place. */ * ensures prefech aborts occur at the right place. */
num_insns ++;
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
!env->singlestep_enabled && !env->singlestep_enabled &&
dc->pc < next_page_start); dc->pc < next_page_start &&
num_insns < max_insns);
if (tb->cflags & CF_LAST_IO) {
if (dc->condjmp) {
/* FIXME: This can theoretically happen with self-modifying
code. */
cpu_abort(env, "IO on conditional branch instruction");
}
gen_io_end();
}
/* At this stage dc->condjmp will only be set when the skipped /* At this stage dc->condjmp will only be set when the skipped
instruction was a conditional branch or trap, and the PC has instruction was a conditional branch or trap, and the PC has
@@ -8726,7 +8752,9 @@ static inline int gen_intermediate_code_internal(CPUState *env,
dc->condjmp = 0; dc->condjmp = 0;
} }
} }
done_generating: done_generating:
gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end; *gen_opc_ptr = INDEX_op_end;
#ifdef DEBUG_DISAS #ifdef DEBUG_DISAS
@@ -8744,6 +8772,7 @@ done_generating:
gen_opc_instr_start[lj++] = 0; gen_opc_instr_start[lj++] = 0;
} else { } else {
tb->size = dc->pc - pc_start; tb->size = dc->pc - pc_start;
tb->icount = num_insns;
} }
return 0; return 0;
} }
+2
View File
@@ -238,5 +238,7 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
#define SFR_RW_MM_TLB_LO env->pregs[PR_SRS]][5 #define SFR_RW_MM_TLB_LO env->pregs[PR_SRS]][5
#define SFR_RW_MM_TLB_HI env->pregs[PR_SRS]][6 #define SFR_RW_MM_TLB_HI env->pregs[PR_SRS]][6
#define CPU_PC_FROM_TB(env, tb) env->pc = tb->pc
#include "cpu-all.h" #include "cpu-all.h"
#endif #endif
+20 -1
View File
@@ -77,6 +77,8 @@ TCGv env_btaken;
TCGv env_btarget; TCGv env_btarget;
TCGv env_pc; TCGv env_pc;
#include "gen-icount.h"
/* This is the state at translation time. */ /* This is the state at translation time. */
typedef struct DisasContext { typedef struct DisasContext {
CPUState *env; CPUState *env;
@@ -3032,6 +3034,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
struct DisasContext *dc = &ctx; struct DisasContext *dc = &ctx;
uint32_t next_page_start; uint32_t next_page_start;
target_ulong npc; target_ulong npc;
int num_insns;
int max_insns;
if (!logfile) if (!logfile)
logfile = stderr; logfile = stderr;
@@ -3092,6 +3096,12 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
lj = -1; lj = -1;
num_insns = 0;
max_insns = tb->cflags & CF_COUNT_MASK;
if (max_insns == 0)
max_insns = CF_COUNT_MASK;
gen_icount_start();
do do
{ {
check_breakpoint(env, dc); check_breakpoint(env, dc);
@@ -3108,6 +3118,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
else else
gen_opc_pc[lj] = dc->pc; gen_opc_pc[lj] = dc->pc;
gen_opc_instr_start[lj] = 1; gen_opc_instr_start[lj] = 1;
gen_opc_icount[lj] = num_insns;
} }
/* Pretty disas. */ /* Pretty disas. */
@@ -3116,6 +3127,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
DIS(fprintf(logfile, "%x ", dc->pc)); DIS(fprintf(logfile, "%x ", dc->pc));
} }
if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
gen_io_start();
dc->clear_x = 1; dc->clear_x = 1;
if (unlikely(loglevel & CPU_LOG_TB_OP)) if (unlikely(loglevel & CPU_LOG_TB_OP))
tcg_gen_debug_insn_start(dc->pc); tcg_gen_debug_insn_start(dc->pc);
@@ -3125,6 +3138,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
if (dc->clear_x) if (dc->clear_x)
cris_clear_x_flag(dc); cris_clear_x_flag(dc);
num_insns++;
/* Check for delayed branches here. If we do it before /* Check for delayed branches here. If we do it before
actually genereating any host code, the simulator will just actually genereating any host code, the simulator will just
loop doing nothing for on this program location. */ loop doing nothing for on this program location. */
@@ -3151,12 +3165,15 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
if (!(tb->pc & 1) && env->singlestep_enabled) if (!(tb->pc & 1) && env->singlestep_enabled)
break; break;
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end
&& (dc->pc < next_page_start)); && (dc->pc < next_page_start)
&& num_insns < max_insns);
npc = dc->pc; npc = dc->pc;
if (dc->jmp == JMP_DIRECT && !dc->delayed_branch) if (dc->jmp == JMP_DIRECT && !dc->delayed_branch)
npc = dc->jmp_pc; npc = dc->jmp_pc;
if (tb->cflags & CF_LAST_IO)
gen_io_end();
/* Force an update if the per-tb cpu state has changed. */ /* Force an update if the per-tb cpu state has changed. */
if (dc->is_jmp == DISAS_NEXT if (dc->is_jmp == DISAS_NEXT
&& (dc->cpustate_changed || !dc->flagx_known && (dc->cpustate_changed || !dc->flagx_known
@@ -3194,6 +3211,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
break; break;
} }
} }
gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end; *gen_opc_ptr = INDEX_op_end;
if (search_pc) { if (search_pc) {
j = gen_opc_ptr - gen_opc_buf; j = gen_opc_ptr - gen_opc_buf;
@@ -3202,6 +3220,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
gen_opc_instr_start[lj++] = 0; gen_opc_instr_start[lj++] = 0;
} else { } else {
tb->size = dc->pc - pc_start; tb->size = dc->pc - pc_start;
tb->icount = num_insns;
} }
#ifdef DEBUG_DISAS #ifdef DEBUG_DISAS
+2
View File
@@ -753,6 +753,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
} }
#endif #endif
#define CPU_PC_FROM_TB(env, tb) env->eip = tb->pc - tb->cs_base
#include "cpu-all.h" #include "cpu-all.h"
#include "svm.h" #include "svm.h"
+61 -4
View File
@@ -65,6 +65,8 @@ static TCGv cpu_T[2], cpu_T3;
static TCGv cpu_tmp0, cpu_tmp1_i64, cpu_tmp2_i32, cpu_tmp3_i32, cpu_tmp4, cpu_ptr0, cpu_ptr1; static TCGv cpu_tmp0, cpu_tmp1_i64, cpu_tmp2_i32, cpu_tmp3_i32, cpu_tmp4, cpu_ptr0, cpu_ptr1;
static TCGv cpu_tmp5, cpu_tmp6; static TCGv cpu_tmp5, cpu_tmp6;
#include "gen-icount.h"
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
static int x86_64_hregs; static int x86_64_hregs;
#endif #endif
@@ -1203,6 +1205,8 @@ static inline void gen_cmps(DisasContext *s, int ot)
static inline void gen_ins(DisasContext *s, int ot) static inline void gen_ins(DisasContext *s, int ot)
{ {
if (use_icount)
gen_io_start();
gen_string_movl_A0_EDI(s); gen_string_movl_A0_EDI(s);
/* Note: we must do this dummy write first to be restartable in /* Note: we must do this dummy write first to be restartable in
case of page fault. */ case of page fault. */
@@ -1215,10 +1219,14 @@ static inline void gen_ins(DisasContext *s, int ot)
gen_op_st_T0_A0(ot + s->mem_index); gen_op_st_T0_A0(ot + s->mem_index);
gen_op_movl_T0_Dshift(ot); gen_op_movl_T0_Dshift(ot);
gen_op_add_reg_T0(s->aflag, R_EDI); gen_op_add_reg_T0(s->aflag, R_EDI);
if (use_icount)
gen_io_end();
} }
static inline void gen_outs(DisasContext *s, int ot) static inline void gen_outs(DisasContext *s, int ot)
{ {
if (use_icount)
gen_io_start();
gen_string_movl_A0_ESI(s); gen_string_movl_A0_ESI(s);
gen_op_ld_T0_A0(ot + s->mem_index); gen_op_ld_T0_A0(ot + s->mem_index);
@@ -1230,6 +1238,8 @@ static inline void gen_outs(DisasContext *s, int ot)
gen_op_movl_T0_Dshift(ot); gen_op_movl_T0_Dshift(ot);
gen_op_add_reg_T0(s->aflag, R_ESI); gen_op_add_reg_T0(s->aflag, R_ESI);
if (use_icount)
gen_io_end();
} }
/* same method as Valgrind : we generate jumps to current or next /* same method as Valgrind : we generate jumps to current or next
@@ -5570,6 +5580,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
} else { } else {
gen_ins(s, ot); gen_ins(s, ot);
if (use_icount) {
gen_jmp(s, s->pc - s->cs_base);
}
} }
break; break;
case 0x6e: /* outsS */ case 0x6e: /* outsS */
@@ -5586,6 +5599,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
} else { } else {
gen_outs(s, ot); gen_outs(s, ot);
if (use_icount) {
gen_jmp(s, s->pc - s->cs_base);
}
} }
break; break;
@@ -5602,9 +5618,15 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_op_movl_T0_im(val); gen_op_movl_T0_im(val);
gen_check_io(s, ot, pc_start - s->cs_base, gen_check_io(s, ot, pc_start - s->cs_base,
SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes)); SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
if (use_icount)
gen_io_start();
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2_i32); tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2_i32);
gen_op_mov_reg_T1(ot, R_EAX); gen_op_mov_reg_T1(ot, R_EAX);
if (use_icount) {
gen_io_end();
gen_jmp(s, s->pc - s->cs_base);
}
break; break;
case 0xe6: case 0xe6:
case 0xe7: case 0xe7:
@@ -5618,10 +5640,16 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
svm_is_rep(prefixes)); svm_is_rep(prefixes));
gen_op_mov_TN_reg(ot, 1, R_EAX); gen_op_mov_TN_reg(ot, 1, R_EAX);
if (use_icount)
gen_io_start();
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff); tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]); tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]);
tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2_i32, cpu_tmp3_i32); tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2_i32, cpu_tmp3_i32);
if (use_icount) {
gen_io_end();
gen_jmp(s, s->pc - s->cs_base);
}
break; break;
case 0xec: case 0xec:
case 0xed: case 0xed:
@@ -5633,9 +5661,15 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_op_andl_T0_ffff(); gen_op_andl_T0_ffff();
gen_check_io(s, ot, pc_start - s->cs_base, gen_check_io(s, ot, pc_start - s->cs_base,
SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes)); SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
if (use_icount)
gen_io_start();
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2_i32); tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2_i32);
gen_op_mov_reg_T1(ot, R_EAX); gen_op_mov_reg_T1(ot, R_EAX);
if (use_icount) {
gen_io_end();
gen_jmp(s, s->pc - s->cs_base);
}
break; break;
case 0xee: case 0xee:
case 0xef: case 0xef:
@@ -5649,10 +5683,16 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
svm_is_rep(prefixes)); svm_is_rep(prefixes));
gen_op_mov_TN_reg(ot, 1, R_EAX); gen_op_mov_TN_reg(ot, 1, R_EAX);
if (use_icount)
gen_io_start();
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff); tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]); tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]);
tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2_i32, cpu_tmp3_i32); tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2_i32, cpu_tmp3_i32);
if (use_icount) {
gen_io_end();
gen_jmp(s, s->pc - s->cs_base);
}
break; break;
/************************/ /************************/
@@ -7109,6 +7149,8 @@ static inline int gen_intermediate_code_internal(CPUState *env,
uint64_t flags; uint64_t flags;
target_ulong pc_start; target_ulong pc_start;
target_ulong cs_base; target_ulong cs_base;
int num_insns;
int max_insns;
/* generate intermediate code */ /* generate intermediate code */
pc_start = tb->pc; pc_start = tb->pc;
@@ -7179,7 +7221,12 @@ static inline int gen_intermediate_code_internal(CPUState *env,
dc->is_jmp = DISAS_NEXT; dc->is_jmp = DISAS_NEXT;
pc_ptr = pc_start; pc_ptr = pc_start;
lj = -1; lj = -1;
num_insns = 0;
max_insns = tb->cflags & CF_COUNT_MASK;
if (max_insns == 0)
max_insns = CF_COUNT_MASK;
gen_icount_start();
for(;;) { for(;;) {
if (env->nb_breakpoints > 0) { if (env->nb_breakpoints > 0) {
for(j = 0; j < env->nb_breakpoints; j++) { for(j = 0; j < env->nb_breakpoints; j++) {
@@ -7199,8 +7246,13 @@ static inline int gen_intermediate_code_internal(CPUState *env,
gen_opc_pc[lj] = pc_ptr; gen_opc_pc[lj] = pc_ptr;
gen_opc_cc_op[lj] = dc->cc_op; gen_opc_cc_op[lj] = dc->cc_op;
gen_opc_instr_start[lj] = 1; gen_opc_instr_start[lj] = 1;
gen_opc_icount[lj] = num_insns;
} }
if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
gen_io_start();
pc_ptr = disas_insn(dc, pc_ptr); pc_ptr = disas_insn(dc, pc_ptr);
num_insns++;
/* stop translation if indicated */ /* stop translation if indicated */
if (dc->is_jmp) if (dc->is_jmp)
break; break;
@@ -7210,20 +7262,23 @@ static inline int gen_intermediate_code_internal(CPUState *env,
the flag and abort the translation to give the irqs a the flag and abort the translation to give the irqs a
change to be happen */ change to be happen */
if (dc->tf || dc->singlestep_enabled || if (dc->tf || dc->singlestep_enabled ||
(flags & HF_INHIBIT_IRQ_MASK) || (flags & HF_INHIBIT_IRQ_MASK)) {
(cflags & CF_SINGLE_INSN)) {
gen_jmp_im(pc_ptr - dc->cs_base); gen_jmp_im(pc_ptr - dc->cs_base);
gen_eob(dc); gen_eob(dc);
break; break;
} }
/* if too long translation, stop generation too */ /* if too long translation, stop generation too */
if (gen_opc_ptr >= gen_opc_end || if (gen_opc_ptr >= gen_opc_end ||
(pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32)) { (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) ||
num_insns >= max_insns) {
gen_jmp_im(pc_ptr - dc->cs_base); gen_jmp_im(pc_ptr - dc->cs_base);
gen_eob(dc); gen_eob(dc);
break; break;
} }
} }
if (tb->cflags & CF_LAST_IO)
gen_io_end();
gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end; *gen_opc_ptr = INDEX_op_end;
/* we don't forget to fill the last values */ /* we don't forget to fill the last values */
if (search_pc) { if (search_pc) {
@@ -7252,8 +7307,10 @@ static inline int gen_intermediate_code_internal(CPUState *env,
} }
#endif #endif
if (!search_pc) if (!search_pc) {
tb->size = pc_ptr - pc_start; tb->size = pc_ptr - pc_start;
tb->icount = num_insns;
}
return 0; return 0;
} }
+2
View File
@@ -235,6 +235,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
} }
#endif #endif
#define CPU_PC_FROM_TB(env, tb) env->pc = tb->pc
#include "cpu-all.h" #include "cpu-all.h"
#endif #endif
+20 -1
View File
@@ -63,6 +63,8 @@ static TCGv NULL_QREG;
/* Used to distinguish stores from bad addressing modes. */ /* Used to distinguish stores from bad addressing modes. */
static TCGv store_dummy; static TCGv store_dummy;
#include "gen-icount.h"
void m68k_tcg_init(void) void m68k_tcg_init(void)
{ {
char *p; char *p;
@@ -2919,6 +2921,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
target_ulong pc_start; target_ulong pc_start;
int pc_offset; int pc_offset;
int last_cc_op; int last_cc_op;
int num_insns;
int max_insns;
/* generate intermediate code */ /* generate intermediate code */
pc_start = tb->pc; pc_start = tb->pc;
@@ -2937,6 +2941,12 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
dc->is_mem = 0; dc->is_mem = 0;
dc->mactmp = NULL_QREG; dc->mactmp = NULL_QREG;
lj = -1; lj = -1;
num_insns = 0;
max_insns = tb->cflags & CF_COUNT_MASK;
if (max_insns == 0)
max_insns = CF_COUNT_MASK;
gen_icount_start();
do { do {
pc_offset = dc->pc - pc_start; pc_offset = dc->pc - pc_start;
gen_throws_exception = NULL; gen_throws_exception = NULL;
@@ -2960,10 +2970,14 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
} }
gen_opc_pc[lj] = dc->pc; gen_opc_pc[lj] = dc->pc;
gen_opc_instr_start[lj] = 1; gen_opc_instr_start[lj] = 1;
gen_opc_icount[lj] = num_insns;
} }
if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
gen_io_start();
last_cc_op = dc->cc_op; last_cc_op = dc->cc_op;
dc->insn_pc = dc->pc; dc->insn_pc = dc->pc;
disas_m68k_insn(env, dc); disas_m68k_insn(env, dc);
num_insns++;
/* Terminate the TB on memory ops if watchpoints are present. */ /* Terminate the TB on memory ops if watchpoints are present. */
/* FIXME: This should be replacd by the deterministic execution /* FIXME: This should be replacd by the deterministic execution
@@ -2972,8 +2986,11 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
break; break;
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
!env->singlestep_enabled && !env->singlestep_enabled &&
(pc_offset) < (TARGET_PAGE_SIZE - 32)); (pc_offset) < (TARGET_PAGE_SIZE - 32) &&
num_insns < max_insns);
if (tb->cflags & CF_LAST_IO)
gen_io_end();
if (__builtin_expect(env->singlestep_enabled, 0)) { if (__builtin_expect(env->singlestep_enabled, 0)) {
/* Make sure the pc is updated, and raise a debug exception. */ /* Make sure the pc is updated, and raise a debug exception. */
if (!dc->is_jmp) { if (!dc->is_jmp) {
@@ -2999,6 +3016,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
break; break;
} }
} }
gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end; *gen_opc_ptr = INDEX_op_end;
#ifdef DEBUG_DISAS #ifdef DEBUG_DISAS
@@ -3016,6 +3034,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
gen_opc_instr_start[lj++] = 0; gen_opc_instr_start[lj++] = 0;
} else { } else {
tb->size = dc->pc - pc_start; tb->size = dc->pc - pc_start;
tb->icount = num_insns;
} }
//optimize_flags(); //optimize_flags();
+6
View File
@@ -572,4 +572,10 @@ CPUMIPSState *cpu_mips_init(const char *cpu_model);
uint32_t cpu_mips_get_clock (void); uint32_t cpu_mips_get_clock (void);
int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc); int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc);
#define CPU_PC_FROM_TB(env, tb) do { \
env->active_tc.PC = tb->pc; \
env->hflags &= ~MIPS_HFLAG_BMASK; \
env->hflags |= tb->flags & MIPS_HFLAG_BMASK; \
} while (0)
#endif /* !defined (__MIPS_CPU_H__) */ #endif /* !defined (__MIPS_CPU_H__) */
+51
View File
@@ -428,6 +428,8 @@ static TCGv cpu_env, current_fpu;
/* FPU TNs, global for now. */ /* FPU TNs, global for now. */
static TCGv fpu32_T[3], fpu64_T[3], fpu32h_T[3]; static TCGv fpu32_T[3], fpu64_T[3], fpu32h_T[3];
#include "gen-icount.h"
static inline void tcg_gen_helper_0_i(void *func, TCGv arg) static inline void tcg_gen_helper_0_i(void *func, TCGv arg)
{ {
TCGv tmp = tcg_const_i32(arg); TCGv tmp = tcg_const_i32(arg);
@@ -3061,7 +3063,14 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int se
case 9: case 9:
switch (sel) { switch (sel) {
case 0: case 0:
/* Mark as an IO operation because we read the time. */
if (use_icount)
gen_io_start();
tcg_gen_helper_1_0(do_mfc0_count, t0); tcg_gen_helper_1_0(do_mfc0_count, t0);
if (use_icount) {
gen_io_end();
ctx->bstate = BS_STOP;
}
rn = "Count"; rn = "Count";
break; break;
/* 6,7 are implementation dependent */ /* 6,7 are implementation dependent */
@@ -3422,6 +3431,9 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int se
if (sel != 0) if (sel != 0)
check_insn(env, ctx, ISA_MIPS32); check_insn(env, ctx, ISA_MIPS32);
if (use_icount)
gen_io_start();
switch (reg) { switch (reg) {
case 0: case 0:
switch (sel) { switch (sel) {
@@ -4004,6 +4016,11 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int se
rn, reg, sel); rn, reg, sel);
} }
#endif #endif
/* For simplicitly assume that all writes can cause interrupts. */
if (use_icount) {
gen_io_end();
ctx->bstate = BS_STOP;
}
return; return;
die: die:
@@ -4238,7 +4255,14 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int s
case 9: case 9:
switch (sel) { switch (sel) {
case 0: case 0:
/* Mark as an IO operation because we read the time. */
if (use_icount)
gen_io_start();
tcg_gen_helper_1_0(do_mfc0_count, t0); tcg_gen_helper_1_0(do_mfc0_count, t0);
if (use_icount) {
gen_io_end();
ctx->bstate = BS_STOP;
}
rn = "Count"; rn = "Count";
break; break;
/* 6,7 are implementation dependent */ /* 6,7 are implementation dependent */
@@ -4591,6 +4615,9 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int s
if (sel != 0) if (sel != 0)
check_insn(env, ctx, ISA_MIPS64); check_insn(env, ctx, ISA_MIPS64);
if (use_icount)
gen_io_start();
switch (reg) { switch (reg) {
case 0: case 0:
switch (sel) { switch (sel) {
@@ -5161,6 +5188,11 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int s
} }
#endif #endif
tcg_temp_free(t0); tcg_temp_free(t0);
/* For simplicitly assume that all writes can cause interrupts. */
if (use_icount) {
gen_io_end();
ctx->bstate = BS_STOP;
}
return; return;
die: die:
@@ -7760,6 +7792,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
ctx->hflags &= ~MIPS_HFLAG_BMASK; ctx->hflags &= ~MIPS_HFLAG_BMASK;
ctx->bstate = BS_BRANCH; ctx->bstate = BS_BRANCH;
save_cpu_state(ctx, 0); save_cpu_state(ctx, 0);
/* FIXME: Need to clear can_do_io. */
switch (hflags) { switch (hflags) {
case MIPS_HFLAG_B: case MIPS_HFLAG_B:
/* unconditional branch */ /* unconditional branch */
@@ -7807,6 +7840,8 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
target_ulong pc_start; target_ulong pc_start;
uint16_t *gen_opc_end; uint16_t *gen_opc_end;
int j, lj = -1; int j, lj = -1;
int num_insns;
int max_insns;
if (search_pc && loglevel) if (search_pc && loglevel)
fprintf (logfile, "search pc %d\n", search_pc); fprintf (logfile, "search pc %d\n", search_pc);
@@ -7826,6 +7861,11 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
#else #else
ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU; ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU;
#endif #endif
num_insns = 0;
num_insns = 0;
max_insns = tb->cflags & CF_COUNT_MASK;
if (max_insns == 0)
max_insns = CF_COUNT_MASK;
#ifdef DEBUG_DISAS #ifdef DEBUG_DISAS
if (loglevel & CPU_LOG_TB_CPU) { if (loglevel & CPU_LOG_TB_CPU) {
fprintf(logfile, "------------------------------------------------\n"); fprintf(logfile, "------------------------------------------------\n");
@@ -7838,6 +7878,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
fprintf(logfile, "\ntb %p idx %d hflags %04x\n", fprintf(logfile, "\ntb %p idx %d hflags %04x\n",
tb, ctx.mem_idx, ctx.hflags); tb, ctx.mem_idx, ctx.hflags);
#endif #endif
gen_icount_start();
while (ctx.bstate == BS_NONE) { while (ctx.bstate == BS_NONE) {
if (env->nb_breakpoints > 0) { if (env->nb_breakpoints > 0) {
for(j = 0; j < env->nb_breakpoints; j++) { for(j = 0; j < env->nb_breakpoints; j++) {
@@ -7863,10 +7904,14 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
gen_opc_pc[lj] = ctx.pc; gen_opc_pc[lj] = ctx.pc;
gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK; gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK;
gen_opc_instr_start[lj] = 1; gen_opc_instr_start[lj] = 1;
gen_opc_icount[lj] = num_insns;
} }
if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
gen_io_start();
ctx.opcode = ldl_code(ctx.pc); ctx.opcode = ldl_code(ctx.pc);
decode_opc(env, &ctx); decode_opc(env, &ctx);
ctx.pc += 4; ctx.pc += 4;
num_insns++;
if (env->singlestep_enabled) if (env->singlestep_enabled)
break; break;
@@ -7880,10 +7925,14 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
if (gen_opc_ptr >= gen_opc_end) if (gen_opc_ptr >= gen_opc_end)
break; break;
if (num_insns >= max_insns)
break;
#if defined (MIPS_SINGLE_STEP) #if defined (MIPS_SINGLE_STEP)
break; break;
#endif #endif
} }
if (tb->cflags & CF_LAST_IO)
gen_io_end();
if (env->singlestep_enabled) { if (env->singlestep_enabled) {
save_cpu_state(&ctx, ctx.bstate == BS_NONE); save_cpu_state(&ctx, ctx.bstate == BS_NONE);
tcg_gen_helper_0_i(do_raise_exception, EXCP_DEBUG); tcg_gen_helper_0_i(do_raise_exception, EXCP_DEBUG);
@@ -7907,6 +7956,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
} }
} }
done_generating: done_generating:
gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end; *gen_opc_ptr = INDEX_op_end;
if (search_pc) { if (search_pc) {
j = gen_opc_ptr - gen_opc_buf; j = gen_opc_ptr - gen_opc_buf;
@@ -7915,6 +7965,7 @@ done_generating:
gen_opc_instr_start[lj++] = 0; gen_opc_instr_start[lj++] = 0;
} else { } else {
tb->size = ctx.pc - pc_start; tb->size = ctx.pc - pc_start;
tb->icount = num_insns;
} }
#ifdef DEBUG_DISAS #ifdef DEBUG_DISAS
#if defined MIPS_DEBUG_DISAS #if defined MIPS_DEBUG_DISAS

Some files were not shown because too many files have changed in this diff Show More