Commit dbdd25065e90ba78c01b03d238785f25476c04a1

Authored by j_mayer
1 parent d68f1306

Implement time-base start/stop helpers.

Implement PowerPC 6xx time-base enable input pin.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3394 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 92 additions and 29 deletions
hw/ppc.c
@@ -30,6 +30,9 @@ @@ -30,6 +30,9 @@
30 extern FILE *logfile; 30 extern FILE *logfile;
31 extern int loglevel; 31 extern int loglevel;
32 32
  33 +static void cpu_ppc_tb_stop (CPUState *env);
  34 +static void cpu_ppc_tb_start (CPUState *env);
  35 +
33 static void ppc_set_irq (CPUState *env, int n_IRQ, int level) 36 static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
34 { 37 {
35 if (level) { 38 if (level) {
@@ -65,6 +68,19 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) @@ -65,6 +68,19 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level)
65 /* Don't generate spurious events */ 68 /* Don't generate spurious events */
66 if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 69 if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
67 switch (pin) { 70 switch (pin) {
  71 + case PPC6xx_INPUT_TBEN:
  72 + /* Level sensitive - active high */
  73 +#if defined(PPC_DEBUG_IRQ)
  74 + if (loglevel & CPU_LOG_INT) {
  75 + fprintf(logfile, "%s: %s the time base\n",
  76 + __func__, level ? "start" : "stop");
  77 + }
  78 +#endif
  79 + if (level) {
  80 + cpu_ppc_tb_start(env);
  81 + } else {
  82 + cpu_ppc_tb_stop(env);
  83 + }
68 case PPC6xx_INPUT_INT: 84 case PPC6xx_INPUT_INT:
69 /* Level sensitive - active high */ 85 /* Level sensitive - active high */
70 #if defined(PPC_DEBUG_IRQ) 86 #if defined(PPC_DEBUG_IRQ)
@@ -402,11 +418,12 @@ void ppc40x_irq_init (CPUState *env) @@ -402,11 +418,12 @@ void ppc40x_irq_init (CPUState *env)
402 /* PowerPC time base and decrementer emulation */ 418 /* PowerPC time base and decrementer emulation */
403 struct ppc_tb_t { 419 struct ppc_tb_t {
404 /* Time base management */ 420 /* Time base management */
405 - int64_t tb_offset; /* Compensation */  
406 - int64_t atb_offset; /* Compensation */  
407 - uint32_t tb_freq; /* TB frequency */ 421 + int64_t tb_offset; /* Compensation */
  422 + int64_t atb_offset; /* Compensation */
  423 + uint32_t tb_freq; /* TB frequency */
408 /* Decrementer management */ 424 /* Decrementer management */
409 - uint64_t decr_next; /* Tick for next decr interrupt */ 425 + uint64_t decr_next; /* Tick for next decr interrupt */
  426 + uint32_t decr_freq; /* decrementer frequency */
410 struct QEMUTimer *decr_timer; 427 struct QEMUTimer *decr_timer;
411 #if defined(TARGET_PPC64H) 428 #if defined(TARGET_PPC64H)
412 /* Hypervisor decrementer management */ 429 /* Hypervisor decrementer management */
@@ -418,12 +435,11 @@ struct ppc_tb_t { @@ -418,12 +435,11 @@ struct ppc_tb_t {
418 void *opaque; 435 void *opaque;
419 }; 436 };
420 437
421 -static always_inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env, 438 +static always_inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env, uint64_t vmclk,
422 int64_t tb_offset) 439 int64_t tb_offset)
423 { 440 {
424 /* TB time in tb periods */ 441 /* TB time in tb periods */
425 - return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset,  
426 - tb_env->tb_freq, ticks_per_sec); 442 + return muldiv64(vmclk, tb_env->tb_freq, ticks_per_sec) + tb_offset;
427 } 443 }
428 444
429 uint32_t cpu_ppc_load_tbl (CPUState *env) 445 uint32_t cpu_ppc_load_tbl (CPUState *env)
@@ -431,7 +447,7 @@ uint32_t cpu_ppc_load_tbl (CPUState *env) @@ -431,7 +447,7 @@ uint32_t cpu_ppc_load_tbl (CPUState *env)
431 ppc_tb_t *tb_env = env->tb_env; 447 ppc_tb_t *tb_env = env->tb_env;
432 uint64_t tb; 448 uint64_t tb;
433 449
434 - tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset); 450 + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
435 #if defined(PPC_DEBUG_TB) 451 #if defined(PPC_DEBUG_TB)
436 if (loglevel != 0) { 452 if (loglevel != 0) {
437 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); 453 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
@@ -446,7 +462,7 @@ static always_inline uint32_t _cpu_ppc_load_tbu (CPUState *env) @@ -446,7 +462,7 @@ static always_inline uint32_t _cpu_ppc_load_tbu (CPUState *env)
446 ppc_tb_t *tb_env = env->tb_env; 462 ppc_tb_t *tb_env = env->tb_env;
447 uint64_t tb; 463 uint64_t tb;
448 464
449 - tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset); 465 + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
450 #if defined(PPC_DEBUG_TB) 466 #if defined(PPC_DEBUG_TB)
451 if (loglevel != 0) { 467 if (loglevel != 0) {
452 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); 468 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
@@ -461,12 +477,11 @@ uint32_t cpu_ppc_load_tbu (CPUState *env) @@ -461,12 +477,11 @@ uint32_t cpu_ppc_load_tbu (CPUState *env)
461 return _cpu_ppc_load_tbu(env); 477 return _cpu_ppc_load_tbu(env);
462 } 478 }
463 479
464 -static always_inline void cpu_ppc_store_tb (ppc_tb_t *tb_env, 480 +static always_inline void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t vmclk,
465 int64_t *tb_offsetp, 481 int64_t *tb_offsetp,
466 uint64_t value) 482 uint64_t value)
467 { 483 {
468 - *tb_offsetp = muldiv64(value, ticks_per_sec, tb_env->tb_freq)  
469 - - qemu_get_clock(vm_clock); 484 + *tb_offsetp = value - muldiv64(vmclk, tb_env->tb_freq, ticks_per_sec);
470 #ifdef PPC_DEBUG_TB 485 #ifdef PPC_DEBUG_TB
471 if (loglevel != 0) { 486 if (loglevel != 0) {
472 fprintf(logfile, "%s: tb=0x%016lx offset=%08lx\n", __func__, value, 487 fprintf(logfile, "%s: tb=0x%016lx offset=%08lx\n", __func__, value,
@@ -480,9 +495,10 @@ void cpu_ppc_store_tbl (CPUState *env, uint32_t value) @@ -480,9 +495,10 @@ void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
480 ppc_tb_t *tb_env = env->tb_env; 495 ppc_tb_t *tb_env = env->tb_env;
481 uint64_t tb; 496 uint64_t tb;
482 497
483 - tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset); 498 + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
484 tb &= 0xFFFFFFFF00000000ULL; 499 tb &= 0xFFFFFFFF00000000ULL;
485 - cpu_ppc_store_tb(tb_env, &tb_env->tb_offset, tb | (uint64_t)value); 500 + cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
  501 + &tb_env->tb_offset, tb | (uint64_t)value);
486 } 502 }
487 503
488 static always_inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value) 504 static always_inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value)
@@ -490,10 +506,10 @@ static always_inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value) @@ -490,10 +506,10 @@ static always_inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value)
490 ppc_tb_t *tb_env = env->tb_env; 506 ppc_tb_t *tb_env = env->tb_env;
491 uint64_t tb; 507 uint64_t tb;
492 508
493 - tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset); 509 + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
494 tb &= 0x00000000FFFFFFFFULL; 510 tb &= 0x00000000FFFFFFFFULL;
495 - cpu_ppc_store_tb(tb_env, &tb_env->tb_offset,  
496 - ((uint64_t)value << 32) | tb); 511 + cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
  512 + &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
497 } 513 }
498 514
499 void cpu_ppc_store_tbu (CPUState *env, uint32_t value) 515 void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
@@ -506,7 +522,7 @@ uint32_t cpu_ppc_load_atbl (CPUState *env) @@ -506,7 +522,7 @@ uint32_t cpu_ppc_load_atbl (CPUState *env)
506 ppc_tb_t *tb_env = env->tb_env; 522 ppc_tb_t *tb_env = env->tb_env;
507 uint64_t tb; 523 uint64_t tb;
508 524
509 - tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset); 525 + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
510 #if defined(PPC_DEBUG_TB) 526 #if defined(PPC_DEBUG_TB)
511 if (loglevel != 0) { 527 if (loglevel != 0) {
512 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); 528 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
@@ -521,7 +537,7 @@ uint32_t cpu_ppc_load_atbu (CPUState *env) @@ -521,7 +537,7 @@ uint32_t cpu_ppc_load_atbu (CPUState *env)
521 ppc_tb_t *tb_env = env->tb_env; 537 ppc_tb_t *tb_env = env->tb_env;
522 uint64_t tb; 538 uint64_t tb;
523 539
524 - tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset); 540 + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
525 #if defined(PPC_DEBUG_TB) 541 #if defined(PPC_DEBUG_TB)
526 if (loglevel != 0) { 542 if (loglevel != 0) {
527 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); 543 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
@@ -536,9 +552,10 @@ void cpu_ppc_store_atbl (CPUState *env, uint32_t value) @@ -536,9 +552,10 @@ void cpu_ppc_store_atbl (CPUState *env, uint32_t value)
536 ppc_tb_t *tb_env = env->tb_env; 552 ppc_tb_t *tb_env = env->tb_env;
537 uint64_t tb; 553 uint64_t tb;
538 554
539 - tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset); 555 + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
540 tb &= 0xFFFFFFFF00000000ULL; 556 tb &= 0xFFFFFFFF00000000ULL;
541 - cpu_ppc_store_tb(tb_env, &tb_env->atb_offset, tb | (uint64_t)value); 557 + cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
  558 + &tb_env->atb_offset, tb | (uint64_t)value);
542 } 559 }
543 560
544 void cpu_ppc_store_atbu (CPUState *env, uint32_t value) 561 void cpu_ppc_store_atbu (CPUState *env, uint32_t value)
@@ -546,10 +563,53 @@ void cpu_ppc_store_atbu (CPUState *env, uint32_t value) @@ -546,10 +563,53 @@ void cpu_ppc_store_atbu (CPUState *env, uint32_t value)
546 ppc_tb_t *tb_env = env->tb_env; 563 ppc_tb_t *tb_env = env->tb_env;
547 uint64_t tb; 564 uint64_t tb;
548 565
549 - tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset); 566 + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
550 tb &= 0x00000000FFFFFFFFULL; 567 tb &= 0x00000000FFFFFFFFULL;
551 - cpu_ppc_store_tb(tb_env, &tb_env->atb_offset,  
552 - ((uint64_t)value << 32) | tb); 568 + cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
  569 + &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
  570 +}
  571 +
  572 +static void cpu_ppc_tb_stop (CPUState *env)
  573 +{
  574 + ppc_tb_t *tb_env = env->tb_env;
  575 + uint64_t tb, atb, vmclk;
  576 +
  577 + /* If the time base is already frozen, do nothing */
  578 + if (tb_env->tb_freq != 0) {
  579 + vmclk = qemu_get_clock(vm_clock);
  580 + /* Get the time base */
  581 + tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
  582 + /* Get the alternate time base */
  583 + atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
  584 + /* Store the time base value (ie compute the current offset) */
  585 + cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
  586 + /* Store the alternate time base value (compute the current offset) */
  587 + cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
  588 + /* Set the time base frequency to zero */
  589 + tb_env->tb_freq = 0;
  590 + /* Now, the time bases are frozen to tb_offset / atb_offset value */
  591 + }
  592 +}
  593 +
  594 +static void cpu_ppc_tb_start (CPUState *env)
  595 +{
  596 + ppc_tb_t *tb_env = env->tb_env;
  597 + uint64_t tb, atb, vmclk;
  598 +
  599 + /* If the time base is not frozen, do nothing */
  600 + if (tb_env->tb_freq == 0) {
  601 + vmclk = qemu_get_clock(vm_clock);
  602 + /* Get the time base from tb_offset */
  603 + tb = tb_env->tb_offset;
  604 + /* Get the alternate time base from atb_offset */
  605 + atb = tb_env->atb_offset;
  606 + /* Restore the tb frequency from the decrementer frequency */
  607 + tb_env->tb_freq = tb_env->decr_freq;
  608 + /* Store the time base value */
  609 + cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
  610 + /* Store the alternate time base value */
  611 + cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
  612 + }
553 } 613 }
554 614
555 static always_inline uint32_t _cpu_ppc_load_decr (CPUState *env, 615 static always_inline uint32_t _cpu_ppc_load_decr (CPUState *env,
@@ -561,9 +621,9 @@ static always_inline uint32_t _cpu_ppc_load_decr (CPUState *env, @@ -561,9 +621,9 @@ static always_inline uint32_t _cpu_ppc_load_decr (CPUState *env,
561 621
562 diff = tb_env->decr_next - qemu_get_clock(vm_clock); 622 diff = tb_env->decr_next - qemu_get_clock(vm_clock);
563 if (diff >= 0) 623 if (diff >= 0)
564 - decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec); 624 + decr = muldiv64(diff, tb_env->decr_freq, ticks_per_sec);
565 else 625 else
566 - decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec); 626 + decr = -muldiv64(-diff, tb_env->decr_freq, ticks_per_sec);
567 #if defined(PPC_DEBUG_TB) 627 #if defined(PPC_DEBUG_TB)
568 if (loglevel != 0) { 628 if (loglevel != 0) {
569 fprintf(logfile, "%s: 0x%08x\n", __func__, decr); 629 fprintf(logfile, "%s: 0x%08x\n", __func__, decr);
@@ -639,7 +699,7 @@ static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp, @@ -639,7 +699,7 @@ static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp,
639 } 699 }
640 #endif 700 #endif
641 now = qemu_get_clock(vm_clock); 701 now = qemu_get_clock(vm_clock);
642 - next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq); 702 + next = now + muldiv64(value, ticks_per_sec, tb_env->decr_freq);
643 if (is_excp) 703 if (is_excp)
644 next += *nextp - now; 704 next += *nextp - now;
645 if (next == now) 705 if (next == now)
@@ -708,6 +768,7 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) @@ -708,6 +768,7 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
708 ppc_tb_t *tb_env = env->tb_env; 768 ppc_tb_t *tb_env = env->tb_env;
709 769
710 tb_env->tb_freq = freq; 770 tb_env->tb_freq = freq;
  771 + tb_env->decr_freq = freq;
711 /* There is a bug in Linux 2.4 kernels: 772 /* There is a bug in Linux 2.4 kernels:
712 * if a decrementer exception is pending when it enables msr_ee at startup, 773 * if a decrementer exception is pending when it enables msr_ee at startup,
713 * it's not ready to handle it... 774 * it's not ready to handle it...
@@ -848,7 +909,7 @@ static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp) @@ -848,7 +909,7 @@ static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
848 #endif 909 #endif
849 now = qemu_get_clock(vm_clock); 910 now = qemu_get_clock(vm_clock);
850 next = now + muldiv64(ppcemb_timer->pit_reload, 911 next = now + muldiv64(ppcemb_timer->pit_reload,
851 - ticks_per_sec, tb_env->tb_freq); 912 + ticks_per_sec, tb_env->decr_freq);
852 if (is_excp) 913 if (is_excp)
853 next += tb_env->decr_next - now; 914 next += tb_env->decr_next - now;
854 if (next == now) 915 if (next == now)
@@ -912,7 +973,7 @@ static void cpu_4xx_wdt_cb (void *opaque) @@ -912,7 +973,7 @@ static void cpu_4xx_wdt_cb (void *opaque)
912 /* Cannot occur, but makes gcc happy */ 973 /* Cannot occur, but makes gcc happy */
913 return; 974 return;
914 } 975 }
915 - next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq); 976 + next = now + muldiv64(next, ticks_per_sec, tb_env->decr_freq);
916 if (next == now) 977 if (next == now)
917 next++; 978 next++;
918 #ifdef PPC_DEBUG_TB 979 #ifdef PPC_DEBUG_TB
@@ -1014,6 +1075,7 @@ static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq) @@ -1014,6 +1075,7 @@ static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
1014 } 1075 }
1015 #endif 1076 #endif
1016 tb_env->tb_freq = freq; 1077 tb_env->tb_freq = freq;
  1078 + tb_env->decr_freq = freq;
1017 /* XXX: we should also update all timers */ 1079 /* XXX: we should also update all timers */
1018 } 1080 }
1019 1081
@@ -1029,6 +1091,7 @@ clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq) @@ -1029,6 +1091,7 @@ clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
1029 env->tb_env = tb_env; 1091 env->tb_env = tb_env;
1030 ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t)); 1092 ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
1031 tb_env->tb_freq = freq; 1093 tb_env->tb_freq = freq;
  1094 + tb_env->decr_freq = freq;
1032 tb_env->opaque = ppcemb_timer; 1095 tb_env->opaque = ppcemb_timer;
1033 #ifdef PPC_DEBUG_TB 1096 #ifdef PPC_DEBUG_TB
1034 if (loglevel != 0) { 1097 if (loglevel != 0) {