mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Add instruction counter.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4799 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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, ...))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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]);
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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__) */
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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();
|
||||||
|
|||||||
@@ -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__) */
|
||||||
|
|||||||
@@ -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
Reference in New Issue
Block a user