amd64 port (Jocelyn Mayer)
[qemu] / translate-all.c
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
33 enum {
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
43 uint16_t gen_opc_buf[OPC_BUF_SIZE];
44 uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
45 uint32_t gen_opc_pc[OPC_BUF_SIZE];
46 uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
47 #if defined(TARGET_I386)
48 uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
49 #endif
50
51 int code_copy_enabled = 1;
52
53 #ifdef DEBUG_DISAS
54 static const char *op_str[] = {
55 #define DEF(s, n, copy_size) #s,
56 #include "opc.h"
57 #undef DEF
58 };
59
60 static uint8_t op_nb_args[] = {
61 #define DEF(s, n, copy_size) n,
62 #include "opc.h"
63 #undef DEF
64 };
65
66 void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
67 {
68     const uint16_t *opc_ptr;
69     const uint32_t *opparam_ptr;
70     int c, n, i;
71
72     opc_ptr = opc_buf;
73     opparam_ptr = opparam_buf;
74     for(;;) {
75         c = *opc_ptr++;
76         n = op_nb_args[c];
77         fprintf(logfile, "0x%04x: %s", 
78                 (int)(opc_ptr - opc_buf - 1), op_str[c]);
79         for(i = 0; i < n; i++) {
80             fprintf(logfile, " 0x%x", opparam_ptr[i]);
81         }
82         fprintf(logfile, "\n");
83         if (c == INDEX_op_end)
84             break;
85         opparam_ptr += n;
86     }
87 }
88
89 #endif
90
91 /* return non zero if the very first instruction is invalid so that
92    the virtual CPU can trigger an exception. 
93
94    '*gen_code_size_ptr' contains the size of the generated code (host
95    code).
96 */
97 int cpu_gen_code(CPUState *env, TranslationBlock *tb,
98                  int max_code_size, int *gen_code_size_ptr)
99 {
100     uint8_t *gen_code_buf;
101     int gen_code_size;
102
103 #ifdef USE_CODE_COPY
104     if (code_copy_enabled &&
105         cpu_gen_code_copy(env, tb, max_code_size, &gen_code_size) == 0) {
106         /* nothing more to do */
107     } else
108 #endif
109     {
110         if (gen_intermediate_code(env, tb) < 0)
111             return -1;
112
113         /* generate machine code */
114         tb->tb_next_offset[0] = 0xffff;
115         tb->tb_next_offset[1] = 0xffff;
116         gen_code_buf = tb->tc_ptr;
117 #ifdef USE_DIRECT_JUMP
118         /* the following two entries are optional (only used for string ops) */
119         tb->tb_jmp_offset[2] = 0xffff;
120         tb->tb_jmp_offset[3] = 0xffff;
121 #endif
122         gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
123 #ifdef USE_DIRECT_JUMP
124                                     tb->tb_jmp_offset,
125 #else
126                                     NULL,
127 #endif
128                                     gen_opc_buf, gen_opparam_buf);
129     }
130     *gen_code_size_ptr = gen_code_size;
131 #ifdef DEBUG_DISAS
132     if (loglevel & CPU_LOG_TB_OUT_ASM) {
133         fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
134         disas(logfile, tb->tc_ptr, *gen_code_size_ptr, 1, 0);
135         fprintf(logfile, "\n");
136         fflush(logfile);
137     }
138 #endif
139     return 0;
140 }
141
142 static const unsigned short opc_copy_size[] = {
143 #define DEF(s, n, copy_size) copy_size,
144 #include "opc.h"
145 #undef DEF
146 };
147
148 /* The cpu state corresponding to 'searched_pc' is restored. 
149  */
150 int cpu_restore_state(TranslationBlock *tb, 
151                       CPUState *env, unsigned long searched_pc,
152                       void *puc)
153 {
154     int j, c;
155     unsigned long tc_ptr;
156     uint16_t *opc_ptr;
157
158 #ifdef USE_CODE_COPY
159     if (tb->cflags & CF_CODE_COPY) {
160         return cpu_restore_state_copy(tb, env, searched_pc, puc);
161     }
162 #endif
163     if (gen_intermediate_code_pc(env, tb) < 0)
164         return -1;
165     
166     /* find opc index corresponding to search_pc */
167     tc_ptr = (unsigned long)tb->tc_ptr;
168     if (searched_pc < tc_ptr)
169         return -1;
170     j = 0;
171     opc_ptr = gen_opc_buf;
172     for(;;) {
173         c = *opc_ptr;
174         if (c == INDEX_op_end)
175             return -1;
176         tc_ptr += opc_copy_size[c];
177         if (searched_pc < tc_ptr)
178             break;
179         opc_ptr++;
180     }
181     j = opc_ptr - gen_opc_buf;
182     /* now find start of instruction before */
183     while (gen_opc_instr_start[j] == 0)
184         j--;
185 #if defined(TARGET_I386)
186     {
187         int cc_op;
188 #ifdef DEBUG_DISAS
189         if (loglevel & CPU_LOG_TB_OP) {
190             int i;
191             fprintf(logfile, "RESTORE:\n");
192             for(i=0;i<=j; i++) {
193                 if (gen_opc_instr_start[i]) {
194                     fprintf(logfile, "0x%04x: 0x%08x\n", i, gen_opc_pc[i]);
195                 }
196             }
197             fprintf(logfile, "spc=0x%08lx j=0x%x eip=0x%x cs_base=%x\n", 
198                     searched_pc, j, gen_opc_pc[j] - tb->cs_base, tb->cs_base);
199         }
200 #endif
201         env->eip = gen_opc_pc[j] - tb->cs_base;
202         cc_op = gen_opc_cc_op[j];
203         if (cc_op != CC_OP_DYNAMIC)
204             env->cc_op = cc_op;
205     }
206 #elif defined(TARGET_ARM)
207     env->regs[15] = gen_opc_pc[j];
208 #elif defined(TARGET_SPARC)
209     /* XXX: restore npc too */
210     env->pc = gen_opc_pc[j];
211 #elif defined(TARGET_PPC)
212     {
213         int type;
214         /* for PPC, we need to look at the micro operation to get the
215            access type */
216         env->nip = gen_opc_pc[j];
217         switch(c) {
218 #if defined(CONFIG_USER_ONLY)
219 #define CASE3(op)\
220         case INDEX_op_ ## op ## _raw
221 #else
222 #define CASE3(op)\
223         case INDEX_op_ ## op ## _user:\
224         case INDEX_op_ ## op ## _kernel
225 #endif
226             
227         CASE3(stfd):
228         CASE3(stfs):
229         CASE3(lfd):
230         CASE3(lfs):
231             type = ACCESS_FLOAT;
232             break;
233         CASE3(lwarx):
234             type = ACCESS_RES;
235             break;
236         CASE3(stwcx):
237             type = ACCESS_RES;
238             break;
239         CASE3(eciwx):
240         CASE3(ecowx):
241             type = ACCESS_EXT;
242             break;
243         default:
244             type = ACCESS_INT;
245             break;
246         }
247         env->access_type = type;
248     }
249 #endif
250     return 0;
251 }