Commit 2e70f6efa8b960d3b5401373ad6fa98747bb9578
1 parent
f6e5889e
Add instruction counter.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4799 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
29 changed files
with
830 additions
and
117 deletions
cpu-all.h
@@ -782,6 +782,8 @@ void cpu_abort(CPUState *env, const char *fmt, ...) | @@ -782,6 +782,8 @@ void cpu_abort(CPUState *env, const char *fmt, ...) | ||
782 | __attribute__ ((__noreturn__)); | 782 | __attribute__ ((__noreturn__)); |
783 | extern CPUState *first_cpu; | 783 | extern CPUState *first_cpu; |
784 | extern CPUState *cpu_single_env; | 784 | extern CPUState *cpu_single_env; |
785 | +extern int64_t qemu_icount; | ||
786 | +extern int use_icount; | ||
785 | 787 | ||
786 | #define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */ | 788 | #define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */ |
787 | #define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ | 789 | #define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ |
cpu-defs.h
@@ -130,17 +130,29 @@ typedef struct CPUTLBEntry { | @@ -130,17 +130,29 @@ typedef struct CPUTLBEntry { | ||
130 | sizeof(target_phys_addr_t))]; | 130 | sizeof(target_phys_addr_t))]; |
131 | } CPUTLBEntry; | 131 | } CPUTLBEntry; |
132 | 132 | ||
133 | +#ifdef WORDS_BIGENDIAN | ||
134 | +typedef struct icount_decr_u16 { | ||
135 | + uint16_t high; | ||
136 | + uint16_t low; | ||
137 | +} icount_decr_u16; | ||
138 | +#else | ||
139 | +typedef struct icount_decr_u16 { | ||
140 | + uint16_t low; | ||
141 | + uint16_t high; | ||
142 | +} icount_decr_u16; | ||
143 | +#endif | ||
144 | + | ||
133 | #define CPU_TEMP_BUF_NLONGS 128 | 145 | #define CPU_TEMP_BUF_NLONGS 128 |
134 | #define CPU_COMMON \ | 146 | #define CPU_COMMON \ |
135 | struct TranslationBlock *current_tb; /* currently executing TB */ \ | 147 | struct TranslationBlock *current_tb; /* currently executing TB */ \ |
136 | /* soft mmu support */ \ | 148 | /* soft mmu support */ \ |
137 | - /* in order to avoid passing too many arguments to the memory \ | ||
138 | - write helpers, we store some rarely used information in the CPU \ | 149 | + /* in order to avoid passing too many arguments to the MMIO \ |
150 | + helpers, we store some rarely used information in the CPU \ | ||
139 | context) */ \ | 151 | context) */ \ |
140 | - unsigned long mem_write_pc; /* host pc at which the memory was \ | ||
141 | - written */ \ | ||
142 | - target_ulong mem_write_vaddr; /* target virtual addr at which the \ | ||
143 | - memory was written */ \ | 152 | + unsigned long mem_io_pc; /* host pc at which the memory was \ |
153 | + accessed */ \ | ||
154 | + target_ulong mem_io_vaddr; /* target virtual addr at which the \ | ||
155 | + memory was accessed */ \ | ||
144 | int halted; /* TRUE if the CPU is in suspend state */ \ | 156 | int halted; /* TRUE if the CPU is in suspend state */ \ |
145 | /* The meaning of the MMU modes is defined in the target code. */ \ | 157 | /* The meaning of the MMU modes is defined in the target code. */ \ |
146 | CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \ | 158 | CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \ |
@@ -149,6 +161,16 @@ typedef struct CPUTLBEntry { | @@ -149,6 +161,16 @@ typedef struct CPUTLBEntry { | ||
149 | /* buffer for temporaries in the code generator */ \ | 161 | /* buffer for temporaries in the code generator */ \ |
150 | long temp_buf[CPU_TEMP_BUF_NLONGS]; \ | 162 | long temp_buf[CPU_TEMP_BUF_NLONGS]; \ |
151 | \ | 163 | \ |
164 | + int64_t icount_extra; /* Instructions until next timer event. */ \ | ||
165 | + /* Number of cycles left, with interrupt flag in high bit. \ | ||
166 | + This allows a single read-compare-cbranch-write sequence to test \ | ||
167 | + for both decrementer underflow and exceptions. */ \ | ||
168 | + union { \ | ||
169 | + uint32_t u32; \ | ||
170 | + icount_decr_u16 u16; \ | ||
171 | + } icount_decr; \ | ||
172 | + uint32_t can_do_io; /* nonzero if memory mapped IO is safe. */ \ | ||
173 | + \ | ||
152 | /* from this point: preserved by CPU reset */ \ | 174 | /* from this point: preserved by CPU reset */ \ |
153 | /* ice debug support */ \ | 175 | /* ice debug support */ \ |
154 | target_ulong breakpoints[MAX_BREAKPOINTS]; \ | 176 | target_ulong breakpoints[MAX_BREAKPOINTS]; \ |
cpu-exec.c
@@ -82,15 +82,40 @@ void cpu_resume_from_signal(CPUState *env1, void *puc) | @@ -82,15 +82,40 @@ void cpu_resume_from_signal(CPUState *env1, void *puc) | ||
82 | longjmp(env->jmp_env, 1); | 82 | longjmp(env->jmp_env, 1); |
83 | } | 83 | } |
84 | 84 | ||
85 | +/* Execute the code without caching the generated code. An interpreter | ||
86 | + could be used if available. */ | ||
87 | +static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb) | ||
88 | +{ | ||
89 | + unsigned long next_tb; | ||
90 | + TranslationBlock *tb; | ||
91 | + | ||
92 | + /* Should never happen. | ||
93 | + We only end up here when an existing TB is too long. */ | ||
94 | + if (max_cycles > CF_COUNT_MASK) | ||
95 | + max_cycles = CF_COUNT_MASK; | ||
96 | + | ||
97 | + tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags, | ||
98 | + max_cycles); | ||
99 | + env->current_tb = tb; | ||
100 | + /* execute the generated code */ | ||
101 | + next_tb = tcg_qemu_tb_exec(tb->tc_ptr); | ||
102 | + | ||
103 | + if ((next_tb & 3) == 2) { | ||
104 | + /* Restore PC. This may happen if async event occurs before | ||
105 | + the TB starts executing. */ | ||
106 | + CPU_PC_FROM_TB(env, tb); | ||
107 | + } | ||
108 | + tb_phys_invalidate(tb, -1); | ||
109 | + tb_free(tb); | ||
110 | +} | ||
111 | + | ||
85 | static TranslationBlock *tb_find_slow(target_ulong pc, | 112 | static TranslationBlock *tb_find_slow(target_ulong pc, |
86 | target_ulong cs_base, | 113 | target_ulong cs_base, |
87 | uint64_t flags) | 114 | uint64_t flags) |
88 | { | 115 | { |
89 | TranslationBlock *tb, **ptb1; | 116 | TranslationBlock *tb, **ptb1; |
90 | - int code_gen_size; | ||
91 | unsigned int h; | 117 | unsigned int h; |
92 | target_ulong phys_pc, phys_page1, phys_page2, virt_page2; | 118 | target_ulong phys_pc, phys_page1, phys_page2, virt_page2; |
93 | - uint8_t *tc_ptr; | ||
94 | 119 | ||
95 | tb_invalidated_flag = 0; | 120 | tb_invalidated_flag = 0; |
96 | 121 | ||
@@ -124,30 +149,8 @@ static TranslationBlock *tb_find_slow(target_ulong pc, | @@ -124,30 +149,8 @@ static TranslationBlock *tb_find_slow(target_ulong pc, | ||
124 | ptb1 = &tb->phys_hash_next; | 149 | ptb1 = &tb->phys_hash_next; |
125 | } | 150 | } |
126 | not_found: | 151 | not_found: |
127 | - /* if no translated code available, then translate it now */ | ||
128 | - tb = tb_alloc(pc); | ||
129 | - if (!tb) { | ||
130 | - /* flush must be done */ | ||
131 | - tb_flush(env); | ||
132 | - /* cannot fail at this point */ | ||
133 | - tb = tb_alloc(pc); | ||
134 | - /* don't forget to invalidate previous TB info */ | ||
135 | - tb_invalidated_flag = 1; | ||
136 | - } | ||
137 | - tc_ptr = code_gen_ptr; | ||
138 | - tb->tc_ptr = tc_ptr; | ||
139 | - tb->cs_base = cs_base; | ||
140 | - tb->flags = flags; | ||
141 | - cpu_gen_code(env, tb, &code_gen_size); | ||
142 | - code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); | ||
143 | - | ||
144 | - /* check next page if needed */ | ||
145 | - virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; | ||
146 | - phys_page2 = -1; | ||
147 | - if ((pc & TARGET_PAGE_MASK) != virt_page2) { | ||
148 | - phys_page2 = get_phys_addr_code(env, virt_page2); | ||
149 | - } | ||
150 | - tb_link_phys(tb, phys_pc, phys_page2); | 152 | + /* if no translated code available, then translate it now */ |
153 | + tb = tb_gen_code(env, pc, cs_base, flags, 0); | ||
151 | 154 | ||
152 | found: | 155 | found: |
153 | /* we add the TB in the virtual pc hash table */ | 156 | /* we add the TB in the virtual pc hash table */ |
@@ -583,6 +586,7 @@ int cpu_exec(CPUState *env1) | @@ -583,6 +586,7 @@ int cpu_exec(CPUState *env1) | ||
583 | of memory exceptions while generating the code, we | 586 | of memory exceptions while generating the code, we |
584 | must recompute the hash index here */ | 587 | must recompute the hash index here */ |
585 | next_tb = 0; | 588 | next_tb = 0; |
589 | + tb_invalidated_flag = 0; | ||
586 | } | 590 | } |
587 | #ifdef DEBUG_EXEC | 591 | #ifdef DEBUG_EXEC |
588 | if ((loglevel & CPU_LOG_EXEC)) { | 592 | if ((loglevel & CPU_LOG_EXEC)) { |
@@ -604,16 +608,45 @@ int cpu_exec(CPUState *env1) | @@ -604,16 +608,45 @@ int cpu_exec(CPUState *env1) | ||
604 | } | 608 | } |
605 | } | 609 | } |
606 | spin_unlock(&tb_lock); | 610 | spin_unlock(&tb_lock); |
607 | - tc_ptr = tb->tc_ptr; | ||
608 | env->current_tb = tb; | 611 | env->current_tb = tb; |
612 | + while (env->current_tb) { | ||
613 | + tc_ptr = tb->tc_ptr; | ||
609 | /* execute the generated code */ | 614 | /* execute the generated code */ |
610 | #if defined(__sparc__) && !defined(HOST_SOLARIS) | 615 | #if defined(__sparc__) && !defined(HOST_SOLARIS) |
611 | #undef env | 616 | #undef env |
612 | - env = cpu_single_env; | 617 | + env = cpu_single_env; |
613 | #define env cpu_single_env | 618 | #define env cpu_single_env |
614 | #endif | 619 | #endif |
615 | - next_tb = tcg_qemu_tb_exec(tc_ptr); | ||
616 | - env->current_tb = NULL; | 620 | + next_tb = tcg_qemu_tb_exec(tc_ptr); |
621 | + env->current_tb = NULL; | ||
622 | + if ((next_tb & 3) == 2) { | ||
623 | + /* Instruction counter exired. */ | ||
624 | + int insns_left; | ||
625 | + tb = (TranslationBlock *)(long)(next_tb & ~3); | ||
626 | + /* Restore PC. */ | ||
627 | + CPU_PC_FROM_TB(env, tb); | ||
628 | + insns_left = env->icount_decr.u32; | ||
629 | + if (env->icount_extra && insns_left >= 0) { | ||
630 | + /* Refill decrementer and continue execution. */ | ||
631 | + env->icount_extra += insns_left; | ||
632 | + if (env->icount_extra > 0xffff) { | ||
633 | + insns_left = 0xffff; | ||
634 | + } else { | ||
635 | + insns_left = env->icount_extra; | ||
636 | + } | ||
637 | + env->icount_extra -= insns_left; | ||
638 | + env->icount_decr.u16.low = insns_left; | ||
639 | + } else { | ||
640 | + if (insns_left > 0) { | ||
641 | + /* Execute remaining instructions. */ | ||
642 | + cpu_exec_nocache(insns_left, tb); | ||
643 | + } | ||
644 | + env->exception_index = EXCP_INTERRUPT; | ||
645 | + next_tb = 0; | ||
646 | + cpu_loop_exit(); | ||
647 | + } | ||
648 | + } | ||
649 | + } | ||
617 | /* reset soft MMU for next block (it can currently | 650 | /* reset soft MMU for next block (it can currently |
618 | only be set by a memory fault) */ | 651 | only be set by a memory fault) */ |
619 | #if defined(USE_KQEMU) | 652 | #if defined(USE_KQEMU) |
exec-all.h
@@ -27,7 +27,7 @@ | @@ -27,7 +27,7 @@ | ||
27 | #define DISAS_UPDATE 2 /* cpu state was modified dynamically */ | 27 | #define DISAS_UPDATE 2 /* cpu state was modified dynamically */ |
28 | #define DISAS_TB_JUMP 3 /* only pc was modified statically */ | 28 | #define DISAS_TB_JUMP 3 /* only pc was modified statically */ |
29 | 29 | ||
30 | -struct TranslationBlock; | 30 | +typedef struct TranslationBlock TranslationBlock; |
31 | 31 | ||
32 | /* XXX: make safe guess about sizes */ | 32 | /* XXX: make safe guess about sizes */ |
33 | #define MAX_OP_PER_INSTR 64 | 33 | #define MAX_OP_PER_INSTR 64 |
@@ -48,6 +48,7 @@ extern target_ulong gen_opc_pc[OPC_BUF_SIZE]; | @@ -48,6 +48,7 @@ extern target_ulong gen_opc_pc[OPC_BUF_SIZE]; | ||
48 | extern target_ulong gen_opc_npc[OPC_BUF_SIZE]; | 48 | extern target_ulong gen_opc_npc[OPC_BUF_SIZE]; |
49 | extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; | 49 | extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; |
50 | extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; | 50 | extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; |
51 | +extern uint16_t gen_opc_icount[OPC_BUF_SIZE]; | ||
51 | extern target_ulong gen_opc_jump_pc[2]; | 52 | extern target_ulong gen_opc_jump_pc[2]; |
52 | extern uint32_t gen_opc_hflags[OPC_BUF_SIZE]; | 53 | extern uint32_t gen_opc_hflags[OPC_BUF_SIZE]; |
53 | 54 | ||
@@ -75,6 +76,10 @@ int cpu_restore_state_copy(struct TranslationBlock *tb, | @@ -75,6 +76,10 @@ int cpu_restore_state_copy(struct TranslationBlock *tb, | ||
75 | CPUState *env, unsigned long searched_pc, | 76 | CPUState *env, unsigned long searched_pc, |
76 | void *puc); | 77 | void *puc); |
77 | void cpu_resume_from_signal(CPUState *env1, void *puc); | 78 | void cpu_resume_from_signal(CPUState *env1, void *puc); |
79 | +void cpu_io_recompile(CPUState *env, void *retaddr); | ||
80 | +TranslationBlock *tb_gen_code(CPUState *env, | ||
81 | + target_ulong pc, target_ulong cs_base, int flags, | ||
82 | + int cflags); | ||
78 | void cpu_exec_init(CPUState *env); | 83 | void cpu_exec_init(CPUState *env); |
79 | int page_unprotect(target_ulong address, unsigned long pc, void *puc); | 84 | int page_unprotect(target_ulong address, unsigned long pc, void *puc); |
80 | void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end, | 85 | 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, | @@ -117,16 +122,15 @@ static inline int tlb_set_page(CPUState *env1, target_ulong vaddr, | ||
117 | #define USE_DIRECT_JUMP | 122 | #define USE_DIRECT_JUMP |
118 | #endif | 123 | #endif |
119 | 124 | ||
120 | -typedef struct TranslationBlock { | 125 | +struct TranslationBlock { |
121 | target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ | 126 | target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ |
122 | target_ulong cs_base; /* CS base for this block */ | 127 | target_ulong cs_base; /* CS base for this block */ |
123 | uint64_t flags; /* flags defining in which context the code was generated */ | 128 | uint64_t flags; /* flags defining in which context the code was generated */ |
124 | uint16_t size; /* size of target code for this block (1 <= | 129 | uint16_t size; /* size of target code for this block (1 <= |
125 | size <= TARGET_PAGE_SIZE) */ | 130 | size <= TARGET_PAGE_SIZE) */ |
126 | uint16_t cflags; /* compile flags */ | 131 | uint16_t cflags; /* compile flags */ |
127 | -#define CF_TB_FP_USED 0x0002 /* fp ops are used in the TB */ | ||
128 | -#define CF_FP_USED 0x0004 /* fp ops are used in the TB or in a chained TB */ | ||
129 | -#define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */ | 132 | +#define CF_COUNT_MASK 0x7fff |
133 | +#define CF_LAST_IO 0x8000 /* Last insn may be an IO access. */ | ||
130 | 134 | ||
131 | uint8_t *tc_ptr; /* pointer to the translated code */ | 135 | uint8_t *tc_ptr; /* pointer to the translated code */ |
132 | /* next matching tb for physical address. */ | 136 | /* next matching tb for physical address. */ |
@@ -150,7 +154,8 @@ typedef struct TranslationBlock { | @@ -150,7 +154,8 @@ typedef struct TranslationBlock { | ||
150 | jmp_first */ | 154 | jmp_first */ |
151 | struct TranslationBlock *jmp_next[2]; | 155 | struct TranslationBlock *jmp_next[2]; |
152 | struct TranslationBlock *jmp_first; | 156 | struct TranslationBlock *jmp_first; |
153 | -} TranslationBlock; | 157 | + uint32_t icount; |
158 | +}; | ||
154 | 159 | ||
155 | static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc) | 160 | static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc) |
156 | { | 161 | { |
@@ -173,9 +178,11 @@ static inline unsigned int tb_phys_hash_func(unsigned long pc) | @@ -173,9 +178,11 @@ static inline unsigned int tb_phys_hash_func(unsigned long pc) | ||
173 | } | 178 | } |
174 | 179 | ||
175 | TranslationBlock *tb_alloc(target_ulong pc); | 180 | TranslationBlock *tb_alloc(target_ulong pc); |
181 | +void tb_free(TranslationBlock *tb); | ||
176 | void tb_flush(CPUState *env); | 182 | void tb_flush(CPUState *env); |
177 | void tb_link_phys(TranslationBlock *tb, | 183 | void tb_link_phys(TranslationBlock *tb, |
178 | target_ulong phys_pc, target_ulong phys_page2); | 184 | target_ulong phys_pc, target_ulong phys_page2); |
185 | +void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr); | ||
179 | 186 | ||
180 | extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; | 187 | extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; |
181 | extern uint8_t *code_gen_ptr; | 188 | extern uint8_t *code_gen_ptr; |
@@ -364,6 +371,20 @@ static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr) | @@ -364,6 +371,20 @@ static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr) | ||
364 | } | 371 | } |
365 | return addr + env1->tlb_table[mmu_idx][page_index].addend - (unsigned long)phys_ram_base; | 372 | return addr + env1->tlb_table[mmu_idx][page_index].addend - (unsigned long)phys_ram_base; |
366 | } | 373 | } |
374 | + | ||
375 | +/* Deterministic execution requires that IO only be performaed on the last | ||
376 | + instruction of a TB so that interrupts take effect immediately. */ | ||
377 | +static inline int can_do_io(CPUState *env) | ||
378 | +{ | ||
379 | + if (!use_icount) | ||
380 | + return 1; | ||
381 | + | ||
382 | + /* If not executing code then assume we are ok. */ | ||
383 | + if (!env->current_tb) | ||
384 | + return 1; | ||
385 | + | ||
386 | + return env->can_do_io != 0; | ||
387 | +} | ||
367 | #endif | 388 | #endif |
368 | 389 | ||
369 | #ifdef USE_KQEMU | 390 | #ifdef USE_KQEMU |
exec.c
@@ -107,6 +107,13 @@ CPUState *first_cpu; | @@ -107,6 +107,13 @@ CPUState *first_cpu; | ||
107 | /* current CPU in the current thread. It is only valid inside | 107 | /* current CPU in the current thread. It is only valid inside |
108 | cpu_exec() */ | 108 | cpu_exec() */ |
109 | CPUState *cpu_single_env; | 109 | CPUState *cpu_single_env; |
110 | +/* 0 = Do not count executed instructions. | ||
111 | + 1 = Precice instruction counting. | ||
112 | + 2 = Adaptive rate instruction counting. */ | ||
113 | +int use_icount = 0; | ||
114 | +/* Current instruction counter. While executing translated code this may | ||
115 | + include some instructions that have not yet been executed. */ | ||
116 | +int64_t qemu_icount; | ||
110 | 117 | ||
111 | typedef struct PageDesc { | 118 | typedef struct PageDesc { |
112 | /* list of TBs intersecting this ram page */ | 119 | /* list of TBs intersecting this ram page */ |
@@ -633,7 +640,7 @@ static inline void tb_reset_jump(TranslationBlock *tb, int n) | @@ -633,7 +640,7 @@ static inline void tb_reset_jump(TranslationBlock *tb, int n) | ||
633 | tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n])); | 640 | tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n])); |
634 | } | 641 | } |
635 | 642 | ||
636 | -static inline void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr) | 643 | +void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr) |
637 | { | 644 | { |
638 | CPUState *env; | 645 | CPUState *env; |
639 | PageDesc *p; | 646 | PageDesc *p; |
@@ -746,11 +753,9 @@ static void build_page_bitmap(PageDesc *p) | @@ -746,11 +753,9 @@ static void build_page_bitmap(PageDesc *p) | ||
746 | } | 753 | } |
747 | } | 754 | } |
748 | 755 | ||
749 | -#ifdef TARGET_HAS_PRECISE_SMC | ||
750 | - | ||
751 | -static void tb_gen_code(CPUState *env, | ||
752 | - target_ulong pc, target_ulong cs_base, int flags, | ||
753 | - int cflags) | 756 | +TranslationBlock *tb_gen_code(CPUState *env, |
757 | + target_ulong pc, target_ulong cs_base, | ||
758 | + int flags, int cflags) | ||
754 | { | 759 | { |
755 | TranslationBlock *tb; | 760 | TranslationBlock *tb; |
756 | uint8_t *tc_ptr; | 761 | uint8_t *tc_ptr; |
@@ -764,6 +769,8 @@ static void tb_gen_code(CPUState *env, | @@ -764,6 +769,8 @@ static void tb_gen_code(CPUState *env, | ||
764 | tb_flush(env); | 769 | tb_flush(env); |
765 | /* cannot fail at this point */ | 770 | /* cannot fail at this point */ |
766 | tb = tb_alloc(pc); | 771 | tb = tb_alloc(pc); |
772 | + /* Don't forget to invalidate previous TB info. */ | ||
773 | + tb_invalidated_flag = 1; | ||
767 | } | 774 | } |
768 | tc_ptr = code_gen_ptr; | 775 | tc_ptr = code_gen_ptr; |
769 | tb->tc_ptr = tc_ptr; | 776 | tb->tc_ptr = tc_ptr; |
@@ -780,8 +787,8 @@ static void tb_gen_code(CPUState *env, | @@ -780,8 +787,8 @@ static void tb_gen_code(CPUState *env, | ||
780 | phys_page2 = get_phys_addr_code(env, virt_page2); | 787 | phys_page2 = get_phys_addr_code(env, virt_page2); |
781 | } | 788 | } |
782 | tb_link_phys(tb, phys_pc, phys_page2); | 789 | tb_link_phys(tb, phys_pc, phys_page2); |
790 | + return tb; | ||
783 | } | 791 | } |
784 | -#endif | ||
785 | 792 | ||
786 | /* invalidate all TBs which intersect with the target physical page | 793 | /* invalidate all TBs which intersect with the target physical page |
787 | starting in range [start;end[. NOTE: start and end must refer to | 794 | 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 | @@ -836,13 +843,13 @@ void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t | ||
836 | if (current_tb_not_found) { | 843 | if (current_tb_not_found) { |
837 | current_tb_not_found = 0; | 844 | current_tb_not_found = 0; |
838 | current_tb = NULL; | 845 | current_tb = NULL; |
839 | - if (env->mem_write_pc) { | 846 | + if (env->mem_io_pc) { |
840 | /* now we have a real cpu fault */ | 847 | /* now we have a real cpu fault */ |
841 | - current_tb = tb_find_pc(env->mem_write_pc); | 848 | + current_tb = tb_find_pc(env->mem_io_pc); |
842 | } | 849 | } |
843 | } | 850 | } |
844 | if (current_tb == tb && | 851 | if (current_tb == tb && |
845 | - !(current_tb->cflags & CF_SINGLE_INSN)) { | 852 | + (current_tb->cflags & CF_COUNT_MASK) != 1) { |
846 | /* If we are modifying the current TB, we must stop | 853 | /* If we are modifying the current TB, we must stop |
847 | its execution. We could be more precise by checking | 854 | its execution. We could be more precise by checking |
848 | that the modification is after the current PC, but it | 855 | 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 | @@ -851,7 +858,7 @@ void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t | ||
851 | 858 | ||
852 | current_tb_modified = 1; | 859 | current_tb_modified = 1; |
853 | cpu_restore_state(current_tb, env, | 860 | cpu_restore_state(current_tb, env, |
854 | - env->mem_write_pc, NULL); | 861 | + env->mem_io_pc, NULL); |
855 | #if defined(TARGET_I386) | 862 | #if defined(TARGET_I386) |
856 | current_flags = env->hflags; | 863 | current_flags = env->hflags; |
857 | current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); | 864 | 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 | @@ -883,7 +890,7 @@ void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t | ||
883 | if (!p->first_tb) { | 890 | if (!p->first_tb) { |
884 | invalidate_page_bitmap(p); | 891 | invalidate_page_bitmap(p); |
885 | if (is_cpu_write_access) { | 892 | if (is_cpu_write_access) { |
886 | - tlb_unprotect_code_phys(env, start, env->mem_write_vaddr); | 893 | + tlb_unprotect_code_phys(env, start, env->mem_io_vaddr); |
887 | } | 894 | } |
888 | } | 895 | } |
889 | #endif | 896 | #endif |
@@ -893,8 +900,7 @@ void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t | @@ -893,8 +900,7 @@ void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t | ||
893 | modifying the memory. It will ensure that it cannot modify | 900 | modifying the memory. It will ensure that it cannot modify |
894 | itself */ | 901 | itself */ |
895 | env->current_tb = NULL; | 902 | env->current_tb = NULL; |
896 | - tb_gen_code(env, current_pc, current_cs_base, current_flags, | ||
897 | - CF_SINGLE_INSN); | 903 | + tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); |
898 | cpu_resume_from_signal(env, NULL); | 904 | cpu_resume_from_signal(env, NULL); |
899 | } | 905 | } |
900 | #endif | 906 | #endif |
@@ -909,7 +915,7 @@ static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int le | @@ -909,7 +915,7 @@ static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int le | ||
909 | if (1) { | 915 | if (1) { |
910 | if (loglevel) { | 916 | if (loglevel) { |
911 | fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n", | 917 | fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n", |
912 | - cpu_single_env->mem_write_vaddr, len, | 918 | + cpu_single_env->mem_io_vaddr, len, |
913 | cpu_single_env->eip, | 919 | cpu_single_env->eip, |
914 | cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base); | 920 | cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base); |
915 | } | 921 | } |
@@ -961,7 +967,7 @@ static void tb_invalidate_phys_page(target_phys_addr_t addr, | @@ -961,7 +967,7 @@ static void tb_invalidate_phys_page(target_phys_addr_t addr, | ||
961 | tb = (TranslationBlock *)((long)tb & ~3); | 967 | tb = (TranslationBlock *)((long)tb & ~3); |
962 | #ifdef TARGET_HAS_PRECISE_SMC | 968 | #ifdef TARGET_HAS_PRECISE_SMC |
963 | if (current_tb == tb && | 969 | if (current_tb == tb && |
964 | - !(current_tb->cflags & CF_SINGLE_INSN)) { | 970 | + (current_tb->cflags & CF_COUNT_MASK) != 1) { |
965 | /* If we are modifying the current TB, we must stop | 971 | /* If we are modifying the current TB, we must stop |
966 | its execution. We could be more precise by checking | 972 | its execution. We could be more precise by checking |
967 | that the modification is after the current PC, but it | 973 | 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, | @@ -990,8 +996,7 @@ static void tb_invalidate_phys_page(target_phys_addr_t addr, | ||
990 | modifying the memory. It will ensure that it cannot modify | 996 | modifying the memory. It will ensure that it cannot modify |
991 | itself */ | 997 | itself */ |
992 | env->current_tb = NULL; | 998 | env->current_tb = NULL; |
993 | - tb_gen_code(env, current_pc, current_cs_base, current_flags, | ||
994 | - CF_SINGLE_INSN); | 999 | + tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); |
995 | cpu_resume_from_signal(env, puc); | 1000 | cpu_resume_from_signal(env, puc); |
996 | } | 1001 | } |
997 | #endif | 1002 | #endif |
@@ -1068,6 +1073,17 @@ TranslationBlock *tb_alloc(target_ulong pc) | @@ -1068,6 +1073,17 @@ TranslationBlock *tb_alloc(target_ulong pc) | ||
1068 | return tb; | 1073 | return tb; |
1069 | } | 1074 | } |
1070 | 1075 | ||
1076 | +void tb_free(TranslationBlock *tb) | ||
1077 | +{ | ||
1078 | + /* In practice this is mostly used for single use temorary TB | ||
1079 | + Ignore the hard cases and just back up if this TB happens to | ||
1080 | + be the last one generated. */ | ||
1081 | + if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) { | ||
1082 | + code_gen_ptr = tb->tc_ptr; | ||
1083 | + nb_tbs--; | ||
1084 | + } | ||
1085 | +} | ||
1086 | + | ||
1071 | /* add a new TB and link it to the physical page tables. phys_page2 is | 1087 | /* add a new TB and link it to the physical page tables. phys_page2 is |
1072 | (-1) to indicate that only one page contains the TB. */ | 1088 | (-1) to indicate that only one page contains the TB. */ |
1073 | void tb_link_phys(TranslationBlock *tb, | 1089 | void tb_link_phys(TranslationBlock *tb, |
@@ -1369,7 +1385,9 @@ void cpu_interrupt(CPUState *env, int mask) | @@ -1369,7 +1385,9 @@ void cpu_interrupt(CPUState *env, int mask) | ||
1369 | TranslationBlock *tb; | 1385 | TranslationBlock *tb; |
1370 | static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED; | 1386 | static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED; |
1371 | #endif | 1387 | #endif |
1388 | + int old_mask; | ||
1372 | 1389 | ||
1390 | + old_mask = env->interrupt_request; | ||
1373 | /* FIXME: This is probably not threadsafe. A different thread could | 1391 | /* FIXME: This is probably not threadsafe. A different thread could |
1374 | be in the mittle of a read-modify-write operation. */ | 1392 | be in the mittle of a read-modify-write operation. */ |
1375 | env->interrupt_request |= mask; | 1393 | env->interrupt_request |= mask; |
@@ -1379,13 +1397,25 @@ void cpu_interrupt(CPUState *env, int mask) | @@ -1379,13 +1397,25 @@ void cpu_interrupt(CPUState *env, int mask) | ||
1379 | emulation this often isn't actually as bad as it sounds. Often | 1397 | emulation this often isn't actually as bad as it sounds. Often |
1380 | signals are used primarily to interrupt blocking syscalls. */ | 1398 | signals are used primarily to interrupt blocking syscalls. */ |
1381 | #else | 1399 | #else |
1382 | - /* if the cpu is currently executing code, we must unlink it and | ||
1383 | - all the potentially executing TB */ | ||
1384 | - tb = env->current_tb; | ||
1385 | - if (tb && !testandset(&interrupt_lock)) { | ||
1386 | - env->current_tb = NULL; | ||
1387 | - tb_reset_jump_recursive(tb); | ||
1388 | - resetlock(&interrupt_lock); | 1400 | + if (use_icount) { |
1401 | + env->icount_decr.u16.high = 0x8000; | ||
1402 | +#ifndef CONFIG_USER_ONLY | ||
1403 | + /* CPU_INTERRUPT_EXIT isn't a real interrupt. It just means | ||
1404 | + an async event happened and we need to process it. */ | ||
1405 | + if (!can_do_io(env) | ||
1406 | + && (mask & ~(old_mask | CPU_INTERRUPT_EXIT)) != 0) { | ||
1407 | + cpu_abort(env, "Raised interrupt while not in I/O function"); | ||
1408 | + } | ||
1409 | +#endif | ||
1410 | + } else { | ||
1411 | + tb = env->current_tb; | ||
1412 | + /* if the cpu is currently executing code, we must unlink it and | ||
1413 | + all the potentially executing TB */ | ||
1414 | + if (tb && !testandset(&interrupt_lock)) { | ||
1415 | + env->current_tb = NULL; | ||
1416 | + tb_reset_jump_recursive(tb); | ||
1417 | + resetlock(&interrupt_lock); | ||
1418 | + } | ||
1389 | } | 1419 | } |
1390 | #endif | 1420 | #endif |
1391 | } | 1421 | } |
@@ -2227,7 +2257,7 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr, | @@ -2227,7 +2257,7 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr, | ||
2227 | /* we remove the notdirty callback only if the code has been | 2257 | /* we remove the notdirty callback only if the code has been |
2228 | flushed */ | 2258 | flushed */ |
2229 | if (dirty_flags == 0xff) | 2259 | if (dirty_flags == 0xff) |
2230 | - tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr); | 2260 | + tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr); |
2231 | } | 2261 | } |
2232 | 2262 | ||
2233 | static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr, | 2263 | 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, | @@ -2252,7 +2282,7 @@ static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr, | ||
2252 | /* we remove the notdirty callback only if the code has been | 2282 | /* we remove the notdirty callback only if the code has been |
2253 | flushed */ | 2283 | flushed */ |
2254 | if (dirty_flags == 0xff) | 2284 | if (dirty_flags == 0xff) |
2255 | - tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr); | 2285 | + tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr); |
2256 | } | 2286 | } |
2257 | 2287 | ||
2258 | static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr, | 2288 | 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, | @@ -2277,7 +2307,7 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr, | ||
2277 | /* we remove the notdirty callback only if the code has been | 2307 | /* we remove the notdirty callback only if the code has been |
2278 | flushed */ | 2308 | flushed */ |
2279 | if (dirty_flags == 0xff) | 2309 | if (dirty_flags == 0xff) |
2280 | - tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr); | 2310 | + tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr); |
2281 | } | 2311 | } |
2282 | 2312 | ||
2283 | static CPUReadMemoryFunc *error_mem_read[3] = { | 2313 | static CPUReadMemoryFunc *error_mem_read[3] = { |
@@ -2299,7 +2329,7 @@ static void check_watchpoint(int offset, int flags) | @@ -2299,7 +2329,7 @@ static void check_watchpoint(int offset, int flags) | ||
2299 | target_ulong vaddr; | 2329 | target_ulong vaddr; |
2300 | int i; | 2330 | int i; |
2301 | 2331 | ||
2302 | - vaddr = (env->mem_write_vaddr & TARGET_PAGE_MASK) + offset; | 2332 | + vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset; |
2303 | for (i = 0; i < env->nb_watchpoints; i++) { | 2333 | for (i = 0; i < env->nb_watchpoints; i++) { |
2304 | if (vaddr == env->watchpoint[i].vaddr | 2334 | if (vaddr == env->watchpoint[i].vaddr |
2305 | && (env->watchpoint[i].type & flags)) { | 2335 | && (env->watchpoint[i].type & flags)) { |
@@ -2967,6 +2997,65 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr, | @@ -2967,6 +2997,65 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr, | ||
2967 | return 0; | 2997 | return 0; |
2968 | } | 2998 | } |
2969 | 2999 | ||
3000 | +/* in deterministic execution mode, instructions doing device I/Os | ||
3001 | + must be at the end of the TB */ | ||
3002 | +void cpu_io_recompile(CPUState *env, void *retaddr) | ||
3003 | +{ | ||
3004 | + TranslationBlock *tb; | ||
3005 | + uint32_t n, cflags; | ||
3006 | + target_ulong pc, cs_base; | ||
3007 | + uint64_t flags; | ||
3008 | + | ||
3009 | + tb = tb_find_pc((unsigned long)retaddr); | ||
3010 | + if (!tb) { | ||
3011 | + cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p", | ||
3012 | + retaddr); | ||
3013 | + } | ||
3014 | + n = env->icount_decr.u16.low + tb->icount; | ||
3015 | + cpu_restore_state(tb, env, (unsigned long)retaddr, NULL); | ||
3016 | + /* Calculate how many instructions had been executed before the fault | ||
3017 | + occured. */ | ||
3018 | + n = n - env->icount_decr.u16.low; | ||
3019 | + /* Generate a new TB ending on the I/O insn. */ | ||
3020 | + n++; | ||
3021 | + /* On MIPS and SH, delay slot instructions can only be restarted if | ||
3022 | + they were already the first instruction in the TB. If this is not | ||
3023 | + the first instruction in a TB then re-execute the preceeding | ||
3024 | + branch. */ | ||
3025 | +#if defined(TARGET_MIPS) | ||
3026 | + if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) { | ||
3027 | + env->active_tc.PC -= 4; | ||
3028 | + env->icount_decr.u16.low++; | ||
3029 | + env->hflags &= ~MIPS_HFLAG_BMASK; | ||
3030 | + } | ||
3031 | +#elif defined(TARGET_SH4) | ||
3032 | + if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0 | ||
3033 | + && n > 1) { | ||
3034 | + env->pc -= 2; | ||
3035 | + env->icount_decr.u16.low++; | ||
3036 | + env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL); | ||
3037 | + } | ||
3038 | +#endif | ||
3039 | + /* This should never happen. */ | ||
3040 | + if (n > CF_COUNT_MASK) | ||
3041 | + cpu_abort(env, "TB too big during recompile"); | ||
3042 | + | ||
3043 | + cflags = n | CF_LAST_IO; | ||
3044 | + pc = tb->pc; | ||
3045 | + cs_base = tb->cs_base; | ||
3046 | + flags = tb->flags; | ||
3047 | + tb_phys_invalidate(tb, -1); | ||
3048 | + /* FIXME: In theory this could raise an exception. In practice | ||
3049 | + we have already translated the block once so it's probably ok. */ | ||
3050 | + tb_gen_code(env, pc, cs_base, flags, cflags); | ||
3051 | + /* TODO: If env->pc != tb->pc (i.e. the failuting instruction was not | ||
3052 | + the first in the TB) then we end up generating a whole new TB and | ||
3053 | + repeating the fault, which is horribly inefficient. | ||
3054 | + Better would be to execute just this insn uncached, or generate a | ||
3055 | + second new TB. */ | ||
3056 | + cpu_resume_from_signal(env, NULL); | ||
3057 | +} | ||
3058 | + | ||
2970 | void dump_exec_info(FILE *f, | 3059 | void dump_exec_info(FILE *f, |
2971 | int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) | 3060 | int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) |
2972 | { | 3061 | { |
hw/mips_timer.c
@@ -91,7 +91,12 @@ static void mips_timer_cb (void *opaque) | @@ -91,7 +91,12 @@ static void mips_timer_cb (void *opaque) | ||
91 | if (env->CP0_Cause & (1 << CP0Ca_DC)) | 91 | if (env->CP0_Cause & (1 << CP0Ca_DC)) |
92 | return; | 92 | return; |
93 | 93 | ||
94 | + /* ??? This callback should occur when the counter is exactly equal to | ||
95 | + the comparator value. Offset the count by one to avoid immediately | ||
96 | + retriggering the callback before any virtual time has passed. */ | ||
97 | + env->CP0_Count++; | ||
94 | cpu_mips_timer_update(env); | 98 | cpu_mips_timer_update(env); |
99 | + env->CP0_Count--; | ||
95 | if (env->insn_flags & ISA_MIPS32R2) | 100 | if (env->insn_flags & ISA_MIPS32R2) |
96 | env->CP0_Cause |= 1 << CP0Ca_TI; | 101 | env->CP0_Cause |= 1 << CP0Ca_TI; |
97 | qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); | 102 | qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); |
qemu-doc.texi
@@ -965,6 +965,17 @@ On M68K this implements the "ColdFire GDB" interface used by libgloss. | @@ -965,6 +965,17 @@ On M68K this implements the "ColdFire GDB" interface used by libgloss. | ||
965 | 965 | ||
966 | Note that this allows guest direct access to the host filesystem, | 966 | Note that this allows guest direct access to the host filesystem, |
967 | so should only be used with trusted guest OS. | 967 | so should only be used with trusted guest OS. |
968 | + | ||
969 | +@item -icount [N|auto] | ||
970 | +Enable virtual instruction counter. The virtual cpu will execute one | ||
971 | +instruction every 2^N ns of virtual time. If @code{auto} is specified | ||
972 | +then the virtual cpu speed will be automatically adjusted to keep virtual | ||
973 | +time within a few seconds of real time. | ||
974 | + | ||
975 | +Note that while this option can give deterministic behavior, it does not | ||
976 | +provide cycle accurate emulation. Modern CPUs contain superscalar out of | ||
977 | +order cores with complex cache heirachies. The number of instructions | ||
978 | +executed often has little or no correlation with actual performance. | ||
968 | @end table | 979 | @end table |
969 | 980 | ||
970 | @c man end | 981 | @c man end |
softmmu_template.h
@@ -51,12 +51,18 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, | @@ -51,12 +51,18 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, | ||
51 | int mmu_idx, | 51 | int mmu_idx, |
52 | void *retaddr); | 52 | void *retaddr); |
53 | static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, | 53 | static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, |
54 | - target_ulong addr) | 54 | + target_ulong addr, |
55 | + void *retaddr) | ||
55 | { | 56 | { |
56 | DATA_TYPE res; | 57 | DATA_TYPE res; |
57 | int index; | 58 | int index; |
58 | index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); | 59 | index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); |
59 | physaddr = (physaddr & TARGET_PAGE_MASK) + addr; | 60 | physaddr = (physaddr & TARGET_PAGE_MASK) + addr; |
61 | + env->mem_io_pc = (unsigned long)retaddr; | ||
62 | + if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT) | ||
63 | + && !can_do_io(env)) { | ||
64 | + cpu_io_recompile(env, retaddr); | ||
65 | + } | ||
60 | 66 | ||
61 | #if SHIFT <= 2 | 67 | #if SHIFT <= 2 |
62 | res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr); | 68 | 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, | @@ -95,8 +101,9 @@ DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, | ||
95 | /* IO access */ | 101 | /* IO access */ |
96 | if ((addr & (DATA_SIZE - 1)) != 0) | 102 | if ((addr & (DATA_SIZE - 1)) != 0) |
97 | goto do_unaligned_access; | 103 | goto do_unaligned_access; |
104 | + retaddr = GETPC(); | ||
98 | addend = env->iotlb[mmu_idx][index]; | 105 | addend = env->iotlb[mmu_idx][index]; |
99 | - res = glue(io_read, SUFFIX)(addend, addr); | 106 | + res = glue(io_read, SUFFIX)(addend, addr, retaddr); |
100 | } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { | 107 | } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { |
101 | /* slow unaligned access (it spans two pages or IO) */ | 108 | /* slow unaligned access (it spans two pages or IO) */ |
102 | do_unaligned_access: | 109 | do_unaligned_access: |
@@ -148,8 +155,9 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, | @@ -148,8 +155,9 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, | ||
148 | /* IO access */ | 155 | /* IO access */ |
149 | if ((addr & (DATA_SIZE - 1)) != 0) | 156 | if ((addr & (DATA_SIZE - 1)) != 0) |
150 | goto do_unaligned_access; | 157 | goto do_unaligned_access; |
158 | + retaddr = GETPC(); | ||
151 | addend = env->iotlb[mmu_idx][index]; | 159 | addend = env->iotlb[mmu_idx][index]; |
152 | - res = glue(io_read, SUFFIX)(addend, addr); | 160 | + res = glue(io_read, SUFFIX)(addend, addr, retaddr); |
153 | } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { | 161 | } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { |
154 | do_unaligned_access: | 162 | do_unaligned_access: |
155 | /* slow unaligned access (it spans two pages) */ | 163 | /* slow unaligned access (it spans two pages) */ |
@@ -194,9 +202,13 @@ static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, | @@ -194,9 +202,13 @@ static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, | ||
194 | int index; | 202 | int index; |
195 | index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); | 203 | index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); |
196 | physaddr = (physaddr & TARGET_PAGE_MASK) + addr; | 204 | physaddr = (physaddr & TARGET_PAGE_MASK) + addr; |
205 | + if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT) | ||
206 | + && !can_do_io(env)) { | ||
207 | + cpu_io_recompile(env, retaddr); | ||
208 | + } | ||
197 | 209 | ||
198 | - env->mem_write_vaddr = addr; | ||
199 | - env->mem_write_pc = (unsigned long)retaddr; | 210 | + env->mem_io_vaddr = addr; |
211 | + env->mem_io_pc = (unsigned long)retaddr; | ||
200 | #if SHIFT <= 2 | 212 | #if SHIFT <= 2 |
201 | io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val); | 213 | io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val); |
202 | #else | 214 | #else |
target-alpha/cpu.h
@@ -415,4 +415,6 @@ void cpu_loop_exit (void); | @@ -415,4 +415,6 @@ void cpu_loop_exit (void); | ||
415 | void pal_init (CPUState *env); | 415 | void pal_init (CPUState *env); |
416 | void call_pal (CPUState *env, int palcode); | 416 | void call_pal (CPUState *env, int palcode); |
417 | 417 | ||
418 | +#define CPU_PC_FROM_TB(env, tb) env->pc = tb->pc | ||
419 | + | ||
418 | #endif /* !defined (__CPU_ALPHA_H__) */ | 420 | #endif /* !defined (__CPU_ALPHA_H__) */ |
target-alpha/translate.c
@@ -43,6 +43,19 @@ struct DisasContext { | @@ -43,6 +43,19 @@ struct DisasContext { | ||
43 | uint32_t amask; | 43 | uint32_t amask; |
44 | }; | 44 | }; |
45 | 45 | ||
46 | +TCGv cpu_env; | ||
47 | + | ||
48 | +#include "gen-icount.h" | ||
49 | + | ||
50 | +void alpha_translate_init() | ||
51 | +{ | ||
52 | + static int done_init = 0; | ||
53 | + if (done_init) | ||
54 | + return; | ||
55 | + cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env"); | ||
56 | + done_init = 1; | ||
57 | +} | ||
58 | + | ||
46 | static always_inline void gen_op_nop (void) | 59 | static always_inline void gen_op_nop (void) |
47 | { | 60 | { |
48 | #if defined(GENERATE_NOP) | 61 | #if defined(GENERATE_NOP) |
@@ -1970,6 +1983,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -1970,6 +1983,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
1970 | uint16_t *gen_opc_end; | 1983 | uint16_t *gen_opc_end; |
1971 | int j, lj = -1; | 1984 | int j, lj = -1; |
1972 | int ret; | 1985 | int ret; |
1986 | + int num_insns; | ||
1987 | + int max_insns; | ||
1973 | 1988 | ||
1974 | pc_start = tb->pc; | 1989 | pc_start = tb->pc; |
1975 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; | 1990 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
@@ -1981,6 +1996,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -1981,6 +1996,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
1981 | ctx.mem_idx = ((env->ps >> 3) & 3); | 1996 | ctx.mem_idx = ((env->ps >> 3) & 3); |
1982 | ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1; | 1997 | ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1; |
1983 | #endif | 1998 | #endif |
1999 | + num_insns = 0; | ||
2000 | + max_insns = tb->cflags & CF_COUNT_MASK; | ||
2001 | + if (max_insns == 0) | ||
2002 | + max_insns = CF_COUNT_MASK; | ||
2003 | + | ||
2004 | + gen_icount_start(); | ||
1984 | for (ret = 0; ret == 0;) { | 2005 | for (ret = 0; ret == 0;) { |
1985 | if (env->nb_breakpoints > 0) { | 2006 | if (env->nb_breakpoints > 0) { |
1986 | for(j = 0; j < env->nb_breakpoints; j++) { | 2007 | for(j = 0; j < env->nb_breakpoints; j++) { |
@@ -1998,8 +2019,11 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -1998,8 +2019,11 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
1998 | gen_opc_instr_start[lj++] = 0; | 2019 | gen_opc_instr_start[lj++] = 0; |
1999 | gen_opc_pc[lj] = ctx.pc; | 2020 | gen_opc_pc[lj] = ctx.pc; |
2000 | gen_opc_instr_start[lj] = 1; | 2021 | gen_opc_instr_start[lj] = 1; |
2022 | + gen_opc_icount[lj] = num_insns; | ||
2001 | } | 2023 | } |
2002 | } | 2024 | } |
2025 | + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) | ||
2026 | + gen_io_start(); | ||
2003 | #if defined ALPHA_DEBUG_DISAS | 2027 | #if defined ALPHA_DEBUG_DISAS |
2004 | insn_count++; | 2028 | insn_count++; |
2005 | if (logfile != NULL) { | 2029 | if (logfile != NULL) { |
@@ -2014,6 +2038,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -2014,6 +2038,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
2014 | fprintf(logfile, "opcode %08x %d\n", insn, insn_count); | 2038 | fprintf(logfile, "opcode %08x %d\n", insn, insn_count); |
2015 | } | 2039 | } |
2016 | #endif | 2040 | #endif |
2041 | + num_insns++; | ||
2017 | ctx.pc += 4; | 2042 | ctx.pc += 4; |
2018 | ret = translate_one(ctxp, insn); | 2043 | ret = translate_one(ctxp, insn); |
2019 | if (ret != 0) | 2044 | if (ret != 0) |
@@ -2022,7 +2047,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -2022,7 +2047,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
2022 | * generation | 2047 | * generation |
2023 | */ | 2048 | */ |
2024 | if (((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) || | 2049 | if (((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) || |
2025 | - (env->singlestep_enabled)) { | 2050 | + (env->singlestep_enabled) || |
2051 | + num_insns >= max_insns) { | ||
2026 | break; | 2052 | break; |
2027 | } | 2053 | } |
2028 | #if defined (DO_SINGLE_STEP) | 2054 | #if defined (DO_SINGLE_STEP) |
@@ -2035,8 +2061,11 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -2035,8 +2061,11 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
2035 | #if defined (DO_TB_FLUSH) | 2061 | #if defined (DO_TB_FLUSH) |
2036 | gen_op_tb_flush(); | 2062 | gen_op_tb_flush(); |
2037 | #endif | 2063 | #endif |
2064 | + if (tb->cflags & CF_LAST_IO) | ||
2065 | + gen_io_end(); | ||
2038 | /* Generate the return instruction */ | 2066 | /* Generate the return instruction */ |
2039 | tcg_gen_exit_tb(0); | 2067 | tcg_gen_exit_tb(0); |
2068 | + gen_icount_end(tb, num_insns); | ||
2040 | *gen_opc_ptr = INDEX_op_end; | 2069 | *gen_opc_ptr = INDEX_op_end; |
2041 | if (search_pc) { | 2070 | if (search_pc) { |
2042 | j = gen_opc_ptr - gen_opc_buf; | 2071 | j = gen_opc_ptr - gen_opc_buf; |
@@ -2045,6 +2074,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -2045,6 +2074,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
2045 | gen_opc_instr_start[lj++] = 0; | 2074 | gen_opc_instr_start[lj++] = 0; |
2046 | } else { | 2075 | } else { |
2047 | tb->size = ctx.pc - pc_start; | 2076 | tb->size = ctx.pc - pc_start; |
2077 | + tb->icount = num_insns; | ||
2048 | } | 2078 | } |
2049 | #if defined ALPHA_DEBUG_DISAS | 2079 | #if defined ALPHA_DEBUG_DISAS |
2050 | if (loglevel & CPU_LOG_TB_CPU) { | 2080 | if (loglevel & CPU_LOG_TB_CPU) { |
@@ -2079,6 +2109,7 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model) | @@ -2079,6 +2109,7 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model) | ||
2079 | if (!env) | 2109 | if (!env) |
2080 | return NULL; | 2110 | return NULL; |
2081 | cpu_exec_init(env); | 2111 | cpu_exec_init(env); |
2112 | + alpha_translate_init(); | ||
2082 | tlb_flush(env, 1); | 2113 | tlb_flush(env, 1); |
2083 | /* XXX: should not be hardcoded */ | 2114 | /* XXX: should not be hardcoded */ |
2084 | env->implver = IMPLVER_2106x; | 2115 | env->implver = IMPLVER_2106x; |
target-arm/cpu.h
@@ -417,6 +417,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) | @@ -417,6 +417,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) | ||
417 | } | 417 | } |
418 | #endif | 418 | #endif |
419 | 419 | ||
420 | +#define CPU_PC_FROM_TB(env, tb) env->regs[15] = tb->pc | ||
421 | + | ||
420 | #include "cpu-all.h" | 422 | #include "cpu-all.h" |
421 | 423 | ||
422 | #endif | 424 | #endif |
target-arm/translate.c
@@ -84,6 +84,9 @@ static TCGv cpu_V0, cpu_V1, cpu_M0; | @@ -84,6 +84,9 @@ static TCGv cpu_V0, cpu_V1, cpu_M0; | ||
84 | static TCGv cpu_T[2]; | 84 | static TCGv cpu_T[2]; |
85 | static TCGv cpu_F0s, cpu_F1s, cpu_F0d, cpu_F1d; | 85 | static TCGv cpu_F0s, cpu_F1s, cpu_F0d, cpu_F1d; |
86 | 86 | ||
87 | +#define ICOUNT_TEMP cpu_T[0] | ||
88 | +#include "gen-icount.h" | ||
89 | + | ||
87 | /* initialize TCG globals. */ | 90 | /* initialize TCG globals. */ |
88 | void arm_translate_init(void) | 91 | void arm_translate_init(void) |
89 | { | 92 | { |
@@ -8539,6 +8542,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -8539,6 +8542,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
8539 | int j, lj; | 8542 | int j, lj; |
8540 | target_ulong pc_start; | 8543 | target_ulong pc_start; |
8541 | uint32_t next_page_start; | 8544 | uint32_t next_page_start; |
8545 | + int num_insns; | ||
8546 | + int max_insns; | ||
8542 | 8547 | ||
8543 | /* generate intermediate code */ | 8548 | /* generate intermediate code */ |
8544 | num_temps = 0; | 8549 | num_temps = 0; |
@@ -8575,6 +8580,12 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -8575,6 +8580,12 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
8575 | cpu_M0 = tcg_temp_new(TCG_TYPE_I64); | 8580 | cpu_M0 = tcg_temp_new(TCG_TYPE_I64); |
8576 | next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; | 8581 | next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; |
8577 | lj = -1; | 8582 | lj = -1; |
8583 | + num_insns = 0; | ||
8584 | + max_insns = tb->cflags & CF_COUNT_MASK; | ||
8585 | + if (max_insns == 0) | ||
8586 | + max_insns = CF_COUNT_MASK; | ||
8587 | + | ||
8588 | + gen_icount_start(); | ||
8578 | /* Reset the conditional execution bits immediately. This avoids | 8589 | /* Reset the conditional execution bits immediately. This avoids |
8579 | complications trying to do it at the end of the block. */ | 8590 | complications trying to do it at the end of the block. */ |
8580 | if (env->condexec_bits) | 8591 | if (env->condexec_bits) |
@@ -8625,8 +8636,12 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -8625,8 +8636,12 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
8625 | } | 8636 | } |
8626 | gen_opc_pc[lj] = dc->pc; | 8637 | gen_opc_pc[lj] = dc->pc; |
8627 | gen_opc_instr_start[lj] = 1; | 8638 | gen_opc_instr_start[lj] = 1; |
8639 | + gen_opc_icount[lj] = num_insns; | ||
8628 | } | 8640 | } |
8629 | 8641 | ||
8642 | + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) | ||
8643 | + gen_io_start(); | ||
8644 | + | ||
8630 | if (env->thumb) { | 8645 | if (env->thumb) { |
8631 | disas_thumb_insn(env, dc); | 8646 | disas_thumb_insn(env, dc); |
8632 | if (dc->condexec_mask) { | 8647 | if (dc->condexec_mask) { |
@@ -8659,9 +8674,20 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -8659,9 +8674,20 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
8659 | * Otherwise the subsequent code could get translated several times. | 8674 | * Otherwise the subsequent code could get translated several times. |
8660 | * Also stop translation when a page boundary is reached. This | 8675 | * Also stop translation when a page boundary is reached. This |
8661 | * ensures prefech aborts occur at the right place. */ | 8676 | * ensures prefech aborts occur at the right place. */ |
8677 | + num_insns ++; | ||
8662 | } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && | 8678 | } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && |
8663 | !env->singlestep_enabled && | 8679 | !env->singlestep_enabled && |
8664 | - dc->pc < next_page_start); | 8680 | + dc->pc < next_page_start && |
8681 | + num_insns < max_insns); | ||
8682 | + | ||
8683 | + if (tb->cflags & CF_LAST_IO) { | ||
8684 | + if (dc->condjmp) { | ||
8685 | + /* FIXME: This can theoretically happen with self-modifying | ||
8686 | + code. */ | ||
8687 | + cpu_abort(env, "IO on conditional branch instruction"); | ||
8688 | + } | ||
8689 | + gen_io_end(); | ||
8690 | + } | ||
8665 | 8691 | ||
8666 | /* At this stage dc->condjmp will only be set when the skipped | 8692 | /* At this stage dc->condjmp will only be set when the skipped |
8667 | instruction was a conditional branch or trap, and the PC has | 8693 | instruction was a conditional branch or trap, and the PC has |
@@ -8726,7 +8752,9 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -8726,7 +8752,9 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
8726 | dc->condjmp = 0; | 8752 | dc->condjmp = 0; |
8727 | } | 8753 | } |
8728 | } | 8754 | } |
8755 | + | ||
8729 | done_generating: | 8756 | done_generating: |
8757 | + gen_icount_end(tb, num_insns); | ||
8730 | *gen_opc_ptr = INDEX_op_end; | 8758 | *gen_opc_ptr = INDEX_op_end; |
8731 | 8759 | ||
8732 | #ifdef DEBUG_DISAS | 8760 | #ifdef DEBUG_DISAS |
@@ -8744,6 +8772,7 @@ done_generating: | @@ -8744,6 +8772,7 @@ done_generating: | ||
8744 | gen_opc_instr_start[lj++] = 0; | 8772 | gen_opc_instr_start[lj++] = 0; |
8745 | } else { | 8773 | } else { |
8746 | tb->size = dc->pc - pc_start; | 8774 | tb->size = dc->pc - pc_start; |
8775 | + tb->icount = num_insns; | ||
8747 | } | 8776 | } |
8748 | return 0; | 8777 | return 0; |
8749 | } | 8778 | } |
target-cris/cpu.h
@@ -238,5 +238,7 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) | @@ -238,5 +238,7 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) | ||
238 | #define SFR_RW_MM_TLB_LO env->pregs[PR_SRS]][5 | 238 | #define SFR_RW_MM_TLB_LO env->pregs[PR_SRS]][5 |
239 | #define SFR_RW_MM_TLB_HI env->pregs[PR_SRS]][6 | 239 | #define SFR_RW_MM_TLB_HI env->pregs[PR_SRS]][6 |
240 | 240 | ||
241 | +#define CPU_PC_FROM_TB(env, tb) env->pc = tb->pc | ||
242 | + | ||
241 | #include "cpu-all.h" | 243 | #include "cpu-all.h" |
242 | #endif | 244 | #endif |
target-cris/translate.c
@@ -77,6 +77,8 @@ TCGv env_btaken; | @@ -77,6 +77,8 @@ TCGv env_btaken; | ||
77 | TCGv env_btarget; | 77 | TCGv env_btarget; |
78 | TCGv env_pc; | 78 | TCGv env_pc; |
79 | 79 | ||
80 | +#include "gen-icount.h" | ||
81 | + | ||
80 | /* This is the state at translation time. */ | 82 | /* This is the state at translation time. */ |
81 | typedef struct DisasContext { | 83 | typedef struct DisasContext { |
82 | CPUState *env; | 84 | CPUState *env; |
@@ -3032,6 +3034,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -3032,6 +3034,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
3032 | struct DisasContext *dc = &ctx; | 3034 | struct DisasContext *dc = &ctx; |
3033 | uint32_t next_page_start; | 3035 | uint32_t next_page_start; |
3034 | target_ulong npc; | 3036 | target_ulong npc; |
3037 | + int num_insns; | ||
3038 | + int max_insns; | ||
3035 | 3039 | ||
3036 | if (!logfile) | 3040 | if (!logfile) |
3037 | logfile = stderr; | 3041 | logfile = stderr; |
@@ -3092,6 +3096,12 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -3092,6 +3096,12 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
3092 | 3096 | ||
3093 | next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; | 3097 | next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; |
3094 | lj = -1; | 3098 | lj = -1; |
3099 | + num_insns = 0; | ||
3100 | + max_insns = tb->cflags & CF_COUNT_MASK; | ||
3101 | + if (max_insns == 0) | ||
3102 | + max_insns = CF_COUNT_MASK; | ||
3103 | + | ||
3104 | + gen_icount_start(); | ||
3095 | do | 3105 | do |
3096 | { | 3106 | { |
3097 | check_breakpoint(env, dc); | 3107 | check_breakpoint(env, dc); |
@@ -3108,6 +3118,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -3108,6 +3118,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
3108 | else | 3118 | else |
3109 | gen_opc_pc[lj] = dc->pc; | 3119 | gen_opc_pc[lj] = dc->pc; |
3110 | gen_opc_instr_start[lj] = 1; | 3120 | gen_opc_instr_start[lj] = 1; |
3121 | + gen_opc_icount[lj] = num_insns; | ||
3111 | } | 3122 | } |
3112 | 3123 | ||
3113 | /* Pretty disas. */ | 3124 | /* Pretty disas. */ |
@@ -3116,6 +3127,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -3116,6 +3127,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
3116 | DIS(fprintf(logfile, "%x ", dc->pc)); | 3127 | DIS(fprintf(logfile, "%x ", dc->pc)); |
3117 | } | 3128 | } |
3118 | 3129 | ||
3130 | + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) | ||
3131 | + gen_io_start(); | ||
3119 | dc->clear_x = 1; | 3132 | dc->clear_x = 1; |
3120 | if (unlikely(loglevel & CPU_LOG_TB_OP)) | 3133 | if (unlikely(loglevel & CPU_LOG_TB_OP)) |
3121 | tcg_gen_debug_insn_start(dc->pc); | 3134 | tcg_gen_debug_insn_start(dc->pc); |
@@ -3125,6 +3138,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -3125,6 +3138,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
3125 | if (dc->clear_x) | 3138 | if (dc->clear_x) |
3126 | cris_clear_x_flag(dc); | 3139 | cris_clear_x_flag(dc); |
3127 | 3140 | ||
3141 | + num_insns++; | ||
3128 | /* Check for delayed branches here. If we do it before | 3142 | /* Check for delayed branches here. If we do it before |
3129 | actually genereating any host code, the simulator will just | 3143 | actually genereating any host code, the simulator will just |
3130 | loop doing nothing for on this program location. */ | 3144 | loop doing nothing for on this program location. */ |
@@ -3151,12 +3165,15 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -3151,12 +3165,15 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
3151 | if (!(tb->pc & 1) && env->singlestep_enabled) | 3165 | if (!(tb->pc & 1) && env->singlestep_enabled) |
3152 | break; | 3166 | break; |
3153 | } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end | 3167 | } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end |
3154 | - && (dc->pc < next_page_start)); | 3168 | + && (dc->pc < next_page_start) |
3169 | + && num_insns < max_insns); | ||
3155 | 3170 | ||
3156 | npc = dc->pc; | 3171 | npc = dc->pc; |
3157 | if (dc->jmp == JMP_DIRECT && !dc->delayed_branch) | 3172 | if (dc->jmp == JMP_DIRECT && !dc->delayed_branch) |
3158 | npc = dc->jmp_pc; | 3173 | npc = dc->jmp_pc; |
3159 | 3174 | ||
3175 | + if (tb->cflags & CF_LAST_IO) | ||
3176 | + gen_io_end(); | ||
3160 | /* Force an update if the per-tb cpu state has changed. */ | 3177 | /* Force an update if the per-tb cpu state has changed. */ |
3161 | if (dc->is_jmp == DISAS_NEXT | 3178 | if (dc->is_jmp == DISAS_NEXT |
3162 | && (dc->cpustate_changed || !dc->flagx_known | 3179 | && (dc->cpustate_changed || !dc->flagx_known |
@@ -3194,6 +3211,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -3194,6 +3211,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
3194 | break; | 3211 | break; |
3195 | } | 3212 | } |
3196 | } | 3213 | } |
3214 | + gen_icount_end(tb, num_insns); | ||
3197 | *gen_opc_ptr = INDEX_op_end; | 3215 | *gen_opc_ptr = INDEX_op_end; |
3198 | if (search_pc) { | 3216 | if (search_pc) { |
3199 | j = gen_opc_ptr - gen_opc_buf; | 3217 | j = gen_opc_ptr - gen_opc_buf; |
@@ -3202,6 +3220,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -3202,6 +3220,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
3202 | gen_opc_instr_start[lj++] = 0; | 3220 | gen_opc_instr_start[lj++] = 0; |
3203 | } else { | 3221 | } else { |
3204 | tb->size = dc->pc - pc_start; | 3222 | tb->size = dc->pc - pc_start; |
3223 | + tb->icount = num_insns; | ||
3205 | } | 3224 | } |
3206 | 3225 | ||
3207 | #ifdef DEBUG_DISAS | 3226 | #ifdef DEBUG_DISAS |
target-i386/cpu.h
@@ -753,6 +753,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) | @@ -753,6 +753,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) | ||
753 | } | 753 | } |
754 | #endif | 754 | #endif |
755 | 755 | ||
756 | +#define CPU_PC_FROM_TB(env, tb) env->eip = tb->pc - tb->cs_base | ||
757 | + | ||
756 | #include "cpu-all.h" | 758 | #include "cpu-all.h" |
757 | 759 | ||
758 | #include "svm.h" | 760 | #include "svm.h" |
target-i386/translate.c
@@ -65,6 +65,8 @@ static TCGv cpu_T[2], cpu_T3; | @@ -65,6 +65,8 @@ static TCGv cpu_T[2], cpu_T3; | ||
65 | static TCGv cpu_tmp0, cpu_tmp1_i64, cpu_tmp2_i32, cpu_tmp3_i32, cpu_tmp4, cpu_ptr0, cpu_ptr1; | 65 | static TCGv cpu_tmp0, cpu_tmp1_i64, cpu_tmp2_i32, cpu_tmp3_i32, cpu_tmp4, cpu_ptr0, cpu_ptr1; |
66 | static TCGv cpu_tmp5, cpu_tmp6; | 66 | static TCGv cpu_tmp5, cpu_tmp6; |
67 | 67 | ||
68 | +#include "gen-icount.h" | ||
69 | + | ||
68 | #ifdef TARGET_X86_64 | 70 | #ifdef TARGET_X86_64 |
69 | static int x86_64_hregs; | 71 | static int x86_64_hregs; |
70 | #endif | 72 | #endif |
@@ -1203,6 +1205,8 @@ static inline void gen_cmps(DisasContext *s, int ot) | @@ -1203,6 +1205,8 @@ static inline void gen_cmps(DisasContext *s, int ot) | ||
1203 | 1205 | ||
1204 | static inline void gen_ins(DisasContext *s, int ot) | 1206 | static inline void gen_ins(DisasContext *s, int ot) |
1205 | { | 1207 | { |
1208 | + if (use_icount) | ||
1209 | + gen_io_start(); | ||
1206 | gen_string_movl_A0_EDI(s); | 1210 | gen_string_movl_A0_EDI(s); |
1207 | /* Note: we must do this dummy write first to be restartable in | 1211 | /* Note: we must do this dummy write first to be restartable in |
1208 | case of page fault. */ | 1212 | case of page fault. */ |
@@ -1215,10 +1219,14 @@ static inline void gen_ins(DisasContext *s, int ot) | @@ -1215,10 +1219,14 @@ static inline void gen_ins(DisasContext *s, int ot) | ||
1215 | gen_op_st_T0_A0(ot + s->mem_index); | 1219 | gen_op_st_T0_A0(ot + s->mem_index); |
1216 | gen_op_movl_T0_Dshift(ot); | 1220 | gen_op_movl_T0_Dshift(ot); |
1217 | gen_op_add_reg_T0(s->aflag, R_EDI); | 1221 | gen_op_add_reg_T0(s->aflag, R_EDI); |
1222 | + if (use_icount) | ||
1223 | + gen_io_end(); | ||
1218 | } | 1224 | } |
1219 | 1225 | ||
1220 | static inline void gen_outs(DisasContext *s, int ot) | 1226 | static inline void gen_outs(DisasContext *s, int ot) |
1221 | { | 1227 | { |
1228 | + if (use_icount) | ||
1229 | + gen_io_start(); | ||
1222 | gen_string_movl_A0_ESI(s); | 1230 | gen_string_movl_A0_ESI(s); |
1223 | gen_op_ld_T0_A0(ot + s->mem_index); | 1231 | gen_op_ld_T0_A0(ot + s->mem_index); |
1224 | 1232 | ||
@@ -1230,6 +1238,8 @@ static inline void gen_outs(DisasContext *s, int ot) | @@ -1230,6 +1238,8 @@ static inline void gen_outs(DisasContext *s, int ot) | ||
1230 | 1238 | ||
1231 | gen_op_movl_T0_Dshift(ot); | 1239 | gen_op_movl_T0_Dshift(ot); |
1232 | gen_op_add_reg_T0(s->aflag, R_ESI); | 1240 | gen_op_add_reg_T0(s->aflag, R_ESI); |
1241 | + if (use_icount) | ||
1242 | + gen_io_end(); | ||
1233 | } | 1243 | } |
1234 | 1244 | ||
1235 | /* same method as Valgrind : we generate jumps to current or next | 1245 | /* 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) | @@ -5570,6 +5580,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | ||
5570 | gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); | 5580 | gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); |
5571 | } else { | 5581 | } else { |
5572 | gen_ins(s, ot); | 5582 | gen_ins(s, ot); |
5583 | + if (use_icount) { | ||
5584 | + gen_jmp(s, s->pc - s->cs_base); | ||
5585 | + } | ||
5573 | } | 5586 | } |
5574 | break; | 5587 | break; |
5575 | case 0x6e: /* outsS */ | 5588 | case 0x6e: /* outsS */ |
@@ -5586,6 +5599,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | @@ -5586,6 +5599,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | ||
5586 | gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); | 5599 | gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); |
5587 | } else { | 5600 | } else { |
5588 | gen_outs(s, ot); | 5601 | gen_outs(s, ot); |
5602 | + if (use_icount) { | ||
5603 | + gen_jmp(s, s->pc - s->cs_base); | ||
5604 | + } | ||
5589 | } | 5605 | } |
5590 | break; | 5606 | break; |
5591 | 5607 | ||
@@ -5602,9 +5618,15 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | @@ -5602,9 +5618,15 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | ||
5602 | gen_op_movl_T0_im(val); | 5618 | gen_op_movl_T0_im(val); |
5603 | gen_check_io(s, ot, pc_start - s->cs_base, | 5619 | gen_check_io(s, ot, pc_start - s->cs_base, |
5604 | SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes)); | 5620 | SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes)); |
5621 | + if (use_icount) | ||
5622 | + gen_io_start(); | ||
5605 | tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); | 5623 | tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); |
5606 | tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2_i32); | 5624 | tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2_i32); |
5607 | gen_op_mov_reg_T1(ot, R_EAX); | 5625 | gen_op_mov_reg_T1(ot, R_EAX); |
5626 | + if (use_icount) { | ||
5627 | + gen_io_end(); | ||
5628 | + gen_jmp(s, s->pc - s->cs_base); | ||
5629 | + } | ||
5608 | break; | 5630 | break; |
5609 | case 0xe6: | 5631 | case 0xe6: |
5610 | case 0xe7: | 5632 | case 0xe7: |
@@ -5618,10 +5640,16 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | @@ -5618,10 +5640,16 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | ||
5618 | svm_is_rep(prefixes)); | 5640 | svm_is_rep(prefixes)); |
5619 | gen_op_mov_TN_reg(ot, 1, R_EAX); | 5641 | gen_op_mov_TN_reg(ot, 1, R_EAX); |
5620 | 5642 | ||
5643 | + if (use_icount) | ||
5644 | + gen_io_start(); | ||
5621 | tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); | 5645 | tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); |
5622 | tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff); | 5646 | tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff); |
5623 | tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]); | 5647 | tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]); |
5624 | tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2_i32, cpu_tmp3_i32); | 5648 | tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2_i32, cpu_tmp3_i32); |
5649 | + if (use_icount) { | ||
5650 | + gen_io_end(); | ||
5651 | + gen_jmp(s, s->pc - s->cs_base); | ||
5652 | + } | ||
5625 | break; | 5653 | break; |
5626 | case 0xec: | 5654 | case 0xec: |
5627 | case 0xed: | 5655 | case 0xed: |
@@ -5633,9 +5661,15 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | @@ -5633,9 +5661,15 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | ||
5633 | gen_op_andl_T0_ffff(); | 5661 | gen_op_andl_T0_ffff(); |
5634 | gen_check_io(s, ot, pc_start - s->cs_base, | 5662 | gen_check_io(s, ot, pc_start - s->cs_base, |
5635 | SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes)); | 5663 | SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes)); |
5664 | + if (use_icount) | ||
5665 | + gen_io_start(); | ||
5636 | tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); | 5666 | tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); |
5637 | tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2_i32); | 5667 | tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2_i32); |
5638 | gen_op_mov_reg_T1(ot, R_EAX); | 5668 | gen_op_mov_reg_T1(ot, R_EAX); |
5669 | + if (use_icount) { | ||
5670 | + gen_io_end(); | ||
5671 | + gen_jmp(s, s->pc - s->cs_base); | ||
5672 | + } | ||
5639 | break; | 5673 | break; |
5640 | case 0xee: | 5674 | case 0xee: |
5641 | case 0xef: | 5675 | case 0xef: |
@@ -5649,10 +5683,16 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | @@ -5649,10 +5683,16 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | ||
5649 | svm_is_rep(prefixes)); | 5683 | svm_is_rep(prefixes)); |
5650 | gen_op_mov_TN_reg(ot, 1, R_EAX); | 5684 | gen_op_mov_TN_reg(ot, 1, R_EAX); |
5651 | 5685 | ||
5686 | + if (use_icount) | ||
5687 | + gen_io_start(); | ||
5652 | tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); | 5688 | tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); |
5653 | tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff); | 5689 | tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff); |
5654 | tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]); | 5690 | tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]); |
5655 | tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2_i32, cpu_tmp3_i32); | 5691 | tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2_i32, cpu_tmp3_i32); |
5692 | + if (use_icount) { | ||
5693 | + gen_io_end(); | ||
5694 | + gen_jmp(s, s->pc - s->cs_base); | ||
5695 | + } | ||
5656 | break; | 5696 | break; |
5657 | 5697 | ||
5658 | /************************/ | 5698 | /************************/ |
@@ -7109,6 +7149,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -7109,6 +7149,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
7109 | uint64_t flags; | 7149 | uint64_t flags; |
7110 | target_ulong pc_start; | 7150 | target_ulong pc_start; |
7111 | target_ulong cs_base; | 7151 | target_ulong cs_base; |
7152 | + int num_insns; | ||
7153 | + int max_insns; | ||
7112 | 7154 | ||
7113 | /* generate intermediate code */ | 7155 | /* generate intermediate code */ |
7114 | pc_start = tb->pc; | 7156 | pc_start = tb->pc; |
@@ -7179,7 +7221,12 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -7179,7 +7221,12 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
7179 | dc->is_jmp = DISAS_NEXT; | 7221 | dc->is_jmp = DISAS_NEXT; |
7180 | pc_ptr = pc_start; | 7222 | pc_ptr = pc_start; |
7181 | lj = -1; | 7223 | lj = -1; |
7224 | + num_insns = 0; | ||
7225 | + max_insns = tb->cflags & CF_COUNT_MASK; | ||
7226 | + if (max_insns == 0) | ||
7227 | + max_insns = CF_COUNT_MASK; | ||
7182 | 7228 | ||
7229 | + gen_icount_start(); | ||
7183 | for(;;) { | 7230 | for(;;) { |
7184 | if (env->nb_breakpoints > 0) { | 7231 | if (env->nb_breakpoints > 0) { |
7185 | for(j = 0; j < env->nb_breakpoints; j++) { | 7232 | for(j = 0; j < env->nb_breakpoints; j++) { |
@@ -7199,8 +7246,13 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -7199,8 +7246,13 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
7199 | gen_opc_pc[lj] = pc_ptr; | 7246 | gen_opc_pc[lj] = pc_ptr; |
7200 | gen_opc_cc_op[lj] = dc->cc_op; | 7247 | gen_opc_cc_op[lj] = dc->cc_op; |
7201 | gen_opc_instr_start[lj] = 1; | 7248 | gen_opc_instr_start[lj] = 1; |
7249 | + gen_opc_icount[lj] = num_insns; | ||
7202 | } | 7250 | } |
7251 | + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) | ||
7252 | + gen_io_start(); | ||
7253 | + | ||
7203 | pc_ptr = disas_insn(dc, pc_ptr); | 7254 | pc_ptr = disas_insn(dc, pc_ptr); |
7255 | + num_insns++; | ||
7204 | /* stop translation if indicated */ | 7256 | /* stop translation if indicated */ |
7205 | if (dc->is_jmp) | 7257 | if (dc->is_jmp) |
7206 | break; | 7258 | break; |
@@ -7210,20 +7262,23 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -7210,20 +7262,23 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
7210 | the flag and abort the translation to give the irqs a | 7262 | the flag and abort the translation to give the irqs a |
7211 | change to be happen */ | 7263 | change to be happen */ |
7212 | if (dc->tf || dc->singlestep_enabled || | 7264 | if (dc->tf || dc->singlestep_enabled || |
7213 | - (flags & HF_INHIBIT_IRQ_MASK) || | ||
7214 | - (cflags & CF_SINGLE_INSN)) { | 7265 | + (flags & HF_INHIBIT_IRQ_MASK)) { |
7215 | gen_jmp_im(pc_ptr - dc->cs_base); | 7266 | gen_jmp_im(pc_ptr - dc->cs_base); |
7216 | gen_eob(dc); | 7267 | gen_eob(dc); |
7217 | break; | 7268 | break; |
7218 | } | 7269 | } |
7219 | /* if too long translation, stop generation too */ | 7270 | /* if too long translation, stop generation too */ |
7220 | if (gen_opc_ptr >= gen_opc_end || | 7271 | if (gen_opc_ptr >= gen_opc_end || |
7221 | - (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32)) { | 7272 | + (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) || |
7273 | + num_insns >= max_insns) { | ||
7222 | gen_jmp_im(pc_ptr - dc->cs_base); | 7274 | gen_jmp_im(pc_ptr - dc->cs_base); |
7223 | gen_eob(dc); | 7275 | gen_eob(dc); |
7224 | break; | 7276 | break; |
7225 | } | 7277 | } |
7226 | } | 7278 | } |
7279 | + if (tb->cflags & CF_LAST_IO) | ||
7280 | + gen_io_end(); | ||
7281 | + gen_icount_end(tb, num_insns); | ||
7227 | *gen_opc_ptr = INDEX_op_end; | 7282 | *gen_opc_ptr = INDEX_op_end; |
7228 | /* we don't forget to fill the last values */ | 7283 | /* we don't forget to fill the last values */ |
7229 | if (search_pc) { | 7284 | if (search_pc) { |
@@ -7252,8 +7307,10 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -7252,8 +7307,10 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
7252 | } | 7307 | } |
7253 | #endif | 7308 | #endif |
7254 | 7309 | ||
7255 | - if (!search_pc) | 7310 | + if (!search_pc) { |
7256 | tb->size = pc_ptr - pc_start; | 7311 | tb->size = pc_ptr - pc_start; |
7312 | + tb->icount = num_insns; | ||
7313 | + } | ||
7257 | return 0; | 7314 | return 0; |
7258 | } | 7315 | } |
7259 | 7316 |
target-m68k/cpu.h
@@ -235,6 +235,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) | @@ -235,6 +235,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) | ||
235 | } | 235 | } |
236 | #endif | 236 | #endif |
237 | 237 | ||
238 | +#define CPU_PC_FROM_TB(env, tb) env->pc = tb->pc | ||
239 | + | ||
238 | #include "cpu-all.h" | 240 | #include "cpu-all.h" |
239 | 241 | ||
240 | #endif | 242 | #endif |
target-m68k/translate.c
@@ -63,6 +63,8 @@ static TCGv NULL_QREG; | @@ -63,6 +63,8 @@ static TCGv NULL_QREG; | ||
63 | /* Used to distinguish stores from bad addressing modes. */ | 63 | /* Used to distinguish stores from bad addressing modes. */ |
64 | static TCGv store_dummy; | 64 | static TCGv store_dummy; |
65 | 65 | ||
66 | +#include "gen-icount.h" | ||
67 | + | ||
66 | void m68k_tcg_init(void) | 68 | void m68k_tcg_init(void) |
67 | { | 69 | { |
68 | char *p; | 70 | char *p; |
@@ -2919,6 +2921,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -2919,6 +2921,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
2919 | target_ulong pc_start; | 2921 | target_ulong pc_start; |
2920 | int pc_offset; | 2922 | int pc_offset; |
2921 | int last_cc_op; | 2923 | int last_cc_op; |
2924 | + int num_insns; | ||
2925 | + int max_insns; | ||
2922 | 2926 | ||
2923 | /* generate intermediate code */ | 2927 | /* generate intermediate code */ |
2924 | pc_start = tb->pc; | 2928 | pc_start = tb->pc; |
@@ -2937,6 +2941,12 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -2937,6 +2941,12 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
2937 | dc->is_mem = 0; | 2941 | dc->is_mem = 0; |
2938 | dc->mactmp = NULL_QREG; | 2942 | dc->mactmp = NULL_QREG; |
2939 | lj = -1; | 2943 | lj = -1; |
2944 | + num_insns = 0; | ||
2945 | + max_insns = tb->cflags & CF_COUNT_MASK; | ||
2946 | + if (max_insns == 0) | ||
2947 | + max_insns = CF_COUNT_MASK; | ||
2948 | + | ||
2949 | + gen_icount_start(); | ||
2940 | do { | 2950 | do { |
2941 | pc_offset = dc->pc - pc_start; | 2951 | pc_offset = dc->pc - pc_start; |
2942 | gen_throws_exception = NULL; | 2952 | gen_throws_exception = NULL; |
@@ -2960,10 +2970,14 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -2960,10 +2970,14 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
2960 | } | 2970 | } |
2961 | gen_opc_pc[lj] = dc->pc; | 2971 | gen_opc_pc[lj] = dc->pc; |
2962 | gen_opc_instr_start[lj] = 1; | 2972 | gen_opc_instr_start[lj] = 1; |
2973 | + gen_opc_icount[lj] = num_insns; | ||
2963 | } | 2974 | } |
2975 | + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) | ||
2976 | + gen_io_start(); | ||
2964 | last_cc_op = dc->cc_op; | 2977 | last_cc_op = dc->cc_op; |
2965 | dc->insn_pc = dc->pc; | 2978 | dc->insn_pc = dc->pc; |
2966 | disas_m68k_insn(env, dc); | 2979 | disas_m68k_insn(env, dc); |
2980 | + num_insns++; | ||
2967 | 2981 | ||
2968 | /* Terminate the TB on memory ops if watchpoints are present. */ | 2982 | /* Terminate the TB on memory ops if watchpoints are present. */ |
2969 | /* FIXME: This should be replacd by the deterministic execution | 2983 | /* FIXME: This should be replacd by the deterministic execution |
@@ -2972,8 +2986,11 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -2972,8 +2986,11 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
2972 | break; | 2986 | break; |
2973 | } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && | 2987 | } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && |
2974 | !env->singlestep_enabled && | 2988 | !env->singlestep_enabled && |
2975 | - (pc_offset) < (TARGET_PAGE_SIZE - 32)); | 2989 | + (pc_offset) < (TARGET_PAGE_SIZE - 32) && |
2990 | + num_insns < max_insns); | ||
2976 | 2991 | ||
2992 | + if (tb->cflags & CF_LAST_IO) | ||
2993 | + gen_io_end(); | ||
2977 | if (__builtin_expect(env->singlestep_enabled, 0)) { | 2994 | if (__builtin_expect(env->singlestep_enabled, 0)) { |
2978 | /* Make sure the pc is updated, and raise a debug exception. */ | 2995 | /* Make sure the pc is updated, and raise a debug exception. */ |
2979 | if (!dc->is_jmp) { | 2996 | if (!dc->is_jmp) { |
@@ -2999,6 +3016,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -2999,6 +3016,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
2999 | break; | 3016 | break; |
3000 | } | 3017 | } |
3001 | } | 3018 | } |
3019 | + gen_icount_end(tb, num_insns); | ||
3002 | *gen_opc_ptr = INDEX_op_end; | 3020 | *gen_opc_ptr = INDEX_op_end; |
3003 | 3021 | ||
3004 | #ifdef DEBUG_DISAS | 3022 | #ifdef DEBUG_DISAS |
@@ -3016,6 +3034,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -3016,6 +3034,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
3016 | gen_opc_instr_start[lj++] = 0; | 3034 | gen_opc_instr_start[lj++] = 0; |
3017 | } else { | 3035 | } else { |
3018 | tb->size = dc->pc - pc_start; | 3036 | tb->size = dc->pc - pc_start; |
3037 | + tb->icount = num_insns; | ||
3019 | } | 3038 | } |
3020 | 3039 | ||
3021 | //optimize_flags(); | 3040 | //optimize_flags(); |
target-mips/cpu.h
@@ -572,4 +572,10 @@ CPUMIPSState *cpu_mips_init(const char *cpu_model); | @@ -572,4 +572,10 @@ CPUMIPSState *cpu_mips_init(const char *cpu_model); | ||
572 | uint32_t cpu_mips_get_clock (void); | 572 | uint32_t cpu_mips_get_clock (void); |
573 | int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc); | 573 | int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc); |
574 | 574 | ||
575 | +#define CPU_PC_FROM_TB(env, tb) do { \ | ||
576 | + env->active_tc.PC = tb->pc; \ | ||
577 | + env->hflags &= ~MIPS_HFLAG_BMASK; \ | ||
578 | + env->hflags |= tb->flags & MIPS_HFLAG_BMASK; \ | ||
579 | + } while (0) | ||
580 | + | ||
575 | #endif /* !defined (__MIPS_CPU_H__) */ | 581 | #endif /* !defined (__MIPS_CPU_H__) */ |
target-mips/translate.c
@@ -428,6 +428,8 @@ static TCGv cpu_env, current_fpu; | @@ -428,6 +428,8 @@ static TCGv cpu_env, current_fpu; | ||
428 | /* FPU TNs, global for now. */ | 428 | /* FPU TNs, global for now. */ |
429 | static TCGv fpu32_T[3], fpu64_T[3], fpu32h_T[3]; | 429 | static TCGv fpu32_T[3], fpu64_T[3], fpu32h_T[3]; |
430 | 430 | ||
431 | +#include "gen-icount.h" | ||
432 | + | ||
431 | static inline void tcg_gen_helper_0_i(void *func, TCGv arg) | 433 | static inline void tcg_gen_helper_0_i(void *func, TCGv arg) |
432 | { | 434 | { |
433 | TCGv tmp = tcg_const_i32(arg); | 435 | TCGv tmp = tcg_const_i32(arg); |
@@ -3061,7 +3063,14 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int se | @@ -3061,7 +3063,14 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int se | ||
3061 | case 9: | 3063 | case 9: |
3062 | switch (sel) { | 3064 | switch (sel) { |
3063 | case 0: | 3065 | case 0: |
3066 | + /* Mark as an IO operation because we read the time. */ | ||
3067 | + if (use_icount) | ||
3068 | + gen_io_start(); | ||
3064 | tcg_gen_helper_1_0(do_mfc0_count, t0); | 3069 | tcg_gen_helper_1_0(do_mfc0_count, t0); |
3070 | + if (use_icount) { | ||
3071 | + gen_io_end(); | ||
3072 | + ctx->bstate = BS_STOP; | ||
3073 | + } | ||
3065 | rn = "Count"; | 3074 | rn = "Count"; |
3066 | break; | 3075 | break; |
3067 | /* 6,7 are implementation dependent */ | 3076 | /* 6,7 are implementation dependent */ |
@@ -3422,6 +3431,9 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int se | @@ -3422,6 +3431,9 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int se | ||
3422 | if (sel != 0) | 3431 | if (sel != 0) |
3423 | check_insn(env, ctx, ISA_MIPS32); | 3432 | check_insn(env, ctx, ISA_MIPS32); |
3424 | 3433 | ||
3434 | + if (use_icount) | ||
3435 | + gen_io_start(); | ||
3436 | + | ||
3425 | switch (reg) { | 3437 | switch (reg) { |
3426 | case 0: | 3438 | case 0: |
3427 | switch (sel) { | 3439 | switch (sel) { |
@@ -4004,6 +4016,11 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int se | @@ -4004,6 +4016,11 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int se | ||
4004 | rn, reg, sel); | 4016 | rn, reg, sel); |
4005 | } | 4017 | } |
4006 | #endif | 4018 | #endif |
4019 | + /* For simplicitly assume that all writes can cause interrupts. */ | ||
4020 | + if (use_icount) { | ||
4021 | + gen_io_end(); | ||
4022 | + ctx->bstate = BS_STOP; | ||
4023 | + } | ||
4007 | return; | 4024 | return; |
4008 | 4025 | ||
4009 | die: | 4026 | die: |
@@ -4238,7 +4255,14 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int s | @@ -4238,7 +4255,14 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int s | ||
4238 | case 9: | 4255 | case 9: |
4239 | switch (sel) { | 4256 | switch (sel) { |
4240 | case 0: | 4257 | case 0: |
4258 | + /* Mark as an IO operation because we read the time. */ | ||
4259 | + if (use_icount) | ||
4260 | + gen_io_start(); | ||
4241 | tcg_gen_helper_1_0(do_mfc0_count, t0); | 4261 | tcg_gen_helper_1_0(do_mfc0_count, t0); |
4262 | + if (use_icount) { | ||
4263 | + gen_io_end(); | ||
4264 | + ctx->bstate = BS_STOP; | ||
4265 | + } | ||
4242 | rn = "Count"; | 4266 | rn = "Count"; |
4243 | break; | 4267 | break; |
4244 | /* 6,7 are implementation dependent */ | 4268 | /* 6,7 are implementation dependent */ |
@@ -4591,6 +4615,9 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int s | @@ -4591,6 +4615,9 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int s | ||
4591 | if (sel != 0) | 4615 | if (sel != 0) |
4592 | check_insn(env, ctx, ISA_MIPS64); | 4616 | check_insn(env, ctx, ISA_MIPS64); |
4593 | 4617 | ||
4618 | + if (use_icount) | ||
4619 | + gen_io_start(); | ||
4620 | + | ||
4594 | switch (reg) { | 4621 | switch (reg) { |
4595 | case 0: | 4622 | case 0: |
4596 | switch (sel) { | 4623 | switch (sel) { |
@@ -5161,6 +5188,11 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int s | @@ -5161,6 +5188,11 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int s | ||
5161 | } | 5188 | } |
5162 | #endif | 5189 | #endif |
5163 | tcg_temp_free(t0); | 5190 | tcg_temp_free(t0); |
5191 | + /* For simplicitly assume that all writes can cause interrupts. */ | ||
5192 | + if (use_icount) { | ||
5193 | + gen_io_end(); | ||
5194 | + ctx->bstate = BS_STOP; | ||
5195 | + } | ||
5164 | return; | 5196 | return; |
5165 | 5197 | ||
5166 | die: | 5198 | die: |
@@ -7760,6 +7792,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | @@ -7760,6 +7792,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | ||
7760 | ctx->hflags &= ~MIPS_HFLAG_BMASK; | 7792 | ctx->hflags &= ~MIPS_HFLAG_BMASK; |
7761 | ctx->bstate = BS_BRANCH; | 7793 | ctx->bstate = BS_BRANCH; |
7762 | save_cpu_state(ctx, 0); | 7794 | save_cpu_state(ctx, 0); |
7795 | + /* FIXME: Need to clear can_do_io. */ | ||
7763 | switch (hflags) { | 7796 | switch (hflags) { |
7764 | case MIPS_HFLAG_B: | 7797 | case MIPS_HFLAG_B: |
7765 | /* unconditional branch */ | 7798 | /* unconditional branch */ |
@@ -7807,6 +7840,8 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | @@ -7807,6 +7840,8 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | ||
7807 | target_ulong pc_start; | 7840 | target_ulong pc_start; |
7808 | uint16_t *gen_opc_end; | 7841 | uint16_t *gen_opc_end; |
7809 | int j, lj = -1; | 7842 | int j, lj = -1; |
7843 | + int num_insns; | ||
7844 | + int max_insns; | ||
7810 | 7845 | ||
7811 | if (search_pc && loglevel) | 7846 | if (search_pc && loglevel) |
7812 | fprintf (logfile, "search pc %d\n", search_pc); | 7847 | fprintf (logfile, "search pc %d\n", search_pc); |
@@ -7826,6 +7861,11 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | @@ -7826,6 +7861,11 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | ||
7826 | #else | 7861 | #else |
7827 | ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU; | 7862 | ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU; |
7828 | #endif | 7863 | #endif |
7864 | + num_insns = 0; | ||
7865 | + num_insns = 0; | ||
7866 | + max_insns = tb->cflags & CF_COUNT_MASK; | ||
7867 | + if (max_insns == 0) | ||
7868 | + max_insns = CF_COUNT_MASK; | ||
7829 | #ifdef DEBUG_DISAS | 7869 | #ifdef DEBUG_DISAS |
7830 | if (loglevel & CPU_LOG_TB_CPU) { | 7870 | if (loglevel & CPU_LOG_TB_CPU) { |
7831 | fprintf(logfile, "------------------------------------------------\n"); | 7871 | fprintf(logfile, "------------------------------------------------\n"); |
@@ -7838,6 +7878,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | @@ -7838,6 +7878,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | ||
7838 | fprintf(logfile, "\ntb %p idx %d hflags %04x\n", | 7878 | fprintf(logfile, "\ntb %p idx %d hflags %04x\n", |
7839 | tb, ctx.mem_idx, ctx.hflags); | 7879 | tb, ctx.mem_idx, ctx.hflags); |
7840 | #endif | 7880 | #endif |
7881 | + gen_icount_start(); | ||
7841 | while (ctx.bstate == BS_NONE) { | 7882 | while (ctx.bstate == BS_NONE) { |
7842 | if (env->nb_breakpoints > 0) { | 7883 | if (env->nb_breakpoints > 0) { |
7843 | for(j = 0; j < env->nb_breakpoints; j++) { | 7884 | for(j = 0; j < env->nb_breakpoints; j++) { |
@@ -7863,10 +7904,14 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | @@ -7863,10 +7904,14 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | ||
7863 | gen_opc_pc[lj] = ctx.pc; | 7904 | gen_opc_pc[lj] = ctx.pc; |
7864 | gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK; | 7905 | gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK; |
7865 | gen_opc_instr_start[lj] = 1; | 7906 | gen_opc_instr_start[lj] = 1; |
7907 | + gen_opc_icount[lj] = num_insns; | ||
7866 | } | 7908 | } |
7909 | + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) | ||
7910 | + gen_io_start(); | ||
7867 | ctx.opcode = ldl_code(ctx.pc); | 7911 | ctx.opcode = ldl_code(ctx.pc); |
7868 | decode_opc(env, &ctx); | 7912 | decode_opc(env, &ctx); |
7869 | ctx.pc += 4; | 7913 | ctx.pc += 4; |
7914 | + num_insns++; | ||
7870 | 7915 | ||
7871 | if (env->singlestep_enabled) | 7916 | if (env->singlestep_enabled) |
7872 | break; | 7917 | break; |
@@ -7880,10 +7925,14 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | @@ -7880,10 +7925,14 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | ||
7880 | if (gen_opc_ptr >= gen_opc_end) | 7925 | if (gen_opc_ptr >= gen_opc_end) |
7881 | break; | 7926 | break; |
7882 | 7927 | ||
7928 | + if (num_insns >= max_insns) | ||
7929 | + break; | ||
7883 | #if defined (MIPS_SINGLE_STEP) | 7930 | #if defined (MIPS_SINGLE_STEP) |
7884 | break; | 7931 | break; |
7885 | #endif | 7932 | #endif |
7886 | } | 7933 | } |
7934 | + if (tb->cflags & CF_LAST_IO) | ||
7935 | + gen_io_end(); | ||
7887 | if (env->singlestep_enabled) { | 7936 | if (env->singlestep_enabled) { |
7888 | save_cpu_state(&ctx, ctx.bstate == BS_NONE); | 7937 | save_cpu_state(&ctx, ctx.bstate == BS_NONE); |
7889 | tcg_gen_helper_0_i(do_raise_exception, EXCP_DEBUG); | 7938 | tcg_gen_helper_0_i(do_raise_exception, EXCP_DEBUG); |
@@ -7907,6 +7956,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | @@ -7907,6 +7956,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | ||
7907 | } | 7956 | } |
7908 | } | 7957 | } |
7909 | done_generating: | 7958 | done_generating: |
7959 | + gen_icount_end(tb, num_insns); | ||
7910 | *gen_opc_ptr = INDEX_op_end; | 7960 | *gen_opc_ptr = INDEX_op_end; |
7911 | if (search_pc) { | 7961 | if (search_pc) { |
7912 | j = gen_opc_ptr - gen_opc_buf; | 7962 | j = gen_opc_ptr - gen_opc_buf; |
@@ -7915,6 +7965,7 @@ done_generating: | @@ -7915,6 +7965,7 @@ done_generating: | ||
7915 | gen_opc_instr_start[lj++] = 0; | 7965 | gen_opc_instr_start[lj++] = 0; |
7916 | } else { | 7966 | } else { |
7917 | tb->size = ctx.pc - pc_start; | 7967 | tb->size = ctx.pc - pc_start; |
7968 | + tb->icount = num_insns; | ||
7918 | } | 7969 | } |
7919 | #ifdef DEBUG_DISAS | 7970 | #ifdef DEBUG_DISAS |
7920 | #if defined MIPS_DEBUG_DISAS | 7971 | #if defined MIPS_DEBUG_DISAS |
target-ppc/cpu.h
@@ -697,6 +697,7 @@ struct mmu_ctx_t { | @@ -697,6 +697,7 @@ struct mmu_ctx_t { | ||
697 | 697 | ||
698 | /*****************************************************************************/ | 698 | /*****************************************************************************/ |
699 | CPUPPCState *cpu_ppc_init (const char *cpu_model); | 699 | CPUPPCState *cpu_ppc_init (const char *cpu_model); |
700 | +void ppc_translate_init(void); | ||
700 | int cpu_ppc_exec (CPUPPCState *s); | 701 | int cpu_ppc_exec (CPUPPCState *s); |
701 | void cpu_ppc_close (CPUPPCState *s); | 702 | void cpu_ppc_close (CPUPPCState *s); |
702 | /* you can call this signal handler from your SIGBUS and SIGSEGV | 703 | /* you can call this signal handler from your SIGBUS and SIGSEGV |
@@ -833,6 +834,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) | @@ -833,6 +834,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) | ||
833 | } | 834 | } |
834 | #endif | 835 | #endif |
835 | 836 | ||
837 | +#define CPU_PC_FROM_TB(env, tb) env->nip = tb->pc | ||
838 | + | ||
836 | #include "cpu-all.h" | 839 | #include "cpu-all.h" |
837 | 840 | ||
838 | /*****************************************************************************/ | 841 | /*****************************************************************************/ |
target-ppc/helper.c
@@ -2977,6 +2977,7 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model) | @@ -2977,6 +2977,7 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model) | ||
2977 | if (!env) | 2977 | if (!env) |
2978 | return NULL; | 2978 | return NULL; |
2979 | cpu_exec_init(env); | 2979 | cpu_exec_init(env); |
2980 | + ppc_translate_init(); | ||
2980 | env->cpu_model_str = cpu_model; | 2981 | env->cpu_model_str = cpu_model; |
2981 | cpu_ppc_register_internal(env, def); | 2982 | cpu_ppc_register_internal(env, def); |
2982 | cpu_ppc_reset(env); | 2983 | cpu_ppc_reset(env); |
target-ppc/translate.c
@@ -43,6 +43,19 @@ | @@ -43,6 +43,19 @@ | ||
43 | /*****************************************************************************/ | 43 | /*****************************************************************************/ |
44 | /* Code translation helpers */ | 44 | /* Code translation helpers */ |
45 | 45 | ||
46 | +static TCGv cpu_env; | ||
47 | + | ||
48 | +#include "gen-icount.h" | ||
49 | + | ||
50 | +void ppc_translate_init(void) | ||
51 | +{ | ||
52 | + int done_init = 0; | ||
53 | + if (done_init) | ||
54 | + return; | ||
55 | + cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env"); | ||
56 | + done_init = 1; | ||
57 | +} | ||
58 | + | ||
46 | #if defined(OPTIMIZE_FPRF_UPDATE) | 59 | #if defined(OPTIMIZE_FPRF_UPDATE) |
47 | static uint16_t *gen_fprf_buf[OPC_BUF_SIZE]; | 60 | static uint16_t *gen_fprf_buf[OPC_BUF_SIZE]; |
48 | static uint16_t **gen_fprf_ptr; | 61 | static uint16_t **gen_fprf_ptr; |
@@ -6168,6 +6181,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -6168,6 +6181,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
6168 | uint16_t *gen_opc_end; | 6181 | uint16_t *gen_opc_end; |
6169 | int supervisor, little_endian; | 6182 | int supervisor, little_endian; |
6170 | int j, lj = -1; | 6183 | int j, lj = -1; |
6184 | + int num_insns; | ||
6185 | + int max_insns; | ||
6171 | 6186 | ||
6172 | pc_start = tb->pc; | 6187 | pc_start = tb->pc; |
6173 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; | 6188 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
@@ -6211,6 +6226,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -6211,6 +6226,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
6211 | /* Single step trace mode */ | 6226 | /* Single step trace mode */ |
6212 | msr_se = 1; | 6227 | msr_se = 1; |
6213 | #endif | 6228 | #endif |
6229 | + num_insns = 0; | ||
6230 | + max_insns = tb->cflags & CF_COUNT_MASK; | ||
6231 | + if (max_insns == 0) | ||
6232 | + max_insns = CF_COUNT_MASK; | ||
6233 | + | ||
6234 | + gen_icount_start(); | ||
6214 | /* Set env in case of segfault during code fetch */ | 6235 | /* Set env in case of segfault during code fetch */ |
6215 | while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) { | 6236 | while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) { |
6216 | if (unlikely(env->nb_breakpoints > 0)) { | 6237 | if (unlikely(env->nb_breakpoints > 0)) { |
@@ -6230,6 +6251,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -6230,6 +6251,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
6230 | gen_opc_instr_start[lj++] = 0; | 6251 | gen_opc_instr_start[lj++] = 0; |
6231 | gen_opc_pc[lj] = ctx.nip; | 6252 | gen_opc_pc[lj] = ctx.nip; |
6232 | gen_opc_instr_start[lj] = 1; | 6253 | gen_opc_instr_start[lj] = 1; |
6254 | + gen_opc_icount[lj] = num_insns; | ||
6233 | } | 6255 | } |
6234 | } | 6256 | } |
6235 | #if defined PPC_DEBUG_DISAS | 6257 | #if defined PPC_DEBUG_DISAS |
@@ -6239,6 +6261,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -6239,6 +6261,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
6239 | ctx.nip, supervisor, (int)msr_ir); | 6261 | ctx.nip, supervisor, (int)msr_ir); |
6240 | } | 6262 | } |
6241 | #endif | 6263 | #endif |
6264 | + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) | ||
6265 | + gen_io_start(); | ||
6242 | if (unlikely(little_endian)) { | 6266 | if (unlikely(little_endian)) { |
6243 | ctx.opcode = bswap32(ldl_code(ctx.nip)); | 6267 | ctx.opcode = bswap32(ldl_code(ctx.nip)); |
6244 | } else { | 6268 | } else { |
@@ -6253,6 +6277,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -6253,6 +6277,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
6253 | #endif | 6277 | #endif |
6254 | ctx.nip += 4; | 6278 | ctx.nip += 4; |
6255 | table = env->opcodes; | 6279 | table = env->opcodes; |
6280 | + num_insns++; | ||
6256 | handler = table[opc1(ctx.opcode)]; | 6281 | handler = table[opc1(ctx.opcode)]; |
6257 | if (is_indirect_opcode(handler)) { | 6282 | if (is_indirect_opcode(handler)) { |
6258 | table = ind_table(handler); | 6283 | table = ind_table(handler); |
@@ -6306,7 +6331,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -6306,7 +6331,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
6306 | ctx.exception != POWERPC_EXCP_BRANCH)) { | 6331 | ctx.exception != POWERPC_EXCP_BRANCH)) { |
6307 | GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0); | 6332 | GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0); |
6308 | } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || | 6333 | } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || |
6309 | - (env->singlestep_enabled))) { | 6334 | + (env->singlestep_enabled) || |
6335 | + num_insns >= max_insns)) { | ||
6310 | /* if we reach a page boundary or are single stepping, stop | 6336 | /* if we reach a page boundary or are single stepping, stop |
6311 | * generation | 6337 | * generation |
6312 | */ | 6338 | */ |
@@ -6316,6 +6342,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -6316,6 +6342,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
6316 | break; | 6342 | break; |
6317 | #endif | 6343 | #endif |
6318 | } | 6344 | } |
6345 | + if (tb->cflags & CF_LAST_IO) | ||
6346 | + gen_io_end(); | ||
6319 | if (ctx.exception == POWERPC_EXCP_NONE) { | 6347 | if (ctx.exception == POWERPC_EXCP_NONE) { |
6320 | gen_goto_tb(&ctx, 0, ctx.nip); | 6348 | gen_goto_tb(&ctx, 0, ctx.nip); |
6321 | } else if (ctx.exception != POWERPC_EXCP_BRANCH) { | 6349 | } else if (ctx.exception != POWERPC_EXCP_BRANCH) { |
@@ -6326,6 +6354,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -6326,6 +6354,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
6326 | /* Generate the return instruction */ | 6354 | /* Generate the return instruction */ |
6327 | tcg_gen_exit_tb(0); | 6355 | tcg_gen_exit_tb(0); |
6328 | } | 6356 | } |
6357 | + gen_icount_end(tb, num_insns); | ||
6329 | *gen_opc_ptr = INDEX_op_end; | 6358 | *gen_opc_ptr = INDEX_op_end; |
6330 | if (unlikely(search_pc)) { | 6359 | if (unlikely(search_pc)) { |
6331 | j = gen_opc_ptr - gen_opc_buf; | 6360 | j = gen_opc_ptr - gen_opc_buf; |
@@ -6334,6 +6363,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | @@ -6334,6 +6363,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, | ||
6334 | gen_opc_instr_start[lj++] = 0; | 6363 | gen_opc_instr_start[lj++] = 0; |
6335 | } else { | 6364 | } else { |
6336 | tb->size = ctx.nip - pc_start; | 6365 | tb->size = ctx.nip - pc_start; |
6366 | + tb->icount = num_insns; | ||
6337 | } | 6367 | } |
6338 | #if defined(DEBUG_DISAS) | 6368 | #if defined(DEBUG_DISAS) |
6339 | if (loglevel & CPU_LOG_TB_CPU) { | 6369 | if (loglevel & CPU_LOG_TB_CPU) { |
target-sh4/cpu.h
@@ -152,6 +152,11 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) | @@ -152,6 +152,11 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) | ||
152 | } | 152 | } |
153 | #endif | 153 | #endif |
154 | 154 | ||
155 | +#define CPU_PC_FROM_TB(env, tb) do { \ | ||
156 | + env->pc = tb->pc; \ | ||
157 | + env->flags = tb->flags; \ | ||
158 | + } while (0) | ||
159 | + | ||
155 | #include "cpu-all.h" | 160 | #include "cpu-all.h" |
156 | 161 | ||
157 | /* Memory access type */ | 162 | /* Memory access type */ |
target-sh4/translate.c
@@ -56,6 +56,19 @@ enum { | @@ -56,6 +56,19 @@ enum { | ||
56 | BS_EXCP = 3, /* We reached an exception condition */ | 56 | BS_EXCP = 3, /* We reached an exception condition */ |
57 | }; | 57 | }; |
58 | 58 | ||
59 | +static TCGv cpu_env; | ||
60 | + | ||
61 | +#include "gen-icount.h" | ||
62 | + | ||
63 | +void sh4_translate_init() | ||
64 | +{ | ||
65 | + static int done_init = 0; | ||
66 | + if (done_init) | ||
67 | + return; | ||
68 | + cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env"); | ||
69 | + done_init = 1; | ||
70 | +} | ||
71 | + | ||
59 | #ifdef CONFIG_USER_ONLY | 72 | #ifdef CONFIG_USER_ONLY |
60 | 73 | ||
61 | #define GEN_OP_LD(width, reg) \ | 74 | #define GEN_OP_LD(width, reg) \ |
@@ -143,6 +156,7 @@ CPUSH4State *cpu_sh4_init(const char *cpu_model) | @@ -143,6 +156,7 @@ CPUSH4State *cpu_sh4_init(const char *cpu_model) | ||
143 | if (!env) | 156 | if (!env) |
144 | return NULL; | 157 | return NULL; |
145 | cpu_exec_init(env); | 158 | cpu_exec_init(env); |
159 | + sh4_translate_init(); | ||
146 | cpu_sh4_reset(env); | 160 | cpu_sh4_reset(env); |
147 | tlb_flush(env, 1); | 161 | tlb_flush(env, 1); |
148 | return env; | 162 | return env; |
@@ -1189,6 +1203,8 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, | @@ -1189,6 +1203,8 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, | ||
1189 | target_ulong pc_start; | 1203 | target_ulong pc_start; |
1190 | static uint16_t *gen_opc_end; | 1204 | static uint16_t *gen_opc_end; |
1191 | int i, ii; | 1205 | int i, ii; |
1206 | + int num_insns; | ||
1207 | + int max_insns; | ||
1192 | 1208 | ||
1193 | pc_start = tb->pc; | 1209 | pc_start = tb->pc; |
1194 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; | 1210 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
@@ -1213,6 +1229,11 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, | @@ -1213,6 +1229,11 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, | ||
1213 | #endif | 1229 | #endif |
1214 | 1230 | ||
1215 | ii = -1; | 1231 | ii = -1; |
1232 | + num_insns = 0; | ||
1233 | + max_insns = tb->cflags & CF_COUNT_MASK; | ||
1234 | + if (max_insns == 0) | ||
1235 | + max_insns = CF_COUNT_MASK; | ||
1236 | + gen_icount_start(); | ||
1216 | while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { | 1237 | while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { |
1217 | if (env->nb_breakpoints > 0) { | 1238 | if (env->nb_breakpoints > 0) { |
1218 | for (i = 0; i < env->nb_breakpoints; i++) { | 1239 | for (i = 0; i < env->nb_breakpoints; i++) { |
@@ -1235,22 +1256,30 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, | @@ -1235,22 +1256,30 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, | ||
1235 | gen_opc_pc[ii] = ctx.pc; | 1256 | gen_opc_pc[ii] = ctx.pc; |
1236 | gen_opc_hflags[ii] = ctx.flags; | 1257 | gen_opc_hflags[ii] = ctx.flags; |
1237 | gen_opc_instr_start[ii] = 1; | 1258 | gen_opc_instr_start[ii] = 1; |
1259 | + gen_opc_icount[ii] = num_insns; | ||
1238 | } | 1260 | } |
1261 | + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) | ||
1262 | + gen_io_start(); | ||
1239 | #if 0 | 1263 | #if 0 |
1240 | fprintf(stderr, "Loading opcode at address 0x%08x\n", ctx.pc); | 1264 | fprintf(stderr, "Loading opcode at address 0x%08x\n", ctx.pc); |
1241 | fflush(stderr); | 1265 | fflush(stderr); |
1242 | #endif | 1266 | #endif |
1243 | ctx.opcode = lduw_code(ctx.pc); | 1267 | ctx.opcode = lduw_code(ctx.pc); |
1244 | decode_opc(&ctx); | 1268 | decode_opc(&ctx); |
1269 | + num_insns++; | ||
1245 | ctx.pc += 2; | 1270 | ctx.pc += 2; |
1246 | if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) | 1271 | if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) |
1247 | break; | 1272 | break; |
1248 | if (env->singlestep_enabled) | 1273 | if (env->singlestep_enabled) |
1249 | break; | 1274 | break; |
1275 | + if (num_insns >= max_insns) | ||
1276 | + break; | ||
1250 | #ifdef SH4_SINGLE_STEP | 1277 | #ifdef SH4_SINGLE_STEP |
1251 | break; | 1278 | break; |
1252 | #endif | 1279 | #endif |
1253 | } | 1280 | } |
1281 | + if (tb->cflags & CF_LAST_IO) | ||
1282 | + gen_io_end(); | ||
1254 | if (env->singlestep_enabled) { | 1283 | if (env->singlestep_enabled) { |
1255 | gen_op_debug(); | 1284 | gen_op_debug(); |
1256 | } else { | 1285 | } else { |
@@ -1274,6 +1303,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, | @@ -1274,6 +1303,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, | ||
1274 | } | 1303 | } |
1275 | } | 1304 | } |
1276 | 1305 | ||
1306 | + gen_icount_end(tb, num_insns); | ||
1277 | *gen_opc_ptr = INDEX_op_end; | 1307 | *gen_opc_ptr = INDEX_op_end; |
1278 | if (search_pc) { | 1308 | if (search_pc) { |
1279 | i = gen_opc_ptr - gen_opc_buf; | 1309 | i = gen_opc_ptr - gen_opc_buf; |
@@ -1282,6 +1312,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, | @@ -1282,6 +1312,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, | ||
1282 | gen_opc_instr_start[ii++] = 0; | 1312 | gen_opc_instr_start[ii++] = 0; |
1283 | } else { | 1313 | } else { |
1284 | tb->size = ctx.pc - pc_start; | 1314 | tb->size = ctx.pc - pc_start; |
1315 | + tb->icount = num_insns; | ||
1285 | } | 1316 | } |
1286 | 1317 | ||
1287 | #ifdef DEBUG_DISAS | 1318 | #ifdef DEBUG_DISAS |
target-sparc/cpu.h
@@ -437,6 +437,11 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) | @@ -437,6 +437,11 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) | ||
437 | } | 437 | } |
438 | #endif | 438 | #endif |
439 | 439 | ||
440 | +#define CPU_PC_FROM_TB(env, tb) do { \ | ||
441 | + env->pc = tb->pc; \ | ||
442 | + env->npc = tb->cs_base; \ | ||
443 | + } while(0) | ||
444 | + | ||
440 | #include "cpu-all.h" | 445 | #include "cpu-all.h" |
441 | 446 | ||
442 | #endif | 447 | #endif |
target-sparc/translate.c
@@ -48,6 +48,8 @@ static TCGv cpu_xcc; | @@ -48,6 +48,8 @@ static TCGv cpu_xcc; | ||
48 | /* local register indexes (only used inside old micro ops) */ | 48 | /* local register indexes (only used inside old micro ops) */ |
49 | static TCGv cpu_tmp0, cpu_tmp32, cpu_tmp64; | 49 | static TCGv cpu_tmp0, cpu_tmp32, cpu_tmp64; |
50 | 50 | ||
51 | +#include "gen-icount.h" | ||
52 | + | ||
51 | typedef struct DisasContext { | 53 | typedef struct DisasContext { |
52 | target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */ | 54 | target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */ |
53 | target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */ | 55 | target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */ |
@@ -4719,6 +4721,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | @@ -4719,6 +4721,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | ||
4719 | uint16_t *gen_opc_end; | 4721 | uint16_t *gen_opc_end; |
4720 | DisasContext dc1, *dc = &dc1; | 4722 | DisasContext dc1, *dc = &dc1; |
4721 | int j, lj = -1; | 4723 | int j, lj = -1; |
4724 | + int num_insns; | ||
4725 | + int max_insns; | ||
4722 | 4726 | ||
4723 | memset(dc, 0, sizeof(DisasContext)); | 4727 | memset(dc, 0, sizeof(DisasContext)); |
4724 | dc->tb = tb; | 4728 | dc->tb = tb; |
@@ -4747,6 +4751,11 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | @@ -4747,6 +4751,11 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | ||
4747 | cpu_val = tcg_temp_local_new(TCG_TYPE_TL); | 4751 | cpu_val = tcg_temp_local_new(TCG_TYPE_TL); |
4748 | cpu_addr = tcg_temp_local_new(TCG_TYPE_TL); | 4752 | cpu_addr = tcg_temp_local_new(TCG_TYPE_TL); |
4749 | 4753 | ||
4754 | + num_insns = 0; | ||
4755 | + max_insns = tb->cflags & CF_COUNT_MASK; | ||
4756 | + if (max_insns == 0) | ||
4757 | + max_insns = CF_COUNT_MASK; | ||
4758 | + gen_icount_start(); | ||
4750 | do { | 4759 | do { |
4751 | if (env->nb_breakpoints > 0) { | 4760 | if (env->nb_breakpoints > 0) { |
4752 | for(j = 0; j < env->nb_breakpoints; j++) { | 4761 | for(j = 0; j < env->nb_breakpoints; j++) { |
@@ -4771,10 +4780,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | @@ -4771,10 +4780,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | ||
4771 | gen_opc_pc[lj] = dc->pc; | 4780 | gen_opc_pc[lj] = dc->pc; |
4772 | gen_opc_npc[lj] = dc->npc; | 4781 | gen_opc_npc[lj] = dc->npc; |
4773 | gen_opc_instr_start[lj] = 1; | 4782 | gen_opc_instr_start[lj] = 1; |
4783 | + gen_opc_icount[lj] = num_insns; | ||
4774 | } | 4784 | } |
4775 | } | 4785 | } |
4786 | + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) | ||
4787 | + gen_io_start(); | ||
4776 | last_pc = dc->pc; | 4788 | last_pc = dc->pc; |
4777 | disas_sparc_insn(dc); | 4789 | disas_sparc_insn(dc); |
4790 | + num_insns++; | ||
4778 | 4791 | ||
4779 | if (dc->is_br) | 4792 | if (dc->is_br) |
4780 | break; | 4793 | break; |
@@ -4793,7 +4806,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | @@ -4793,7 +4806,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | ||
4793 | break; | 4806 | break; |
4794 | } | 4807 | } |
4795 | } while ((gen_opc_ptr < gen_opc_end) && | 4808 | } while ((gen_opc_ptr < gen_opc_end) && |
4796 | - (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); | 4809 | + (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32) && |
4810 | + num_insns < max_insns); | ||
4797 | 4811 | ||
4798 | exit_gen_loop: | 4812 | exit_gen_loop: |
4799 | tcg_temp_free(cpu_addr); | 4813 | tcg_temp_free(cpu_addr); |
@@ -4802,6 +4816,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | @@ -4802,6 +4816,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | ||
4802 | tcg_temp_free(cpu_tmp64); | 4816 | tcg_temp_free(cpu_tmp64); |
4803 | tcg_temp_free(cpu_tmp32); | 4817 | tcg_temp_free(cpu_tmp32); |
4804 | tcg_temp_free(cpu_tmp0); | 4818 | tcg_temp_free(cpu_tmp0); |
4819 | + if (tb->cflags & CF_LAST_IO) | ||
4820 | + gen_io_end(); | ||
4805 | if (!dc->is_br) { | 4821 | if (!dc->is_br) { |
4806 | if (dc->pc != DYNAMIC_PC && | 4822 | if (dc->pc != DYNAMIC_PC && |
4807 | (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) { | 4823 | (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) { |
@@ -4814,6 +4830,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | @@ -4814,6 +4830,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | ||
4814 | tcg_gen_exit_tb(0); | 4830 | tcg_gen_exit_tb(0); |
4815 | } | 4831 | } |
4816 | } | 4832 | } |
4833 | + gen_icount_end(tb, num_insns); | ||
4817 | *gen_opc_ptr = INDEX_op_end; | 4834 | *gen_opc_ptr = INDEX_op_end; |
4818 | if (spc) { | 4835 | if (spc) { |
4819 | j = gen_opc_ptr - gen_opc_buf; | 4836 | j = gen_opc_ptr - gen_opc_buf; |
@@ -4829,6 +4846,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | @@ -4829,6 +4846,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | ||
4829 | gen_opc_jump_pc[1] = dc->jump_pc[1]; | 4846 | gen_opc_jump_pc[1] = dc->jump_pc[1]; |
4830 | } else { | 4847 | } else { |
4831 | tb->size = last_pc + 4 - pc_start; | 4848 | tb->size = last_pc + 4 - pc_start; |
4849 | + tb->icount = num_insns; | ||
4832 | } | 4850 | } |
4833 | #ifdef DEBUG_DISAS | 4851 | #ifdef DEBUG_DISAS |
4834 | if (loglevel & CPU_LOG_TB_IN_ASM) { | 4852 | if (loglevel & CPU_LOG_TB_IN_ASM) { |
translate-all.c
@@ -38,6 +38,7 @@ uint16_t gen_opc_buf[OPC_BUF_SIZE]; | @@ -38,6 +38,7 @@ uint16_t gen_opc_buf[OPC_BUF_SIZE]; | ||
38 | TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE]; | 38 | TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE]; |
39 | 39 | ||
40 | target_ulong gen_opc_pc[OPC_BUF_SIZE]; | 40 | target_ulong gen_opc_pc[OPC_BUF_SIZE]; |
41 | +uint16_t gen_opc_icount[OPC_BUF_SIZE]; | ||
41 | uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; | 42 | uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; |
42 | #if defined(TARGET_I386) | 43 | #if defined(TARGET_I386) |
43 | uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; | 44 | uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; |
@@ -158,6 +159,13 @@ int cpu_restore_state(TranslationBlock *tb, | @@ -158,6 +159,13 @@ int cpu_restore_state(TranslationBlock *tb, | ||
158 | if (gen_intermediate_code_pc(env, tb) < 0) | 159 | if (gen_intermediate_code_pc(env, tb) < 0) |
159 | return -1; | 160 | return -1; |
160 | 161 | ||
162 | + if (use_icount) { | ||
163 | + /* Reset the cycle counter to the start of the block. */ | ||
164 | + env->icount_decr.u16.low += tb->icount; | ||
165 | + /* Clear the IO flag. */ | ||
166 | + env->can_do_io = 0; | ||
167 | + } | ||
168 | + | ||
161 | /* find opc index corresponding to search_pc */ | 169 | /* find opc index corresponding to search_pc */ |
162 | tc_ptr = (unsigned long)tb->tc_ptr; | 170 | tc_ptr = (unsigned long)tb->tc_ptr; |
163 | if (searched_pc < tc_ptr) | 171 | if (searched_pc < tc_ptr) |
@@ -177,6 +185,7 @@ int cpu_restore_state(TranslationBlock *tb, | @@ -177,6 +185,7 @@ int cpu_restore_state(TranslationBlock *tb, | ||
177 | /* now find start of instruction before */ | 185 | /* now find start of instruction before */ |
178 | while (gen_opc_instr_start[j] == 0) | 186 | while (gen_opc_instr_start[j] == 0) |
179 | j--; | 187 | j--; |
188 | + env->icount_decr.u16.low -= gen_opc_icount[j]; | ||
180 | 189 | ||
181 | gen_pc_load(env, tb, searched_pc, j, puc); | 190 | gen_pc_load(env, tb, searched_pc, j, puc); |
182 | 191 |
vl.c
@@ -239,6 +239,14 @@ struct drive_opt { | @@ -239,6 +239,14 @@ struct drive_opt { | ||
239 | static CPUState *cur_cpu; | 239 | static CPUState *cur_cpu; |
240 | static CPUState *next_cpu; | 240 | static CPUState *next_cpu; |
241 | static int event_pending = 1; | 241 | static int event_pending = 1; |
242 | +/* Conversion factor from emulated instrctions to virtual clock ticks. */ | ||
243 | +static int icount_time_shift; | ||
244 | +/* Arbitrarily pick 1MIPS as the minimum alowable speed. */ | ||
245 | +#define MAX_ICOUNT_SHIFT 10 | ||
246 | +/* Compensate for varying guest execution speed. */ | ||
247 | +static int64_t qemu_icount_bias; | ||
248 | +QEMUTimer *icount_rt_timer; | ||
249 | +QEMUTimer *icount_vm_timer; | ||
242 | 250 | ||
243 | #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) | 251 | #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) |
244 | 252 | ||
@@ -733,9 +741,22 @@ static int64_t get_clock(void) | @@ -733,9 +741,22 @@ static int64_t get_clock(void) | ||
733 | return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000); | 741 | return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000); |
734 | } | 742 | } |
735 | } | 743 | } |
736 | - | ||
737 | #endif | 744 | #endif |
738 | 745 | ||
746 | +/* Return the virtual CPU time, based on the instruction counter. */ | ||
747 | +static int64_t cpu_get_icount(void) | ||
748 | +{ | ||
749 | + int64_t icount; | ||
750 | + CPUState *env = cpu_single_env;; | ||
751 | + icount = qemu_icount; | ||
752 | + if (env) { | ||
753 | + if (!can_do_io(env)) | ||
754 | + fprintf(stderr, "Bad clock read\n"); | ||
755 | + icount -= (env->icount_decr.u16.low + env->icount_extra); | ||
756 | + } | ||
757 | + return qemu_icount_bias + (icount << icount_time_shift); | ||
758 | +} | ||
759 | + | ||
739 | /***********************************************************/ | 760 | /***********************************************************/ |
740 | /* guest cycle counter */ | 761 | /* guest cycle counter */ |
741 | 762 | ||
@@ -747,6 +768,9 @@ static int cpu_ticks_enabled; | @@ -747,6 +768,9 @@ static int cpu_ticks_enabled; | ||
747 | /* return the host CPU cycle counter and handle stop/restart */ | 768 | /* return the host CPU cycle counter and handle stop/restart */ |
748 | int64_t cpu_get_ticks(void) | 769 | int64_t cpu_get_ticks(void) |
749 | { | 770 | { |
771 | + if (use_icount) { | ||
772 | + return cpu_get_icount(); | ||
773 | + } | ||
750 | if (!cpu_ticks_enabled) { | 774 | if (!cpu_ticks_enabled) { |
751 | return cpu_ticks_offset; | 775 | return cpu_ticks_offset; |
752 | } else { | 776 | } else { |
@@ -878,6 +902,71 @@ static void rtc_stop_timer(struct qemu_alarm_timer *t); | @@ -878,6 +902,71 @@ static void rtc_stop_timer(struct qemu_alarm_timer *t); | ||
878 | 902 | ||
879 | #endif /* _WIN32 */ | 903 | #endif /* _WIN32 */ |
880 | 904 | ||
905 | +/* Correlation between real and virtual time is always going to be | ||
906 | + farly approximate, so ignore small variation. | ||
907 | + When the guest is idle real and virtual time will be aligned in | ||
908 | + the IO wait loop. */ | ||
909 | +#define ICOUNT_WOBBLE (QEMU_TIMER_BASE / 10) | ||
910 | + | ||
911 | +static void icount_adjust(void) | ||
912 | +{ | ||
913 | + int64_t cur_time; | ||
914 | + int64_t cur_icount; | ||
915 | + int64_t delta; | ||
916 | + static int64_t last_delta; | ||
917 | + /* If the VM is not running, then do nothing. */ | ||
918 | + if (!vm_running) | ||
919 | + return; | ||
920 | + | ||
921 | + cur_time = cpu_get_clock(); | ||
922 | + cur_icount = qemu_get_clock(vm_clock); | ||
923 | + delta = cur_icount - cur_time; | ||
924 | + /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */ | ||
925 | + if (delta > 0 | ||
926 | + && last_delta + ICOUNT_WOBBLE < delta * 2 | ||
927 | + && icount_time_shift > 0) { | ||
928 | + /* The guest is getting too far ahead. Slow time down. */ | ||
929 | + icount_time_shift--; | ||
930 | + } | ||
931 | + if (delta < 0 | ||
932 | + && last_delta - ICOUNT_WOBBLE > delta * 2 | ||
933 | + && icount_time_shift < MAX_ICOUNT_SHIFT) { | ||
934 | + /* The guest is getting too far behind. Speed time up. */ | ||
935 | + icount_time_shift++; | ||
936 | + } | ||
937 | + last_delta = delta; | ||
938 | + qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift); | ||
939 | +} | ||
940 | + | ||
941 | +static void icount_adjust_rt(void * opaque) | ||
942 | +{ | ||
943 | + qemu_mod_timer(icount_rt_timer, | ||
944 | + qemu_get_clock(rt_clock) + 1000); | ||
945 | + icount_adjust(); | ||
946 | +} | ||
947 | + | ||
948 | +static void icount_adjust_vm(void * opaque) | ||
949 | +{ | ||
950 | + qemu_mod_timer(icount_vm_timer, | ||
951 | + qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10); | ||
952 | + icount_adjust(); | ||
953 | +} | ||
954 | + | ||
955 | +static void init_icount_adjust(void) | ||
956 | +{ | ||
957 | + /* Have both realtime and virtual time triggers for speed adjustment. | ||
958 | + The realtime trigger catches emulated time passing too slowly, | ||
959 | + the virtual time trigger catches emulated time passing too fast. | ||
960 | + Realtime triggers occur even when idle, so use them less frequently | ||
961 | + than VM triggers. */ | ||
962 | + icount_rt_timer = qemu_new_timer(rt_clock, icount_adjust_rt, NULL); | ||
963 | + qemu_mod_timer(icount_rt_timer, | ||
964 | + qemu_get_clock(rt_clock) + 1000); | ||
965 | + icount_vm_timer = qemu_new_timer(vm_clock, icount_adjust_vm, NULL); | ||
966 | + qemu_mod_timer(icount_vm_timer, | ||
967 | + qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10); | ||
968 | +} | ||
969 | + | ||
881 | static struct qemu_alarm_timer alarm_timers[] = { | 970 | static struct qemu_alarm_timer alarm_timers[] = { |
882 | #ifndef _WIN32 | 971 | #ifndef _WIN32 |
883 | #ifdef __linux__ | 972 | #ifdef __linux__ |
@@ -914,6 +1003,7 @@ static void configure_alarms(char const *opt) | @@ -914,6 +1003,7 @@ static void configure_alarms(char const *opt) | ||
914 | int count = (sizeof(alarm_timers) / sizeof(*alarm_timers)) - 1; | 1003 | int count = (sizeof(alarm_timers) / sizeof(*alarm_timers)) - 1; |
915 | char *arg; | 1004 | char *arg; |
916 | char *name; | 1005 | char *name; |
1006 | + struct qemu_alarm_timer tmp; | ||
917 | 1007 | ||
918 | if (!strcmp(opt, "?")) { | 1008 | if (!strcmp(opt, "?")) { |
919 | show_available_alarms(); | 1009 | show_available_alarms(); |
@@ -925,8 +1015,6 @@ static void configure_alarms(char const *opt) | @@ -925,8 +1015,6 @@ static void configure_alarms(char const *opt) | ||
925 | /* Reorder the array */ | 1015 | /* Reorder the array */ |
926 | name = strtok(arg, ","); | 1016 | name = strtok(arg, ","); |
927 | while (name) { | 1017 | while (name) { |
928 | - struct qemu_alarm_timer tmp; | ||
929 | - | ||
930 | for (i = 0; i < count && alarm_timers[i].name; i++) { | 1018 | for (i = 0; i < count && alarm_timers[i].name; i++) { |
931 | if (!strcmp(alarm_timers[i].name, name)) | 1019 | if (!strcmp(alarm_timers[i].name, name)) |
932 | break; | 1020 | break; |
@@ -954,7 +1042,7 @@ next: | @@ -954,7 +1042,7 @@ next: | ||
954 | free(arg); | 1042 | free(arg); |
955 | 1043 | ||
956 | if (cur) { | 1044 | if (cur) { |
957 | - /* Disable remaining timers */ | 1045 | + /* Disable remaining timers */ |
958 | for (i = cur; i < count; i++) | 1046 | for (i = cur; i < count; i++) |
959 | alarm_timers[i].name = NULL; | 1047 | alarm_timers[i].name = NULL; |
960 | } else { | 1048 | } else { |
@@ -1039,9 +1127,15 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) | @@ -1039,9 +1127,15 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) | ||
1039 | *pt = ts; | 1127 | *pt = ts; |
1040 | 1128 | ||
1041 | /* Rearm if necessary */ | 1129 | /* Rearm if necessary */ |
1042 | - if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0 && | ||
1043 | - pt == &active_timers[ts->clock->type]) | ||
1044 | - qemu_rearm_alarm_timer(alarm_timer); | 1130 | + if (pt == &active_timers[ts->clock->type]) { |
1131 | + if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0) { | ||
1132 | + qemu_rearm_alarm_timer(alarm_timer); | ||
1133 | + } | ||
1134 | + /* Interrupt execution to force deadline recalculation. */ | ||
1135 | + if (use_icount && cpu_single_env) { | ||
1136 | + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); | ||
1137 | + } | ||
1138 | + } | ||
1045 | } | 1139 | } |
1046 | 1140 | ||
1047 | int qemu_timer_pending(QEMUTimer *ts) | 1141 | int qemu_timer_pending(QEMUTimer *ts) |
@@ -1085,7 +1179,11 @@ int64_t qemu_get_clock(QEMUClock *clock) | @@ -1085,7 +1179,11 @@ int64_t qemu_get_clock(QEMUClock *clock) | ||
1085 | return get_clock() / 1000000; | 1179 | return get_clock() / 1000000; |
1086 | default: | 1180 | default: |
1087 | case QEMU_TIMER_VIRTUAL: | 1181 | case QEMU_TIMER_VIRTUAL: |
1088 | - return cpu_get_clock(); | 1182 | + if (use_icount) { |
1183 | + return cpu_get_icount(); | ||
1184 | + } else { | ||
1185 | + return cpu_get_clock(); | ||
1186 | + } | ||
1089 | } | 1187 | } |
1090 | } | 1188 | } |
1091 | 1189 | ||
@@ -1184,8 +1282,9 @@ static void host_alarm_handler(int host_signum) | @@ -1184,8 +1282,9 @@ static void host_alarm_handler(int host_signum) | ||
1184 | } | 1282 | } |
1185 | #endif | 1283 | #endif |
1186 | if (alarm_has_dynticks(alarm_timer) || | 1284 | if (alarm_has_dynticks(alarm_timer) || |
1187 | - qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], | ||
1188 | - qemu_get_clock(vm_clock)) || | 1285 | + (!use_icount && |
1286 | + qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], | ||
1287 | + qemu_get_clock(vm_clock))) || | ||
1189 | qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], | 1288 | qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], |
1190 | qemu_get_clock(rt_clock))) { | 1289 | qemu_get_clock(rt_clock))) { |
1191 | #ifdef _WIN32 | 1290 | #ifdef _WIN32 |
@@ -1209,28 +1308,45 @@ static void host_alarm_handler(int host_signum) | @@ -1209,28 +1308,45 @@ static void host_alarm_handler(int host_signum) | ||
1209 | } | 1308 | } |
1210 | } | 1309 | } |
1211 | 1310 | ||
1212 | -static uint64_t qemu_next_deadline(void) | 1311 | +static int64_t qemu_next_deadline(void) |
1213 | { | 1312 | { |
1214 | - int64_t nearest_delta_us = INT64_MAX; | ||
1215 | - int64_t vmdelta_us; | ||
1216 | - | ||
1217 | - if (active_timers[QEMU_TIMER_REALTIME]) | ||
1218 | - nearest_delta_us = (active_timers[QEMU_TIMER_REALTIME]->expire_time - | ||
1219 | - qemu_get_clock(rt_clock))*1000; | 1313 | + int64_t delta; |
1220 | 1314 | ||
1221 | if (active_timers[QEMU_TIMER_VIRTUAL]) { | 1315 | if (active_timers[QEMU_TIMER_VIRTUAL]) { |
1222 | - /* round up */ | ||
1223 | - vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time - | ||
1224 | - qemu_get_clock(vm_clock)+999)/1000; | ||
1225 | - if (vmdelta_us < nearest_delta_us) | ||
1226 | - nearest_delta_us = vmdelta_us; | 1316 | + delta = active_timers[QEMU_TIMER_VIRTUAL]->expire_time - |
1317 | + qemu_get_clock(vm_clock); | ||
1318 | + } else { | ||
1319 | + /* To avoid problems with overflow limit this to 2^32. */ | ||
1320 | + delta = INT32_MAX; | ||
1227 | } | 1321 | } |
1228 | 1322 | ||
1229 | - /* Avoid arming the timer to negative, zero, or too low values */ | ||
1230 | - if (nearest_delta_us <= MIN_TIMER_REARM_US) | ||
1231 | - nearest_delta_us = MIN_TIMER_REARM_US; | 1323 | + if (delta < 0) |
1324 | + delta = 0; | ||
1232 | 1325 | ||
1233 | - return nearest_delta_us; | 1326 | + return delta; |
1327 | +} | ||
1328 | + | ||
1329 | +static uint64_t qemu_next_deadline_dyntick(void) | ||
1330 | +{ | ||
1331 | + int64_t delta; | ||
1332 | + int64_t rtdelta; | ||
1333 | + | ||
1334 | + if (use_icount) | ||
1335 | + delta = INT32_MAX; | ||
1336 | + else | ||
1337 | + delta = (qemu_next_deadline() + 999) / 1000; | ||
1338 | + | ||
1339 | + if (active_timers[QEMU_TIMER_REALTIME]) { | ||
1340 | + rtdelta = (active_timers[QEMU_TIMER_REALTIME]->expire_time - | ||
1341 | + qemu_get_clock(rt_clock))*1000; | ||
1342 | + if (rtdelta < delta) | ||
1343 | + delta = rtdelta; | ||
1344 | + } | ||
1345 | + | ||
1346 | + if (delta < MIN_TIMER_REARM_US) | ||
1347 | + delta = MIN_TIMER_REARM_US; | ||
1348 | + | ||
1349 | + return delta; | ||
1234 | } | 1350 | } |
1235 | 1351 | ||
1236 | #ifndef _WIN32 | 1352 | #ifndef _WIN32 |
@@ -1386,7 +1502,7 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t) | @@ -1386,7 +1502,7 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t) | ||
1386 | !active_timers[QEMU_TIMER_VIRTUAL]) | 1502 | !active_timers[QEMU_TIMER_VIRTUAL]) |
1387 | return; | 1503 | return; |
1388 | 1504 | ||
1389 | - nearest_delta_us = qemu_next_deadline(); | 1505 | + nearest_delta_us = qemu_next_deadline_dyntick(); |
1390 | 1506 | ||
1391 | /* check whether a timer is already running */ | 1507 | /* check whether a timer is already running */ |
1392 | if (timer_gettime(host_timer, &timeout)) { | 1508 | if (timer_gettime(host_timer, &timeout)) { |
@@ -1513,7 +1629,7 @@ static void win32_rearm_timer(struct qemu_alarm_timer *t) | @@ -1513,7 +1629,7 @@ static void win32_rearm_timer(struct qemu_alarm_timer *t) | ||
1513 | !active_timers[QEMU_TIMER_VIRTUAL]) | 1629 | !active_timers[QEMU_TIMER_VIRTUAL]) |
1514 | return; | 1630 | return; |
1515 | 1631 | ||
1516 | - nearest_delta_us = qemu_next_deadline(); | 1632 | + nearest_delta_us = qemu_next_deadline_dyntick(); |
1517 | nearest_delta_us /= 1000; | 1633 | nearest_delta_us /= 1000; |
1518 | 1634 | ||
1519 | timeKillEvent(data->timerId); | 1635 | timeKillEvent(data->timerId); |
@@ -7068,10 +7184,33 @@ static int main_loop(void) | @@ -7068,10 +7184,33 @@ static int main_loop(void) | ||
7068 | #ifdef CONFIG_PROFILER | 7184 | #ifdef CONFIG_PROFILER |
7069 | ti = profile_getclock(); | 7185 | ti = profile_getclock(); |
7070 | #endif | 7186 | #endif |
7187 | + if (use_icount) { | ||
7188 | + int64_t count; | ||
7189 | + int decr; | ||
7190 | + qemu_icount -= (env->icount_decr.u16.low + env->icount_extra); | ||
7191 | + env->icount_decr.u16.low = 0; | ||
7192 | + env->icount_extra = 0; | ||
7193 | + count = qemu_next_deadline(); | ||
7194 | + count = (count + (1 << icount_time_shift) - 1) | ||
7195 | + >> icount_time_shift; | ||
7196 | + qemu_icount += count; | ||
7197 | + decr = (count > 0xffff) ? 0xffff : count; | ||
7198 | + count -= decr; | ||
7199 | + env->icount_decr.u16.low = decr; | ||
7200 | + env->icount_extra = count; | ||
7201 | + } | ||
7071 | ret = cpu_exec(env); | 7202 | ret = cpu_exec(env); |
7072 | #ifdef CONFIG_PROFILER | 7203 | #ifdef CONFIG_PROFILER |
7073 | qemu_time += profile_getclock() - ti; | 7204 | qemu_time += profile_getclock() - ti; |
7074 | #endif | 7205 | #endif |
7206 | + if (use_icount) { | ||
7207 | + /* Fold pending instructions back into the | ||
7208 | + instruction counter, and clear the interrupt flag. */ | ||
7209 | + qemu_icount -= (env->icount_decr.u16.low | ||
7210 | + + env->icount_extra); | ||
7211 | + env->icount_decr.u32 = 0; | ||
7212 | + env->icount_extra = 0; | ||
7213 | + } | ||
7075 | next_cpu = env->next_cpu ?: first_cpu; | 7214 | next_cpu = env->next_cpu ?: first_cpu; |
7076 | if (event_pending && likely(ret != EXCP_DEBUG)) { | 7215 | if (event_pending && likely(ret != EXCP_DEBUG)) { |
7077 | ret = EXCP_INTERRUPT; | 7216 | ret = EXCP_INTERRUPT; |
@@ -7115,10 +7254,46 @@ static int main_loop(void) | @@ -7115,10 +7254,46 @@ static int main_loop(void) | ||
7115 | } | 7254 | } |
7116 | /* If all cpus are halted then wait until the next IRQ */ | 7255 | /* If all cpus are halted then wait until the next IRQ */ |
7117 | /* XXX: use timeout computed from timers */ | 7256 | /* XXX: use timeout computed from timers */ |
7118 | - if (ret == EXCP_HALTED) | ||
7119 | - timeout = 10; | ||
7120 | - else | 7257 | + if (ret == EXCP_HALTED) { |
7258 | + if (use_icount) { | ||
7259 | + int64_t add; | ||
7260 | + int64_t delta; | ||
7261 | + /* Advance virtual time to the next event. */ | ||
7262 | + if (use_icount == 1) { | ||
7263 | + /* When not using an adaptive execution frequency | ||
7264 | + we tend to get badly out of sync with real time, | ||
7265 | + so just delay for a resonable amount of time. */ | ||
7266 | + delta = 0; | ||
7267 | + } else { | ||
7268 | + delta = cpu_get_icount() - cpu_get_clock(); | ||
7269 | + } | ||
7270 | + if (delta > 0) { | ||
7271 | + /* If virtual time is ahead of real time then just | ||
7272 | + wait for IO. */ | ||
7273 | + timeout = (delta / 1000000) + 1; | ||
7274 | + } else { | ||
7275 | + /* Wait for either IO to occur or the next | ||
7276 | + timer event. */ | ||
7277 | + add = qemu_next_deadline(); | ||
7278 | + /* We advance the timer before checking for IO. | ||
7279 | + Limit the amount we advance so that early IO | ||
7280 | + activity won't get the guest too far ahead. */ | ||
7281 | + if (add > 10000000) | ||
7282 | + add = 10000000; | ||
7283 | + delta += add; | ||
7284 | + add = (add + (1 << icount_time_shift) - 1) | ||
7285 | + >> icount_time_shift; | ||
7286 | + qemu_icount += add; | ||
7287 | + timeout = delta / 1000000; | ||
7288 | + if (timeout < 0) | ||
7289 | + timeout = 0; | ||
7290 | + } | ||
7291 | + } else { | ||
7292 | + timeout = 10; | ||
7293 | + } | ||
7294 | + } else { | ||
7121 | timeout = 0; | 7295 | timeout = 0; |
7296 | + } | ||
7122 | } else { | 7297 | } else { |
7123 | timeout = 10; | 7298 | timeout = 10; |
7124 | } | 7299 | } |
@@ -7270,6 +7445,8 @@ static void help(int exitcode) | @@ -7270,6 +7445,8 @@ static void help(int exitcode) | ||
7270 | "-clock force the use of the given methods for timer alarm.\n" | 7445 | "-clock force the use of the given methods for timer alarm.\n" |
7271 | " To see what timers are available use -clock ?\n" | 7446 | " To see what timers are available use -clock ?\n" |
7272 | "-startdate select initial date of the clock\n" | 7447 | "-startdate select initial date of the clock\n" |
7448 | + "-icount [N|auto]\n" | ||
7449 | + " Enable virtual instruction counter with 2^N clock ticks per instructon\n" | ||
7273 | "\n" | 7450 | "\n" |
7274 | "During emulation, the following keys are useful:\n" | 7451 | "During emulation, the following keys are useful:\n" |
7275 | "ctrl-alt-f toggle full screen\n" | 7452 | "ctrl-alt-f toggle full screen\n" |
@@ -7374,6 +7551,7 @@ enum { | @@ -7374,6 +7551,7 @@ enum { | ||
7374 | QEMU_OPTION_clock, | 7551 | QEMU_OPTION_clock, |
7375 | QEMU_OPTION_startdate, | 7552 | QEMU_OPTION_startdate, |
7376 | QEMU_OPTION_tb_size, | 7553 | QEMU_OPTION_tb_size, |
7554 | + QEMU_OPTION_icount, | ||
7377 | }; | 7555 | }; |
7378 | 7556 | ||
7379 | typedef struct QEMUOption { | 7557 | typedef struct QEMUOption { |
@@ -7486,6 +7664,7 @@ const QEMUOption qemu_options[] = { | @@ -7486,6 +7664,7 @@ const QEMUOption qemu_options[] = { | ||
7486 | { "clock", HAS_ARG, QEMU_OPTION_clock }, | 7664 | { "clock", HAS_ARG, QEMU_OPTION_clock }, |
7487 | { "startdate", HAS_ARG, QEMU_OPTION_startdate }, | 7665 | { "startdate", HAS_ARG, QEMU_OPTION_startdate }, |
7488 | { "tb-size", HAS_ARG, QEMU_OPTION_tb_size }, | 7666 | { "tb-size", HAS_ARG, QEMU_OPTION_tb_size }, |
7667 | + { "icount", HAS_ARG, QEMU_OPTION_icount }, | ||
7489 | { NULL }, | 7668 | { NULL }, |
7490 | }; | 7669 | }; |
7491 | 7670 | ||
@@ -8310,6 +8489,14 @@ int main(int argc, char **argv) | @@ -8310,6 +8489,14 @@ int main(int argc, char **argv) | ||
8310 | if (tb_size < 0) | 8489 | if (tb_size < 0) |
8311 | tb_size = 0; | 8490 | tb_size = 0; |
8312 | break; | 8491 | break; |
8492 | + case QEMU_OPTION_icount: | ||
8493 | + use_icount = 1; | ||
8494 | + if (strcmp(optarg, "auto") == 0) { | ||
8495 | + icount_time_shift = -1; | ||
8496 | + } else { | ||
8497 | + icount_time_shift = strtol(optarg, NULL, 0); | ||
8498 | + } | ||
8499 | + break; | ||
8313 | } | 8500 | } |
8314 | } | 8501 | } |
8315 | } | 8502 | } |
@@ -8395,6 +8582,13 @@ int main(int argc, char **argv) | @@ -8395,6 +8582,13 @@ int main(int argc, char **argv) | ||
8395 | init_timers(); | 8582 | init_timers(); |
8396 | init_timer_alarm(); | 8583 | init_timer_alarm(); |
8397 | qemu_aio_init(); | 8584 | qemu_aio_init(); |
8585 | + if (use_icount && icount_time_shift < 0) { | ||
8586 | + use_icount = 2; | ||
8587 | + /* 125MIPS seems a reasonable initial guess at the guest speed. | ||
8588 | + It will be corrected fairly quickly anyway. */ | ||
8589 | + icount_time_shift = 3; | ||
8590 | + init_icount_adjust(); | ||
8591 | + } | ||
8398 | 8592 | ||
8399 | #ifdef _WIN32 | 8593 | #ifdef _WIN32 |
8400 | socket_init(); | 8594 | socket_init(); |