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
20
21
22
23
24
25void translator_loop_temp_check(DisasContextBase *db)
26{
27 if (tcg_check_temp_count()) {
28 qemu_log("warning: TCG temporary leaks before "
29 TARGET_FMT_lx "\n", db->pc_next);
30 }
31}
32
33void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
34 CPUState *cpu, TranslationBlock *tb, int max_insns)
35{
36 int bp_insn = 0;
37
38
39 db->tb = tb;
40 db->pc_first = tb->pc;
41 db->pc_next = db->pc_first;
42 db->is_jmp = DISAS_NEXT;
43 db->num_insns = 0;
44 db->max_insns = max_insns;
45 db->singlestep_enabled = cpu->singlestep_enabled;
46
47 ops->init_disas_context(db, cpu);
48 tcg_debug_assert(db->is_jmp == DISAS_NEXT);
49
50
51 tcg_clear_temp_count();
52
53
54 gen_tb_start(db->tb);
55 ops->tb_start(db, cpu);
56 tcg_debug_assert(db->is_jmp == DISAS_NEXT);
57
58 while (true) {
59 db->num_insns++;
60 ops->insn_start(db, cpu);
61 tcg_debug_assert(db->is_jmp == DISAS_NEXT);
62
63
64 if (!db->singlestep_enabled
65 && unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
66 CPUBreakpoint *bp;
67 QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
68 if (bp->pc == db->pc_next) {
69 if (ops->breakpoint_check(db, cpu, bp)) {
70 bp_insn = 1;
71 break;
72 }
73 }
74 }
75
76
77
78
79 if (db->is_jmp > DISAS_TOO_MANY) {
80 break;
81 }
82 }
83
84
85
86
87
88 if (db->num_insns == db->max_insns
89 && (tb_cflags(db->tb) & CF_LAST_IO)) {
90
91 gen_io_start();
92 ops->translate_insn(db, cpu);
93 gen_io_end();
94 } else {
95 ops->translate_insn(db, cpu);
96 }
97
98
99 if (db->is_jmp != DISAS_NEXT) {
100 break;
101 }
102
103
104
105 if (tcg_op_buf_full() || db->num_insns >= db->max_insns) {
106 db->is_jmp = DISAS_TOO_MANY;
107 break;
108 }
109 }
110
111
112 ops->tb_stop(db, cpu);
113 gen_tb_end(db->tb, db->num_insns - bp_insn);
114
115
116 db->tb->size = db->pc_next - db->pc_first;
117 db->tb->icount = db->num_insns;
118
119#ifdef DEBUG_DISAS
120 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
121 && qemu_log_in_addr_range(db->pc_first)) {
122 qemu_log_lock();
123 qemu_log("----------------\n");
124 ops->disas_log(db, cpu);
125 qemu_log("\n");
126 qemu_log_unlock();
127 }
128#endif
129}
130