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 30 extern FILE *logfile;
31 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 36 static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
34 37 {
35 38 if (level) {
... ... @@ -65,6 +68,19 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level)
65 68 /* Don't generate spurious events */
66 69 if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
67 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 84 case PPC6xx_INPUT_INT:
69 85 /* Level sensitive - active high */
70 86 #if defined(PPC_DEBUG_IRQ)
... ... @@ -402,11 +418,12 @@ void ppc40x_irq_init (CPUState *env)
402 418 /* PowerPC time base and decrementer emulation */
403 419 struct ppc_tb_t {
404 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 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 427 struct QEMUTimer *decr_timer;
411 428 #if defined(TARGET_PPC64H)
412 429 /* Hypervisor decrementer management */
... ... @@ -418,12 +435,11 @@ struct ppc_tb_t {
418 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 439 int64_t tb_offset)
423 440 {
424 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 445 uint32_t cpu_ppc_load_tbl (CPUState *env)
... ... @@ -431,7 +447,7 @@ uint32_t cpu_ppc_load_tbl (CPUState *env)
431 447 ppc_tb_t *tb_env = env->tb_env;
432 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 451 #if defined(PPC_DEBUG_TB)
436 452 if (loglevel != 0) {
437 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 462 ppc_tb_t *tb_env = env->tb_env;
447 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 466 #if defined(PPC_DEBUG_TB)
451 467 if (loglevel != 0) {
452 468 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
... ... @@ -461,12 +477,11 @@ uint32_t cpu_ppc_load_tbu (CPUState *env)
461 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 481 int64_t *tb_offsetp,
466 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 485 #ifdef PPC_DEBUG_TB
471 486 if (loglevel != 0) {
472 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 495 ppc_tb_t *tb_env = env->tb_env;
481 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 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 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 506 ppc_tb_t *tb_env = env->tb_env;
491 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 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 515 void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
... ... @@ -506,7 +522,7 @@ uint32_t cpu_ppc_load_atbl (CPUState *env)
506 522 ppc_tb_t *tb_env = env->tb_env;
507 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 526 #if defined(PPC_DEBUG_TB)
511 527 if (loglevel != 0) {
512 528 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
... ... @@ -521,7 +537,7 @@ uint32_t cpu_ppc_load_atbu (CPUState *env)
521 537 ppc_tb_t *tb_env = env->tb_env;
522 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 541 #if defined(PPC_DEBUG_TB)
526 542 if (loglevel != 0) {
527 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 552 ppc_tb_t *tb_env = env->tb_env;
537 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 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 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 563 ppc_tb_t *tb_env = env->tb_env;
547 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 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 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 621  
562 622 diff = tb_env->decr_next - qemu_get_clock(vm_clock);
563 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 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 627 #if defined(PPC_DEBUG_TB)
568 628 if (loglevel != 0) {
569 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 699 }
640 700 #endif
641 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 703 if (is_excp)
644 704 next += *nextp - now;
645 705 if (next == now)
... ... @@ -708,6 +768,7 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
708 768 ppc_tb_t *tb_env = env->tb_env;
709 769  
710 770 tb_env->tb_freq = freq;
  771 + tb_env->decr_freq = freq;
711 772 /* There is a bug in Linux 2.4 kernels:
712 773 * if a decrementer exception is pending when it enables msr_ee at startup,
713 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 909 #endif
849 910 now = qemu_get_clock(vm_clock);
850 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 913 if (is_excp)
853 914 next += tb_env->decr_next - now;
854 915 if (next == now)
... ... @@ -912,7 +973,7 @@ static void cpu_4xx_wdt_cb (void *opaque)
912 973 /* Cannot occur, but makes gcc happy */
913 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 977 if (next == now)
917 978 next++;
918 979 #ifdef PPC_DEBUG_TB
... ... @@ -1014,6 +1075,7 @@ static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
1014 1075 }
1015 1076 #endif
1016 1077 tb_env->tb_freq = freq;
  1078 + tb_env->decr_freq = freq;
1017 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 1091 env->tb_env = tb_env;
1030 1092 ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
1031 1093 tb_env->tb_freq = freq;
  1094 + tb_env->decr_freq = freq;
1032 1095 tb_env->opaque = ppcemb_timer;
1033 1096 #ifdef PPC_DEBUG_TB
1034 1097 if (loglevel != 0) {
... ...