Commit 5898e816840dd7cb2492c4cce85525e7383f8def
1 parent
394411ac
ARM emulation support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@232 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
1586 additions
and
0 deletions
cpu-arm.h
0 → 100644
1 | +/* | |
2 | + * ARM virtual CPU header | |
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 | +#ifndef CPU_ARM_H | |
21 | +#define CPU_ARM_H | |
22 | + | |
23 | +#include "config.h" | |
24 | +#include <setjmp.h> | |
25 | + | |
26 | +#define EXCP_UDEF 1 /* undefined instruction */ | |
27 | +#define EXCP_SWI 2 /* software interrupt */ | |
28 | +#define EXCP_INTERRUPT 256 /* async interruption */ | |
29 | + | |
30 | +typedef struct CPUARMState { | |
31 | + uint32_t regs[16]; | |
32 | + uint32_t cpsr; | |
33 | + | |
34 | + /* cpsr flag cache for faster execution */ | |
35 | + uint32_t CF; /* 0 or 1 */ | |
36 | + uint32_t VF; /* V is the bit 31. All other bits are undefined */ | |
37 | + uint32_t NZF; /* N is bit 31. Z is computed from NZF */ | |
38 | + | |
39 | + /* exception/interrupt handling */ | |
40 | + jmp_buf jmp_env; | |
41 | + int exception_index; | |
42 | + int interrupt_request; | |
43 | + | |
44 | + /* user data */ | |
45 | + void *opaque; | |
46 | +} CPUARMState; | |
47 | + | |
48 | +CPUARMState *cpu_arm_init(void); | |
49 | +int cpu_arm_exec(CPUARMState *s); | |
50 | +void cpu_arm_interrupt(CPUARMState *s); | |
51 | +void cpu_arm_close(CPUARMState *s); | |
52 | +/* you can call this signal handler from your SIGBUS and SIGSEGV | |
53 | + signal handlers to inform the virtual CPU of exceptions. non zero | |
54 | + is returned if the signal was handled by the virtual CPU. */ | |
55 | +struct siginfo; | |
56 | +int cpu_arm_signal_handler(int host_signum, struct siginfo *info, | |
57 | + void *puc); | |
58 | + | |
59 | +void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags); | |
60 | + | |
61 | +#define TARGET_PAGE_BITS 12 | |
62 | +#include "cpu-all.h" | |
63 | + | |
64 | +#endif | ... | ... |
exec-arm.h
0 → 100644
1 | +/* | |
2 | + * ARM execution defines | |
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 "dyngen-exec.h" | |
21 | + | |
22 | +register struct CPUARMState *env asm(AREG0); | |
23 | +register uint32_t T0 asm(AREG1); | |
24 | +register uint32_t T1 asm(AREG2); | |
25 | +register uint32_t T2 asm(AREG3); | |
26 | + | |
27 | +#include "cpu-arm.h" | |
28 | +#include "exec.h" | |
29 | + | |
30 | +void cpu_lock(void); | |
31 | +void cpu_unlock(void); | |
32 | +void cpu_loop_exit(void); | ... | ... |
op-arm-template.h
0 → 100644
1 | +/* | |
2 | + * ARM micro operations (templates for various register related | |
3 | + * operations) | |
4 | + * | |
5 | + * Copyright (c) 2003 Fabrice Bellard | |
6 | + * | |
7 | + * This library is free software; you can redistribute it and/or | |
8 | + * modify it under the terms of the GNU Lesser General Public | |
9 | + * License as published by the Free Software Foundation; either | |
10 | + * version 2 of the License, or (at your option) any later version. | |
11 | + * | |
12 | + * This library is distributed in the hope that it will be useful, | |
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | + * Lesser General Public License for more details. | |
16 | + * | |
17 | + * You should have received a copy of the GNU Lesser General Public | |
18 | + * License along with this library; if not, write to the Free Software | |
19 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 | + */ | |
21 | + | |
22 | +void OPPROTO glue(op_movl_T0_, REGNAME)(void) | |
23 | +{ | |
24 | + T0 = REG; | |
25 | +} | |
26 | + | |
27 | +void OPPROTO glue(op_movl_T1_, REGNAME)(void) | |
28 | +{ | |
29 | + T1 = REG; | |
30 | +} | |
31 | + | |
32 | +void OPPROTO glue(op_movl_T2_, REGNAME)(void) | |
33 | +{ | |
34 | + T2 = REG; | |
35 | +} | |
36 | + | |
37 | +void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void) | |
38 | +{ | |
39 | + REG = T0; | |
40 | +} | |
41 | + | |
42 | +void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void) | |
43 | +{ | |
44 | + REG = T1; | |
45 | +} | |
46 | + | |
47 | +#undef REG | |
48 | +#undef REGNAME | ... | ... |
op-arm.c
0 → 100644
1 | +/* | |
2 | + * ARM micro operations | |
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 "exec-arm.h" | |
21 | + | |
22 | +#define REGNAME r0 | |
23 | +#define REG (env->regs[0]) | |
24 | +#include "op-arm-template.h" | |
25 | + | |
26 | +#define REGNAME r1 | |
27 | +#define REG (env->regs[1]) | |
28 | +#include "op-arm-template.h" | |
29 | + | |
30 | +#define REGNAME r2 | |
31 | +#define REG (env->regs[2]) | |
32 | +#include "op-arm-template.h" | |
33 | + | |
34 | +#define REGNAME r3 | |
35 | +#define REG (env->regs[3]) | |
36 | +#include "op-arm-template.h" | |
37 | + | |
38 | +#define REGNAME r4 | |
39 | +#define REG (env->regs[4]) | |
40 | +#include "op-arm-template.h" | |
41 | + | |
42 | +#define REGNAME r5 | |
43 | +#define REG (env->regs[5]) | |
44 | +#include "op-arm-template.h" | |
45 | + | |
46 | +#define REGNAME r6 | |
47 | +#define REG (env->regs[6]) | |
48 | +#include "op-arm-template.h" | |
49 | + | |
50 | +#define REGNAME r7 | |
51 | +#define REG (env->regs[7]) | |
52 | +#include "op-arm-template.h" | |
53 | + | |
54 | +#define REGNAME r8 | |
55 | +#define REG (env->regs[8]) | |
56 | +#include "op-arm-template.h" | |
57 | + | |
58 | +#define REGNAME r9 | |
59 | +#define REG (env->regs[9]) | |
60 | +#include "op-arm-template.h" | |
61 | + | |
62 | +#define REGNAME r10 | |
63 | +#define REG (env->regs[10]) | |
64 | +#include "op-arm-template.h" | |
65 | + | |
66 | +#define REGNAME r11 | |
67 | +#define REG (env->regs[11]) | |
68 | +#include "op-arm-template.h" | |
69 | + | |
70 | +#define REGNAME r12 | |
71 | +#define REG (env->regs[12]) | |
72 | +#include "op-arm-template.h" | |
73 | + | |
74 | +#define REGNAME r13 | |
75 | +#define REG (env->regs[13]) | |
76 | +#include "op-arm-template.h" | |
77 | + | |
78 | +#define REGNAME r14 | |
79 | +#define REG (env->regs[14]) | |
80 | +#include "op-arm-template.h" | |
81 | + | |
82 | +#define REGNAME r15 | |
83 | +#define REG (env->regs[15]) | |
84 | +#include "op-arm-template.h" | |
85 | + | |
86 | +void OPPROTO op_movl_T0_0(void) | |
87 | +{ | |
88 | + T0 = 0; | |
89 | +} | |
90 | + | |
91 | +void OPPROTO op_movl_T0_im(void) | |
92 | +{ | |
93 | + T0 = PARAM1; | |
94 | +} | |
95 | + | |
96 | +void OPPROTO op_movl_T1_im(void) | |
97 | +{ | |
98 | + T1 = PARAM1; | |
99 | +} | |
100 | + | |
101 | +void OPPROTO op_movl_T2_im(void) | |
102 | +{ | |
103 | + T2 = PARAM1; | |
104 | +} | |
105 | + | |
106 | +void OPPROTO op_addl_T1_im(void) | |
107 | +{ | |
108 | + T1 += PARAM1; | |
109 | +} | |
110 | + | |
111 | +void OPPROTO op_addl_T1_T2(void) | |
112 | +{ | |
113 | + T1 += T2; | |
114 | +} | |
115 | + | |
116 | +void OPPROTO op_subl_T1_T2(void) | |
117 | +{ | |
118 | + T1 -= T2; | |
119 | +} | |
120 | + | |
121 | +void OPPROTO op_addl_T0_T1(void) | |
122 | +{ | |
123 | + T0 += T1; | |
124 | +} | |
125 | + | |
126 | +void OPPROTO op_addl_T0_T1_cc(void) | |
127 | +{ | |
128 | + unsigned int src1; | |
129 | + src1 = T0; | |
130 | + T0 += T1; | |
131 | + env->NZF = T0; | |
132 | + env->CF = T0 < src1; | |
133 | + env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); | |
134 | +} | |
135 | + | |
136 | +void OPPROTO op_adcl_T0_T1(void) | |
137 | +{ | |
138 | + T0 += T1 + env->CF; | |
139 | +} | |
140 | + | |
141 | +void OPPROTO op_adcl_T0_T1_cc(void) | |
142 | +{ | |
143 | + unsigned int src1; | |
144 | + src1 = T0; | |
145 | + if (!env->CF) { | |
146 | + T0 += T1; | |
147 | + env->CF = T0 < src1; | |
148 | + } else { | |
149 | + T0 += T1 + 1; | |
150 | + env->CF = T0 <= src1; | |
151 | + } | |
152 | + env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); | |
153 | + env->NZF = T0; | |
154 | + FORCE_RET(); | |
155 | +} | |
156 | + | |
157 | +#define OPSUB(sub, sbc, T0, T1) \ | |
158 | + \ | |
159 | +void OPPROTO op_ ## sub ## l_T0_T1(void) \ | |
160 | +{ \ | |
161 | + T0 -= T1; \ | |
162 | +} \ | |
163 | + \ | |
164 | +void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ | |
165 | +{ \ | |
166 | + unsigned int src1; \ | |
167 | + src1 = T0; \ | |
168 | + T0 -= T1; \ | |
169 | + env->NZF = T0; \ | |
170 | + env->CF = src1 < T1; \ | |
171 | + env->VF = (src1 ^ T1) & (src1 ^ T0); \ | |
172 | +} \ | |
173 | + \ | |
174 | +void OPPROTO op_ ## sbc ## l_T0_T1(void) \ | |
175 | +{ \ | |
176 | + T0 = T0 - T1 + env->CF - 1; \ | |
177 | +} \ | |
178 | + \ | |
179 | +void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ | |
180 | +{ \ | |
181 | + unsigned int src1; \ | |
182 | + src1 = T0; \ | |
183 | + if (!env->CF) { \ | |
184 | + T0 = T0 - T1 - 1; \ | |
185 | + T0 += T1; \ | |
186 | + env->CF = src1 < T1; \ | |
187 | + } else { \ | |
188 | + T0 = T0 - T1; \ | |
189 | + env->CF = src1 <= T1; \ | |
190 | + } \ | |
191 | + env->VF = (src1 ^ T1) & (src1 ^ T0); \ | |
192 | + env->NZF = T0; \ | |
193 | + FORCE_RET(); \ | |
194 | +} | |
195 | + | |
196 | +OPSUB(sub, sbc, T0, T1) | |
197 | + | |
198 | +OPSUB(rsb, rsc, T1, T0) | |
199 | + | |
200 | +void OPPROTO op_andl_T0_T1(void) | |
201 | +{ | |
202 | + T0 &= T1; | |
203 | +} | |
204 | + | |
205 | +void OPPROTO op_xorl_T0_T1(void) | |
206 | +{ | |
207 | + T0 ^= T1; | |
208 | +} | |
209 | + | |
210 | +void OPPROTO op_orl_T0_T1(void) | |
211 | +{ | |
212 | + T0 |= T1; | |
213 | +} | |
214 | + | |
215 | +void OPPROTO op_bicl_T0_T1(void) | |
216 | +{ | |
217 | + T0 &= ~T1; | |
218 | +} | |
219 | + | |
220 | +void OPPROTO op_notl_T1(void) | |
221 | +{ | |
222 | + T1 = ~T1; | |
223 | +} | |
224 | + | |
225 | +void OPPROTO op_logic_cc(void) | |
226 | +{ | |
227 | + env->NZF = T0; | |
228 | +} | |
229 | + | |
230 | +#define EIP (env->regs[15]) | |
231 | + | |
232 | +void OPPROTO op_test_eq(void) | |
233 | +{ | |
234 | + if (env->NZF == 0) | |
235 | + JUMP_TB(PARAM1, 0, PARAM2); | |
236 | + FORCE_RET(); | |
237 | +} | |
238 | + | |
239 | +void OPPROTO op_test_ne(void) | |
240 | +{ | |
241 | + if (env->NZF != 0) | |
242 | + JUMP_TB(PARAM1, 0, PARAM2); | |
243 | + FORCE_RET(); | |
244 | +} | |
245 | + | |
246 | +void OPPROTO op_test_cs(void) | |
247 | +{ | |
248 | + if (env->CF != 0) | |
249 | + JUMP_TB(PARAM1, 0, PARAM2); | |
250 | + FORCE_RET(); | |
251 | +} | |
252 | + | |
253 | +void OPPROTO op_test_cc(void) | |
254 | +{ | |
255 | + if (env->CF == 0) | |
256 | + JUMP_TB(PARAM1, 0, PARAM2); | |
257 | + FORCE_RET(); | |
258 | +} | |
259 | + | |
260 | +void OPPROTO op_test_mi(void) | |
261 | +{ | |
262 | + if ((env->NZF & 0x80000000) != 0) | |
263 | + JUMP_TB(PARAM1, 0, PARAM2); | |
264 | + FORCE_RET(); | |
265 | +} | |
266 | + | |
267 | +void OPPROTO op_test_pl(void) | |
268 | +{ | |
269 | + if ((env->NZF & 0x80000000) == 0) | |
270 | + JUMP_TB(PARAM1, 0, PARAM2); | |
271 | + FORCE_RET(); | |
272 | +} | |
273 | + | |
274 | +void OPPROTO op_test_vs(void) | |
275 | +{ | |
276 | + if ((env->VF & 0x80000000) != 0) | |
277 | + JUMP_TB(PARAM1, 0, PARAM2); | |
278 | + FORCE_RET(); | |
279 | +} | |
280 | + | |
281 | +void OPPROTO op_test_vc(void) | |
282 | +{ | |
283 | + if ((env->VF & 0x80000000) == 0) | |
284 | + JUMP_TB(PARAM1, 0, PARAM2); | |
285 | + FORCE_RET(); | |
286 | +} | |
287 | + | |
288 | +void OPPROTO op_test_hi(void) | |
289 | +{ | |
290 | + if (env->CF != 0 && env->NZF != 0) | |
291 | + JUMP_TB(PARAM1, 0, PARAM2); | |
292 | + FORCE_RET(); | |
293 | +} | |
294 | + | |
295 | +void OPPROTO op_test_ls(void) | |
296 | +{ | |
297 | + if (env->CF == 0 || env->NZF == 0) | |
298 | + JUMP_TB(PARAM1, 0, PARAM2); | |
299 | + FORCE_RET(); | |
300 | +} | |
301 | + | |
302 | +void OPPROTO op_test_ge(void) | |
303 | +{ | |
304 | + if (((env->VF ^ env->NZF) & 0x80000000) == 0) | |
305 | + JUMP_TB(PARAM1, 0, PARAM2); | |
306 | + FORCE_RET(); | |
307 | +} | |
308 | + | |
309 | +void OPPROTO op_test_lt(void) | |
310 | +{ | |
311 | + if (((env->VF ^ env->NZF) & 0x80000000) != 0) | |
312 | + JUMP_TB(PARAM1, 0, PARAM2); | |
313 | + FORCE_RET(); | |
314 | +} | |
315 | + | |
316 | +void OPPROTO op_test_gt(void) | |
317 | +{ | |
318 | + if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0) | |
319 | + JUMP_TB(PARAM1, 0, PARAM2); | |
320 | + FORCE_RET(); | |
321 | +} | |
322 | + | |
323 | +void OPPROTO op_test_le(void) | |
324 | +{ | |
325 | + if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0) | |
326 | + JUMP_TB(PARAM1, 0, PARAM2); | |
327 | + FORCE_RET(); | |
328 | +} | |
329 | + | |
330 | +void OPPROTO op_jmp(void) | |
331 | +{ | |
332 | + JUMP_TB(PARAM1, 1, PARAM2); | |
333 | +} | |
334 | + | |
335 | +void OPPROTO op_movl_T0_psr(void) | |
336 | +{ | |
337 | + int ZF; | |
338 | + ZF = (env->NZF == 0); | |
339 | + T0 = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | | |
340 | + (env->CF << 29) | ((env->VF & 0x80000000) >> 3); | |
341 | +} | |
342 | + | |
343 | +/* NOTE: N = 1 and Z = 1 cannot be stored currently */ | |
344 | +void OPPROTO op_movl_psr_T0(void) | |
345 | +{ | |
346 | + unsigned int psr; | |
347 | + psr = T0; | |
348 | + env->CF = (psr >> 29) & 1; | |
349 | + env->NZF = (psr & 0xc0000000) ^ 0x40000000; | |
350 | + env->VF = (psr << 3) & 0x80000000; | |
351 | + /* for user mode we do not update other state info */ | |
352 | +} | |
353 | + | |
354 | +void OPPROTO op_mul_T0_T1(void) | |
355 | +{ | |
356 | + T0 = T0 * T1; | |
357 | +} | |
358 | + | |
359 | +/* 64 bit unsigned mul */ | |
360 | +void OPPROTO op_mull_T0_T1(void) | |
361 | +{ | |
362 | + uint64_t res; | |
363 | + res = T0 * T1; | |
364 | + T1 = res >> 32; | |
365 | + T0 = res; | |
366 | +} | |
367 | + | |
368 | +/* 64 bit signed mul */ | |
369 | +void OPPROTO op_imull_T0_T1(void) | |
370 | +{ | |
371 | + uint64_t res; | |
372 | + res = (int32_t)T0 * (int32_t)T1; | |
373 | + T1 = res >> 32; | |
374 | + T0 = res; | |
375 | +} | |
376 | + | |
377 | +void OPPROTO op_addq_T0_T1(void) | |
378 | +{ | |
379 | + uint64_t res; | |
380 | + res = ((uint64_t)T1 << 32) | T0; | |
381 | + res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); | |
382 | + T1 = res >> 32; | |
383 | + T0 = res; | |
384 | +} | |
385 | + | |
386 | +void OPPROTO op_logicq_cc(void) | |
387 | +{ | |
388 | + env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0); | |
389 | +} | |
390 | + | |
391 | +/* memory access */ | |
392 | + | |
393 | +void OPPROTO op_ldub_T0_T1(void) | |
394 | +{ | |
395 | + T0 = ldub((void *)T1); | |
396 | +} | |
397 | + | |
398 | +void OPPROTO op_ldsb_T0_T1(void) | |
399 | +{ | |
400 | + T0 = ldsb((void *)T1); | |
401 | +} | |
402 | + | |
403 | +void OPPROTO op_lduw_T0_T1(void) | |
404 | +{ | |
405 | + T0 = lduw((void *)T1); | |
406 | +} | |
407 | + | |
408 | +void OPPROTO op_ldsw_T0_T1(void) | |
409 | +{ | |
410 | + T0 = ldsw((void *)T1); | |
411 | +} | |
412 | + | |
413 | +void OPPROTO op_ldl_T0_T1(void) | |
414 | +{ | |
415 | + T0 = ldl((void *)T1); | |
416 | +} | |
417 | + | |
418 | +void OPPROTO op_stb_T0_T1(void) | |
419 | +{ | |
420 | + stb((void *)T1, T0); | |
421 | +} | |
422 | + | |
423 | +void OPPROTO op_stw_T0_T1(void) | |
424 | +{ | |
425 | + stw((void *)T1, T0); | |
426 | +} | |
427 | + | |
428 | +void OPPROTO op_stl_T0_T1(void) | |
429 | +{ | |
430 | + stl((void *)T1, T0); | |
431 | +} | |
432 | + | |
433 | +void OPPROTO op_swpb_T0_T1(void) | |
434 | +{ | |
435 | + int tmp; | |
436 | + | |
437 | + cpu_lock(); | |
438 | + tmp = ldub((void *)T1); | |
439 | + stb((void *)T1, T0); | |
440 | + T0 = tmp; | |
441 | + cpu_unlock(); | |
442 | +} | |
443 | + | |
444 | +void OPPROTO op_swpl_T0_T1(void) | |
445 | +{ | |
446 | + int tmp; | |
447 | + | |
448 | + cpu_lock(); | |
449 | + tmp = ldl((void *)T1); | |
450 | + stl((void *)T1, T0); | |
451 | + T0 = tmp; | |
452 | + cpu_unlock(); | |
453 | +} | |
454 | + | |
455 | +/* shifts */ | |
456 | + | |
457 | +/* T1 based */ | |
458 | +void OPPROTO op_shll_T1_im(void) | |
459 | +{ | |
460 | + T1 = T1 << PARAM1; | |
461 | +} | |
462 | + | |
463 | +void OPPROTO op_shrl_T1_im(void) | |
464 | +{ | |
465 | + T1 = (uint32_t)T1 >> PARAM1; | |
466 | +} | |
467 | + | |
468 | +void OPPROTO op_sarl_T1_im(void) | |
469 | +{ | |
470 | + T1 = (int32_t)T1 >> PARAM1; | |
471 | +} | |
472 | + | |
473 | +void OPPROTO op_rorl_T1_im(void) | |
474 | +{ | |
475 | + int shift; | |
476 | + shift = PARAM1; | |
477 | + T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
478 | +} | |
479 | + | |
480 | +/* T1 based, set C flag */ | |
481 | +void OPPROTO op_shll_T1_im_cc(void) | |
482 | +{ | |
483 | + env->CF = (T1 >> (32 - PARAM1)) & 1; | |
484 | + T1 = T1 << PARAM1; | |
485 | +} | |
486 | + | |
487 | +void OPPROTO op_shrl_T1_im_cc(void) | |
488 | +{ | |
489 | + env->CF = (T1 >> (PARAM1 - 1)) & 1; | |
490 | + T1 = (uint32_t)T1 >> PARAM1; | |
491 | +} | |
492 | + | |
493 | +void OPPROTO op_sarl_T1_im_cc(void) | |
494 | +{ | |
495 | + env->CF = (T1 >> (PARAM1 - 1)) & 1; | |
496 | + T1 = (int32_t)T1 >> PARAM1; | |
497 | +} | |
498 | + | |
499 | +void OPPROTO op_rorl_T1_im_cc(void) | |
500 | +{ | |
501 | + int shift; | |
502 | + shift = PARAM1; | |
503 | + env->CF = (T1 >> (shift - 1)) & 1; | |
504 | + T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
505 | +} | |
506 | + | |
507 | +/* T2 based */ | |
508 | +void OPPROTO op_shll_T2_im(void) | |
509 | +{ | |
510 | + T2 = T2 << PARAM1; | |
511 | +} | |
512 | + | |
513 | +void OPPROTO op_shrl_T2_im(void) | |
514 | +{ | |
515 | + T2 = (uint32_t)T2 >> PARAM1; | |
516 | +} | |
517 | + | |
518 | +void OPPROTO op_sarl_T2_im(void) | |
519 | +{ | |
520 | + T2 = (int32_t)T2 >> PARAM1; | |
521 | +} | |
522 | + | |
523 | +void OPPROTO op_rorl_T2_im(void) | |
524 | +{ | |
525 | + int shift; | |
526 | + shift = PARAM1; | |
527 | + T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift)); | |
528 | +} | |
529 | + | |
530 | +/* T1 based, use T0 as shift count */ | |
531 | + | |
532 | +void OPPROTO op_shll_T1_T0(void) | |
533 | +{ | |
534 | + int shift; | |
535 | + shift = T0 & 0xff; | |
536 | + if (shift >= 32) | |
537 | + T1 = 0; | |
538 | + else | |
539 | + T1 = T1 << shift; | |
540 | + FORCE_RET(); | |
541 | +} | |
542 | + | |
543 | +void OPPROTO op_shrl_T1_T0(void) | |
544 | +{ | |
545 | + int shift; | |
546 | + shift = T0 & 0xff; | |
547 | + if (shift >= 32) | |
548 | + T1 = 0; | |
549 | + else | |
550 | + T1 = (uint32_t)T1 >> shift; | |
551 | + FORCE_RET(); | |
552 | +} | |
553 | + | |
554 | +void OPPROTO op_sarl_T1_T0(void) | |
555 | +{ | |
556 | + int shift; | |
557 | + shift = T0 & 0xff; | |
558 | + if (shift >= 32) | |
559 | + shift = 31; | |
560 | + T1 = (int32_t)T1 >> shift; | |
561 | +} | |
562 | + | |
563 | +void OPPROTO op_rorl_T1_T0(void) | |
564 | +{ | |
565 | + int shift; | |
566 | + shift = T0 & 0x1f; | |
567 | + if (shift) { | |
568 | + T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
569 | + } | |
570 | + FORCE_RET(); | |
571 | +} | |
572 | + | |
573 | +/* T1 based, use T0 as shift count and compute CF */ | |
574 | + | |
575 | +void OPPROTO op_shll_T1_T0_cc(void) | |
576 | +{ | |
577 | + int shift; | |
578 | + shift = T0 & 0xff; | |
579 | + if (shift >= 32) { | |
580 | + if (shift == 32) | |
581 | + env->CF = T1 & 1; | |
582 | + else | |
583 | + env->CF = 0; | |
584 | + T1 = 0; | |
585 | + } else if (shift != 0) { | |
586 | + env->CF = (T1 >> (32 - shift)) & 1; | |
587 | + T1 = T1 << shift; | |
588 | + } | |
589 | + FORCE_RET(); | |
590 | +} | |
591 | + | |
592 | +void OPPROTO op_shrl_T1_T0_cc(void) | |
593 | +{ | |
594 | + int shift; | |
595 | + shift = T0 & 0xff; | |
596 | + if (shift >= 32) { | |
597 | + if (shift == 32) | |
598 | + env->CF = (T1 >> 31) & 1; | |
599 | + else | |
600 | + env->CF = 0; | |
601 | + T1 = 0; | |
602 | + } else if (shift != 0) { | |
603 | + env->CF = (T1 >> (shift - 1)) & 1; | |
604 | + T1 = (uint32_t)T1 >> shift; | |
605 | + } | |
606 | + FORCE_RET(); | |
607 | +} | |
608 | + | |
609 | +void OPPROTO op_sarl_T1_T0_cc(void) | |
610 | +{ | |
611 | + int shift; | |
612 | + shift = T0 & 0xff; | |
613 | + if (shift >= 32) { | |
614 | + env->CF = (T1 >> 31) & 1; | |
615 | + T1 = (int32_t)T1 >> 31; | |
616 | + } else { | |
617 | + env->CF = (T1 >> (shift - 1)) & 1; | |
618 | + T1 = (int32_t)T1 >> shift; | |
619 | + } | |
620 | + FORCE_RET(); | |
621 | +} | |
622 | + | |
623 | +void OPPROTO op_rorl_T1_T0_cc(void) | |
624 | +{ | |
625 | + int shift1, shift; | |
626 | + shift1 = T0 & 0xff; | |
627 | + shift = shift1 & 0x1f; | |
628 | + if (shift == 0) { | |
629 | + if (shift1 != 0) | |
630 | + env->CF = (T1 >> 31) & 1; | |
631 | + } else { | |
632 | + env->CF = (T1 >> (shift - 1)) & 1; | |
633 | + T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
634 | + } | |
635 | + FORCE_RET(); | |
636 | +} | |
637 | + | |
638 | +/* exceptions */ | |
639 | + | |
640 | +void OPPROTO op_swi(void) | |
641 | +{ | |
642 | + env->exception_index = EXCP_SWI; | |
643 | + cpu_loop_exit(); | |
644 | +} | |
645 | + | |
646 | +void OPPROTO op_undef_insn(void) | |
647 | +{ | |
648 | + env->exception_index = EXCP_UDEF; | |
649 | + cpu_loop_exit(); | |
650 | +} | |
651 | + | |
652 | +/* thread support */ | |
653 | + | |
654 | +spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; | |
655 | + | |
656 | +void cpu_lock(void) | |
657 | +{ | |
658 | + spin_lock(&global_cpu_lock); | |
659 | +} | |
660 | + | |
661 | +void cpu_unlock(void) | |
662 | +{ | |
663 | + spin_unlock(&global_cpu_lock); | |
664 | +} | |
665 | + | ... | ... |
syscall-arm.h
0 → 100644
1 | + | |
2 | +/* this struct defines the way the registers are stored on the | |
3 | + stack during a system call. */ | |
4 | + | |
5 | +struct target_pt_regs { | |
6 | + target_long uregs[18]; | |
7 | +}; | |
8 | + | |
9 | +#define ARM_cpsr uregs[16] | |
10 | +#define ARM_pc uregs[15] | |
11 | +#define ARM_lr uregs[14] | |
12 | +#define ARM_sp uregs[13] | |
13 | +#define ARM_ip uregs[12] | |
14 | +#define ARM_fp uregs[11] | |
15 | +#define ARM_r10 uregs[10] | |
16 | +#define ARM_r9 uregs[9] | |
17 | +#define ARM_r8 uregs[8] | |
18 | +#define ARM_r7 uregs[7] | |
19 | +#define ARM_r6 uregs[6] | |
20 | +#define ARM_r5 uregs[5] | |
21 | +#define ARM_r4 uregs[4] | |
22 | +#define ARM_r3 uregs[3] | |
23 | +#define ARM_r2 uregs[2] | |
24 | +#define ARM_r1 uregs[1] | |
25 | +#define ARM_r0 uregs[0] | |
26 | +#define ARM_ORIG_r0 uregs[17] | |
27 | + | ... | ... |
translate-arm.c
0 → 100644
1 | +/* | |
2 | + * ARM translation | |
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 "cpu-arm.h" | |
27 | +#include "exec.h" | |
28 | +#include "disas.h" | |
29 | + | |
30 | +/* internal defines */ | |
31 | +typedef struct DisasContext { | |
32 | + uint8_t *pc; | |
33 | + int is_jmp; | |
34 | + struct TranslationBlock *tb; | |
35 | +} DisasContext; | |
36 | + | |
37 | +/* XXX: move that elsewhere */ | |
38 | +static uint16_t *gen_opc_ptr; | |
39 | +static uint32_t *gen_opparam_ptr; | |
40 | +extern FILE *logfile; | |
41 | +extern int loglevel; | |
42 | + | |
43 | +enum { | |
44 | +#define DEF(s, n, copy_size) INDEX_op_ ## s, | |
45 | +#include "opc-arm.h" | |
46 | +#undef DEF | |
47 | + NB_OPS, | |
48 | +}; | |
49 | + | |
50 | +#include "gen-op-arm.h" | |
51 | + | |
52 | +typedef void (GenOpFunc)(void); | |
53 | +typedef void (GenOpFunc1)(long); | |
54 | +typedef void (GenOpFunc2)(long, long); | |
55 | +typedef void (GenOpFunc3)(long, long, long); | |
56 | + | |
57 | +static GenOpFunc2 *gen_test_cc[14] = { | |
58 | + gen_op_test_eq, | |
59 | + gen_op_test_ne, | |
60 | + gen_op_test_cs, | |
61 | + gen_op_test_cc, | |
62 | + gen_op_test_mi, | |
63 | + gen_op_test_pl, | |
64 | + gen_op_test_vs, | |
65 | + gen_op_test_vc, | |
66 | + gen_op_test_hi, | |
67 | + gen_op_test_ls, | |
68 | + gen_op_test_ge, | |
69 | + gen_op_test_lt, | |
70 | + gen_op_test_gt, | |
71 | + gen_op_test_le, | |
72 | +}; | |
73 | + | |
74 | +const uint8_t table_logic_cc[16] = { | |
75 | + 1, /* and */ | |
76 | + 1, /* xor */ | |
77 | + 0, /* sub */ | |
78 | + 0, /* rsb */ | |
79 | + 0, /* add */ | |
80 | + 0, /* adc */ | |
81 | + 0, /* sbc */ | |
82 | + 0, /* rsc */ | |
83 | + 1, /* andl */ | |
84 | + 1, /* xorl */ | |
85 | + 0, /* cmp */ | |
86 | + 0, /* cmn */ | |
87 | + 1, /* orr */ | |
88 | + 1, /* mov */ | |
89 | + 1, /* bic */ | |
90 | + 1, /* mvn */ | |
91 | +}; | |
92 | + | |
93 | +static GenOpFunc1 *gen_shift_T1_im[4] = { | |
94 | + gen_op_shll_T1_im, | |
95 | + gen_op_shrl_T1_im, | |
96 | + gen_op_sarl_T1_im, | |
97 | + gen_op_rorl_T1_im, | |
98 | +}; | |
99 | + | |
100 | +static GenOpFunc1 *gen_shift_T2_im[4] = { | |
101 | + gen_op_shll_T2_im, | |
102 | + gen_op_shrl_T2_im, | |
103 | + gen_op_sarl_T2_im, | |
104 | + gen_op_rorl_T2_im, | |
105 | +}; | |
106 | + | |
107 | +static GenOpFunc1 *gen_shift_T1_im_cc[4] = { | |
108 | + gen_op_shll_T1_im_cc, | |
109 | + gen_op_shrl_T1_im_cc, | |
110 | + gen_op_sarl_T1_im_cc, | |
111 | + gen_op_rorl_T1_im_cc, | |
112 | +}; | |
113 | + | |
114 | +static GenOpFunc *gen_shift_T1_T0[4] = { | |
115 | + gen_op_shll_T1_T0, | |
116 | + gen_op_shrl_T1_T0, | |
117 | + gen_op_sarl_T1_T0, | |
118 | + gen_op_rorl_T1_T0, | |
119 | +}; | |
120 | + | |
121 | +static GenOpFunc *gen_shift_T1_T0_cc[4] = { | |
122 | + gen_op_shll_T1_T0_cc, | |
123 | + gen_op_shrl_T1_T0_cc, | |
124 | + gen_op_sarl_T1_T0_cc, | |
125 | + gen_op_rorl_T1_T0_cc, | |
126 | +}; | |
127 | + | |
128 | +static GenOpFunc *gen_op_movl_TN_reg[3][16] = { | |
129 | + { | |
130 | + gen_op_movl_T0_r0, | |
131 | + gen_op_movl_T0_r1, | |
132 | + gen_op_movl_T0_r2, | |
133 | + gen_op_movl_T0_r3, | |
134 | + gen_op_movl_T0_r4, | |
135 | + gen_op_movl_T0_r5, | |
136 | + gen_op_movl_T0_r6, | |
137 | + gen_op_movl_T0_r7, | |
138 | + gen_op_movl_T0_r8, | |
139 | + gen_op_movl_T0_r9, | |
140 | + gen_op_movl_T0_r10, | |
141 | + gen_op_movl_T0_r11, | |
142 | + gen_op_movl_T0_r12, | |
143 | + gen_op_movl_T0_r13, | |
144 | + gen_op_movl_T0_r14, | |
145 | + gen_op_movl_T0_r15, | |
146 | + }, | |
147 | + { | |
148 | + gen_op_movl_T1_r0, | |
149 | + gen_op_movl_T1_r1, | |
150 | + gen_op_movl_T1_r2, | |
151 | + gen_op_movl_T1_r3, | |
152 | + gen_op_movl_T1_r4, | |
153 | + gen_op_movl_T1_r5, | |
154 | + gen_op_movl_T1_r6, | |
155 | + gen_op_movl_T1_r7, | |
156 | + gen_op_movl_T1_r8, | |
157 | + gen_op_movl_T1_r9, | |
158 | + gen_op_movl_T1_r10, | |
159 | + gen_op_movl_T1_r11, | |
160 | + gen_op_movl_T1_r12, | |
161 | + gen_op_movl_T1_r13, | |
162 | + gen_op_movl_T1_r14, | |
163 | + gen_op_movl_T1_r15, | |
164 | + }, | |
165 | + { | |
166 | + gen_op_movl_T2_r0, | |
167 | + gen_op_movl_T2_r1, | |
168 | + gen_op_movl_T2_r2, | |
169 | + gen_op_movl_T2_r3, | |
170 | + gen_op_movl_T2_r4, | |
171 | + gen_op_movl_T2_r5, | |
172 | + gen_op_movl_T2_r6, | |
173 | + gen_op_movl_T2_r7, | |
174 | + gen_op_movl_T2_r8, | |
175 | + gen_op_movl_T2_r9, | |
176 | + gen_op_movl_T2_r10, | |
177 | + gen_op_movl_T2_r11, | |
178 | + gen_op_movl_T2_r12, | |
179 | + gen_op_movl_T2_r13, | |
180 | + gen_op_movl_T2_r14, | |
181 | + gen_op_movl_T2_r15, | |
182 | + }, | |
183 | +}; | |
184 | + | |
185 | +static GenOpFunc *gen_op_movl_reg_TN[2][16] = { | |
186 | + { | |
187 | + gen_op_movl_r0_T0, | |
188 | + gen_op_movl_r1_T0, | |
189 | + gen_op_movl_r2_T0, | |
190 | + gen_op_movl_r3_T0, | |
191 | + gen_op_movl_r4_T0, | |
192 | + gen_op_movl_r5_T0, | |
193 | + gen_op_movl_r6_T0, | |
194 | + gen_op_movl_r7_T0, | |
195 | + gen_op_movl_r8_T0, | |
196 | + gen_op_movl_r9_T0, | |
197 | + gen_op_movl_r10_T0, | |
198 | + gen_op_movl_r11_T0, | |
199 | + gen_op_movl_r12_T0, | |
200 | + gen_op_movl_r13_T0, | |
201 | + gen_op_movl_r14_T0, | |
202 | + gen_op_movl_r15_T0, | |
203 | + }, | |
204 | + { | |
205 | + gen_op_movl_r0_T1, | |
206 | + gen_op_movl_r1_T1, | |
207 | + gen_op_movl_r2_T1, | |
208 | + gen_op_movl_r3_T1, | |
209 | + gen_op_movl_r4_T1, | |
210 | + gen_op_movl_r5_T1, | |
211 | + gen_op_movl_r6_T1, | |
212 | + gen_op_movl_r7_T1, | |
213 | + gen_op_movl_r8_T1, | |
214 | + gen_op_movl_r9_T1, | |
215 | + gen_op_movl_r10_T1, | |
216 | + gen_op_movl_r11_T1, | |
217 | + gen_op_movl_r12_T1, | |
218 | + gen_op_movl_r13_T1, | |
219 | + gen_op_movl_r14_T1, | |
220 | + gen_op_movl_r15_T1, | |
221 | + }, | |
222 | +}; | |
223 | + | |
224 | +static GenOpFunc1 *gen_op_movl_TN_im[3] = { | |
225 | + gen_op_movl_T0_im, | |
226 | + gen_op_movl_T1_im, | |
227 | + gen_op_movl_T2_im, | |
228 | +}; | |
229 | + | |
230 | +static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t) | |
231 | +{ | |
232 | + int val; | |
233 | + | |
234 | + if (reg == 15) { | |
235 | + /* normaly, since we updated PC, we need only to add 4 */ | |
236 | + val = (long)s->pc + 4; | |
237 | + gen_op_movl_TN_im[t](val); | |
238 | + } else { | |
239 | + gen_op_movl_TN_reg[t][reg](); | |
240 | + } | |
241 | +} | |
242 | + | |
243 | +static inline void gen_movl_T0_reg(DisasContext *s, int reg) | |
244 | +{ | |
245 | + gen_movl_TN_reg(s, reg, 0); | |
246 | +} | |
247 | + | |
248 | +static inline void gen_movl_T1_reg(DisasContext *s, int reg) | |
249 | +{ | |
250 | + gen_movl_TN_reg(s, reg, 1); | |
251 | +} | |
252 | + | |
253 | +static inline void gen_movl_T2_reg(DisasContext *s, int reg) | |
254 | +{ | |
255 | + gen_movl_TN_reg(s, reg, 2); | |
256 | +} | |
257 | + | |
258 | +static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t) | |
259 | +{ | |
260 | + gen_op_movl_reg_TN[t][reg](); | |
261 | + if (reg == 15) { | |
262 | + s->is_jmp = DISAS_JUMP; | |
263 | + } | |
264 | +} | |
265 | + | |
266 | +static inline void gen_movl_reg_T0(DisasContext *s, int reg) | |
267 | +{ | |
268 | + gen_movl_reg_TN(s, reg, 0); | |
269 | +} | |
270 | + | |
271 | +static inline void gen_movl_reg_T1(DisasContext *s, int reg) | |
272 | +{ | |
273 | + gen_movl_reg_TN(s, reg, 1); | |
274 | +} | |
275 | + | |
276 | +static inline void gen_add_data_offset(DisasContext *s, unsigned int insn) | |
277 | +{ | |
278 | + int val, rm, shift; | |
279 | + | |
280 | + if (!(insn & (1 << 25))) { | |
281 | + /* immediate */ | |
282 | + val = insn & 0xfff; | |
283 | + if (!(insn & (1 << 23))) | |
284 | + val = -val; | |
285 | + gen_op_addl_T1_im(val); | |
286 | + } else { | |
287 | + /* shift/register */ | |
288 | + rm = (insn) & 0xf; | |
289 | + shift = (insn >> 7) & 0x1f; | |
290 | + gen_movl_T2_reg(s, rm); | |
291 | + if (shift != 0) { | |
292 | + gen_shift_T2_im[(insn >> 5) & 3](shift); | |
293 | + } | |
294 | + if (!(insn & (1 << 23))) | |
295 | + gen_op_subl_T1_T2(); | |
296 | + else | |
297 | + gen_op_addl_T1_T2(); | |
298 | + } | |
299 | +} | |
300 | + | |
301 | +static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn) | |
302 | +{ | |
303 | + int val, rm; | |
304 | + | |
305 | + if (insn & (1 << 22)) { | |
306 | + /* immediate */ | |
307 | + val = (insn & 0xf) | ((insn >> 4) & 0xf0); | |
308 | + if (!(insn & (1 << 23))) | |
309 | + val = -val; | |
310 | + gen_op_addl_T1_im(val); | |
311 | + } else { | |
312 | + /* register */ | |
313 | + rm = (insn) & 0xf; | |
314 | + gen_movl_T2_reg(s, rm); | |
315 | + if (!(insn & (1 << 23))) | |
316 | + gen_op_subl_T1_T2(); | |
317 | + else | |
318 | + gen_op_addl_T1_T2(); | |
319 | + } | |
320 | +} | |
321 | + | |
322 | +static void disas_arm_insn(DisasContext *s) | |
323 | +{ | |
324 | + unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; | |
325 | + | |
326 | + insn = ldl(s->pc); | |
327 | + s->pc += 4; | |
328 | + | |
329 | + cond = insn >> 28; | |
330 | + if (cond == 0xf) | |
331 | + goto illegal_op; | |
332 | + if (cond != 0xe) { | |
333 | + /* if not always execute, we generate a conditional jump to | |
334 | + next instruction */ | |
335 | + gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); | |
336 | + s->is_jmp = 1; | |
337 | + } | |
338 | + if ((insn & 0x0c000000) == 0 && | |
339 | + (insn & 0x00000090) != 0x90) { | |
340 | + int set_cc, logic_cc, shiftop; | |
341 | + | |
342 | + op1 = (insn >> 21) & 0xf; | |
343 | + set_cc = (insn >> 20) & 1; | |
344 | + logic_cc = table_logic_cc[op1] & set_cc; | |
345 | + | |
346 | + /* data processing instruction */ | |
347 | + if (insn & (1 << 25)) { | |
348 | + /* immediate operand */ | |
349 | + val = insn & 0xff; | |
350 | + shift = ((insn >> 8) & 0xf) * 2; | |
351 | + if (shift) | |
352 | + val = (val >> shift) | (val << (32 - shift)); | |
353 | + gen_op_movl_T1_im(val); | |
354 | + /* XXX: is CF modified ? */ | |
355 | + } else { | |
356 | + /* register */ | |
357 | + rm = (insn) & 0xf; | |
358 | + gen_movl_T1_reg(s, rm); | |
359 | + shiftop = (insn >> 5) & 3; | |
360 | + if (!(insn & (1 << 4))) { | |
361 | + shift = (insn >> 7) & 0x1f; | |
362 | + if (shift != 0) { | |
363 | + if (logic_cc) { | |
364 | + gen_shift_T1_im_cc[shiftop](shift); | |
365 | + } else { | |
366 | + gen_shift_T1_im[shiftop](shift); | |
367 | + } | |
368 | + } | |
369 | + } else { | |
370 | + rs = (insn >> 16) & 0xf; | |
371 | + gen_movl_T0_reg(s, rs); | |
372 | + if (logic_cc) { | |
373 | + gen_shift_T1_T0_cc[shiftop](); | |
374 | + } else { | |
375 | + gen_shift_T1_T0[shiftop](); | |
376 | + } | |
377 | + } | |
378 | + } | |
379 | + if (op1 != 0x0f && op1 != 0x0d) { | |
380 | + rn = (insn >> 16) & 0xf; | |
381 | + gen_movl_T0_reg(s, rn); | |
382 | + } | |
383 | + rd = (insn >> 12) & 0xf; | |
384 | + switch(op1) { | |
385 | + case 0x00: | |
386 | + gen_op_andl_T0_T1(); | |
387 | + gen_movl_reg_T0(s, rd); | |
388 | + break; | |
389 | + case 0x01: | |
390 | + gen_op_xorl_T0_T1(); | |
391 | + gen_movl_reg_T0(s, rd); | |
392 | + break; | |
393 | + case 0x02: | |
394 | + if (set_cc) | |
395 | + gen_op_subl_T0_T1_cc(); | |
396 | + else | |
397 | + gen_op_subl_T0_T1(); | |
398 | + gen_movl_reg_T0(s, rd); | |
399 | + break; | |
400 | + case 0x03: | |
401 | + if (set_cc) | |
402 | + gen_op_rsbl_T0_T1_cc(); | |
403 | + else | |
404 | + gen_op_rsbl_T0_T1(); | |
405 | + gen_movl_reg_T0(s, rd); | |
406 | + break; | |
407 | + case 0x04: | |
408 | + if (set_cc) | |
409 | + gen_op_addl_T0_T1_cc(); | |
410 | + else | |
411 | + gen_op_addl_T0_T1(); | |
412 | + gen_movl_reg_T0(s, rd); | |
413 | + break; | |
414 | + case 0x05: | |
415 | + if (set_cc) | |
416 | + gen_op_adcl_T0_T1_cc(); | |
417 | + else | |
418 | + gen_op_adcl_T0_T1(); | |
419 | + gen_movl_reg_T0(s, rd); | |
420 | + break; | |
421 | + case 0x06: | |
422 | + if (set_cc) | |
423 | + gen_op_sbcl_T0_T1_cc(); | |
424 | + else | |
425 | + gen_op_sbcl_T0_T1(); | |
426 | + gen_movl_reg_T0(s, rd); | |
427 | + break; | |
428 | + case 0x07: | |
429 | + if (set_cc) | |
430 | + gen_op_rscl_T0_T1_cc(); | |
431 | + else | |
432 | + gen_op_rscl_T0_T1(); | |
433 | + gen_movl_reg_T0(s, rd); | |
434 | + break; | |
435 | + case 0x08: | |
436 | + if (set_cc) { | |
437 | + gen_op_andl_T0_T1(); | |
438 | + } | |
439 | + break; | |
440 | + case 0x09: | |
441 | + if (set_cc) { | |
442 | + gen_op_xorl_T0_T1(); | |
443 | + } | |
444 | + break; | |
445 | + case 0x0a: | |
446 | + if (set_cc) { | |
447 | + gen_op_subl_T0_T1_cc(); | |
448 | + } | |
449 | + break; | |
450 | + case 0x0b: | |
451 | + if (set_cc) { | |
452 | + gen_op_addl_T0_T1_cc(); | |
453 | + } | |
454 | + break; | |
455 | + case 0x0c: | |
456 | + gen_op_orl_T0_T1(); | |
457 | + gen_movl_reg_T0(s, rd); | |
458 | + break; | |
459 | + case 0x0d: | |
460 | + gen_movl_reg_T1(s, rd); | |
461 | + break; | |
462 | + case 0x0e: | |
463 | + gen_op_bicl_T0_T1(); | |
464 | + gen_movl_reg_T0(s, rd); | |
465 | + break; | |
466 | + default: | |
467 | + case 0x0f: | |
468 | + gen_op_notl_T1(); | |
469 | + gen_movl_reg_T1(s, rd); | |
470 | + break; | |
471 | + } | |
472 | + if (logic_cc) | |
473 | + gen_op_logic_cc(); | |
474 | + } else { | |
475 | + /* other instructions */ | |
476 | + op1 = (insn >> 24) & 0xf; | |
477 | + switch(op1) { | |
478 | + case 0x0: | |
479 | + case 0x1: | |
480 | + sh = (insn >> 5) & 3; | |
481 | + if (sh == 0) { | |
482 | + if (op1 == 0x0) { | |
483 | + rd = (insn >> 16) & 0xf; | |
484 | + rn = (insn >> 12) & 0xf; | |
485 | + rs = (insn >> 8) & 0xf; | |
486 | + rm = (insn) & 0xf; | |
487 | + if (!(insn & (1 << 23))) { | |
488 | + /* 32 bit mul */ | |
489 | + gen_movl_T0_reg(s, rs); | |
490 | + gen_movl_T1_reg(s, rm); | |
491 | + gen_op_mul_T0_T1(); | |
492 | + if (insn & (1 << 21)) { | |
493 | + gen_movl_T1_reg(s, rn); | |
494 | + gen_op_addl_T0_T1(); | |
495 | + } | |
496 | + if (insn & (1 << 20)) | |
497 | + gen_op_logic_cc(); | |
498 | + gen_movl_reg_T0(s, rd); | |
499 | + } else { | |
500 | + /* 64 bit mul */ | |
501 | + gen_movl_T0_reg(s, rs); | |
502 | + gen_movl_T1_reg(s, rm); | |
503 | + if (insn & (1 << 22)) | |
504 | + gen_op_mull_T0_T1(); | |
505 | + else | |
506 | + gen_op_imull_T0_T1(); | |
507 | + if (insn & (1 << 21)) | |
508 | + gen_op_addq_T0_T1(rn, rd); | |
509 | + if (insn & (1 << 20)) | |
510 | + gen_op_logicq_cc(); | |
511 | + gen_movl_reg_T0(s, rn); | |
512 | + gen_movl_reg_T1(s, rd); | |
513 | + } | |
514 | + } else { | |
515 | + /* SWP instruction */ | |
516 | + rn = (insn >> 16) & 0xf; | |
517 | + rd = (insn >> 12) & 0xf; | |
518 | + rm = (insn) & 0xf; | |
519 | + | |
520 | + gen_movl_T0_reg(s, rm); | |
521 | + gen_movl_T1_reg(s, rn); | |
522 | + if (insn & (1 << 22)) { | |
523 | + gen_op_swpb_T0_T1(); | |
524 | + } else { | |
525 | + gen_op_swpl_T0_T1(); | |
526 | + } | |
527 | + gen_movl_reg_T0(s, rd); | |
528 | + } | |
529 | + } else { | |
530 | + /* load/store half word */ | |
531 | + rn = (insn >> 16) & 0xf; | |
532 | + rd = (insn >> 12) & 0xf; | |
533 | + gen_movl_T1_reg(s, rn); | |
534 | + if (insn & (1 << 25)) | |
535 | + gen_add_datah_offset(s, insn); | |
536 | + if (insn & (1 << 20)) { | |
537 | + /* load */ | |
538 | + switch(sh) { | |
539 | + case 1: | |
540 | + gen_op_lduw_T0_T1(); | |
541 | + break; | |
542 | + case 2: | |
543 | + gen_op_ldsb_T0_T1(); | |
544 | + break; | |
545 | + default: | |
546 | + case 3: | |
547 | + gen_op_ldsw_T0_T1(); | |
548 | + break; | |
549 | + } | |
550 | + } else { | |
551 | + /* store */ | |
552 | + gen_op_stw_T0_T1(); | |
553 | + } | |
554 | + if (!(insn & (1 << 24))) | |
555 | + gen_add_datah_offset(s, insn); | |
556 | + if (insn & (1 << 21)) | |
557 | + gen_movl_reg_T1(s, rn); | |
558 | + } | |
559 | + break; | |
560 | + case 0x4: | |
561 | + case 0x5: | |
562 | + case 0x6: | |
563 | + case 0x7: | |
564 | + /* load/store byte/word */ | |
565 | + rn = (insn >> 16) & 0xf; | |
566 | + rd = (insn >> 12) & 0xf; | |
567 | + gen_movl_T1_reg(s, rn); | |
568 | + if (insn & (1 << 24)) | |
569 | + gen_add_data_offset(s, insn); | |
570 | + if (insn & (1 << 20)) { | |
571 | + /* load */ | |
572 | + if (insn & (1 << 22)) | |
573 | + gen_op_ldub_T0_T1(); | |
574 | + else | |
575 | + gen_op_ldl_T0_T1(); | |
576 | + gen_movl_reg_T0(s, rd); | |
577 | + } else { | |
578 | + /* store */ | |
579 | + gen_movl_T0_reg(s, rd); | |
580 | + if (insn & (1 << 22)) | |
581 | + gen_op_stb_T0_T1(); | |
582 | + else | |
583 | + gen_op_stl_T0_T1(); | |
584 | + } | |
585 | + if (!(insn & (1 << 24))) | |
586 | + gen_add_data_offset(s, insn); | |
587 | + if (insn & (1 << 21)) | |
588 | + gen_movl_reg_T1(s, rn); | |
589 | + break; | |
590 | + case 0x08: | |
591 | + case 0x09: | |
592 | + /* load/store multiple words */ | |
593 | + if (insn & (1 << 22)) | |
594 | + goto illegal_op; /* only usable in supervisor mode */ | |
595 | + rn = (insn >> 16) & 0xf; | |
596 | + gen_movl_T1_reg(s, rn); | |
597 | + val = 4; | |
598 | + if (!(insn & (1 << 23))) | |
599 | + val = -val; | |
600 | + for(i=0;i<16;i++) { | |
601 | + if (insn & (1 << i)) { | |
602 | + if (insn & (1 << 24)) | |
603 | + gen_op_addl_T1_im(val); | |
604 | + if (insn & (1 << 20)) { | |
605 | + /* load */ | |
606 | + gen_op_ldl_T0_T1(); | |
607 | + gen_movl_reg_T0(s, i); | |
608 | + } else { | |
609 | + /* store */ | |
610 | + gen_movl_T0_reg(s, i); | |
611 | + gen_op_stl_T0_T1(); | |
612 | + } | |
613 | + if (!(insn & (1 << 24))) | |
614 | + gen_op_addl_T1_im(val); | |
615 | + } | |
616 | + } | |
617 | + if (insn & (1 << 21)) | |
618 | + gen_movl_reg_T1(s, rn); | |
619 | + break; | |
620 | + case 0xa: | |
621 | + case 0xb: | |
622 | + { | |
623 | + int offset; | |
624 | + | |
625 | + /* branch (and link) */ | |
626 | + val = (int)s->pc; | |
627 | + if (insn & (1 << 24)) { | |
628 | + gen_op_movl_T0_im(val); | |
629 | + gen_op_movl_reg_TN[0][14](); | |
630 | + } | |
631 | + offset = (((int)insn << 8) >> 8); | |
632 | + val += (offset << 2) + 4; | |
633 | + gen_op_jmp((long)s->tb, val); | |
634 | + s->is_jmp = DISAS_TB_JUMP; | |
635 | + } | |
636 | + break; | |
637 | + case 0xf: | |
638 | + /* swi */ | |
639 | + gen_op_movl_T0_im((long)s->pc); | |
640 | + gen_op_movl_reg_TN[0][15](); | |
641 | + gen_op_swi(); | |
642 | + s->is_jmp = DISAS_JUMP; | |
643 | + break; | |
644 | + default: | |
645 | + illegal_op: | |
646 | + gen_op_movl_T0_im((long)s->pc - 4); | |
647 | + gen_op_movl_reg_TN[0][15](); | |
648 | + gen_op_undef_insn(); | |
649 | + s->is_jmp = DISAS_JUMP; | |
650 | + break; | |
651 | + } | |
652 | + } | |
653 | +} | |
654 | + | |
655 | +/* generate intermediate code in gen_opc_buf and gen_opparam_buf for | |
656 | + basic block 'tb'. If search_pc is TRUE, also generate PC | |
657 | + information for each intermediate instruction. */ | |
658 | +int gen_intermediate_code(TranslationBlock *tb, int search_pc) | |
659 | +{ | |
660 | + DisasContext dc1, *dc = &dc1; | |
661 | + uint16_t *gen_opc_end; | |
662 | + int j, lj; | |
663 | + uint8_t *pc_start; | |
664 | + | |
665 | + /* generate intermediate code */ | |
666 | + pc_start = (uint8_t *)tb->pc; | |
667 | + | |
668 | + dc->tb = tb; | |
669 | + | |
670 | + gen_opc_ptr = gen_opc_buf; | |
671 | + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; | |
672 | + gen_opparam_ptr = gen_opparam_buf; | |
673 | + | |
674 | + dc->is_jmp = DISAS_NEXT; | |
675 | + dc->pc = pc_start; | |
676 | + lj = -1; | |
677 | + do { | |
678 | + if (search_pc) { | |
679 | + j = gen_opc_ptr - gen_opc_buf; | |
680 | + if (lj < j) { | |
681 | + lj++; | |
682 | + while (lj < j) | |
683 | + gen_opc_instr_start[lj++] = 0; | |
684 | + gen_opc_pc[lj] = (uint32_t)dc->pc; | |
685 | + gen_opc_instr_start[lj] = 1; | |
686 | + } | |
687 | + } | |
688 | + disas_arm_insn(dc); | |
689 | + } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && | |
690 | + (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); | |
691 | + /* we must store the eflags state if it is not already done */ | |
692 | + if (dc->is_jmp != DISAS_TB_JUMP && | |
693 | + dc->is_jmp != DISAS_JUMP) { | |
694 | + gen_op_movl_T0_im((long)dc->pc - 4); | |
695 | + gen_op_movl_reg_TN[0][15](); | |
696 | + } | |
697 | + if (dc->is_jmp != DISAS_TB_JUMP) { | |
698 | + /* indicate that the hash table must be used to find the next TB */ | |
699 | + gen_op_movl_T0_0(); | |
700 | + } | |
701 | + *gen_opc_ptr = INDEX_op_end; | |
702 | + | |
703 | +#ifdef DEBUG_DISAS | |
704 | + if (loglevel) { | |
705 | + fprintf(logfile, "----------------\n"); | |
706 | + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); | |
707 | + disas(logfile, pc_start, dc->pc - pc_start, 0, 0); | |
708 | + fprintf(logfile, "\n"); | |
709 | + | |
710 | + fprintf(logfile, "OP:\n"); | |
711 | + dump_ops(gen_opc_buf, gen_opparam_buf); | |
712 | + fprintf(logfile, "\n"); | |
713 | + } | |
714 | +#endif | |
715 | + if (!search_pc) | |
716 | + tb->size = dc->pc - pc_start; | |
717 | + return 0; | |
718 | +} | |
719 | + | |
720 | +CPUARMState *cpu_arm_init(void) | |
721 | +{ | |
722 | + CPUARMState *env; | |
723 | + | |
724 | + cpu_exec_init(); | |
725 | + | |
726 | + env = malloc(sizeof(CPUARMState)); | |
727 | + if (!env) | |
728 | + return NULL; | |
729 | + memset(env, 0, sizeof(CPUARMState)); | |
730 | + return env; | |
731 | +} | |
732 | + | |
733 | +void cpu_arm_close(CPUARMState *env) | |
734 | +{ | |
735 | + free(env); | |
736 | +} | |
737 | + | |
738 | +void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags) | |
739 | +{ | |
740 | + int i; | |
741 | + | |
742 | + for(i=0;i<16;i++) { | |
743 | + fprintf(f, "R%02d=%08x", i, env->regs[i]); | |
744 | + if ((i % 4) == 3) | |
745 | + fprintf(f, "\n"); | |
746 | + else | |
747 | + fprintf(f, " "); | |
748 | + } | |
749 | + fprintf(f, "CPSR=%08x", env->cpsr); | |
750 | +} | ... | ... |