]> git.proxmox.com Git - qemu.git/blame - target-arm/translate.c
test and set fixes
[qemu.git] / target-arm / translate.c
CommitLineData
2c0262af
FB
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.h"
27#include "exec-all.h"
28#include "disas.h"
29
30/* internal defines */
31typedef struct DisasContext {
0fa85d43 32 target_ulong pc;
2c0262af
FB
33 int is_jmp;
34 struct TranslationBlock *tb;
35} DisasContext;
36
37#define DISAS_JUMP_NEXT 4
38
39/* XXX: move that elsewhere */
40static uint16_t *gen_opc_ptr;
41static uint32_t *gen_opparam_ptr;
42extern FILE *logfile;
43extern int loglevel;
44
45enum {
46#define DEF(s, n, copy_size) INDEX_op_ ## s,
47#include "opc.h"
48#undef DEF
49 NB_OPS,
50};
51
52#include "gen-op.h"
53
2c0262af
FB
54static GenOpFunc2 *gen_test_cc[14] = {
55 gen_op_test_eq,
56 gen_op_test_ne,
57 gen_op_test_cs,
58 gen_op_test_cc,
59 gen_op_test_mi,
60 gen_op_test_pl,
61 gen_op_test_vs,
62 gen_op_test_vc,
63 gen_op_test_hi,
64 gen_op_test_ls,
65 gen_op_test_ge,
66 gen_op_test_lt,
67 gen_op_test_gt,
68 gen_op_test_le,
69};
70
71const uint8_t table_logic_cc[16] = {
72 1, /* and */
73 1, /* xor */
74 0, /* sub */
75 0, /* rsb */
76 0, /* add */
77 0, /* adc */
78 0, /* sbc */
79 0, /* rsc */
80 1, /* andl */
81 1, /* xorl */
82 0, /* cmp */
83 0, /* cmn */
84 1, /* orr */
85 1, /* mov */
86 1, /* bic */
87 1, /* mvn */
88};
89
90static GenOpFunc1 *gen_shift_T1_im[4] = {
91 gen_op_shll_T1_im,
92 gen_op_shrl_T1_im,
93 gen_op_sarl_T1_im,
94 gen_op_rorl_T1_im,
95};
96
1e8d4eec
FB
97static GenOpFunc *gen_shift_T1_0[4] = {
98 NULL,
99 gen_op_shrl_T1_0,
100 gen_op_sarl_T1_0,
101 gen_op_rrxl_T1,
102};
103
2c0262af
FB
104static GenOpFunc1 *gen_shift_T2_im[4] = {
105 gen_op_shll_T2_im,
106 gen_op_shrl_T2_im,
107 gen_op_sarl_T2_im,
108 gen_op_rorl_T2_im,
109};
110
1e8d4eec
FB
111static GenOpFunc *gen_shift_T2_0[4] = {
112 NULL,
113 gen_op_shrl_T2_0,
114 gen_op_sarl_T2_0,
115 gen_op_rrxl_T2,
116};
117
2c0262af
FB
118static GenOpFunc1 *gen_shift_T1_im_cc[4] = {
119 gen_op_shll_T1_im_cc,
120 gen_op_shrl_T1_im_cc,
121 gen_op_sarl_T1_im_cc,
122 gen_op_rorl_T1_im_cc,
123};
124
1e8d4eec
FB
125static GenOpFunc *gen_shift_T1_0_cc[4] = {
126 NULL,
127 gen_op_shrl_T1_0_cc,
128 gen_op_sarl_T1_0_cc,
129 gen_op_rrxl_T1_cc,
130};
131
2c0262af
FB
132static GenOpFunc *gen_shift_T1_T0[4] = {
133 gen_op_shll_T1_T0,
134 gen_op_shrl_T1_T0,
135 gen_op_sarl_T1_T0,
136 gen_op_rorl_T1_T0,
137};
138
139static GenOpFunc *gen_shift_T1_T0_cc[4] = {
140 gen_op_shll_T1_T0_cc,
141 gen_op_shrl_T1_T0_cc,
142 gen_op_sarl_T1_T0_cc,
143 gen_op_rorl_T1_T0_cc,
144};
145
146static GenOpFunc *gen_op_movl_TN_reg[3][16] = {
147 {
148 gen_op_movl_T0_r0,
149 gen_op_movl_T0_r1,
150 gen_op_movl_T0_r2,
151 gen_op_movl_T0_r3,
152 gen_op_movl_T0_r4,
153 gen_op_movl_T0_r5,
154 gen_op_movl_T0_r6,
155 gen_op_movl_T0_r7,
156 gen_op_movl_T0_r8,
157 gen_op_movl_T0_r9,
158 gen_op_movl_T0_r10,
159 gen_op_movl_T0_r11,
160 gen_op_movl_T0_r12,
161 gen_op_movl_T0_r13,
162 gen_op_movl_T0_r14,
163 gen_op_movl_T0_r15,
164 },
165 {
166 gen_op_movl_T1_r0,
167 gen_op_movl_T1_r1,
168 gen_op_movl_T1_r2,
169 gen_op_movl_T1_r3,
170 gen_op_movl_T1_r4,
171 gen_op_movl_T1_r5,
172 gen_op_movl_T1_r6,
173 gen_op_movl_T1_r7,
174 gen_op_movl_T1_r8,
175 gen_op_movl_T1_r9,
176 gen_op_movl_T1_r10,
177 gen_op_movl_T1_r11,
178 gen_op_movl_T1_r12,
179 gen_op_movl_T1_r13,
180 gen_op_movl_T1_r14,
181 gen_op_movl_T1_r15,
182 },
183 {
184 gen_op_movl_T2_r0,
185 gen_op_movl_T2_r1,
186 gen_op_movl_T2_r2,
187 gen_op_movl_T2_r3,
188 gen_op_movl_T2_r4,
189 gen_op_movl_T2_r5,
190 gen_op_movl_T2_r6,
191 gen_op_movl_T2_r7,
192 gen_op_movl_T2_r8,
193 gen_op_movl_T2_r9,
194 gen_op_movl_T2_r10,
195 gen_op_movl_T2_r11,
196 gen_op_movl_T2_r12,
197 gen_op_movl_T2_r13,
198 gen_op_movl_T2_r14,
199 gen_op_movl_T2_r15,
200 },
201};
202
203static GenOpFunc *gen_op_movl_reg_TN[2][16] = {
204 {
205 gen_op_movl_r0_T0,
206 gen_op_movl_r1_T0,
207 gen_op_movl_r2_T0,
208 gen_op_movl_r3_T0,
209 gen_op_movl_r4_T0,
210 gen_op_movl_r5_T0,
211 gen_op_movl_r6_T0,
212 gen_op_movl_r7_T0,
213 gen_op_movl_r8_T0,
214 gen_op_movl_r9_T0,
215 gen_op_movl_r10_T0,
216 gen_op_movl_r11_T0,
217 gen_op_movl_r12_T0,
218 gen_op_movl_r13_T0,
219 gen_op_movl_r14_T0,
220 gen_op_movl_r15_T0,
221 },
222 {
223 gen_op_movl_r0_T1,
224 gen_op_movl_r1_T1,
225 gen_op_movl_r2_T1,
226 gen_op_movl_r3_T1,
227 gen_op_movl_r4_T1,
228 gen_op_movl_r5_T1,
229 gen_op_movl_r6_T1,
230 gen_op_movl_r7_T1,
231 gen_op_movl_r8_T1,
232 gen_op_movl_r9_T1,
233 gen_op_movl_r10_T1,
234 gen_op_movl_r11_T1,
235 gen_op_movl_r12_T1,
236 gen_op_movl_r13_T1,
237 gen_op_movl_r14_T1,
238 gen_op_movl_r15_T1,
239 },
240};
241
242static GenOpFunc1 *gen_op_movl_TN_im[3] = {
243 gen_op_movl_T0_im,
244 gen_op_movl_T1_im,
245 gen_op_movl_T2_im,
246};
247
99c475ab
FB
248static GenOpFunc1 *gen_shift_T0_im_thumb[3] = {
249 gen_op_shll_T0_im_thumb,
250 gen_op_shrl_T0_im_thumb,
251 gen_op_sarl_T0_im_thumb,
252};
253
254static inline void gen_bx(DisasContext *s)
255{
256 s->is_jmp = DISAS_UPDATE;
257 gen_op_bx_T0();
258}
259
2c0262af
FB
260static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t)
261{
262 int val;
263
264 if (reg == 15) {
265 /* normaly, since we updated PC, we need only to add 4 */
266 val = (long)s->pc + 4;
267 gen_op_movl_TN_im[t](val);
268 } else {
269 gen_op_movl_TN_reg[t][reg]();
270 }
271}
272
273static inline void gen_movl_T0_reg(DisasContext *s, int reg)
274{
275 gen_movl_TN_reg(s, reg, 0);
276}
277
278static inline void gen_movl_T1_reg(DisasContext *s, int reg)
279{
280 gen_movl_TN_reg(s, reg, 1);
281}
282
283static inline void gen_movl_T2_reg(DisasContext *s, int reg)
284{
285 gen_movl_TN_reg(s, reg, 2);
286}
287
288static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
289{
290 gen_op_movl_reg_TN[t][reg]();
291 if (reg == 15) {
292 s->is_jmp = DISAS_JUMP;
293 }
294}
295
296static inline void gen_movl_reg_T0(DisasContext *s, int reg)
297{
298 gen_movl_reg_TN(s, reg, 0);
299}
300
301static inline void gen_movl_reg_T1(DisasContext *s, int reg)
302{
303 gen_movl_reg_TN(s, reg, 1);
304}
305
306static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
307{
1e8d4eec 308 int val, rm, shift, shiftop;
2c0262af
FB
309
310 if (!(insn & (1 << 25))) {
311 /* immediate */
312 val = insn & 0xfff;
313 if (!(insn & (1 << 23)))
314 val = -val;
537730b9
FB
315 if (val != 0)
316 gen_op_addl_T1_im(val);
2c0262af
FB
317 } else {
318 /* shift/register */
319 rm = (insn) & 0xf;
320 shift = (insn >> 7) & 0x1f;
321 gen_movl_T2_reg(s, rm);
1e8d4eec 322 shiftop = (insn >> 5) & 3;
2c0262af 323 if (shift != 0) {
1e8d4eec
FB
324 gen_shift_T2_im[shiftop](shift);
325 } else if (shiftop != 0) {
326 gen_shift_T2_0[shiftop]();
2c0262af
FB
327 }
328 if (!(insn & (1 << 23)))
329 gen_op_subl_T1_T2();
330 else
331 gen_op_addl_T1_T2();
332 }
333}
334
335static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn)
336{
337 int val, rm;
338
339 if (insn & (1 << 22)) {
340 /* immediate */
341 val = (insn & 0xf) | ((insn >> 4) & 0xf0);
342 if (!(insn & (1 << 23)))
343 val = -val;
537730b9
FB
344 if (val != 0)
345 gen_op_addl_T1_im(val);
2c0262af
FB
346 } else {
347 /* register */
348 rm = (insn) & 0xf;
349 gen_movl_T2_reg(s, rm);
350 if (!(insn & (1 << 23)))
351 gen_op_subl_T1_T2();
352 else
353 gen_op_addl_T1_T2();
354 }
355}
356
357static void disas_arm_insn(DisasContext *s)
358{
359 unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
360
361 insn = ldl(s->pc);
362 s->pc += 4;
363
364 cond = insn >> 28;
99c475ab
FB
365 if (cond == 0xf){
366 if ((insn & 0x0d70f000) == 0x0550f000)
367 return; /* PLD */
368 else if ((insn & 0x0e000000) == 0x0a000000) {
369 /* branch link and change to thumb (blx <offset>) */
370 int32_t offset;
371
372 val = (uint32_t)s->pc;
373 gen_op_movl_T0_im(val);
374 gen_movl_reg_T0(s, 14);
375 /* Sign-extend the 24-bit offset */
376 offset = (((int32_t)insn) << 8) >> 8;
377 /* offset * 4 + bit24 * 2 + (thumb bit) */
378 val += (offset << 2) | ((insn >> 23) & 2) | 1;
379 /* pipeline offset */
380 val += 4;
381 gen_op_movl_T0_im(val);
382 gen_bx(s);
383 return;
384 }
2c0262af 385 goto illegal_op;
99c475ab 386 }
2c0262af
FB
387 if (cond != 0xe) {
388 /* if not always execute, we generate a conditional jump to
389 next instruction */
390 gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
391 s->is_jmp = DISAS_JUMP_NEXT;
392 }
99c475ab
FB
393 if ((insn & 0x0f900000) == 0x03000000) {
394 if ((insn & 0x0ff0f000) != 0x0360f000)
395 goto illegal_op;
396 /* CPSR = immediate */
397 val = insn & 0xff;
398 shift = ((insn >> 8) & 0xf) * 2;
399 if (shift)
400 val = (val >> shift) | (val << (32 - shift));
401 gen_op_movl_T0_im(val);
402 if (insn & (1 << 19))
403 gen_op_movl_psr_T0();
404 } else if ((insn & 0x0f900000) == 0x01000000
405 && (insn & 0x00000090) != 0x00000090) {
406 /* miscellaneous instructions */
407 op1 = (insn >> 21) & 3;
408 sh = (insn >> 4) & 0xf;
409 rm = insn & 0xf;
410 switch (sh) {
411 case 0x0: /* move program status register */
412 if (op1 & 2) {
413 /* SPSR not accessible in user mode */
414 goto illegal_op;
415 }
416 if (op1 & 1) {
417 /* CPSR = reg */
418 gen_movl_T0_reg(s, rm);
419 if (insn & (1 << 19))
420 gen_op_movl_psr_T0();
421 } else {
422 /* reg = CPSR */
423 rd = (insn >> 12) & 0xf;
424 gen_op_movl_T0_psr();
425 gen_movl_reg_T0(s, rd);
426 }
427 case 0x1:
428 if (op1 == 1) {
429 /* branch/exchange thumb (bx). */
430 gen_movl_T0_reg(s, rm);
431 gen_bx(s);
432 } else if (op1 == 3) {
433 /* clz */
434 rd = (insn >> 12) & 0xf;
435 gen_movl_T0_reg(s, rm);
436 gen_op_clz_T0();
437 gen_movl_reg_T0(s, rd);
438 } else {
439 goto illegal_op;
440 }
441 break;
442 case 0x3:
443 if (op1 != 1)
444 goto illegal_op;
445
446 /* branch link/exchange thumb (blx) */
447 val = (uint32_t)s->pc;
448 gen_op_movl_T0_im(val);
449 gen_movl_reg_T0(s, 14);
450 gen_movl_T0_reg(s, rm);
451 gen_bx(s);
452 break;
453 case 0x5: /* saturating add/subtract */
454 rd = (insn >> 12) & 0xf;
455 rn = (insn >> 16) & 0xf;
456 gen_movl_T0_reg(s, rn);
457 if (op1 & 2) {
458 gen_movl_T1_reg(s, rn);
459 if (op1 & 1)
460 gen_op_subl_T0_T1_saturate();
461 else
462 gen_op_addl_T0_T1_saturate();
463 }
464 gen_movl_T1_reg(s, rm);
465 if (op1 & 1)
466 gen_op_subl_T0_T1_saturate();
467 else
468 gen_op_addl_T0_T1_saturate();
469 gen_movl_reg_T0(s, rn);
470 break;
471 case 0x8: /* signed multiply */
472 case 0xa:
473 case 0xc:
474 case 0xe:
475 rs = (insn >> 8) & 0xf;
476 rn = (insn >> 12) & 0xf;
477 rd = (insn >> 16) & 0xf;
478 if (op1 == 1) {
479 /* (32 * 16) >> 16 */
480 gen_movl_T0_reg(s, rm);
481 gen_movl_T1_reg(s, rs);
482 if (sh & 4)
483 gen_op_sarl_T1_im(16);
484 else
485 gen_op_sxl_T1();
486 gen_op_imulw_T0_T1();
487 if ((sh & 2) == 0) {
488 gen_movl_T1_reg(s, rn);
489 gen_op_addl_T0_T1_setq();
490 }
491 gen_movl_reg_T0(s, rd);
492 } else {
493 /* 16 * 16 */
494 gen_movl_T0_reg(s, rm);
495 if (sh & 2)
496 gen_op_sarl_T0_im(16);
497 else
498 gen_op_sxl_T0();
499 gen_movl_T1_reg(s, rs);
500 if (sh & 4)
501 gen_op_sarl_T1_im(16);
502 else
503 gen_op_sxl_T1();
504 if (op1 == 2) {
505 gen_op_imull_T0_T1();
506 gen_op_addq_T0_T1(rn, rd);
507 gen_movl_reg_T0(s, rn);
508 gen_movl_reg_T1(s, rd);
509 } else {
510 gen_op_mul_T0_T1();
511 if (op1 == 0) {
512 gen_movl_T1_reg(s, rn);
513 gen_op_addl_T0_T1_setq();
514 }
515 gen_movl_reg_T0(s, rd);
516 }
517 }
518 break;
519 default:
520 goto illegal_op;
521 }
522 } else if (((insn & 0x0e000000) == 0 &&
523 (insn & 0x00000090) != 0x90) ||
524 ((insn & 0x0e000000) == (1 << 25))) {
2c0262af
FB
525 int set_cc, logic_cc, shiftop;
526
527 op1 = (insn >> 21) & 0xf;
528 set_cc = (insn >> 20) & 1;
529 logic_cc = table_logic_cc[op1] & set_cc;
530
531 /* data processing instruction */
532 if (insn & (1 << 25)) {
533 /* immediate operand */
534 val = insn & 0xff;
535 shift = ((insn >> 8) & 0xf) * 2;
536 if (shift)
537 val = (val >> shift) | (val << (32 - shift));
538 gen_op_movl_T1_im(val);
7ff4d218
FB
539 if (logic_cc && shift)
540 gen_op_mov_CF_T1();
2c0262af
FB
541 } else {
542 /* register */
543 rm = (insn) & 0xf;
544 gen_movl_T1_reg(s, rm);
545 shiftop = (insn >> 5) & 3;
546 if (!(insn & (1 << 4))) {
547 shift = (insn >> 7) & 0x1f;
548 if (shift != 0) {
549 if (logic_cc) {
550 gen_shift_T1_im_cc[shiftop](shift);
551 } else {
552 gen_shift_T1_im[shiftop](shift);
553 }
1e8d4eec
FB
554 } else if (shiftop != 0) {
555 if (logic_cc) {
556 gen_shift_T1_0_cc[shiftop]();
557 } else {
558 gen_shift_T1_0[shiftop]();
559 }
2c0262af
FB
560 }
561 } else {
562 rs = (insn >> 8) & 0xf;
563 gen_movl_T0_reg(s, rs);
564 if (logic_cc) {
565 gen_shift_T1_T0_cc[shiftop]();
566 } else {
567 gen_shift_T1_T0[shiftop]();
568 }
569 }
570 }
571 if (op1 != 0x0f && op1 != 0x0d) {
572 rn = (insn >> 16) & 0xf;
573 gen_movl_T0_reg(s, rn);
574 }
575 rd = (insn >> 12) & 0xf;
576 switch(op1) {
577 case 0x00:
578 gen_op_andl_T0_T1();
579 gen_movl_reg_T0(s, rd);
580 if (logic_cc)
581 gen_op_logic_T0_cc();
582 break;
583 case 0x01:
584 gen_op_xorl_T0_T1();
585 gen_movl_reg_T0(s, rd);
586 if (logic_cc)
587 gen_op_logic_T0_cc();
588 break;
589 case 0x02:
590 if (set_cc)
591 gen_op_subl_T0_T1_cc();
592 else
593 gen_op_subl_T0_T1();
594 gen_movl_reg_T0(s, rd);
595 break;
596 case 0x03:
597 if (set_cc)
598 gen_op_rsbl_T0_T1_cc();
599 else
600 gen_op_rsbl_T0_T1();
601 gen_movl_reg_T0(s, rd);
602 break;
603 case 0x04:
604 if (set_cc)
605 gen_op_addl_T0_T1_cc();
606 else
607 gen_op_addl_T0_T1();
608 gen_movl_reg_T0(s, rd);
609 break;
610 case 0x05:
611 if (set_cc)
612 gen_op_adcl_T0_T1_cc();
613 else
614 gen_op_adcl_T0_T1();
615 gen_movl_reg_T0(s, rd);
616 break;
617 case 0x06:
618 if (set_cc)
619 gen_op_sbcl_T0_T1_cc();
620 else
621 gen_op_sbcl_T0_T1();
622 gen_movl_reg_T0(s, rd);
623 break;
624 case 0x07:
625 if (set_cc)
626 gen_op_rscl_T0_T1_cc();
627 else
628 gen_op_rscl_T0_T1();
629 gen_movl_reg_T0(s, rd);
630 break;
631 case 0x08:
632 if (set_cc) {
633 gen_op_andl_T0_T1();
634 gen_op_logic_T0_cc();
635 }
636 break;
637 case 0x09:
638 if (set_cc) {
639 gen_op_xorl_T0_T1();
640 gen_op_logic_T0_cc();
641 }
642 break;
643 case 0x0a:
644 if (set_cc) {
645 gen_op_subl_T0_T1_cc();
646 }
647 break;
648 case 0x0b:
649 if (set_cc) {
650 gen_op_addl_T0_T1_cc();
651 }
652 break;
653 case 0x0c:
654 gen_op_orl_T0_T1();
655 gen_movl_reg_T0(s, rd);
656 if (logic_cc)
657 gen_op_logic_T0_cc();
658 break;
659 case 0x0d:
660 gen_movl_reg_T1(s, rd);
661 if (logic_cc)
662 gen_op_logic_T1_cc();
663 break;
664 case 0x0e:
665 gen_op_bicl_T0_T1();
666 gen_movl_reg_T0(s, rd);
667 if (logic_cc)
668 gen_op_logic_T0_cc();
669 break;
670 default:
671 case 0x0f:
672 gen_op_notl_T1();
673 gen_movl_reg_T1(s, rd);
674 if (logic_cc)
675 gen_op_logic_T1_cc();
676 break;
677 }
678 } else {
679 /* other instructions */
680 op1 = (insn >> 24) & 0xf;
681 switch(op1) {
682 case 0x0:
683 case 0x1:
99c475ab 684 /* multiplies, extra load/stores */
2c0262af
FB
685 sh = (insn >> 5) & 3;
686 if (sh == 0) {
687 if (op1 == 0x0) {
688 rd = (insn >> 16) & 0xf;
689 rn = (insn >> 12) & 0xf;
690 rs = (insn >> 8) & 0xf;
691 rm = (insn) & 0xf;
99c475ab 692 if (((insn >> 22) & 3) == 0) {
2c0262af
FB
693 /* 32 bit mul */
694 gen_movl_T0_reg(s, rs);
695 gen_movl_T1_reg(s, rm);
696 gen_op_mul_T0_T1();
697 if (insn & (1 << 21)) {
698 gen_movl_T1_reg(s, rn);
699 gen_op_addl_T0_T1();
700 }
701 if (insn & (1 << 20))
702 gen_op_logic_T0_cc();
703 gen_movl_reg_T0(s, rd);
704 } else {
705 /* 64 bit mul */
706 gen_movl_T0_reg(s, rs);
707 gen_movl_T1_reg(s, rm);
708 if (insn & (1 << 22))
2c0262af 709 gen_op_imull_T0_T1();
2e134c9c
FB
710 else
711 gen_op_mull_T0_T1();
99c475ab 712 if (insn & (1 << 21)) /* mult accumulate */
2c0262af 713 gen_op_addq_T0_T1(rn, rd);
99c475ab
FB
714 if (!(insn & (1 << 23))) { /* double accumulate */
715 gen_op_addq_lo_T0_T1(rn);
716 gen_op_addq_lo_T0_T1(rd);
717 }
2c0262af
FB
718 if (insn & (1 << 20))
719 gen_op_logicq_cc();
720 gen_movl_reg_T0(s, rn);
721 gen_movl_reg_T1(s, rd);
722 }
723 } else {
2c0262af
FB
724 rn = (insn >> 16) & 0xf;
725 rd = (insn >> 12) & 0xf;
99c475ab
FB
726 if (insn & (1 << 23)) {
727 /* load/store exclusive */
728 goto illegal_op;
2c0262af 729 } else {
99c475ab
FB
730 /* SWP instruction */
731 rm = (insn) & 0xf;
732
733 gen_movl_T0_reg(s, rm);
734 gen_movl_T1_reg(s, rn);
735 if (insn & (1 << 22)) {
736 gen_op_swpb_T0_T1();
737 } else {
738 gen_op_swpl_T0_T1();
739 }
740 gen_movl_reg_T0(s, rd);
2c0262af 741 }
2c0262af
FB
742 }
743 } else {
99c475ab 744 /* Misc load/store */
2c0262af
FB
745 rn = (insn >> 16) & 0xf;
746 rd = (insn >> 12) & 0xf;
747 gen_movl_T1_reg(s, rn);
beddab75
FB
748 if (insn & (1 << 24))
749 gen_add_datah_offset(s, insn);
2c0262af
FB
750 if (insn & (1 << 20)) {
751 /* load */
752 switch(sh) {
753 case 1:
754 gen_op_lduw_T0_T1();
755 break;
756 case 2:
757 gen_op_ldsb_T0_T1();
758 break;
759 default:
760 case 3:
761 gen_op_ldsw_T0_T1();
762 break;
763 }
e748ba4f 764 gen_movl_reg_T0(s, rd);
99c475ab
FB
765 } else if (sh & 2) {
766 /* doubleword */
767 if (sh & 1) {
768 /* store */
769 gen_movl_T0_reg(s, rd);
770 gen_op_stl_T0_T1();
771 gen_op_addl_T1_im(4);
772 gen_movl_T0_reg(s, rd + 1);
773 gen_op_stl_T0_T1();
774 if ((insn & (1 << 24)) || (insn & (1 << 20)))
775 gen_op_addl_T1_im(-4);
776 } else {
777 /* load */
778 gen_op_ldl_T0_T1();
779 gen_movl_reg_T0(s, rd);
780 gen_op_addl_T1_im(4);
781 gen_op_ldl_T0_T1();
782 gen_movl_reg_T0(s, rd + 1);
783 if ((insn & (1 << 24)) || (insn & (1 << 20)))
784 gen_op_addl_T1_im(-4);
785 }
2c0262af
FB
786 } else {
787 /* store */
e748ba4f 788 gen_movl_T0_reg(s, rd);
2c0262af
FB
789 gen_op_stw_T0_T1();
790 }
791 if (!(insn & (1 << 24))) {
792 gen_add_datah_offset(s, insn);
793 gen_movl_reg_T1(s, rn);
794 } else if (insn & (1 << 21)) {
795 gen_movl_reg_T1(s, rn);
796 }
797 }
798 break;
799 case 0x4:
800 case 0x5:
801 case 0x6:
802 case 0x7:
803 /* load/store byte/word */
804 rn = (insn >> 16) & 0xf;
805 rd = (insn >> 12) & 0xf;
806 gen_movl_T1_reg(s, rn);
807 if (insn & (1 << 24))
808 gen_add_data_offset(s, insn);
809 if (insn & (1 << 20)) {
810 /* load */
811 if (insn & (1 << 22))
812 gen_op_ldub_T0_T1();
813 else
814 gen_op_ldl_T0_T1();
99c475ab
FB
815 if (rd == 15)
816 gen_bx(s);
817 else
818 gen_movl_reg_T0(s, rd);
2c0262af
FB
819 } else {
820 /* store */
821 gen_movl_T0_reg(s, rd);
822 if (insn & (1 << 22))
823 gen_op_stb_T0_T1();
824 else
825 gen_op_stl_T0_T1();
826 }
827 if (!(insn & (1 << 24))) {
828 gen_add_data_offset(s, insn);
829 gen_movl_reg_T1(s, rn);
830 } else if (insn & (1 << 21))
831 gen_movl_reg_T1(s, rn); {
832 }
833 break;
834 case 0x08:
835 case 0x09:
836 {
837 int j, n;
838 /* load/store multiple words */
839 /* XXX: store correct base if write back */
840 if (insn & (1 << 22))
841 goto illegal_op; /* only usable in supervisor mode */
842 rn = (insn >> 16) & 0xf;
843 gen_movl_T1_reg(s, rn);
844
845 /* compute total size */
846 n = 0;
847 for(i=0;i<16;i++) {
848 if (insn & (1 << i))
849 n++;
850 }
851 /* XXX: test invalid n == 0 case ? */
852 if (insn & (1 << 23)) {
853 if (insn & (1 << 24)) {
854 /* pre increment */
855 gen_op_addl_T1_im(4);
856 } else {
857 /* post increment */
858 }
859 } else {
860 if (insn & (1 << 24)) {
861 /* pre decrement */
862 gen_op_addl_T1_im(-(n * 4));
863 } else {
864 /* post decrement */
865 if (n != 1)
866 gen_op_addl_T1_im(-((n - 1) * 4));
867 }
868 }
869 j = 0;
870 for(i=0;i<16;i++) {
871 if (insn & (1 << i)) {
872 if (insn & (1 << 20)) {
873 /* load */
874 gen_op_ldl_T0_T1();
99c475ab
FB
875 if (i == 15)
876 gen_bx(s);
877 else
878 gen_movl_reg_T0(s, i);
2c0262af
FB
879 } else {
880 /* store */
881 if (i == 15) {
882 /* special case: r15 = PC + 12 */
883 val = (long)s->pc + 8;
884 gen_op_movl_TN_im[0](val);
885 } else {
886 gen_movl_T0_reg(s, i);
887 }
888 gen_op_stl_T0_T1();
889 }
890 j++;
891 /* no need to add after the last transfer */
892 if (j != n)
893 gen_op_addl_T1_im(4);
894 }
895 }
896 if (insn & (1 << 21)) {
897 /* write back */
898 if (insn & (1 << 23)) {
899 if (insn & (1 << 24)) {
900 /* pre increment */
901 } else {
902 /* post increment */
903 gen_op_addl_T1_im(4);
904 }
905 } else {
906 if (insn & (1 << 24)) {
907 /* pre decrement */
908 if (n != 1)
909 gen_op_addl_T1_im(-((n - 1) * 4));
910 } else {
911 /* post decrement */
912 gen_op_addl_T1_im(-(n * 4));
913 }
914 }
915 gen_movl_reg_T1(s, rn);
916 }
917 }
918 break;
919 case 0xa:
920 case 0xb:
921 {
99c475ab 922 int32_t offset;
2c0262af
FB
923
924 /* branch (and link) */
99c475ab 925 val = (int32_t)s->pc;
2c0262af
FB
926 if (insn & (1 << 24)) {
927 gen_op_movl_T0_im(val);
928 gen_op_movl_reg_TN[0][14]();
929 }
99c475ab 930 offset = (((int32_t)insn << 8) >> 8);
2c0262af
FB
931 val += (offset << 2) + 4;
932 gen_op_jmp((long)s->tb, val);
933 s->is_jmp = DISAS_TB_JUMP;
934 }
935 break;
936 case 0xf:
937 /* swi */
938 gen_op_movl_T0_im((long)s->pc);
939 gen_op_movl_reg_TN[0][15]();
940 gen_op_swi();
941 s->is_jmp = DISAS_JUMP;
942 break;
2c0262af
FB
943 default:
944 illegal_op:
945 gen_op_movl_T0_im((long)s->pc - 4);
946 gen_op_movl_reg_TN[0][15]();
947 gen_op_undef_insn();
948 s->is_jmp = DISAS_JUMP;
949 break;
950 }
951 }
952}
953
99c475ab
FB
954static void disas_thumb_insn(DisasContext *s)
955{
956 uint32_t val, insn, op, rm, rn, rd, shift, cond;
957 int32_t offset;
958 int i;
959
960 insn = lduw(s->pc);
961 s->pc += 2;
962
963 switch (insn >> 12) {
964 case 0: case 1:
965 rd = insn & 7;
966 op = (insn >> 11) & 3;
967 if (op == 3) {
968 /* add/subtract */
969 rn = (insn >> 3) & 7;
970 gen_movl_T0_reg(s, rn);
971 if (insn & (1 << 10)) {
972 /* immediate */
973 gen_op_movl_T1_im((insn >> 6) & 7);
974 } else {
975 /* reg */
976 rm = (insn >> 6) & 7;
977 gen_movl_T1_reg(s, rm);
978 }
979 if (insn & (1 << 9))
980 gen_op_addl_T0_T1_cc();
981 else
982 gen_op_addl_T0_T1_cc();
983 gen_movl_reg_T0(s, rd);
984 } else {
985 /* shift immediate */
986 rm = (insn >> 3) & 7;
987 shift = (insn >> 6) & 0x1f;
988 gen_movl_T0_reg(s, rm);
989 gen_shift_T0_im_thumb[op](shift);
990 gen_movl_reg_T0(s, rd);
991 }
992 break;
993 case 2: case 3:
994 /* arithmetic large immediate */
995 op = (insn >> 11) & 3;
996 rd = (insn >> 8) & 0x7;
997 if (op == 0) {
998 gen_op_movl_T0_im(insn & 0xff);
999 } else {
1000 gen_movl_T0_reg(s, rd);
1001 gen_op_movl_T1_im(insn & 0xff);
1002 }
1003 switch (op) {
1004 case 0: /* mov */
1005 gen_op_logic_T0_cc();
1006 break;
1007 case 1: /* cmp */
1008 gen_op_subl_T0_T1_cc();
1009 break;
1010 case 2: /* add */
1011 gen_op_addl_T0_T1_cc();
1012 break;
1013 case 3: /* sub */
1014 gen_op_subl_T0_T1_cc();
1015 break;
1016 }
1017 if (op != 1)
1018 gen_movl_reg_T0(s, rd);
1019 break;
1020 case 4:
1021 if (insn & (1 << 11)) {
1022 rd = (insn >> 8) & 7;
1023 /* load pc-relative */
1024 val = (insn & 0xff) * 4;
1025 gen_op_movl_T1_im(val);
1026 gen_movl_T2_reg(s, 15);
1027 gen_op_addl_T1_T2();
1028 gen_op_ldl_T0_T1();
1029 gen_movl_reg_T0(s, rd);
1030 break;
1031 }
1032 if (insn & (1 << 10)) {
1033 /* data processing extended or blx */
1034 rd = (insn & 7) | ((insn >> 4) & 8);
1035 rm = (insn >> 3) & 0xf;
1036 op = (insn >> 8) & 3;
1037 switch (op) {
1038 case 0: /* add */
1039 gen_movl_T0_reg(s, rd);
1040 gen_movl_T1_reg(s, rm);
1041 gen_op_addl_T0_T1();
1042 gen_movl_reg_T0(s, rd);
1043 break;
1044 case 1: /* cmp */
1045 gen_movl_T0_reg(s, rd);
1046 gen_movl_T1_reg(s, rm);
1047 gen_op_subl_T0_T1_cc();
1048 break;
1049 case 2: /* mov/cpy */
1050 gen_movl_T0_reg(s, rm);
1051 gen_movl_reg_T0(s, rd);
1052 break;
1053 case 3:/* branch [and link] exchange thumb register */
1054 if (insn & (1 << 7)) {
1055 val = (uint32_t)s->pc | 1;
1056 gen_op_movl_T1_im(val);
1057 gen_movl_reg_T1(s, 14);
1058 }
1059 gen_movl_T0_reg(s, rm);
1060 gen_bx(s);
1061 break;
1062 }
1063 break;
1064 }
1065
1066 /* data processing register */
1067 rd = insn & 7;
1068 rm = (insn >> 3) & 7;
1069 op = (insn >> 6) & 0xf;
1070 if (op == 2 || op == 3 || op == 4 || op == 7) {
1071 /* the shift/rotate ops want the operands backwards */
1072 val = rm;
1073 rm = rd;
1074 rd = val;
1075 val = 1;
1076 } else {
1077 val = 0;
1078 }
1079
1080 if (op == 9) /* neg */
1081 gen_op_movl_T0_im(0);
1082 else if (op != 0xf) /* mvn doesn't read its first operand */
1083 gen_movl_T0_reg(s, rd);
1084
1085 gen_movl_T1_reg(s, rm);
1086 switch (insn >> 6) {
1087 case 0x0: /* and */
1088 gen_op_andl_T0_T1();
1089 gen_op_logic_T0_cc();
1090 break;
1091 case 0x1: /* eor */
1092 gen_op_xorl_T0_T1();
1093 gen_op_logic_T0_cc();
1094 break;
1095 case 0x2: /* lsl */
1096 gen_op_shll_T1_T0_cc();
1097 break;
1098 case 0x3: /* lsr */
1099 gen_op_shrl_T1_T0_cc();
1100 break;
1101 case 0x4: /* asr */
1102 gen_op_sarl_T1_T0_cc();
1103 break;
1104 case 0x5: /* adc */
1105 gen_op_adcl_T0_T1_cc();
1106 break;
1107 case 0x6: /* sbc */
1108 gen_op_sbcl_T0_T1_cc();
1109 break;
1110 case 0x7: /* ror */
1111 gen_op_rorl_T1_T0_cc();
1112 break;
1113 case 0x8: /* tst */
1114 gen_op_andl_T0_T1();
1115 gen_op_logic_T0_cc();
1116 rd = 16;
1117 case 0x9: /* neg */
1118 gen_op_rsbl_T0_T1_cc();
1119 break;
1120 case 0xa: /* cmp */
1121 gen_op_subl_T0_T1_cc();
1122 rd = 16;
1123 break;
1124 case 0xb: /* cmn */
1125 gen_op_addl_T0_T1_cc();
1126 rd = 16;
1127 break;
1128 case 0xc: /* orr */
1129 gen_op_orl_T0_T1();
1130 gen_op_logic_T0_cc();
1131 break;
1132 case 0xd: /* mul */
1133 gen_op_mull_T0_T1();
1134 gen_op_logic_T0_cc();
1135 break;
1136 case 0xe: /* bic */
1137 gen_op_bicl_T0_T1();
1138 gen_op_logic_T0_cc();
1139 break;
1140 case 0xf: /* mvn */
1141 gen_op_notl_T1();
1142 gen_op_logic_T1_cc();
1143 val = 1;
1144 break;
1145 }
1146 if (rd != 16) {
1147 if (val)
1148 gen_movl_reg_T1(s, rd);
1149 else
1150 gen_movl_reg_T0(s, rd);
1151 }
1152 break;
1153
1154 case 5:
1155 /* load/store register offset. */
1156 rd = insn & 7;
1157 rn = (insn >> 3) & 7;
1158 rm = (insn >> 6) & 7;
1159 op = (insn >> 9) & 7;
1160 gen_movl_T1_reg(s, rn);
1161 gen_movl_T2_reg(s, rm);
1162 gen_op_addl_T1_T2();
1163
1164 if (op < 3) /* store */
1165 gen_movl_T0_reg(s, rd);
1166
1167 switch (op) {
1168 case 0: /* str */
1169 gen_op_stl_T0_T1();
1170 break;
1171 case 1: /* strh */
1172 gen_op_stw_T0_T1();
1173 break;
1174 case 2: /* strb */
1175 gen_op_stb_T0_T1();
1176 break;
1177 case 3: /* ldrsb */
1178 gen_op_ldsb_T0_T1();
1179 break;
1180 case 4: /* ldr */
1181 gen_op_ldl_T0_T1();
1182 break;
1183 case 5: /* ldrh */
1184 gen_op_ldsw_T0_T1();
1185 break;
1186 case 6: /* ldrb */
1187 gen_op_ldub_T0_T1();
1188 break;
1189 case 7: /* ldrsh */
1190 gen_op_ldsw_T0_T1();
1191 break;
1192 }
1193 if (op >= 3) /* load */
1194 gen_movl_reg_T0(s, rd);
1195 break;
1196
1197 case 6:
1198 /* load/store word immediate offset */
1199 rd = insn & 7;
1200 rn = (insn >> 3) & 7;
1201 gen_movl_T1_reg(s, rn);
1202 val = (insn >> 4) & 0x7c;
1203 gen_op_movl_T2_im(val);
1204 gen_op_addl_T1_T2();
1205
1206 if (insn & (1 << 11)) {
1207 /* load */
1208 gen_op_ldl_T0_T1();
1209 gen_movl_reg_T0(s, rd);
1210 } else {
1211 /* store */
1212 gen_movl_T0_reg(s, rd);
1213 gen_op_stl_T0_T1();
1214 }
1215 break;
1216
1217 case 7:
1218 /* load/store byte immediate offset */
1219 rd = insn & 7;
1220 rn = (insn >> 3) & 7;
1221 gen_movl_T1_reg(s, rn);
1222 val = (insn >> 6) & 0x1f;
1223 gen_op_movl_T2_im(val);
1224 gen_op_addl_T1_T2();
1225
1226 if (insn & (1 << 11)) {
1227 /* load */
1228 gen_op_ldub_T0_T1();
1229 gen_movl_reg_T0(s, rd);
1230 } else {
1231 /* store */
1232 gen_movl_T0_reg(s, rd);
1233 gen_op_stb_T0_T1();
1234 }
1235 break;
1236
1237 case 8:
1238 /* load/store halfword immediate offset */
1239 rd = insn & 7;
1240 rn = (insn >> 3) & 7;
1241 gen_movl_T1_reg(s, rn);
1242 val = (insn >> 5) & 0x3e;
1243 gen_op_movl_T2_im(val);
1244 gen_op_addl_T1_T2();
1245
1246 if (insn & (1 << 11)) {
1247 /* load */
1248 gen_op_lduw_T0_T1();
1249 gen_movl_reg_T0(s, rd);
1250 } else {
1251 /* store */
1252 gen_movl_T0_reg(s, rd);
1253 gen_op_stw_T0_T1();
1254 }
1255 break;
1256
1257 case 9:
1258 /* load/store from stack */
1259 rd = (insn >> 8) & 7;
1260 gen_movl_T1_reg(s, 13);
1261 val = (insn & 0xff) * 4;
1262 gen_op_movl_T2_im(val);
1263 gen_op_addl_T1_T2();
1264
1265 if (insn & (1 << 11)) {
1266 /* load */
1267 gen_op_ldl_T0_T1();
1268 gen_movl_reg_T0(s, rd);
1269 } else {
1270 /* store */
1271 gen_movl_T0_reg(s, rd);
1272 gen_op_stl_T0_T1();
1273 }
1274 break;
1275
1276 case 10:
1277 /* add to high reg */
1278 rd = (insn >> 8) & 7;
1279 if (insn & (1 << 11))
1280 rm = 13; /* sp */
1281 else
1282 rm = 15; /* pc */
1283 gen_movl_T0_reg(s, rm);
1284 val = (insn & 0xff) * 4;
1285 gen_op_movl_T1_im(val);
1286 gen_op_addl_T0_T1();
1287 gen_movl_reg_T0(s, rd);
1288 break;
1289
1290 case 11:
1291 /* misc */
1292 op = (insn >> 8) & 0xf;
1293 switch (op) {
1294 case 0:
1295 /* adjust stack pointer */
1296 gen_movl_T1_reg(s, 13);
1297 val = (insn & 0x7f) * 4;
1298 if (insn & (1 << 7))
1299 val = -(int32_t)val;
1300 gen_op_movl_T2_im(val);
1301 gen_op_addl_T1_T2();
1302 gen_movl_reg_T1(s, 13);
1303 break;
1304
1305 case 4: case 5: case 0xc: case 0xd:
1306 /* push/pop */
1307 gen_movl_T1_reg(s, 13);
1308 if (insn & (1 << 11))
1309 val = 4;
1310 else
1311 val = -4;
1312 gen_op_movl_T2_im(val);
1313 for (i = 0; i < 8; i++) {
1314 if (insn & (1 << i)) {
1315 if (insn & (1 << 11)) {
1316 /* pop */
1317 gen_op_ldl_T0_T1();
1318 gen_movl_reg_T0(s, i);
1319 } else {
1320 /* push */
1321 gen_movl_T0_reg(s, i);
1322 gen_op_stl_T0_T1();
1323 }
1324 /* move to the next address */
1325 gen_op_addl_T1_T2();
1326 }
1327 }
1328 if (insn & (1 << 8)) {
1329 if (insn & (1 << 11)) {
1330 /* pop pc */
1331 gen_op_ldl_T0_T1();
1332 /* don't set the pc until the rest of the instruction
1333 has completed */
1334 } else {
1335 /* push lr */
1336 gen_movl_T0_reg(s, 14);
1337 gen_op_stl_T0_T1();
1338 }
1339 gen_op_addl_T1_T2();
1340 }
1341
1342 /* write back the new stack pointer */
1343 gen_movl_reg_T1(s, 13);
1344 /* set the new PC value */
1345 if ((insn & 0x0900) == 0x0900)
1346 gen_bx(s);
1347 break;
1348
1349 default:
1350 goto undef;
1351 }
1352 break;
1353
1354 case 12:
1355 /* load/store multiple */
1356 rn = (insn >> 8) & 0x7;
1357 gen_movl_T1_reg(s, rn);
1358 gen_op_movl_T2_im(4);
1359 val = 0;
1360 for (i = 0; i < 8; i++) {
1361 if (insn & (1 << i)) {
1362 /* advance to the next address */
1363 if (val)
1364 gen_op_addl_T1_T2();
1365 else
1366 val = 1;
1367 if (insn & (1 << 11)) {
1368 /* load */
1369 gen_op_ldl_T0_T1();
1370 gen_movl_reg_T0(s, i);
1371 } else {
1372 /* store */
1373 gen_movl_T0_reg(s, i);
1374 gen_op_stl_T0_T1();
1375 }
1376 }
1377 }
1378 break;
1379
1380 case 13:
1381 /* conditional branch or swi */
1382 cond = (insn >> 8) & 0xf;
1383 if (cond == 0xe)
1384 goto undef;
1385
1386 if (cond == 0xf) {
1387 /* swi */
1388 gen_op_movl_T0_im((long)s->pc | 1);
1389 /* Don't set r15. */
1390 gen_op_movl_reg_TN[0][15]();
1391 gen_op_swi();
1392 s->is_jmp = DISAS_JUMP;
1393 break;
1394 }
1395 /* generate a conditional jump to next instruction */
1396 gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
1397 s->is_jmp = DISAS_JUMP_NEXT;
1398 gen_movl_T1_reg(s, 15);
1399
1400 /* jump to the offset */
1401 val = (uint32_t)s->pc;
1402 offset = ((int32_t)insn << 24) >> 24;
1403 val += (offset << 1) + 2;
1404 gen_op_jmp((long)s->tb, val);
1405 s->is_jmp = DISAS_TB_JUMP;
1406 break;
1407
1408 case 14:
1409 /* unconditional branch */
1410 if (insn & (1 << 11))
1411 goto undef; /* Second half of a blx */
1412 val = (uint32_t)s->pc;
1413 offset = ((int32_t)insn << 21) >> 21;
1414 val += (offset << 1) + 2;
1415 gen_op_jmp((long)s->tb, val);
1416 s->is_jmp = DISAS_TB_JUMP;
1417 break;
1418
1419 case 15:
1420 /* branch and link [and switch to arm] */
1421 offset = ((int32_t)insn << 21) >> 10;
1422 insn = lduw(s->pc);
1423 offset |= insn & 0x7ff;
1424
1425 val = (uint32_t)s->pc + 2;
1426 gen_op_movl_T1_im(val | 1);
1427 gen_movl_reg_T1(s, 14);
1428
1429 val += offset;
1430 if (insn & (1 << 11)) {
1431 /* bl */
1432 gen_op_jmp((long)s->tb, val);
1433 s->is_jmp = DISAS_TB_JUMP;
1434 } else {
1435 /* blx */
1436 gen_op_movl_T0_im(val);
1437 gen_bx(s);
1438 }
1439 }
1440 return;
1441undef:
1442 gen_op_movl_T0_im((long)s->pc - 4);
1443 gen_op_movl_reg_TN[0][15]();
1444 gen_op_undef_insn();
1445 s->is_jmp = DISAS_JUMP;
1446}
1447
2c0262af
FB
1448/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
1449 basic block 'tb'. If search_pc is TRUE, also generate PC
1450 information for each intermediate instruction. */
1451static inline int gen_intermediate_code_internal(CPUState *env,
1452 TranslationBlock *tb,
1453 int search_pc)
1454{
1455 DisasContext dc1, *dc = &dc1;
1456 uint16_t *gen_opc_end;
1457 int j, lj;
0fa85d43 1458 target_ulong pc_start;
2c0262af
FB
1459
1460 /* generate intermediate code */
0fa85d43 1461 pc_start = tb->pc;
2c0262af
FB
1462
1463 dc->tb = tb;
1464
1465 gen_opc_ptr = gen_opc_buf;
1466 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
1467 gen_opparam_ptr = gen_opparam_buf;
1468
1469 dc->is_jmp = DISAS_NEXT;
1470 dc->pc = pc_start;
1471 lj = -1;
1472 do {
1473 if (search_pc) {
1474 j = gen_opc_ptr - gen_opc_buf;
1475 if (lj < j) {
1476 lj++;
1477 while (lj < j)
1478 gen_opc_instr_start[lj++] = 0;
1479 }
0fa85d43 1480 gen_opc_pc[lj] = dc->pc;
2c0262af
FB
1481 gen_opc_instr_start[lj] = 1;
1482 }
99c475ab
FB
1483 if (env->thumb)
1484 disas_thumb_insn(dc);
1485 else
1486 disas_arm_insn(dc);
2c0262af
FB
1487 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
1488 (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
1489 switch(dc->is_jmp) {
1490 case DISAS_JUMP_NEXT:
1491 case DISAS_NEXT:
1492 gen_op_jmp((long)dc->tb, (long)dc->pc);
1493 break;
1494 default:
1495 case DISAS_JUMP:
99c475ab 1496 case DISAS_UPDATE:
2c0262af
FB
1497 /* indicate that the hash table must be used to find the next TB */
1498 gen_op_movl_T0_0();
1499 gen_op_exit_tb();
1500 break;
1501 case DISAS_TB_JUMP:
1502 /* nothing more to generate */
1503 break;
1504 }
1505 *gen_opc_ptr = INDEX_op_end;
1506
1507#ifdef DEBUG_DISAS
e19e89a5 1508 if (loglevel & CPU_LOG_TB_IN_ASM) {
2c0262af
FB
1509 fprintf(logfile, "----------------\n");
1510 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
0fa85d43 1511 target_disas(logfile, pc_start, dc->pc - pc_start, 0);
2c0262af 1512 fprintf(logfile, "\n");
e19e89a5
FB
1513 if (loglevel & (CPU_LOG_TB_OP)) {
1514 fprintf(logfile, "OP:\n");
1515 dump_ops(gen_opc_buf, gen_opparam_buf);
1516 fprintf(logfile, "\n");
1517 }
2c0262af
FB
1518 }
1519#endif
1520 if (!search_pc)
1521 tb->size = dc->pc - pc_start;
1522 return 0;
1523}
1524
1525int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
1526{
1527 return gen_intermediate_code_internal(env, tb, 0);
1528}
1529
1530int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
1531{
1532 return gen_intermediate_code_internal(env, tb, 1);
1533}
1534
1535CPUARMState *cpu_arm_init(void)
1536{
1537 CPUARMState *env;
1538
1539 cpu_exec_init();
1540
1541 env = malloc(sizeof(CPUARMState));
1542 if (!env)
1543 return NULL;
1544 memset(env, 0, sizeof(CPUARMState));
7496f526 1545 cpu_single_env = env;
2c0262af
FB
1546 return env;
1547}
1548
1549void cpu_arm_close(CPUARMState *env)
1550{
1551 free(env);
1552}
1553
7fe48483
FB
1554void cpu_dump_state(CPUState *env, FILE *f,
1555 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
1556 int flags)
2c0262af
FB
1557{
1558 int i;
1559
1560 for(i=0;i<16;i++) {
7fe48483 1561 cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
2c0262af 1562 if ((i % 4) == 3)
7fe48483 1563 cpu_fprintf(f, "\n");
2c0262af 1564 else
7fe48483 1565 cpu_fprintf(f, " ");
2c0262af 1566 }
7fe48483 1567 cpu_fprintf(f, "PSR=%08x %c%c%c%c\n",
2c0262af
FB
1568 env->cpsr,
1569 env->cpsr & (1 << 31) ? 'N' : '-',
1570 env->cpsr & (1 << 30) ? 'Z' : '-',
1571 env->cpsr & (1 << 29) ? 'C' : '-',
1572 env->cpsr & (1 << 28) ? 'V' : '-');
1573}
a6b025d3
FB
1574
1575target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
1576{
1577 return addr;
1578}