Commit 4b6d0a4c7a3d029cdc4bf6520280275814f501c9

Authored by j_mayer
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 /*****************************************************************************/
... ...