]> git.proxmox.com Git - qemu.git/blame - translate-arm.c
update
[qemu.git] / translate-arm.c
CommitLineData
5898e816
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-arm.h"
27#include "exec.h"
28#include "disas.h"
29
30/* internal defines */
31typedef struct DisasContext {
32 uint8_t *pc;
33 int is_jmp;
34 struct TranslationBlock *tb;
35} DisasContext;
36
37/* XXX: move that elsewhere */
38static uint16_t *gen_opc_ptr;
39static uint32_t *gen_opparam_ptr;
40extern FILE *logfile;
41extern int loglevel;
42
43enum {
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
52typedef void (GenOpFunc)(void);
53typedef void (GenOpFunc1)(long);
54typedef void (GenOpFunc2)(long, long);
55typedef void (GenOpFunc3)(long, long, long);
56
57static 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
74const 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
93static 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
100static 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
107static 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
114static 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
121static 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
128static 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
185static 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
224static 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
230static 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
243static inline void gen_movl_T0_reg(DisasContext *s, int reg)
244{
245 gen_movl_TN_reg(s, reg, 0);
246}
247
248static inline void gen_movl_T1_reg(DisasContext *s, int reg)
249{
250 gen_movl_TN_reg(s, reg, 1);
251}
252
253static inline void gen_movl_T2_reg(DisasContext *s, int reg)
254{
255 gen_movl_TN_reg(s, reg, 2);
256}
257
258static 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
266static inline void gen_movl_reg_T0(DisasContext *s, int reg)
267{
268 gen_movl_reg_TN(s, reg, 0);
269}
270
271static inline void gen_movl_reg_T1(DisasContext *s, int reg)
272{
273 gen_movl_reg_TN(s, reg, 1);
274}
275
276static 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
301static 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
322static 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. */
658int 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
720CPUARMState *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
733void cpu_arm_close(CPUARMState *env)
734{
735 free(env);
736}
737
738void 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}