]>
Commit | Line | Data |
---|---|---|
cb9c377f | 1 | #ifndef GEN_ICOUNT_H |
175de524 | 2 | #define GEN_ICOUNT_H |
cb9c377f | 3 | |
91150447 | 4 | #include "exec/exec-all.h" |
1de7afc9 | 5 | #include "qemu/timer.h" |
29e922b6 | 6 | |
bf20dc07 | 7 | /* Helpers for instruction counting code generation. */ |
dd5d6fe9 | 8 | |
15fa08f8 | 9 | static TCGOp *icount_start_insn; |
dd5d6fe9 | 10 | |
ba3e7926 PD |
11 | static inline void gen_io_start(void) |
12 | { | |
13 | TCGv_i32 tmp = tcg_const_i32(1); | |
14 | tcg_gen_st_i32(tmp, cpu_env, | |
15 | offsetof(ArchCPU, parent_obj.can_do_io) - | |
16 | offsetof(ArchCPU, env)); | |
17 | tcg_temp_free_i32(tmp); | |
18 | } | |
19 | ||
d9971435 | 20 | static inline void gen_tb_start(const TranslationBlock *tb) |
dd5d6fe9 | 21 | { |
0e1ea43a | 22 | TCGv_i32 count; |
378df4b2 | 23 | |
c5a49c63 | 24 | if (tb_cflags(tb) & CF_USE_ICOUNT) { |
1aab16c2 PB |
25 | count = tcg_temp_local_new_i32(); |
26 | } else { | |
27 | count = tcg_temp_new_i32(); | |
c45cb8bb | 28 | } |
dd5d6fe9 | 29 | |
1c2adb95 | 30 | tcg_gen_ld_i32(count, cpu_env, |
5e140196 RH |
31 | offsetof(ArchCPU, neg.icount_decr.u32) - |
32 | offsetof(ArchCPU, env)); | |
c45cb8bb | 33 | |
c5a49c63 | 34 | if (tb_cflags(tb) & CF_USE_ICOUNT) { |
0e1ea43a RH |
35 | /* |
36 | * We emit a sub with a dummy immediate argument. Keep the insn index | |
37 | * of the sub so that we later (when we know the actual insn count) | |
38 | * can update the argument with the actual insn count. | |
39 | */ | |
40 | tcg_gen_sub_i32(count, count, tcg_constant_i32(0)); | |
15fa08f8 | 41 | icount_start_insn = tcg_last_op(); |
1aab16c2 PB |
42 | } |
43 | ||
48e14066 AB |
44 | /* |
45 | * Emit the check against icount_decr.u32 to see if we should exit | |
46 | * unless we suppress the check with CF_NOIRQ. If we are using | |
47 | * icount and have suppressed interruption the higher level code | |
48 | * should have ensured we don't run more instructions than the | |
49 | * budget. | |
50 | */ | |
51 | if (tb_cflags(tb) & CF_NOIRQ) { | |
52 | tcg_ctx->exitreq_label = NULL; | |
53 | } else { | |
54 | tcg_ctx->exitreq_label = gen_new_label(); | |
55 | tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, tcg_ctx->exitreq_label); | |
56 | } | |
c45cb8bb | 57 | |
c5a49c63 | 58 | if (tb_cflags(tb) & CF_USE_ICOUNT) { |
1c2adb95 | 59 | tcg_gen_st16_i32(count, cpu_env, |
5e140196 RH |
60 | offsetof(ArchCPU, neg.icount_decr.u16.low) - |
61 | offsetof(ArchCPU, env)); | |
f383eb80 PM |
62 | /* |
63 | * cpu->can_do_io is cleared automatically here at the beginning of | |
64 | * each translation block. The cost is minimal and only paid for | |
65 | * -icount, plus it would be very easy to forget doing it in the | |
66 | * translator. Doing it here means we don't need a gen_io_end() to | |
67 | * go with gen_io_start(). | |
68 | */ | |
69 | tcg_gen_st_i32(tcg_constant_i32(0), cpu_env, | |
70 | offsetof(ArchCPU, parent_obj.can_do_io) - | |
71 | offsetof(ArchCPU, env)); | |
1aab16c2 | 72 | } |
dd5d6fe9 | 73 | |
a7812ae4 | 74 | tcg_temp_free_i32(count); |
dd5d6fe9 PB |
75 | } |
76 | ||
d9971435 | 77 | static inline void gen_tb_end(const TranslationBlock *tb, int num_insns) |
dd5d6fe9 | 78 | { |
c5a49c63 | 79 | if (tb_cflags(tb) & CF_USE_ICOUNT) { |
0e1ea43a RH |
80 | /* |
81 | * Update the num_insn immediate parameter now that we know | |
82 | * the actual insn count. | |
83 | */ | |
84 | tcg_set_insn_param(icount_start_insn, 2, | |
85 | tcgv_i32_arg(tcg_constant_i32(num_insns))); | |
dd5d6fe9 | 86 | } |
0a7df5da | 87 | |
48e14066 AB |
88 | if (tcg_ctx->exitreq_label) { |
89 | gen_set_label(tcg_ctx->exitreq_label); | |
90 | tcg_gen_exit_tb(tb, TB_EXIT_REQUESTED); | |
91 | } | |
dd5d6fe9 PB |
92 | } |
93 | ||
cb9c377f | 94 | #endif |