Commit 4b6d0a4c7a3d029cdc4bf6520280275814f501c9
1 parent
e9ebed4d
PowerPC embedded timers fixes.
Improve PowerPC timers debug. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2715 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
101 additions
and
53 deletions
hw/ppc.c
| ... | ... | @@ -25,6 +25,7 @@ |
| 25 | 25 | #include "m48t59.h" |
| 26 | 26 | |
| 27 | 27 | //#define PPC_DEBUG_IRQ |
| 28 | +//#define PPC_DEBUG_TB | |
| 28 | 29 | |
| 29 | 30 | extern FILE *logfile; |
| 30 | 31 | extern int loglevel; |
| ... | ... | @@ -404,8 +405,6 @@ void ppc405_irq_init (CPUState *env) |
| 404 | 405 | |
| 405 | 406 | /*****************************************************************************/ |
| 406 | 407 | /* PowerPC time base and decrementer emulation */ |
| 407 | -//#define DEBUG_TB | |
| 408 | - | |
| 409 | 408 | struct ppc_tb_t { |
| 410 | 409 | /* Time base management */ |
| 411 | 410 | int64_t tb_offset; /* Compensation */ |
| ... | ... | @@ -429,14 +428,14 @@ uint32_t cpu_ppc_load_tbl (CPUState *env) |
| 429 | 428 | uint64_t tb; |
| 430 | 429 | |
| 431 | 430 | tb = cpu_ppc_get_tb(tb_env); |
| 432 | -#ifdef DEBUG_TB | |
| 431 | +#ifdef PPC_DEBUG_TB | |
| 433 | 432 | { |
| 434 | 433 | static int last_time; |
| 435 | 434 | int now; |
| 436 | 435 | now = time(NULL); |
| 437 | 436 | if (last_time != now) { |
| 438 | 437 | last_time = now; |
| 439 | - if (loglevel) { | |
| 438 | + if (loglevel != 0) { | |
| 440 | 439 | fprintf(logfile, "%s: tb=0x%016lx %d %08lx\n", |
| 441 | 440 | __func__, tb, now, tb_env->tb_offset); |
| 442 | 441 | } |
| ... | ... | @@ -453,8 +452,8 @@ uint32_t cpu_ppc_load_tbu (CPUState *env) |
| 453 | 452 | uint64_t tb; |
| 454 | 453 | |
| 455 | 454 | tb = cpu_ppc_get_tb(tb_env); |
| 456 | -#ifdef DEBUG_TB | |
| 457 | - if (loglevel) { | |
| 455 | +#if defined(PPC_DEBUG_TB) | |
| 456 | + if (loglevel != 0) { | |
| 458 | 457 | fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); |
| 459 | 458 | } |
| 460 | 459 | #endif |
| ... | ... | @@ -466,9 +465,10 @@ static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value) |
| 466 | 465 | { |
| 467 | 466 | tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq) |
| 468 | 467 | - qemu_get_clock(vm_clock); |
| 469 | -#ifdef DEBUG_TB | |
| 470 | - if (loglevel) { | |
| 471 | - fprintf(logfile, "%s: tb=0x%016lx offset=%08x\n", __func__, value); | |
| 468 | +#ifdef PPC_DEBUG_TB | |
| 469 | + if (loglevel != 0) { | |
| 470 | + fprintf(logfile, "%s: tb=0x%016lx offset=%08lx\n", __func__, value, | |
| 471 | + tb_env->tb_offset); | |
| 472 | 472 | } |
| 473 | 473 | #endif |
| 474 | 474 | } |
| ... | ... | @@ -500,8 +500,8 @@ uint32_t cpu_ppc_load_decr (CPUState *env) |
| 500 | 500 | decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec); |
| 501 | 501 | else |
| 502 | 502 | decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec); |
| 503 | -#if defined(DEBUG_TB) | |
| 504 | - if (loglevel) { | |
| 503 | +#if defined(PPC_DEBUG_TB) | |
| 504 | + if (loglevel != 0) { | |
| 505 | 505 | fprintf(logfile, "%s: 0x%08x\n", __func__, decr); |
| 506 | 506 | } |
| 507 | 507 | #endif |
| ... | ... | @@ -515,8 +515,8 @@ uint32_t cpu_ppc_load_decr (CPUState *env) |
| 515 | 515 | static inline void cpu_ppc_decr_excp (CPUState *env) |
| 516 | 516 | { |
| 517 | 517 | /* Raise it */ |
| 518 | -#ifdef DEBUG_TB | |
| 519 | - if (loglevel) { | |
| 518 | +#ifdef PPC_DEBUG_TB | |
| 519 | + if (loglevel != 0) { | |
| 520 | 520 | fprintf(logfile, "raise decrementer exception\n"); |
| 521 | 521 | } |
| 522 | 522 | #endif |
| ... | ... | @@ -529,8 +529,8 @@ static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, |
| 529 | 529 | ppc_tb_t *tb_env = env->tb_env; |
| 530 | 530 | uint64_t now, next; |
| 531 | 531 | |
| 532 | -#ifdef DEBUG_TB | |
| 533 | - if (loglevel) { | |
| 532 | +#ifdef PPC_DEBUG_TB | |
| 533 | + if (loglevel != 0) { | |
| 534 | 534 | fprintf(logfile, "%s: 0x%08x => 0x%08x\n", __func__, decr, value); |
| 535 | 535 | } |
| 536 | 536 | #endif |
| ... | ... | @@ -657,42 +657,69 @@ static void cpu_4xx_fit_cb (void *opaque) |
| 657 | 657 | if (next == now) |
| 658 | 658 | next++; |
| 659 | 659 | qemu_mod_timer(ppcemb_timer->fit_timer, next); |
| 660 | - tb_env->decr_next = next; | |
| 661 | 660 | env->spr[SPR_40x_TSR] |= 1 << 26; |
| 662 | 661 | if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) |
| 663 | 662 | ppc_set_irq(env, PPC_INTERRUPT_FIT, 1); |
| 664 | - if (loglevel) { | |
| 663 | +#ifdef PPC_DEBUG_TB | |
| 664 | + if (loglevel != 0) { | |
| 665 | 665 | fprintf(logfile, "%s: ir %d TCR " ADDRX " TSR " ADDRX "\n", __func__, |
| 666 | 666 | (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), |
| 667 | 667 | env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); |
| 668 | 668 | } |
| 669 | +#endif | |
| 669 | 670 | } |
| 670 | 671 | |
| 671 | 672 | /* Programmable interval timer */ |
| 672 | -static void cpu_4xx_pit_cb (void *opaque) | |
| 673 | +static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp) | |
| 673 | 674 | { |
| 674 | - CPUState *env; | |
| 675 | - ppc_tb_t *tb_env; | |
| 676 | 675 | ppcemb_timer_t *ppcemb_timer; |
| 677 | 676 | uint64_t now, next; |
| 678 | 677 | |
| 679 | - env = opaque; | |
| 680 | - tb_env = env->tb_env; | |
| 681 | 678 | ppcemb_timer = tb_env->opaque; |
| 682 | - now = qemu_get_clock(vm_clock); | |
| 683 | - if ((env->spr[SPR_40x_TCR] >> 22) & 0x1) { | |
| 684 | - /* Auto reload */ | |
| 679 | + if (ppcemb_timer->pit_reload <= 1 || | |
| 680 | + !((env->spr[SPR_40x_TCR] >> 26) & 0x1) || | |
| 681 | + (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) { | |
| 682 | + /* Stop PIT */ | |
| 683 | +#ifdef PPC_DEBUG_TB | |
| 684 | + if (loglevel != 0) { | |
| 685 | + fprintf(logfile, "%s: stop PIT\n", __func__); | |
| 686 | + } | |
| 687 | +#endif | |
| 688 | + qemu_del_timer(tb_env->decr_timer); | |
| 689 | + } else { | |
| 690 | +#ifdef PPC_DEBUG_TB | |
| 691 | + if (loglevel != 0) { | |
| 692 | + fprintf(logfile, "%s: start PIT 0x" REGX "\n", | |
| 693 | + __func__, ppcemb_timer->pit_reload); | |
| 694 | + } | |
| 695 | +#endif | |
| 696 | + now = qemu_get_clock(vm_clock); | |
| 685 | 697 | next = now + muldiv64(ppcemb_timer->pit_reload, |
| 686 | 698 | ticks_per_sec, tb_env->tb_freq); |
| 699 | + if (is_excp) | |
| 700 | + next += tb_env->decr_next - now; | |
| 687 | 701 | if (next == now) |
| 688 | 702 | next++; |
| 689 | 703 | qemu_mod_timer(tb_env->decr_timer, next); |
| 690 | 704 | tb_env->decr_next = next; |
| 691 | 705 | } |
| 706 | +} | |
| 707 | + | |
| 708 | +static void cpu_4xx_pit_cb (void *opaque) | |
| 709 | +{ | |
| 710 | + CPUState *env; | |
| 711 | + ppc_tb_t *tb_env; | |
| 712 | + ppcemb_timer_t *ppcemb_timer; | |
| 713 | + | |
| 714 | + env = opaque; | |
| 715 | + tb_env = env->tb_env; | |
| 716 | + ppcemb_timer = tb_env->opaque; | |
| 692 | 717 | env->spr[SPR_40x_TSR] |= 1 << 27; |
| 693 | 718 | if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) |
| 694 | 719 | ppc_set_irq(env, PPC_INTERRUPT_PIT, 1); |
| 695 | - if (loglevel) { | |
| 720 | + start_stop_pit(env, tb_env, 1); | |
| 721 | +#ifdef PPC_DEBUG_TB | |
| 722 | + if (loglevel != 0) { | |
| 696 | 723 | fprintf(logfile, "%s: ar %d ir %d TCR " ADDRX " TSR " ADDRX " " |
| 697 | 724 | "%016" PRIx64 "\n", __func__, |
| 698 | 725 | (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), |
| ... | ... | @@ -700,6 +727,7 @@ static void cpu_4xx_pit_cb (void *opaque) |
| 700 | 727 | env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], |
| 701 | 728 | ppcemb_timer->pit_reload); |
| 702 | 729 | } |
| 730 | +#endif | |
| 703 | 731 | } |
| 704 | 732 | |
| 705 | 733 | /* Watchdog timer */ |
| ... | ... | @@ -734,10 +762,12 @@ static void cpu_4xx_wdt_cb (void *opaque) |
| 734 | 762 | next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq); |
| 735 | 763 | if (next == now) |
| 736 | 764 | next++; |
| 737 | - if (loglevel) { | |
| 765 | +#ifdef PPC_DEBUG_TB | |
| 766 | + if (loglevel != 0) { | |
| 738 | 767 | fprintf(logfile, "%s: TCR " ADDRX " TSR " ADDRX "\n", __func__, |
| 739 | 768 | env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); |
| 740 | 769 | } |
| 770 | +#endif | |
| 741 | 771 | switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { |
| 742 | 772 | case 0x0: |
| 743 | 773 | case 0x1: |
| ... | ... | @@ -776,31 +806,16 @@ void store_40x_pit (CPUState *env, target_ulong val) |
| 776 | 806 | { |
| 777 | 807 | ppc_tb_t *tb_env; |
| 778 | 808 | ppcemb_timer_t *ppcemb_timer; |
| 779 | - uint64_t now, next; | |
| 780 | 809 | |
| 781 | 810 | tb_env = env->tb_env; |
| 782 | 811 | ppcemb_timer = tb_env->opaque; |
| 783 | - if (loglevel) { | |
| 812 | +#ifdef PPC_DEBUG_TB | |
| 813 | + if (loglevel != 0) { | |
| 784 | 814 | fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer); |
| 785 | 815 | } |
| 816 | +#endif | |
| 786 | 817 | ppcemb_timer->pit_reload = val; |
| 787 | - if (val == 0) { | |
| 788 | - /* Stop PIT */ | |
| 789 | - if (loglevel) { | |
| 790 | - fprintf(logfile, "%s: stop PIT\n", __func__); | |
| 791 | - } | |
| 792 | - qemu_del_timer(tb_env->decr_timer); | |
| 793 | - } else { | |
| 794 | - if (loglevel) { | |
| 795 | - fprintf(logfile, "%s: start PIT 0x" ADDRX "\n", __func__, val); | |
| 796 | - } | |
| 797 | - now = qemu_get_clock(vm_clock); | |
| 798 | - next = now + muldiv64(val, ticks_per_sec, tb_env->tb_freq); | |
| 799 | - if (next == now) | |
| 800 | - next++; | |
| 801 | - qemu_mod_timer(tb_env->decr_timer, next); | |
| 802 | - tb_env->decr_next = next; | |
| 803 | - } | |
| 818 | + start_stop_pit(env, tb_env, 0); | |
| 804 | 819 | } |
| 805 | 820 | |
| 806 | 821 | target_ulong load_40x_pit (CPUState *env) |
| ... | ... | @@ -810,30 +825,64 @@ target_ulong load_40x_pit (CPUState *env) |
| 810 | 825 | |
| 811 | 826 | void store_booke_tsr (CPUState *env, target_ulong val) |
| 812 | 827 | { |
| 813 | - env->spr[SPR_40x_TSR] = val & 0xFC000000; | |
| 828 | +#ifdef PPC_DEBUG_TB | |
| 829 | + if (loglevel != 0) { | |
| 830 | + fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val); | |
| 831 | + } | |
| 832 | +#endif | |
| 833 | + env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000); | |
| 834 | + if (val & 0x80000000) | |
| 835 | + ppc_set_irq(env, PPC_INTERRUPT_PIT, 0); | |
| 814 | 836 | } |
| 815 | 837 | |
| 816 | 838 | void store_booke_tcr (CPUState *env, target_ulong val) |
| 817 | 839 | { |
| 818 | - env->spr[SPR_40x_TCR] = val & 0xFF800000; | |
| 840 | + ppc_tb_t *tb_env; | |
| 841 | + | |
| 842 | + tb_env = env->tb_env; | |
| 843 | +#ifdef PPC_DEBUG_TB | |
| 844 | + if (loglevel != 0) { | |
| 845 | + fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val); | |
| 846 | + } | |
| 847 | +#endif | |
| 848 | + env->spr[SPR_40x_TCR] = val & 0xFFC00000; | |
| 849 | + start_stop_pit(env, tb_env, 1); | |
| 819 | 850 | cpu_4xx_wdt_cb(env); |
| 820 | 851 | } |
| 821 | 852 | |
| 853 | +static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq) | |
| 854 | +{ | |
| 855 | + CPUState *env = opaque; | |
| 856 | + ppc_tb_t *tb_env = env->tb_env; | |
| 857 | + | |
| 858 | +#ifdef PPC_DEBUG_TB | |
| 859 | + if (loglevel != 0) { | |
| 860 | + fprintf(logfile, "%s set new frequency to %u\n", __func__, freq); | |
| 861 | + } | |
| 862 | +#endif | |
| 863 | + tb_env->tb_freq = freq; | |
| 864 | + /* XXX: we should also update all timers */ | |
| 865 | +} | |
| 866 | + | |
| 822 | 867 | clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq) |
| 823 | 868 | { |
| 824 | 869 | ppc_tb_t *tb_env; |
| 825 | 870 | ppcemb_timer_t *ppcemb_timer; |
| 826 | 871 | |
| 827 | 872 | tb_env = qemu_mallocz(sizeof(ppc_tb_t)); |
| 828 | - if (tb_env == NULL) | |
| 873 | + if (tb_env == NULL) { | |
| 829 | 874 | return NULL; |
| 875 | + } | |
| 830 | 876 | env->tb_env = tb_env; |
| 831 | 877 | ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t)); |
| 832 | 878 | tb_env->tb_freq = freq; |
| 833 | 879 | tb_env->opaque = ppcemb_timer; |
| 834 | - if (loglevel) { | |
| 835 | - fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer); | |
| 880 | +#ifdef PPC_DEBUG_TB | |
| 881 | + if (loglevel != 0) { | |
| 882 | + fprintf(logfile, "%s %p %p %p\n", __func__, tb_env, ppcemb_timer, | |
| 883 | + &ppc_emb_set_tb_clk); | |
| 836 | 884 | } |
| 885 | +#endif | |
| 837 | 886 | if (ppcemb_timer != NULL) { |
| 838 | 887 | /* We use decr timer for PIT */ |
| 839 | 888 | tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env); |
| ... | ... | @@ -843,8 +892,7 @@ clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq) |
| 843 | 892 | qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env); |
| 844 | 893 | } |
| 845 | 894 | |
| 846 | - /* XXX: TODO: add callback for clock frequency change */ | |
| 847 | - return NULL; | |
| 895 | + return &ppc_emb_set_tb_clk; | |
| 848 | 896 | } |
| 849 | 897 | |
| 850 | 898 | /*****************************************************************************/ | ... | ... |