On Fri, 1 Jul 2011 16:13:41 +0200
Fabien Chouteau <chout...@adacore.com> wrote:

> +uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset)
>  {
>      /* TB time in tb periods */
>      return muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec()) + tb_offset;
> @@ -678,18 +661,23 @@ static void __cpu_ppc_store_decr (CPUState *env, 
> uint64_t *nextp,
>                  decr, value);
>      now = qemu_get_clock_ns(vm_clock);
>      next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq);
> -    if (is_excp)
> +    if (is_excp) {
>          next += *nextp - now;
> -    if (next == now)
> +    }
> +    if (next == now) {
>          next++;
> +    }
>      *nextp = next;
>      /* Adjust timer */
>      qemu_mod_timer(timer, next);
>      /* If we set a negative value and the decrementer was positive,
> -     * raise an exception.
> +     * raise an exception (not for booke).
>       */
> -    if ((value & 0x80000000) && !(decr & 0x80000000))
> +    if (! (env->insns_flags & PPC_BOOKE)
> +        && (value & 0x80000000)
> +        && !(decr & 0x80000000)) {
>          (*raise_excp)(env);
> +    }
>  }
>  

Also, load_decr should go from this:

    if (diff >= 0)
        decr = muldiv64(diff, tb_env->decr_freq, get_ticks_per_sec());
    else
        decr = -muldiv64(-diff, tb_env->decr_freq, get_ticks_per_sec());

to something like this:

    if (diff >= 0) {
        decr = muldiv64(diff, tb_env->decr_freq, get_ticks_per_sec());
    } else if (env->insns_flags & PPC_BOOKE) {
        decr = 0;
    } else {
        decr = -muldiv64(-diff, tb_env->decr_freq, get_ticks_per_sec());
    }

> +/* Return the location of the bit of time base at which the FIT will raise an
> +   interrupt */
> +static uint8_t booke_get_fit_target(CPUState *env)
> +{
> +    uint8_t fp = (env->spr[SPR_BOOKE_TCR] & TCR_FP_MASK) >> TCR_FP_SHIFT;
> +
> +    /* Only for e500 */
> +    if (env->insns_flags2 & PPC2_E500) {
> +        uint32_t fpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_FPEXT_MASK)
> +            >> TCR_E500_FPEXT_SHIFT;
> +        fp |= fpext << 2;
> +    } else {
> +        fp = env->fit_period[fp];
> +    }
> +
> +    return fp;
> +}
> +
> +/* Return the location of the bit of time base at which the WDT will raise an
> +   interrupt */
> +static uint8_t booke_get_wdt_target(CPUState *env)
> +{
> +    uint8_t wp = (env->spr[SPR_BOOKE_TCR] & TCR_WP_MASK) >> TCR_WP_SHIFT;
> +
> +    /* Only for e500 */
> +    if (env->insns_flags2 & PPC2_E500) {
> +        uint32_t wpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_WPEXT_MASK)
> +            >> TCR_E500_WPEXT_SHIFT;
> +        wp |= wpext << 2;
> +    } else {
> +        wp = env->wdt_period[wp];
> +    }
> +
> +    return wp;
> +}

e500 fp/wp is expressed as bits from the MSB side of TB, so we need to
subtract from 63 to get something sane -- and document that fit/wdt_period
is from the LSB side.

> +static void booke_update_fixed_timer(CPUState         *env,
> +                                     uint8_t           target_bit,
> +                                     uint64_t          *next,
> +                                     struct QEMUTimer *timer)
> +{
> +    ppc_tb_t *tb_env = env->tb_env;
> +    uint64_t lapse;
> +    uint64_t tb;
> +    uint64_t period = 1 << (target_bit + 1);
> +    uint64_t now;
> +
> +    now = qemu_get_clock_ns(vm_clock);
> +    tb  = cpu_ppc_get_tb(tb_env, now, tb_env->tb_offset);
> +
> +    if (tb <= (1 << target_bit)) {
> +        lapse = (1 << target_bit) - tb;
> +    } else {
> +        lapse = period - ((tb - (1 << target_bit)) % period);

We know period is a power of two, so just do "& (period - 1)".

That should let you get rid of the special case for
"tb <= (1 << target_bit)" as well.

-Scott


Reply via email to