VirtualBox

source: vbox/trunk/src/recompiler/translate-all.c@ 1140

Last change on this file since 1140 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
File size: 8.0 KB
Line 
1/*
2 * Host code generation
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <stdarg.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <inttypes.h>
25
26#include "config.h"
27
28#define NO_CPU_IO_DEFS
29#include "cpu.h"
30#include "exec-all.h"
31#include "disas.h"
32
33enum {
34#define DEF(s, n, copy_size) INDEX_op_ ## s,
35#include "opc.h"
36#undef DEF
37 NB_OPS,
38};
39
40#include "dyngen.h"
41#include "op.h"
42
43uint16_t gen_opc_buf[OPC_BUF_SIZE];
44uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
45long gen_labels[OPC_BUF_SIZE];
46int nb_gen_labels;
47
48target_ulong gen_opc_pc[OPC_BUF_SIZE];
49uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
50#if defined(TARGET_I386)
51uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
52#elif defined(TARGET_SPARC)
53target_ulong gen_opc_npc[OPC_BUF_SIZE];
54#endif
55
56int code_copy_enabled = 1;
57
58#ifdef DEBUG_DISAS
59static const char *op_str[] = {
60#define DEF(s, n, copy_size) #s,
61#include "opc.h"
62#undef DEF
63};
64
65static uint8_t op_nb_args[] = {
66#define DEF(s, n, copy_size) n,
67#include "opc.h"
68#undef DEF
69};
70#endif /* bird: opc_copy_size is used ouside DEBUG_DISAS and VBOX isn't necessarily defining DEBUG_DISAS presently. */
71
72static const unsigned short opc_copy_size[] = {
73#define DEF(s, n, copy_size) copy_size,
74#include "opc.h"
75#undef DEF
76};
77
78#ifdef DEBUG_DISAS /* bird: see previous bird comment. */
79void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
80{
81 const uint16_t *opc_ptr;
82 const uint32_t *opparam_ptr;
83 int c, n, i;
84
85 opc_ptr = opc_buf;
86 opparam_ptr = opparam_buf;
87 for(;;) {
88 c = *opc_ptr++;
89 n = op_nb_args[c];
90 fprintf(logfile, "0x%04x: %s",
91 (int)(opc_ptr - opc_buf - 1), op_str[c]);
92 for(i = 0; i < n; i++) {
93 fprintf(logfile, " 0x%x", opparam_ptr[i]);
94 }
95 fprintf(logfile, "\n");
96 if (c == INDEX_op_end)
97 break;
98 opparam_ptr += n;
99 }
100}
101
102#endif
103
104/* compute label info */
105static void dyngen_labels(long *gen_labels, int nb_gen_labels,
106 uint8_t *gen_code_buf, const uint16_t *opc_buf)
107{
108 uint8_t *gen_code_ptr;
109 int c, i;
110 unsigned long gen_code_addr[OPC_BUF_SIZE];
111
112 if (nb_gen_labels == 0)
113 return;
114 /* compute the address of each op code */
115
116 gen_code_ptr = gen_code_buf;
117 i = 0;
118 for(;;) {
119 c = opc_buf[i];
120 gen_code_addr[i] =(unsigned long)gen_code_ptr;
121 if (c == INDEX_op_end)
122 break;
123 gen_code_ptr += opc_copy_size[c];
124 i++;
125 }
126
127 /* compute the address of each label */
128 for(i = 0; i < nb_gen_labels; i++) {
129 gen_labels[i] = gen_code_addr[gen_labels[i]];
130 }
131}
132
133/* return non zero if the very first instruction is invalid so that
134 the virtual CPU can trigger an exception.
135
136 '*gen_code_size_ptr' contains the size of the generated code (host
137 code).
138*/
139int cpu_gen_code(CPUState *env, TranslationBlock *tb,
140 int max_code_size, int *gen_code_size_ptr)
141{
142 uint8_t *gen_code_buf;
143 int gen_code_size;
144
145#ifdef USE_CODE_COPY
146 if (code_copy_enabled &&
147 cpu_gen_code_copy(env, tb, max_code_size, &gen_code_size) == 0) {
148 /* nothing more to do */
149 } else
150#endif
151 {
152#ifdef VBOX
153 RAWEx_ProfileStart(env, STATS_QEMU_COMPILATION);
154 if (gen_intermediate_code(env, tb) < 0)
155 {
156 RAWEx_ProfileStop(env, STATS_QEMU_COMPILATION);
157 return -1;
158 }
159#else
160 if (gen_intermediate_code(env, tb) < 0)
161 return -1;
162#endif
163 /* generate machine code */
164 tb->tb_next_offset[0] = 0xffff;
165 tb->tb_next_offset[1] = 0xffff;
166 gen_code_buf = tb->tc_ptr;
167#ifdef USE_DIRECT_JUMP
168 /* the following two entries are optional (only used for string ops) */
169 tb->tb_jmp_offset[2] = 0xffff;
170 tb->tb_jmp_offset[3] = 0xffff;
171#endif
172 dyngen_labels(gen_labels, nb_gen_labels, gen_code_buf, gen_opc_buf);
173
174 gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
175#ifdef USE_DIRECT_JUMP
176 tb->tb_jmp_offset,
177#else
178 NULL,
179#endif
180 gen_opc_buf, gen_opparam_buf, gen_labels);
181
182#ifdef VBOX
183 RAWEx_ProfileStop(env, STATS_QEMU_COMPILATION);
184#endif
185 }
186 *gen_code_size_ptr = gen_code_size;
187#ifdef DEBUG_DISAS
188 if (loglevel & CPU_LOG_TB_OUT_ASM) {
189 fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
190 disas(logfile, tb->tc_ptr, *gen_code_size_ptr);
191 fprintf(logfile, "\n");
192 fflush(logfile);
193 }
194#endif
195 return 0;
196}
197
198/* The cpu state corresponding to 'searched_pc' is restored.
199 */
200int cpu_restore_state(TranslationBlock *tb,
201 CPUState *env, unsigned long searched_pc,
202 void *puc)
203{
204 int j, c;
205 unsigned long tc_ptr;
206 uint16_t *opc_ptr;
207
208#ifdef USE_CODE_COPY
209 if (tb->cflags & CF_CODE_COPY) {
210 return cpu_restore_state_copy(tb, env, searched_pc, puc);
211 }
212#endif
213 if (gen_intermediate_code_pc(env, tb) < 0)
214 return -1;
215
216 /* find opc index corresponding to search_pc */
217 tc_ptr = (unsigned long)tb->tc_ptr;
218 if (searched_pc < tc_ptr)
219 return -1;
220 j = 0;
221 opc_ptr = gen_opc_buf;
222 for(;;) {
223 c = *opc_ptr;
224 if (c == INDEX_op_end)
225 return -1;
226 tc_ptr += opc_copy_size[c];
227 if (searched_pc < tc_ptr)
228 break;
229 opc_ptr++;
230 }
231 j = opc_ptr - gen_opc_buf;
232 /* now find start of instruction before */
233 while (gen_opc_instr_start[j] == 0)
234 j--;
235#if defined(TARGET_I386)
236 {
237 int cc_op;
238#ifdef DEBUG_DISAS
239 if (loglevel & CPU_LOG_TB_OP) {
240 int i;
241 fprintf(logfile, "RESTORE:\n");
242 for(i=0;i<=j; i++) {
243 if (gen_opc_instr_start[i]) {
244 fprintf(logfile, "0x%04x: " TARGET_FMT_lx "\n", i, gen_opc_pc[i]);
245 }
246 }
247 fprintf(logfile, "spc=0x%08lx j=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n",
248 searched_pc, j, gen_opc_pc[j] - tb->cs_base,
249 (uint32_t)tb->cs_base);
250 }
251#endif
252 env->eip = gen_opc_pc[j] - tb->cs_base;
253 cc_op = gen_opc_cc_op[j];
254 if (cc_op != CC_OP_DYNAMIC)
255 env->cc_op = cc_op;
256 }
257#elif defined(TARGET_ARM)
258 env->regs[15] = gen_opc_pc[j];
259#elif defined(TARGET_SPARC)
260 /* XXX: restore npc too */
261 env->pc = gen_opc_pc[j];
262 env->npc = gen_opc_npc[j];
263#elif defined(TARGET_PPC)
264 {
265 int type;
266 /* for PPC, we need to look at the micro operation to get the
267 access type */
268 env->nip = gen_opc_pc[j];
269 switch(c) {
270#if defined(CONFIG_USER_ONLY)
271#define CASE3(op)\
272 case INDEX_op_ ## op ## _raw
273#else
274#define CASE3(op)\
275 case INDEX_op_ ## op ## _user:\
276 case INDEX_op_ ## op ## _kernel
277#endif
278
279 CASE3(stfd):
280 CASE3(stfs):
281 CASE3(lfd):
282 CASE3(lfs):
283 type = ACCESS_FLOAT;
284 break;
285 CASE3(lwarx):
286 type = ACCESS_RES;
287 break;
288 CASE3(stwcx):
289 type = ACCESS_RES;
290 break;
291 CASE3(eciwx):
292 CASE3(ecowx):
293 type = ACCESS_EXT;
294 break;
295 default:
296 type = ACCESS_INT;
297 break;
298 }
299 env->access_type = type;
300 }
301#endif
302 return 0;
303}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette