1
2
3
4
5
6
7
8
9
10#include "qemu/osdep.h"
11#include "qemu/error-report.h"
12#include "cpu.h"
13#include "tcg/tcg.h"
14#include "tcg/tcg-op.h"
15#include "exec/exec-all.h"
16#include "exec/gen-icount.h"
17#include "exec/log.h"
18#include "exec/translator.h"
19#include "exec/plugin-gen.h"
20#include "trace-tcg.h"
21
22
23
24
25
26
27void translator_loop_temp_check(DisasContextBase *db)
28{
29 if (tcg_check_temp_count()) {
30 qemu_log("warning: TCG temporary leaks before "
31 TARGET_FMT_lx "\n", db->pc_next);
32 }
33}
34
35static TCGOp *gen_trace_tb_enter(TranslationBlock *tb)
36{
37 TCGOp *last_pc_op;
38
39 TCGv pc_end = tcg_temp_new();
40
41
42 tcg_gen_movi_tl(pc_end, 0xdeadbeef);
43 last_pc_op = tcg_last_op();
44
45 trace_tb_enter_tcg(tcg_ctx->cpu, cpu_env, tb->pc, pc_end);
46 tcg_temp_free(pc_end);
47
48 return last_pc_op;
49}
50
51void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
52 CPUState *cpu, TranslationBlock *tb, int max_insns)
53{
54 TCGOp *trace_pc_end;
55 int bp_insn = 0;
56 bool plugin_enabled;
57
58
59 db->tb = tb;
60 db->pc_first = tb->pc;
61 db->pc_next = db->pc_first;
62 db->is_jmp = DISAS_NEXT;
63 db->num_insns = 0;
64 db->max_insns = max_insns;
65 db->singlestep_enabled = cpu->singlestep_enabled;
66
67 ops->init_disas_context(db, cpu);
68 tcg_debug_assert(db->is_jmp == DISAS_NEXT);
69
70
71 tcg_clear_temp_count();
72
73
74 gen_tb_start(db->tb);
75
76 trace_pc_end = gen_trace_tb_enter(tb);
77
78 ops->tb_start(db, cpu);
79 tcg_debug_assert(db->is_jmp == DISAS_NEXT);
80
81 plugin_enabled = plugin_gen_tb_start(cpu, tb);
82
83 while (true) {
84 db->num_insns++;
85 ops->insn_start(db, cpu);
86 tcg_debug_assert(db->is_jmp == DISAS_NEXT);
87
88 if (plugin_enabled) {
89 plugin_gen_insn_start(cpu, db);
90 }
91
92
93 if (!db->singlestep_enabled
94 && unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
95 CPUBreakpoint *bp;
96 QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
97 if (bp->pc == db->pc_next) {
98 if (ops->breakpoint_check(db, cpu, bp)) {
99 bp_insn = 1;
100 break;
101 }
102 }
103 }
104
105
106
107
108 if (db->is_jmp > DISAS_TOO_MANY) {
109 break;
110 }
111 }
112
113
114
115
116
117 if (db->num_insns == db->max_insns
118 && (tb_cflags(db->tb) & CF_LAST_IO)) {
119
120 gen_io_start();
121 ops->translate_insn(db, cpu);
122 } else {
123 ops->translate_insn(db, cpu);
124 }
125
126
127 if (db->is_jmp != DISAS_NEXT) {
128 break;
129 }
130
131
132
133
134
135 if (plugin_enabled) {
136 plugin_gen_insn_end();
137 }
138
139
140
141 if (tcg_op_buf_full() || db->num_insns >= db->max_insns) {
142 db->is_jmp = DISAS_TOO_MANY;
143 break;
144 }
145 }
146
147
148 ops->tb_stop(db, cpu);
149 gen_tb_end(db->tb, db->num_insns - bp_insn);
150
151
152 tcg_set_insn_param(trace_pc_end, 1, db->pc_next);
153
154 if (plugin_enabled) {
155 plugin_gen_tb_end(cpu);
156 }
157
158
159 db->tb->size = db->pc_next - db->pc_first;
160 db->tb->icount = db->num_insns;
161
162#ifdef DEBUG_DISAS
163 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
164 && qemu_log_in_addr_range(db->pc_first)) {
165 qemu_log_lock();
166 qemu_log("----------------\n");
167 ops->disas_log(db, cpu);
168 qemu_log("\n");
169 qemu_log_unlock();
170 }
171#endif
172}
173