Commit 6e295807acbaf7eb3200a685376fb968ebdb8571
1 parent
f2674e31
ARM fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@314 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
209 additions
and
58 deletions
arm-dis.c
... | ... | @@ -560,8 +560,8 @@ static arm_regname regnames[] = |
560 | 560 | { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }} |
561 | 561 | }; |
562 | 562 | |
563 | -/* Default to GCC register name set. */ | |
564 | -static unsigned int regname_selected = 1; | |
563 | +/* Default to STD register name set. */ | |
564 | +static unsigned int regname_selected = 2; | |
565 | 565 | |
566 | 566 | #define NUM_ARM_REGNAMES NUM_ELEM (regnames) |
567 | 567 | #define arm_regnames regnames[regname_selected].reg_names | ... | ... |
exec-arm.h
... | ... | @@ -30,3 +30,11 @@ register uint32_t T2 asm(AREG3); |
30 | 30 | void cpu_lock(void); |
31 | 31 | void cpu_unlock(void); |
32 | 32 | void cpu_loop_exit(void); |
33 | + | |
34 | +static inline int compute_cpsr(void) | |
35 | +{ | |
36 | + int ZF; | |
37 | + ZF = (env->NZF == 0); | |
38 | + return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | | |
39 | + (env->CF << 29) | ((env->VF & 0x80000000) >> 3); | |
40 | +} | ... | ... |
op-arm.c
... | ... | @@ -154,11 +154,11 @@ void OPPROTO op_adcl_T0_T1_cc(void) |
154 | 154 | FORCE_RET(); |
155 | 155 | } |
156 | 156 | |
157 | -#define OPSUB(sub, sbc, T0, T1) \ | |
157 | +#define OPSUB(sub, sbc, res, T0, T1) \ | |
158 | 158 | \ |
159 | 159 | void OPPROTO op_ ## sub ## l_T0_T1(void) \ |
160 | 160 | { \ |
161 | - T0 -= T1; \ | |
161 | + res = T0 - T1; \ | |
162 | 162 | } \ |
163 | 163 | \ |
164 | 164 | void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ |
... | ... | @@ -167,13 +167,14 @@ void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ |
167 | 167 | src1 = T0; \ |
168 | 168 | T0 -= T1; \ |
169 | 169 | env->NZF = T0; \ |
170 | - env->CF = src1 < T1; \ | |
170 | + env->CF = src1 >= T1; \ | |
171 | 171 | env->VF = (src1 ^ T1) & (src1 ^ T0); \ |
172 | + res = T0; \ | |
172 | 173 | } \ |
173 | 174 | \ |
174 | 175 | void OPPROTO op_ ## sbc ## l_T0_T1(void) \ |
175 | 176 | { \ |
176 | - T0 = T0 - T1 + env->CF - 1; \ | |
177 | + res = T0 - T1 + env->CF - 1; \ | |
177 | 178 | } \ |
178 | 179 | \ |
179 | 180 | void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ |
... | ... | @@ -182,20 +183,20 @@ void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ |
182 | 183 | src1 = T0; \ |
183 | 184 | if (!env->CF) { \ |
184 | 185 | T0 = T0 - T1 - 1; \ |
185 | - T0 += T1; \ | |
186 | - env->CF = src1 < T1; \ | |
186 | + env->CF = src1 >= T1; \ | |
187 | 187 | } else { \ |
188 | 188 | T0 = T0 - T1; \ |
189 | - env->CF = src1 <= T1; \ | |
189 | + env->CF = src1 > T1; \ | |
190 | 190 | } \ |
191 | 191 | env->VF = (src1 ^ T1) & (src1 ^ T0); \ |
192 | 192 | env->NZF = T0; \ |
193 | + res = T0; \ | |
193 | 194 | FORCE_RET(); \ |
194 | 195 | } |
195 | 196 | |
196 | -OPSUB(sub, sbc, T0, T1) | |
197 | +OPSUB(sub, sbc, T0, T0, T1) | |
197 | 198 | |
198 | -OPSUB(rsb, rsc, T1, T0) | |
199 | +OPSUB(rsb, rsc, T0, T1, T0) | |
199 | 200 | |
200 | 201 | void OPPROTO op_andl_T0_T1(void) |
201 | 202 | { |
... | ... | @@ -222,11 +223,16 @@ void OPPROTO op_notl_T1(void) |
222 | 223 | T1 = ~T1; |
223 | 224 | } |
224 | 225 | |
225 | -void OPPROTO op_logic_cc(void) | |
226 | +void OPPROTO op_logic_T0_cc(void) | |
226 | 227 | { |
227 | 228 | env->NZF = T0; |
228 | 229 | } |
229 | 230 | |
231 | +void OPPROTO op_logic_T1_cc(void) | |
232 | +{ | |
233 | + env->NZF = T1; | |
234 | +} | |
235 | + | |
230 | 236 | #define EIP (env->regs[15]) |
231 | 237 | |
232 | 238 | void OPPROTO op_test_eq(void) |
... | ... | @@ -334,10 +340,7 @@ void OPPROTO op_jmp(void) |
334 | 340 | |
335 | 341 | void OPPROTO op_movl_T0_psr(void) |
336 | 342 | { |
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); | |
343 | + T0 = compute_cpsr(); | |
341 | 344 | } |
342 | 345 | |
343 | 346 | /* NOTE: N = 1 and Z = 1 cannot be stored currently */ | ... | ... |
translate-arm.c
... | ... | @@ -34,6 +34,8 @@ typedef struct DisasContext { |
34 | 34 | struct TranslationBlock *tb; |
35 | 35 | } DisasContext; |
36 | 36 | |
37 | +#define DISAS_JUMP_NEXT 4 | |
38 | + | |
37 | 39 | /* XXX: move that elsewhere */ |
38 | 40 | static uint16_t *gen_opc_ptr; |
39 | 41 | static uint32_t *gen_opparam_ptr; |
... | ... | @@ -333,10 +335,11 @@ static void disas_arm_insn(DisasContext *s) |
333 | 335 | /* if not always execute, we generate a conditional jump to |
334 | 336 | next instruction */ |
335 | 337 | gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); |
336 | - s->is_jmp = 1; | |
338 | + s->is_jmp = DISAS_JUMP_NEXT; | |
337 | 339 | } |
338 | - if ((insn & 0x0c000000) == 0 && | |
339 | - (insn & 0x00000090) != 0x90) { | |
340 | + if (((insn & 0x0e000000) == 0 && | |
341 | + (insn & 0x00000090) != 0x90) || | |
342 | + ((insn & 0x0e000000) == (1 << 25))) { | |
340 | 343 | int set_cc, logic_cc, shiftop; |
341 | 344 | |
342 | 345 | op1 = (insn >> 21) & 0xf; |
... | ... | @@ -367,7 +370,7 @@ static void disas_arm_insn(DisasContext *s) |
367 | 370 | } |
368 | 371 | } |
369 | 372 | } else { |
370 | - rs = (insn >> 16) & 0xf; | |
373 | + rs = (insn >> 8) & 0xf; | |
371 | 374 | gen_movl_T0_reg(s, rs); |
372 | 375 | if (logic_cc) { |
373 | 376 | gen_shift_T1_T0_cc[shiftop](); |
... | ... | @@ -385,10 +388,14 @@ static void disas_arm_insn(DisasContext *s) |
385 | 388 | case 0x00: |
386 | 389 | gen_op_andl_T0_T1(); |
387 | 390 | gen_movl_reg_T0(s, rd); |
391 | + if (logic_cc) | |
392 | + gen_op_logic_T0_cc(); | |
388 | 393 | break; |
389 | 394 | case 0x01: |
390 | 395 | gen_op_xorl_T0_T1(); |
391 | 396 | gen_movl_reg_T0(s, rd); |
397 | + if (logic_cc) | |
398 | + gen_op_logic_T0_cc(); | |
392 | 399 | break; |
393 | 400 | case 0x02: |
394 | 401 | if (set_cc) |
... | ... | @@ -435,11 +442,13 @@ static void disas_arm_insn(DisasContext *s) |
435 | 442 | case 0x08: |
436 | 443 | if (set_cc) { |
437 | 444 | gen_op_andl_T0_T1(); |
445 | + gen_op_logic_T0_cc(); | |
438 | 446 | } |
439 | 447 | break; |
440 | 448 | case 0x09: |
441 | 449 | if (set_cc) { |
442 | 450 | gen_op_xorl_T0_T1(); |
451 | + gen_op_logic_T0_cc(); | |
443 | 452 | } |
444 | 453 | break; |
445 | 454 | case 0x0a: |
... | ... | @@ -455,22 +464,28 @@ static void disas_arm_insn(DisasContext *s) |
455 | 464 | case 0x0c: |
456 | 465 | gen_op_orl_T0_T1(); |
457 | 466 | gen_movl_reg_T0(s, rd); |
467 | + if (logic_cc) | |
468 | + gen_op_logic_T0_cc(); | |
458 | 469 | break; |
459 | 470 | case 0x0d: |
460 | 471 | gen_movl_reg_T1(s, rd); |
472 | + if (logic_cc) | |
473 | + gen_op_logic_T1_cc(); | |
461 | 474 | break; |
462 | 475 | case 0x0e: |
463 | 476 | gen_op_bicl_T0_T1(); |
464 | 477 | gen_movl_reg_T0(s, rd); |
478 | + if (logic_cc) | |
479 | + gen_op_logic_T0_cc(); | |
465 | 480 | break; |
466 | 481 | default: |
467 | 482 | case 0x0f: |
468 | 483 | gen_op_notl_T1(); |
469 | 484 | gen_movl_reg_T1(s, rd); |
485 | + if (logic_cc) | |
486 | + gen_op_logic_T1_cc(); | |
470 | 487 | break; |
471 | 488 | } |
472 | - if (logic_cc) | |
473 | - gen_op_logic_cc(); | |
474 | 489 | } else { |
475 | 490 | /* other instructions */ |
476 | 491 | op1 = (insn >> 24) & 0xf; |
... | ... | @@ -494,7 +509,7 @@ static void disas_arm_insn(DisasContext *s) |
494 | 509 | gen_op_addl_T0_T1(); |
495 | 510 | } |
496 | 511 | if (insn & (1 << 20)) |
497 | - gen_op_logic_cc(); | |
512 | + gen_op_logic_T0_cc(); | |
498 | 513 | gen_movl_reg_T0(s, rd); |
499 | 514 | } else { |
500 | 515 | /* 64 bit mul */ |
... | ... | @@ -551,10 +566,12 @@ static void disas_arm_insn(DisasContext *s) |
551 | 566 | /* store */ |
552 | 567 | gen_op_stw_T0_T1(); |
553 | 568 | } |
554 | - if (!(insn & (1 << 24))) | |
569 | + if (!(insn & (1 << 24))) { | |
555 | 570 | gen_add_datah_offset(s, insn); |
556 | - if (insn & (1 << 21)) | |
557 | 571 | gen_movl_reg_T1(s, rn); |
572 | + } else if (insn & (1 << 21)) { | |
573 | + gen_movl_reg_T1(s, rn); | |
574 | + } | |
558 | 575 | } |
559 | 576 | break; |
560 | 577 | case 0x4: |
... | ... | @@ -582,40 +599,94 @@ static void disas_arm_insn(DisasContext *s) |
582 | 599 | else |
583 | 600 | gen_op_stl_T0_T1(); |
584 | 601 | } |
585 | - if (!(insn & (1 << 24))) | |
602 | + if (!(insn & (1 << 24))) { | |
586 | 603 | gen_add_data_offset(s, insn); |
587 | - if (insn & (1 << 21)) | |
588 | 604 | gen_movl_reg_T1(s, rn); |
605 | + } else if (insn & (1 << 21)) | |
606 | + gen_movl_reg_T1(s, rn); { | |
607 | + } | |
589 | 608 | break; |
590 | 609 | case 0x08: |
591 | 610 | 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); | |
611 | + { | |
612 | + int j, n; | |
613 | + /* load/store multiple words */ | |
614 | + /* XXX: store correct base if write back */ | |
615 | + if (insn & (1 << 22)) | |
616 | + goto illegal_op; /* only usable in supervisor mode */ | |
617 | + rn = (insn >> 16) & 0xf; | |
618 | + gen_movl_T1_reg(s, rn); | |
619 | + | |
620 | + /* compute total size */ | |
621 | + n = 0; | |
622 | + for(i=0;i<16;i++) { | |
623 | + if (insn & (1 << i)) | |
624 | + n++; | |
625 | + } | |
626 | + /* XXX: test invalid n == 0 case ? */ | |
627 | + if (insn & (1 << 23)) { | |
628 | + if (insn & (1 << 24)) { | |
629 | + /* pre increment */ | |
630 | + gen_op_addl_T1_im(4); | |
608 | 631 | } else { |
609 | - /* store */ | |
610 | - gen_movl_T0_reg(s, i); | |
611 | - gen_op_stl_T0_T1(); | |
632 | + /* post increment */ | |
633 | + } | |
634 | + } else { | |
635 | + if (insn & (1 << 24)) { | |
636 | + /* pre decrement */ | |
637 | + gen_op_addl_T1_im(-(n * 4)); | |
638 | + } else { | |
639 | + /* post decrement */ | |
640 | + if (n != 1) | |
641 | + gen_op_addl_T1_im(-((n - 1) * 4)); | |
642 | + } | |
643 | + } | |
644 | + j = 0; | |
645 | + for(i=0;i<16;i++) { | |
646 | + if (insn & (1 << i)) { | |
647 | + if (insn & (1 << 20)) { | |
648 | + /* load */ | |
649 | + gen_op_ldl_T0_T1(); | |
650 | + gen_movl_reg_T0(s, i); | |
651 | + } else { | |
652 | + /* store */ | |
653 | + if (i == 15) { | |
654 | + /* special case: r15 = PC + 12 */ | |
655 | + val = (long)s->pc + 8; | |
656 | + gen_op_movl_TN_im[0](val); | |
657 | + } else { | |
658 | + gen_movl_T0_reg(s, i); | |
659 | + } | |
660 | + gen_op_stl_T0_T1(); | |
661 | + } | |
662 | + j++; | |
663 | + /* no need to add after the last transfer */ | |
664 | + if (j != n) | |
665 | + gen_op_addl_T1_im(4); | |
612 | 666 | } |
613 | - if (!(insn & (1 << 24))) | |
614 | - gen_op_addl_T1_im(val); | |
667 | + } | |
668 | + if (insn & (1 << 21)) { | |
669 | + /* write back */ | |
670 | + if (insn & (1 << 23)) { | |
671 | + if (insn & (1 << 24)) { | |
672 | + /* pre increment */ | |
673 | + } else { | |
674 | + /* post increment */ | |
675 | + gen_op_addl_T1_im(4); | |
676 | + } | |
677 | + } else { | |
678 | + if (insn & (1 << 24)) { | |
679 | + /* pre decrement */ | |
680 | + if (n != 1) | |
681 | + gen_op_addl_T1_im(-((n - 1) * 4)); | |
682 | + } else { | |
683 | + /* post decrement */ | |
684 | + gen_op_addl_T1_im(-(n * 4)); | |
685 | + } | |
686 | + } | |
687 | + gen_movl_reg_T1(s, rn); | |
615 | 688 | } |
616 | 689 | } |
617 | - if (insn & (1 << 21)) | |
618 | - gen_movl_reg_T1(s, rn); | |
619 | 690 | break; |
620 | 691 | case 0xa: |
621 | 692 | case 0xb: |
... | ... | @@ -641,6 +712,66 @@ static void disas_arm_insn(DisasContext *s) |
641 | 712 | gen_op_swi(); |
642 | 713 | s->is_jmp = DISAS_JUMP; |
643 | 714 | break; |
715 | + case 0xc: | |
716 | + case 0xd: | |
717 | + rd = (insn >> 12) & 0x7; | |
718 | + rn = (insn >> 16) & 0xf; | |
719 | + gen_movl_T1_reg(s, rn); | |
720 | + val = (insn) & 0xff; | |
721 | + if (!(insn & (1 << 23))) | |
722 | + val = -val; | |
723 | + switch((insn >> 8) & 0xf) { | |
724 | + case 0x1: | |
725 | + /* load/store */ | |
726 | + if ((insn & (1 << 24))) | |
727 | + gen_op_addl_T1_im(val); | |
728 | + /* XXX: do it */ | |
729 | + if (!(insn & (1 << 24))) | |
730 | + gen_op_addl_T1_im(val); | |
731 | + if (insn & (1 << 21)) | |
732 | + gen_movl_reg_T1(s, rn); | |
733 | + break; | |
734 | + case 0x2: | |
735 | + { | |
736 | + int n, i; | |
737 | + /* load store multiple */ | |
738 | + if ((insn & (1 << 24))) | |
739 | + gen_op_addl_T1_im(val); | |
740 | + switch(insn & 0x00408000) { | |
741 | + case 0x00008000: n = 1; break; | |
742 | + case 0x00400000: n = 2; break; | |
743 | + case 0x00408000: n = 3; break; | |
744 | + default: n = 4; break; | |
745 | + } | |
746 | + for(i = 0;i < n; i++) { | |
747 | + /* XXX: do it */ | |
748 | + } | |
749 | + if (!(insn & (1 << 24))) | |
750 | + gen_op_addl_T1_im(val); | |
751 | + if (insn & (1 << 21)) | |
752 | + gen_movl_reg_T1(s, rn); | |
753 | + } | |
754 | + break; | |
755 | + default: | |
756 | + goto illegal_op; | |
757 | + } | |
758 | + break; | |
759 | + case 0x0e: | |
760 | + /* float ops */ | |
761 | + /* XXX: do it */ | |
762 | + switch((insn >> 20) & 0xf) { | |
763 | + case 0x2: /* wfs */ | |
764 | + break; | |
765 | + case 0x3: /* rfs */ | |
766 | + break; | |
767 | + case 0x4: /* wfc */ | |
768 | + break; | |
769 | + case 0x5: /* rfc */ | |
770 | + break; | |
771 | + default: | |
772 | + goto illegal_op; | |
773 | + } | |
774 | + break; | |
644 | 775 | default: |
645 | 776 | illegal_op: |
646 | 777 | gen_op_movl_T0_im((long)s->pc - 4); |
... | ... | @@ -688,15 +819,19 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc |
688 | 819 | disas_arm_insn(dc); |
689 | 820 | } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && |
690 | 821 | (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) { | |
822 | + switch(dc->is_jmp) { | |
823 | + case DISAS_JUMP_NEXT: | |
824 | + case DISAS_NEXT: | |
825 | + gen_op_jmp((long)dc->tb, (long)dc->pc); | |
826 | + break; | |
827 | + default: | |
828 | + case DISAS_JUMP: | |
698 | 829 | /* indicate that the hash table must be used to find the next TB */ |
699 | 830 | gen_op_movl_T0_0(); |
831 | + break; | |
832 | + case DISAS_TB_JUMP: | |
833 | + /* nothing more to generate */ | |
834 | + break; | |
700 | 835 | } |
701 | 836 | *gen_opc_ptr = INDEX_op_end; |
702 | 837 | |
... | ... | @@ -756,5 +891,10 @@ void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags) |
756 | 891 | else |
757 | 892 | fprintf(f, " "); |
758 | 893 | } |
759 | - fprintf(f, "CPSR=%08x", env->cpsr); | |
894 | + fprintf(f, "PSR=%08x %c%c%c%c\n", | |
895 | + env->cpsr, | |
896 | + env->cpsr & (1 << 31) ? 'N' : '-', | |
897 | + env->cpsr & (1 << 30) ? 'Z' : '-', | |
898 | + env->cpsr & (1 << 29) ? 'C' : '-', | |
899 | + env->cpsr & (1 << 28) ? 'V' : '-'); | |
760 | 900 | } | ... | ... |