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 "sysemu/replay.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
35void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
36 CPUState *cpu, TranslationBlock *tb, int max_insns)
37{
38 int bp_insn = 0;
39 bool plugin_enabled;
40
41
42 db->tb = tb;
43 db->pc_first = tb->pc;
44 db->pc_next = db->pc_first;
45 db->is_jmp = DISAS_NEXT;
46 db->num_insns = 0;
47 db->max_insns = max_insns;
48 db->singlestep_enabled = cpu->singlestep_enabled;
49
50 ops->init_disas_context(db, cpu);
51 tcg_debug_assert(db->is_jmp == DISAS_NEXT);
52
53
54 tcg_clear_temp_count();
55
56
57 gen_tb_start(db->tb);
58 ops->tb_start(db, cpu);
59 tcg_debug_assert(db->is_jmp == DISAS_NEXT);
60
61 plugin_enabled = plugin_gen_tb_start(cpu, tb,
62 tb_cflags(db->tb) & CF_MEMI_ONLY);
63
64 while (true) {
65 db->num_insns++;
66 ops->insn_start(db, cpu);
67 tcg_debug_assert(db->is_jmp == DISAS_NEXT);
68
69 if (plugin_enabled) {
70 plugin_gen_insn_start(cpu, db);
71 }
72
73
74 if (!db->singlestep_enabled
75 && unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
76 CPUBreakpoint *bp;
77 QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
78 if (bp->pc == db->pc_next) {
79 if (ops->breakpoint_check(db, cpu, bp)) {
80 bp_insn = 1;
81 break;
82 }
83 }
84 }
85
86
87
88
89 if (db->is_jmp > DISAS_TOO_MANY) {
90 break;
91 }
92 }
93
94
95
96
97
98 if (db->num_insns == db->max_insns
99 && (tb_cflags(db->tb) & CF_LAST_IO)) {
100
101 gen_io_start();
102 ops->translate_insn(db, cpu);
103 } else {
104
105 tcg_debug_assert(!(tb_cflags(db->tb) & CF_MEMI_ONLY));
106 ops->translate_insn(db, cpu);
107 }
108
109
110 if (db->is_jmp != DISAS_NEXT) {
111 break;
112 }
113
114
115
116
117
118 if (plugin_enabled) {
119 plugin_gen_insn_end();
120 }
121
122
123
124 if (tcg_op_buf_full() || db->num_insns >= db->max_insns) {
125 db->is_jmp = DISAS_TOO_MANY;
126 break;
127 }
128 }
129
130
131 ops->tb_stop(db, cpu);
132 gen_tb_end(db->tb, db->num_insns - bp_insn);
133
134 if (plugin_enabled) {
135 plugin_gen_tb_end(cpu);
136 }
137
138
139 tb->size = db->pc_next - db->pc_first;
140 tb->icount = db->num_insns;
141
142#ifdef DEBUG_DISAS
143 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
144 && qemu_log_in_addr_range(db->pc_first)) {
145 FILE *logfile = qemu_log_lock();
146 qemu_log("----------------\n");
147 ops->disas_log(db, cpu);
148 qemu_log("\n");
149 qemu_log_unlock(logfile);
150 }
151#endif
152}
153