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,6 +25,7 @@
25 #include "m48t59.h" 25 #include "m48t59.h"
26 26
27 //#define PPC_DEBUG_IRQ 27 //#define PPC_DEBUG_IRQ
  28 +//#define PPC_DEBUG_TB
28 29
29 extern FILE *logfile; 30 extern FILE *logfile;
30 extern int loglevel; 31 extern int loglevel;
@@ -404,8 +405,6 @@ void ppc405_irq_init (CPUState *env) @@ -404,8 +405,6 @@ void ppc405_irq_init (CPUState *env)
404 405
405 /*****************************************************************************/ 406 /*****************************************************************************/
406 /* PowerPC time base and decrementer emulation */ 407 /* PowerPC time base and decrementer emulation */
407 -//#define DEBUG_TB  
408 -  
409 struct ppc_tb_t { 408 struct ppc_tb_t {
410 /* Time base management */ 409 /* Time base management */
411 int64_t tb_offset; /* Compensation */ 410 int64_t tb_offset; /* Compensation */
@@ -429,14 +428,14 @@ uint32_t cpu_ppc_load_tbl (CPUState *env) @@ -429,14 +428,14 @@ uint32_t cpu_ppc_load_tbl (CPUState *env)
429 uint64_t tb; 428 uint64_t tb;
430 429
431 tb = cpu_ppc_get_tb(tb_env); 430 tb = cpu_ppc_get_tb(tb_env);
432 -#ifdef DEBUG_TB 431 +#ifdef PPC_DEBUG_TB
433 { 432 {
434 static int last_time; 433 static int last_time;
435 int now; 434 int now;
436 now = time(NULL); 435 now = time(NULL);
437 if (last_time != now) { 436 if (last_time != now) {
438 last_time = now; 437 last_time = now;
439 - if (loglevel) { 438 + if (loglevel != 0) {
440 fprintf(logfile, "%s: tb=0x%016lx %d %08lx\n", 439 fprintf(logfile, "%s: tb=0x%016lx %d %08lx\n",
441 __func__, tb, now, tb_env->tb_offset); 440 __func__, tb, now, tb_env->tb_offset);
442 } 441 }
@@ -453,8 +452,8 @@ uint32_t cpu_ppc_load_tbu (CPUState *env) @@ -453,8 +452,8 @@ uint32_t cpu_ppc_load_tbu (CPUState *env)
453 uint64_t tb; 452 uint64_t tb;
454 453
455 tb = cpu_ppc_get_tb(tb_env); 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 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); 457 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
459 } 458 }
460 #endif 459 #endif
@@ -466,9 +465,10 @@ static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value) @@ -466,9 +465,10 @@ static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value)
466 { 465 {
467 tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq) 466 tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq)
468 - qemu_get_clock(vm_clock); 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 #endif 473 #endif
474 } 474 }
@@ -500,8 +500,8 @@ uint32_t cpu_ppc_load_decr (CPUState *env) @@ -500,8 +500,8 @@ uint32_t cpu_ppc_load_decr (CPUState *env)
500 decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec); 500 decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
501 else 501 else
502 decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec); 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 fprintf(logfile, "%s: 0x%08x\n", __func__, decr); 505 fprintf(logfile, "%s: 0x%08x\n", __func__, decr);
506 } 506 }
507 #endif 507 #endif
@@ -515,8 +515,8 @@ uint32_t cpu_ppc_load_decr (CPUState *env) @@ -515,8 +515,8 @@ uint32_t cpu_ppc_load_decr (CPUState *env)
515 static inline void cpu_ppc_decr_excp (CPUState *env) 515 static inline void cpu_ppc_decr_excp (CPUState *env)
516 { 516 {
517 /* Raise it */ 517 /* Raise it */
518 -#ifdef DEBUG_TB  
519 - if (loglevel) { 518 +#ifdef PPC_DEBUG_TB
  519 + if (loglevel != 0) {
520 fprintf(logfile, "raise decrementer exception\n"); 520 fprintf(logfile, "raise decrementer exception\n");
521 } 521 }
522 #endif 522 #endif
@@ -529,8 +529,8 @@ static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, @@ -529,8 +529,8 @@ static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
529 ppc_tb_t *tb_env = env->tb_env; 529 ppc_tb_t *tb_env = env->tb_env;
530 uint64_t now, next; 530 uint64_t now, next;
531 531
532 -#ifdef DEBUG_TB  
533 - if (loglevel) { 532 +#ifdef PPC_DEBUG_TB
  533 + if (loglevel != 0) {
534 fprintf(logfile, "%s: 0x%08x => 0x%08x\n", __func__, decr, value); 534 fprintf(logfile, "%s: 0x%08x => 0x%08x\n", __func__, decr, value);
535 } 535 }
536 #endif 536 #endif
@@ -657,42 +657,69 @@ static void cpu_4xx_fit_cb (void *opaque) @@ -657,42 +657,69 @@ static void cpu_4xx_fit_cb (void *opaque)
657 if (next == now) 657 if (next == now)
658 next++; 658 next++;
659 qemu_mod_timer(ppcemb_timer->fit_timer, next); 659 qemu_mod_timer(ppcemb_timer->fit_timer, next);
660 - tb_env->decr_next = next;  
661 env->spr[SPR_40x_TSR] |= 1 << 26; 660 env->spr[SPR_40x_TSR] |= 1 << 26;
662 if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) 661 if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
663 ppc_set_irq(env, PPC_INTERRUPT_FIT, 1); 662 ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
664 - if (loglevel) { 663 +#ifdef PPC_DEBUG_TB
  664 + if (loglevel != 0) {
665 fprintf(logfile, "%s: ir %d TCR " ADDRX " TSR " ADDRX "\n", __func__, 665 fprintf(logfile, "%s: ir %d TCR " ADDRX " TSR " ADDRX "\n", __func__,
666 (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), 666 (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
667 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 667 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
668 } 668 }
  669 +#endif
669 } 670 }
670 671
671 /* Programmable interval timer */ 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 ppcemb_timer_t *ppcemb_timer; 675 ppcemb_timer_t *ppcemb_timer;
677 uint64_t now, next; 676 uint64_t now, next;
678 677
679 - env = opaque;  
680 - tb_env = env->tb_env;  
681 ppcemb_timer = tb_env->opaque; 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 next = now + muldiv64(ppcemb_timer->pit_reload, 697 next = now + muldiv64(ppcemb_timer->pit_reload,
686 ticks_per_sec, tb_env->tb_freq); 698 ticks_per_sec, tb_env->tb_freq);
  699 + if (is_excp)
  700 + next += tb_env->decr_next - now;
687 if (next == now) 701 if (next == now)
688 next++; 702 next++;
689 qemu_mod_timer(tb_env->decr_timer, next); 703 qemu_mod_timer(tb_env->decr_timer, next);
690 tb_env->decr_next = next; 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 env->spr[SPR_40x_TSR] |= 1 << 27; 717 env->spr[SPR_40x_TSR] |= 1 << 27;
693 if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) 718 if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
694 ppc_set_irq(env, PPC_INTERRUPT_PIT, 1); 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 fprintf(logfile, "%s: ar %d ir %d TCR " ADDRX " TSR " ADDRX " " 723 fprintf(logfile, "%s: ar %d ir %d TCR " ADDRX " TSR " ADDRX " "
697 "%016" PRIx64 "\n", __func__, 724 "%016" PRIx64 "\n", __func__,
698 (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), 725 (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
@@ -700,6 +727,7 @@ static void cpu_4xx_pit_cb (void *opaque) @@ -700,6 +727,7 @@ static void cpu_4xx_pit_cb (void *opaque)
700 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], 727 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
701 ppcemb_timer->pit_reload); 728 ppcemb_timer->pit_reload);
702 } 729 }
  730 +#endif
703 } 731 }
704 732
705 /* Watchdog timer */ 733 /* Watchdog timer */
@@ -734,10 +762,12 @@ static void cpu_4xx_wdt_cb (void *opaque) @@ -734,10 +762,12 @@ static void cpu_4xx_wdt_cb (void *opaque)
734 next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq); 762 next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
735 if (next == now) 763 if (next == now)
736 next++; 764 next++;
737 - if (loglevel) { 765 +#ifdef PPC_DEBUG_TB
  766 + if (loglevel != 0) {
738 fprintf(logfile, "%s: TCR " ADDRX " TSR " ADDRX "\n", __func__, 767 fprintf(logfile, "%s: TCR " ADDRX " TSR " ADDRX "\n", __func__,
739 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 768 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
740 } 769 }
  770 +#endif
741 switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { 771 switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
742 case 0x0: 772 case 0x0:
743 case 0x1: 773 case 0x1:
@@ -776,31 +806,16 @@ void store_40x_pit (CPUState *env, target_ulong val) @@ -776,31 +806,16 @@ void store_40x_pit (CPUState *env, target_ulong val)
776 { 806 {
777 ppc_tb_t *tb_env; 807 ppc_tb_t *tb_env;
778 ppcemb_timer_t *ppcemb_timer; 808 ppcemb_timer_t *ppcemb_timer;
779 - uint64_t now, next;  
780 809
781 tb_env = env->tb_env; 810 tb_env = env->tb_env;
782 ppcemb_timer = tb_env->opaque; 811 ppcemb_timer = tb_env->opaque;
783 - if (loglevel) { 812 +#ifdef PPC_DEBUG_TB
  813 + if (loglevel != 0) {
784 fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer); 814 fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer);
785 } 815 }
  816 +#endif
786 ppcemb_timer->pit_reload = val; 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 target_ulong load_40x_pit (CPUState *env) 821 target_ulong load_40x_pit (CPUState *env)
@@ -810,30 +825,64 @@ target_ulong load_40x_pit (CPUState *env) @@ -810,30 +825,64 @@ target_ulong load_40x_pit (CPUState *env)
810 825
811 void store_booke_tsr (CPUState *env, target_ulong val) 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 void store_booke_tcr (CPUState *env, target_ulong val) 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 cpu_4xx_wdt_cb(env); 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 clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq) 867 clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
823 { 868 {
824 ppc_tb_t *tb_env; 869 ppc_tb_t *tb_env;
825 ppcemb_timer_t *ppcemb_timer; 870 ppcemb_timer_t *ppcemb_timer;
826 871
827 tb_env = qemu_mallocz(sizeof(ppc_tb_t)); 872 tb_env = qemu_mallocz(sizeof(ppc_tb_t));
828 - if (tb_env == NULL) 873 + if (tb_env == NULL) {
829 return NULL; 874 return NULL;
  875 + }
830 env->tb_env = tb_env; 876 env->tb_env = tb_env;
831 ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t)); 877 ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
832 tb_env->tb_freq = freq; 878 tb_env->tb_freq = freq;
833 tb_env->opaque = ppcemb_timer; 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 if (ppcemb_timer != NULL) { 886 if (ppcemb_timer != NULL) {
838 /* We use decr timer for PIT */ 887 /* We use decr timer for PIT */
839 tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env); 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,8 +892,7 @@ clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
843 qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env); 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 /*****************************************************************************/