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,24 +643,43 @@ void OPPROTO op_next_insn(void) | ||
643 | env->npc = env->npc + 4; | 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 | if (T2) { | 654 | if (T2) { |
649 | - env->npc = PARAM1; | 655 | + env->npc = PARAM2 + 4; |
656 | + JUMP_TB(op_branch2, PARAM1, 0, PARAM2); | ||
650 | } else { | 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 | FORCE_RET(); | 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 | if (T2) { | 678 | if (T2) { |
659 | - env->pc = PARAM2; | ||
660 | env->npc = PARAM1; | 679 | env->npc = PARAM1; |
661 | } else { | 680 | } else { |
662 | - env->pc = PARAM2 + 4; | ||
663 | - env->npc = PARAM2 + 8; | 681 | + env->npc = PARAM2; |
664 | } | 682 | } |
665 | FORCE_RET(); | 683 | FORCE_RET(); |
666 | } | 684 | } |
685 | + |
target-sparc/translate.c
@@ -42,9 +42,14 @@ | @@ -42,9 +42,14 @@ | ||
42 | 42 | ||
43 | #define DEBUG_DISAS | 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 | typedef struct DisasContext { | 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 | int is_br; | 53 | int is_br; |
49 | struct TranslationBlock *tb; | 54 | struct TranslationBlock *tb; |
50 | } DisasContext; | 55 | } DisasContext; |
@@ -306,6 +311,31 @@ static inline void gen_movl_T1_reg(int reg) | @@ -306,6 +311,31 @@ static inline void gen_movl_T1_reg(int reg) | ||
306 | gen_movl_TN_reg(reg, 1); | 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 | static void gen_cond(int cond) | 339 | static void gen_cond(int cond) |
310 | { | 340 | { |
311 | switch (cond) { | 341 | switch (cond) { |
@@ -378,25 +408,23 @@ static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn) | @@ -378,25 +408,23 @@ static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn) | ||
378 | } else if (cond == 0x8) { | 408 | } else if (cond == 0x8) { |
379 | /* unconditional taken */ | 409 | /* unconditional taken */ |
380 | if (a) { | 410 | if (a) { |
381 | - dc->pc = (uint8_t *) target; | 411 | + dc->pc = target; |
382 | dc->npc = dc->pc + 4; | 412 | dc->npc = dc->pc + 4; |
383 | } else { | 413 | } else { |
384 | dc->pc = dc->npc; | 414 | dc->pc = dc->npc; |
385 | - dc->npc = (uint8_t *) target; | 415 | + dc->npc = target; |
386 | } | 416 | } |
387 | } else { | 417 | } else { |
418 | + flush_T2(dc); | ||
388 | gen_cond(cond); | 419 | gen_cond(cond); |
389 | if (a) { | 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 | dc->is_br = 1; | 422 | dc->is_br = 1; |
393 | - dc->pc = NULL; | ||
394 | - dc->npc = NULL; | ||
395 | } else { | 423 | } else { |
396 | dc->pc = dc->npc; | 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,18 +437,11 @@ static int sign_extend(int x, int len) | ||
409 | return (x << len) >> len; | 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 | static void disas_sparc_insn(DisasContext * dc) | 440 | static void disas_sparc_insn(DisasContext * dc) |
420 | { | 441 | { |
421 | unsigned int insn, opc, rs1, rs2, rd; | 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 | opc = GET_FIELD(insn, 0, 1); | 445 | opc = GET_FIELD(insn, 0, 1); |
425 | 446 | ||
426 | rd = GET_FIELD(insn, 2, 6); | 447 | rd = GET_FIELD(insn, 2, 6); |
@@ -458,9 +479,9 @@ static void disas_sparc_insn(DisasContext * dc) | @@ -458,9 +479,9 @@ static void disas_sparc_insn(DisasContext * dc) | ||
458 | 479 | ||
459 | gen_op_movl_T0_im((long) (dc->pc)); | 480 | gen_op_movl_T0_im((long) (dc->pc)); |
460 | gen_movl_T0_reg(15); | 481 | gen_movl_T0_reg(15); |
461 | - target = (long) dc->pc + target; | 482 | + target = dc->pc + target; |
462 | dc->pc = dc->npc; | 483 | dc->pc = dc->npc; |
463 | - dc->npc = (uint8_t *) target; | 484 | + dc->npc = target; |
464 | } | 485 | } |
465 | goto jmp_insn; | 486 | goto jmp_insn; |
466 | case 2: /* FPU & Logical Operations */ | 487 | case 2: /* FPU & Logical Operations */ |
@@ -625,7 +646,7 @@ static void disas_sparc_insn(DisasContext * dc) | @@ -625,7 +646,7 @@ static void disas_sparc_insn(DisasContext * dc) | ||
625 | gen_movl_T0_reg(rd); | 646 | gen_movl_T0_reg(rd); |
626 | } | 647 | } |
627 | dc->pc = dc->npc; | 648 | dc->pc = dc->npc; |
628 | - dc->npc = NULL; | 649 | + dc->npc = DYNAMIC_PC; |
629 | } | 650 | } |
630 | goto jmp_insn; | 651 | goto jmp_insn; |
631 | case 0x3b: /* flush */ | 652 | case 0x3b: /* flush */ |
@@ -705,6 +726,7 @@ static void disas_sparc_insn(DisasContext * dc) | @@ -705,6 +726,7 @@ static void disas_sparc_insn(DisasContext * dc) | ||
705 | gen_op_sth(); | 726 | gen_op_sth(); |
706 | break; | 727 | break; |
707 | case 0x7: | 728 | case 0x7: |
729 | + flush_T2(dc); | ||
708 | gen_movl_reg_T2(rd + 1); | 730 | gen_movl_reg_T2(rd + 1); |
709 | gen_op_std(); | 731 | gen_op_std(); |
710 | break; | 732 | break; |
@@ -713,19 +735,21 @@ static void disas_sparc_insn(DisasContext * dc) | @@ -713,19 +735,21 @@ static void disas_sparc_insn(DisasContext * dc) | ||
713 | } | 735 | } |
714 | } | 736 | } |
715 | /* default case for non jump instructions */ | 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 | dc->pc = dc->npc; | 746 | dc->pc = dc->npc; |
718 | dc->npc = dc->npc + 4; | 747 | dc->npc = dc->npc + 4; |
719 | - } else { | ||
720 | - dc->pc = NULL; | ||
721 | - gen_op_next_insn(); | ||
722 | } | 748 | } |
723 | jmp_insn:; | 749 | jmp_insn:; |
724 | return; | 750 | return; |
725 | illegal_insn: | 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 | gen_op_exception(TT_ILL_INSN); | 753 | gen_op_exception(TT_ILL_INSN); |
730 | dc->is_br = 1; | 754 | dc->is_br = 1; |
731 | } | 755 | } |
@@ -733,7 +757,7 @@ static void disas_sparc_insn(DisasContext * dc) | @@ -733,7 +757,7 @@ static void disas_sparc_insn(DisasContext * dc) | ||
733 | static inline int gen_intermediate_code_internal(TranslationBlock * tb, | 757 | static inline int gen_intermediate_code_internal(TranslationBlock * tb, |
734 | int spc) | 758 | int spc) |
735 | { | 759 | { |
736 | - uint8_t *pc_start, *last_pc; | 760 | + target_ulong pc_start, last_pc; |
737 | uint16_t *gen_opc_end; | 761 | uint16_t *gen_opc_end; |
738 | DisasContext dc1, *dc = &dc1; | 762 | DisasContext dc1, *dc = &dc1; |
739 | 763 | ||
@@ -743,9 +767,9 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | @@ -743,9 +767,9 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | ||
743 | exit(0); | 767 | exit(0); |
744 | } | 768 | } |
745 | dc->tb = tb; | 769 | dc->tb = tb; |
746 | - pc_start = (uint8_t *) tb->pc; | 770 | + pc_start = tb->pc; |
747 | dc->pc = pc_start; | 771 | dc->pc = pc_start; |
748 | - dc->npc = (uint8_t *) tb->cs_base; | 772 | + dc->npc = (target_ulong) tb->cs_base; |
749 | 773 | ||
750 | gen_opc_ptr = gen_opc_buf; | 774 | gen_opc_ptr = gen_opc_buf; |
751 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; | 775 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
@@ -761,19 +785,25 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | @@ -761,19 +785,25 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | ||
761 | break; | 785 | break; |
762 | } while ((gen_opc_ptr < gen_opc_end) && | 786 | } while ((gen_opc_ptr < gen_opc_end) && |
763 | (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); | 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 | *gen_opc_ptr = INDEX_op_end; | 801 | *gen_opc_ptr = INDEX_op_end; |
772 | #ifdef DEBUG_DISAS | 802 | #ifdef DEBUG_DISAS |
773 | if (loglevel) { | 803 | if (loglevel) { |
774 | fprintf(logfile, "--------------\n"); | 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 | fprintf(logfile, "\n"); | 807 | fprintf(logfile, "\n"); |
778 | fprintf(logfile, "OP:\n"); | 808 | fprintf(logfile, "OP:\n"); |
779 | dump_ops(gen_opc_buf, gen_opparam_buf); | 809 | dump_ops(gen_opc_buf, gen_opparam_buf); |