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