Revision dbdd2506

b/hw/ppc.c
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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) {

Also available in: Unified diff