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); | ... | ... |