Commit 72cbca10e184637ec0e813ead71975b7446cc695
1 parent
34f715e7
direct chaining support for SPARC
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@607 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
97 additions
and
48 deletions
target-sparc/op.c
| ... | ... | @@ -643,24 +643,43 @@ void OPPROTO op_next_insn(void) |
| 643 | 643 | env->npc = env->npc + 4; |
| 644 | 644 | } |
| 645 | 645 | |
| 646 | -void OPPROTO op_generic_branch(void) | |
| 646 | +void OPPROTO op_branch(void) | |
| 647 | +{ | |
| 648 | + env->npc = PARAM3; /* XXX: optimize */ | |
| 649 | + JUMP_TB(op_branch, PARAM1, 0, PARAM2); | |
| 650 | +} | |
| 651 | + | |
| 652 | +void OPPROTO op_branch2(void) | |
| 647 | 653 | { |
| 648 | 654 | if (T2) { |
| 649 | - env->npc = PARAM1; | |
| 655 | + env->npc = PARAM2 + 4; | |
| 656 | + JUMP_TB(op_branch2, PARAM1, 0, PARAM2); | |
| 650 | 657 | } else { |
| 651 | - env->npc = PARAM2; | |
| 658 | + env->npc = PARAM3 + 4; | |
| 659 | + JUMP_TB(op_branch2, PARAM1, 1, PARAM3); | |
| 660 | + } | |
| 661 | + FORCE_RET(); | |
| 662 | +} | |
| 663 | + | |
| 664 | +void OPPROTO op_branch_a(void) | |
| 665 | +{ | |
| 666 | + if (T2) { | |
| 667 | + env->npc = PARAM2; /* XXX: optimize */ | |
| 668 | + JUMP_TB(op_generic_branch_a, PARAM1, 0, PARAM3); | |
| 669 | + } else { | |
| 670 | + env->npc = PARAM3 + 8; /* XXX: optimize */ | |
| 671 | + JUMP_TB(op_generic_branch_a, PARAM1, 1, PARAM3 + 4); | |
| 652 | 672 | } |
| 653 | 673 | FORCE_RET(); |
| 654 | 674 | } |
| 655 | 675 | |
| 656 | -void OPPROTO op_generic_branch_a(void) | |
| 676 | +void OPPROTO op_generic_branch(void) | |
| 657 | 677 | { |
| 658 | 678 | if (T2) { |
| 659 | - env->pc = PARAM2; | |
| 660 | 679 | env->npc = PARAM1; |
| 661 | 680 | } else { |
| 662 | - env->pc = PARAM2 + 4; | |
| 663 | - env->npc = PARAM2 + 8; | |
| 681 | + env->npc = PARAM2; | |
| 664 | 682 | } |
| 665 | 683 | FORCE_RET(); |
| 666 | 684 | } |
| 685 | + | ... | ... |
target-sparc/translate.c
| ... | ... | @@ -42,9 +42,14 @@ |
| 42 | 42 | |
| 43 | 43 | #define DEBUG_DISAS |
| 44 | 44 | |
| 45 | +#define DYNAMIC_PC 1 /* dynamic pc value */ | |
| 46 | +#define JUMP_PC 2 /* dynamic pc value which takes only two values | |
| 47 | + according to jump_pc[T2] */ | |
| 48 | + | |
| 45 | 49 | typedef struct DisasContext { |
| 46 | - uint8_t *pc; /* NULL means dynamic value */ | |
| 47 | - uint8_t *npc; /* NULL means dynamic value */ | |
| 50 | + target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */ | |
| 51 | + target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */ | |
| 52 | + target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */ | |
| 48 | 53 | int is_br; |
| 49 | 54 | struct TranslationBlock *tb; |
| 50 | 55 | } DisasContext; |
| ... | ... | @@ -306,6 +311,31 @@ static inline void gen_movl_T1_reg(int reg) |
| 306 | 311 | gen_movl_TN_reg(reg, 1); |
| 307 | 312 | } |
| 308 | 313 | |
| 314 | +/* call this function before using T2 as it may have been set for a jump */ | |
| 315 | +static inline void flush_T2(DisasContext * dc) | |
| 316 | +{ | |
| 317 | + if (dc->npc == JUMP_PC) { | |
| 318 | + gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); | |
| 319 | + dc->npc = DYNAMIC_PC; | |
| 320 | + } | |
| 321 | +} | |
| 322 | + | |
| 323 | +static inline void save_npc(DisasContext * dc) | |
| 324 | +{ | |
| 325 | + if (dc->npc == JUMP_PC) { | |
| 326 | + gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); | |
| 327 | + dc->npc = DYNAMIC_PC; | |
| 328 | + } else if (dc->npc != DYNAMIC_PC) { | |
| 329 | + gen_op_movl_npc_im(dc->npc); | |
| 330 | + } | |
| 331 | +} | |
| 332 | + | |
| 333 | +static inline void save_state(DisasContext * dc) | |
| 334 | +{ | |
| 335 | + gen_op_jmp_im((uint32_t)dc->pc); | |
| 336 | + save_npc(dc); | |
| 337 | +} | |
| 338 | + | |
| 309 | 339 | static void gen_cond(int cond) |
| 310 | 340 | { |
| 311 | 341 | switch (cond) { |
| ... | ... | @@ -378,25 +408,23 @@ static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn) |
| 378 | 408 | } else if (cond == 0x8) { |
| 379 | 409 | /* unconditional taken */ |
| 380 | 410 | if (a) { |
| 381 | - dc->pc = (uint8_t *) target; | |
| 411 | + dc->pc = target; | |
| 382 | 412 | dc->npc = dc->pc + 4; |
| 383 | 413 | } else { |
| 384 | 414 | dc->pc = dc->npc; |
| 385 | - dc->npc = (uint8_t *) target; | |
| 415 | + dc->npc = target; | |
| 386 | 416 | } |
| 387 | 417 | } else { |
| 418 | + flush_T2(dc); | |
| 388 | 419 | gen_cond(cond); |
| 389 | 420 | if (a) { |
| 390 | - gen_op_generic_branch_a((uint32_t) target, | |
| 391 | - (uint32_t) (dc->npc)); | |
| 421 | + gen_op_branch_a((long)dc->tb, target, dc->npc); | |
| 392 | 422 | dc->is_br = 1; |
| 393 | - dc->pc = NULL; | |
| 394 | - dc->npc = NULL; | |
| 395 | 423 | } else { |
| 396 | 424 | dc->pc = dc->npc; |
| 397 | - gen_op_generic_branch((uint32_t) target, | |
| 398 | - (uint32_t) (dc->npc + 4)); | |
| 399 | - dc->npc = NULL; | |
| 425 | + dc->jump_pc[0] = target; | |
| 426 | + dc->jump_pc[1] = dc->npc + 4; | |
| 427 | + dc->npc = JUMP_PC; | |
| 400 | 428 | } |
| 401 | 429 | } |
| 402 | 430 | } |
| ... | ... | @@ -409,18 +437,11 @@ static int sign_extend(int x, int len) |
| 409 | 437 | return (x << len) >> len; |
| 410 | 438 | } |
| 411 | 439 | |
| 412 | -static inline void save_state(DisasContext * dc) | |
| 413 | -{ | |
| 414 | - gen_op_jmp_im((uint32_t)dc->pc); | |
| 415 | - if (dc->npc != NULL) | |
| 416 | - gen_op_movl_npc_im((long) dc->npc); | |
| 417 | -} | |
| 418 | - | |
| 419 | 440 | static void disas_sparc_insn(DisasContext * dc) |
| 420 | 441 | { |
| 421 | 442 | unsigned int insn, opc, rs1, rs2, rd; |
| 422 | 443 | |
| 423 | - insn = ldl_code(dc->pc); | |
| 444 | + insn = ldl_code((uint8_t *)dc->pc); | |
| 424 | 445 | opc = GET_FIELD(insn, 0, 1); |
| 425 | 446 | |
| 426 | 447 | rd = GET_FIELD(insn, 2, 6); |
| ... | ... | @@ -458,9 +479,9 @@ static void disas_sparc_insn(DisasContext * dc) |
| 458 | 479 | |
| 459 | 480 | gen_op_movl_T0_im((long) (dc->pc)); |
| 460 | 481 | gen_movl_T0_reg(15); |
| 461 | - target = (long) dc->pc + target; | |
| 482 | + target = dc->pc + target; | |
| 462 | 483 | dc->pc = dc->npc; |
| 463 | - dc->npc = (uint8_t *) target; | |
| 484 | + dc->npc = target; | |
| 464 | 485 | } |
| 465 | 486 | goto jmp_insn; |
| 466 | 487 | case 2: /* FPU & Logical Operations */ |
| ... | ... | @@ -625,7 +646,7 @@ static void disas_sparc_insn(DisasContext * dc) |
| 625 | 646 | gen_movl_T0_reg(rd); |
| 626 | 647 | } |
| 627 | 648 | dc->pc = dc->npc; |
| 628 | - dc->npc = NULL; | |
| 649 | + dc->npc = DYNAMIC_PC; | |
| 629 | 650 | } |
| 630 | 651 | goto jmp_insn; |
| 631 | 652 | case 0x3b: /* flush */ |
| ... | ... | @@ -705,6 +726,7 @@ static void disas_sparc_insn(DisasContext * dc) |
| 705 | 726 | gen_op_sth(); |
| 706 | 727 | break; |
| 707 | 728 | case 0x7: |
| 729 | + flush_T2(dc); | |
| 708 | 730 | gen_movl_reg_T2(rd + 1); |
| 709 | 731 | gen_op_std(); |
| 710 | 732 | break; |
| ... | ... | @@ -713,19 +735,21 @@ static void disas_sparc_insn(DisasContext * dc) |
| 713 | 735 | } |
| 714 | 736 | } |
| 715 | 737 | /* default case for non jump instructions */ |
| 716 | - if (dc->npc != NULL) { | |
| 738 | + if (dc->npc == DYNAMIC_PC) { | |
| 739 | + dc->pc = DYNAMIC_PC; | |
| 740 | + gen_op_next_insn(); | |
| 741 | + } else if (dc->npc == JUMP_PC) { | |
| 742 | + /* we can do a static jump */ | |
| 743 | + gen_op_branch2((long)dc->tb, dc->jump_pc[0], dc->jump_pc[1]); | |
| 744 | + dc->is_br = 1; | |
| 745 | + } else { | |
| 717 | 746 | dc->pc = dc->npc; |
| 718 | 747 | dc->npc = dc->npc + 4; |
| 719 | - } else { | |
| 720 | - dc->pc = NULL; | |
| 721 | - gen_op_next_insn(); | |
| 722 | 748 | } |
| 723 | 749 | jmp_insn:; |
| 724 | 750 | return; |
| 725 | 751 | illegal_insn: |
| 726 | - gen_op_jmp_im((uint32_t)dc->pc); | |
| 727 | - if (dc->npc != NULL) | |
| 728 | - gen_op_movl_npc_im((long) dc->npc); | |
| 752 | + save_state(dc); | |
| 729 | 753 | gen_op_exception(TT_ILL_INSN); |
| 730 | 754 | dc->is_br = 1; |
| 731 | 755 | } |
| ... | ... | @@ -733,7 +757,7 @@ static void disas_sparc_insn(DisasContext * dc) |
| 733 | 757 | static inline int gen_intermediate_code_internal(TranslationBlock * tb, |
| 734 | 758 | int spc) |
| 735 | 759 | { |
| 736 | - uint8_t *pc_start, *last_pc; | |
| 760 | + target_ulong pc_start, last_pc; | |
| 737 | 761 | uint16_t *gen_opc_end; |
| 738 | 762 | DisasContext dc1, *dc = &dc1; |
| 739 | 763 | |
| ... | ... | @@ -743,9 +767,9 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, |
| 743 | 767 | exit(0); |
| 744 | 768 | } |
| 745 | 769 | dc->tb = tb; |
| 746 | - pc_start = (uint8_t *) tb->pc; | |
| 770 | + pc_start = tb->pc; | |
| 747 | 771 | dc->pc = pc_start; |
| 748 | - dc->npc = (uint8_t *) tb->cs_base; | |
| 772 | + dc->npc = (target_ulong) tb->cs_base; | |
| 749 | 773 | |
| 750 | 774 | gen_opc_ptr = gen_opc_buf; |
| 751 | 775 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
| ... | ... | @@ -761,19 +785,25 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, |
| 761 | 785 | break; |
| 762 | 786 | } while ((gen_opc_ptr < gen_opc_end) && |
| 763 | 787 | (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); |
| 764 | - if (dc->pc != NULL) | |
| 765 | - gen_op_jmp_im((long) dc->pc); | |
| 766 | - if (dc->npc != NULL) | |
| 767 | - gen_op_movl_npc_im((long) dc->npc); | |
| 768 | - gen_op_movl_T0_0(); | |
| 769 | - gen_op_exit_tb(); | |
| 770 | - | |
| 788 | + if (!dc->is_br) { | |
| 789 | + if (dc->pc != DYNAMIC_PC && | |
| 790 | + (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) { | |
| 791 | + /* static PC and NPC: we can use direct chaining */ | |
| 792 | + gen_op_branch((long)tb, dc->pc, dc->npc); | |
| 793 | + } else { | |
| 794 | + if (dc->pc != DYNAMIC_PC) | |
| 795 | + gen_op_jmp_im(dc->pc); | |
| 796 | + save_npc(dc); | |
| 797 | + gen_op_movl_T0_0(); | |
| 798 | + gen_op_exit_tb(); | |
| 799 | + } | |
| 800 | + } | |
| 771 | 801 | *gen_opc_ptr = INDEX_op_end; |
| 772 | 802 | #ifdef DEBUG_DISAS |
| 773 | 803 | if (loglevel) { |
| 774 | 804 | fprintf(logfile, "--------------\n"); |
| 775 | - fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); | |
| 776 | - disas(logfile, pc_start, last_pc + 4 - pc_start, 0, 0); | |
| 805 | + fprintf(logfile, "IN: %s\n", lookup_symbol((uint8_t *)pc_start)); | |
| 806 | + disas(logfile, (uint8_t *)pc_start, last_pc + 4 - pc_start, 0, 0); | |
| 777 | 807 | fprintf(logfile, "\n"); |
| 778 | 808 | fprintf(logfile, "OP:\n"); |
| 779 | 809 | dump_ops(gen_opc_buf, gen_opparam_buf); | ... | ... |