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 | } | ... | ... |