diff mbox

[V2,PowerPC,RFC] booke timers

Message ID 1309529621-27691-1-git-send-email-chouteau@adacore.com
State New
Headers show

Commit Message

Fabien Chouteau July 1, 2011, 2:13 p.m. UTC
While working on the emulation of the freescale p2010 (e500v2) I realized that
there's no implementation of booke's timers features. Currently mpc8544 uses
ppc_emb (ppc_emb_timers_init) which is close but not exactly like booke (for
example booke uses different SPR).

This is a first attempt for a distinct and clean implementation of booke's
timers.

Please feel free to comment.

V2:
  - Fix fixed timer, now trigger each time the selected
    bit switch from 0 to 1.
  - Fix e500 criterion.
  - Trigger an interrupt when user set DIE/FIE/WIE while
    DIS/FIS/WIS is already set.
  - Minor fixes (mask definition, variable name...).
  - rename ppc_emb to ppc_40x

Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
---
 Makefile.target             |    2 +-
 hw/ppc.c                    |  126 +++++++-------------
 hw/ppc.h                    |   25 ++++-
 hw/ppc4xx_devs.c            |    2 +-
 hw/ppc_booke.c              |  266 +++++++++++++++++++++++++++++++++++++++++++
 hw/ppce500_mpc8544ds.c      |    4 +-
 hw/virtex_ml507.c           |   11 +--
 target-ppc/cpu.h            |   22 ++++
 target-ppc/helper.c         |   12 ++-
 target-ppc/translate_init.c |   43 +++++++-
 10 files changed, 412 insertions(+), 101 deletions(-)
 create mode 100644 hw/ppc_booke.c

Comments

Scott Wood July 1, 2011, 8:22 p.m. UTC | #1
On Fri, 1 Jul 2011 16:13:41 +0200
Fabien Chouteau <chouteau@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
Fabien Chouteau July 4, 2011, 3:06 p.m. UTC | #2
On 01/07/2011 22:22, Scott Wood wrote:
> On Fri, 1 Jul 2011 16:13:41 +0200
> Fabien Chouteau <chouteau@adacore.com> wrote:
>> +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.
> 

Do you mean "lapse = period - ((tb - (1 << target_bit)) & (period - 1));" ?

I don't see how this solves the "tb <= (1 << target_bit)" case.
Scott Wood July 5, 2011, 4:02 p.m. UTC | #3
On Mon, 4 Jul 2011 17:06:54 +0200
Fabien Chouteau <chouteau@adacore.com> wrote:

> On 01/07/2011 22:22, Scott Wood wrote:
> > On Fri, 1 Jul 2011 16:13:41 +0200
> > Fabien Chouteau <chouteau@adacore.com> wrote:
> >> +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.
> > 
> 
> Do you mean "lapse = period - ((tb - (1 << target_bit)) & (period - 1));" ?

Yes.

Or more simply:

lapse = period - ((tb - period) & (period - 1));

> I don't see how this solves the "tb <= (1 << target_bit)" case.

Actually, since everything is unsigned the special case shouldn't be needed
regardless.

-Scott
Fabien Chouteau July 5, 2011, 4:41 p.m. UTC | #4
On 05/07/2011 18:02, Scott Wood wrote:
> On Mon, 4 Jul 2011 17:06:54 +0200
> Fabien Chouteau <chouteau@adacore.com> wrote:
> 
>> On 01/07/2011 22:22, Scott Wood wrote:
>>> On Fri, 1 Jul 2011 16:13:41 +0200
>>> Fabien Chouteau <chouteau@adacore.com> wrote:
>>>> +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.
>>>
>>
>> Do you mean "lapse = period - ((tb - (1 << target_bit)) & (period - 1));" ?
> 
> Yes.
> 
> Or more simply:
> 
> lapse = period - ((tb - period) & (period - 1));
> 

Are you sure? Note that period != (1 << target_bit).

>> I don't see how this solves the "tb <= (1 << target_bit)" case.
> 
> Actually, since everything is unsigned the special case shouldn't be needed
> regardless.

You're right about this one, it's tricky though :)
Scott Wood July 5, 2011, 6:05 p.m. UTC | #5
On Tue, 5 Jul 2011 18:41:13 +0200
Fabien Chouteau <chouteau@adacore.com> wrote:

> On 05/07/2011 18:02, Scott Wood wrote:
> > On Mon, 4 Jul 2011 17:06:54 +0200
> > Fabien Chouteau <chouteau@adacore.com> wrote:
> >> Do you mean "lapse = period - ((tb - (1 << target_bit)) & (period - 1));" ?
> > 
> > Yes.
> > 
> > Or more simply:
> > 
> > lapse = period - ((tb - period) & (period - 1));
> > 
> 
> Are you sure? Note that period != (1 << target_bit).

Ah, right -- misread that.

-Scott
diff mbox

Patch

diff --git a/Makefile.target b/Makefile.target
index 38afdb8..f0d4062 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -242,7 +242,7 @@  obj-i386-$(CONFIG_KVM) += kvmclock.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
-obj-ppc-y = ppc.o
+obj-ppc-y = ppc.o ppc_booke.o
 obj-ppc-y += vga.o
 # PREP target
 obj-ppc-y += i8259.o mc146818rtc.o
diff --git a/hw/ppc.c b/hw/ppc.c
index 9157719..f13f4ea 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -50,7 +50,7 @@ 
 static void cpu_ppc_tb_stop (CPUState *env);
 static void cpu_ppc_tb_start (CPUState *env);
 
-static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
+void ppc_set_irq (CPUState *env, int n_IRQ, int level)
 {
     unsigned int old_pending = env->pending_interrupts;
 
@@ -423,25 +423,8 @@  void ppce500_irq_init (CPUState *env)
 }
 /*****************************************************************************/
 /* PowerPC time base and decrementer emulation */
-struct ppc_tb_t {
-    /* Time base management */
-    int64_t  tb_offset;    /* Compensation                    */
-    int64_t  atb_offset;   /* Compensation                    */
-    uint32_t tb_freq;      /* TB frequency                    */
-    /* Decrementer management */
-    uint64_t decr_next;    /* Tick for next decr interrupt    */
-    uint32_t decr_freq;    /* decrementer frequency           */
-    struct QEMUTimer *decr_timer;
-    /* Hypervisor decrementer management */
-    uint64_t hdecr_next;    /* Tick for next hdecr interrupt  */
-    struct QEMUTimer *hdecr_timer;
-    uint64_t purr_load;
-    uint64_t purr_start;
-    void *opaque;
-};
 
-static inline uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk,
-                                      int64_t tb_offset)
+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);
+    }
 }
 
 static inline void _cpu_ppc_store_decr(CPUState *env, uint32_t decr,
@@ -806,11 +794,11 @@  uint32_t cpu_ppc601_load_rtcl (CPUState *env)
 }
 
 /*****************************************************************************/
-/* Embedded PowerPC timers */
+/* PowerPC 40x timers */
 
 /* PIT, FIT & WDT */
-typedef struct ppcemb_timer_t ppcemb_timer_t;
-struct ppcemb_timer_t {
+typedef struct ppc40x_timer_t ppc40x_timer_t;
+struct ppc40x_timer_t {
     uint64_t pit_reload;  /* PIT auto-reload value        */
     uint64_t fit_next;    /* Tick for next FIT interrupt  */
     struct QEMUTimer *fit_timer;
@@ -826,12 +814,12 @@  static void cpu_4xx_fit_cb (void *opaque)
 {
     CPUState *env;
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
     uint64_t now, next;
 
     env = opaque;
     tb_env = env->tb_env;
-    ppcemb_timer = tb_env->opaque;
+    ppc40x_timer = tb_env->opaque;
     now = qemu_get_clock_ns(vm_clock);
     switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
     case 0:
@@ -853,7 +841,7 @@  static void cpu_4xx_fit_cb (void *opaque)
     next = now + muldiv64(next, get_ticks_per_sec(), tb_env->tb_freq);
     if (next == now)
         next++;
-    qemu_mod_timer(ppcemb_timer->fit_timer, next);
+    qemu_mod_timer(ppc40x_timer->fit_timer, next);
     env->spr[SPR_40x_TSR] |= 1 << 26;
     if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
         ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
@@ -865,11 +853,11 @@  static void cpu_4xx_fit_cb (void *opaque)
 /* Programmable interval timer */
 static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
 {
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
     uint64_t now, next;
 
-    ppcemb_timer = tb_env->opaque;
-    if (ppcemb_timer->pit_reload <= 1 ||
+    ppc40x_timer = tb_env->opaque;
+    if (ppc40x_timer->pit_reload <= 1 ||
         !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
         (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
         /* Stop PIT */
@@ -877,9 +865,9 @@  static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
         qemu_del_timer(tb_env->decr_timer);
     } else {
         LOG_TB("%s: start PIT %016" PRIx64 "\n",
-                    __func__, ppcemb_timer->pit_reload);
+                    __func__, ppc40x_timer->pit_reload);
         now = qemu_get_clock_ns(vm_clock);
-        next = now + muldiv64(ppcemb_timer->pit_reload,
+        next = now + muldiv64(ppc40x_timer->pit_reload,
                               get_ticks_per_sec(), tb_env->decr_freq);
         if (is_excp)
             next += tb_env->decr_next - now;
@@ -894,21 +882,21 @@  static void cpu_4xx_pit_cb (void *opaque)
 {
     CPUState *env;
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
 
     env = opaque;
     tb_env = env->tb_env;
-    ppcemb_timer = tb_env->opaque;
+    ppc40x_timer = tb_env->opaque;
     env->spr[SPR_40x_TSR] |= 1 << 27;
     if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
-        ppc_set_irq(env, ppcemb_timer->decr_excp, 1);
+        ppc_set_irq(env, ppc40x_timer->decr_excp, 1);
     start_stop_pit(env, tb_env, 1);
     LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " "
            "%016" PRIx64 "\n", __func__,
            (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
            (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
            env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
-           ppcemb_timer->pit_reload);
+           ppc40x_timer->pit_reload);
 }
 
 /* Watchdog timer */
@@ -916,12 +904,12 @@  static void cpu_4xx_wdt_cb (void *opaque)
 {
     CPUState *env;
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
     uint64_t now, next;
 
     env = opaque;
     tb_env = env->tb_env;
-    ppcemb_timer = tb_env->opaque;
+    ppc40x_timer = tb_env->opaque;
     now = qemu_get_clock_ns(vm_clock);
     switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
     case 0:
@@ -948,13 +936,13 @@  static void cpu_4xx_wdt_cb (void *opaque)
     switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
     case 0x0:
     case 0x1:
-        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
-        ppcemb_timer->wdt_next = next;
+        qemu_mod_timer(ppc40x_timer->wdt_timer, next);
+        ppc40x_timer->wdt_next = next;
         env->spr[SPR_40x_TSR] |= 1 << 31;
         break;
     case 0x2:
-        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
-        ppcemb_timer->wdt_next = next;
+        qemu_mod_timer(ppc40x_timer->wdt_timer, next);
+        ppc40x_timer->wdt_next = next;
         env->spr[SPR_40x_TSR] |= 1 << 30;
         if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
             ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
@@ -982,12 +970,12 @@  static void cpu_4xx_wdt_cb (void *opaque)
 void store_40x_pit (CPUState *env, target_ulong val)
 {
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
 
     tb_env = env->tb_env;
-    ppcemb_timer = tb_env->opaque;
+    ppc40x_timer = tb_env->opaque;
     LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val);
-    ppcemb_timer->pit_reload = val;
+    ppc40x_timer->pit_reload = val;
     start_stop_pit(env, tb_env, 0);
 }
 
@@ -996,31 +984,7 @@  target_ulong load_40x_pit (CPUState *env)
     return cpu_ppc_load_decr(env);
 }
 
-void store_booke_tsr (CPUState *env, target_ulong val)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    ppcemb_timer_t *ppcemb_timer;
-
-    ppcemb_timer = tb_env->opaque;
-
-    LOG_TB("%s: val " TARGET_FMT_lx "\n", __func__, val);
-    env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
-    if (val & 0x80000000)
-        ppc_set_irq(env, ppcemb_timer->decr_excp, 0);
-}
-
-void store_booke_tcr (CPUState *env, target_ulong val)
-{
-    ppc_tb_t *tb_env;
-
-    tb_env = env->tb_env;
-    LOG_TB("%s: val " TARGET_FMT_lx "\n", __func__, val);
-    env->spr[SPR_40x_TCR] = val & 0xFFC00000;
-    start_stop_pit(env, tb_env, 1);
-    cpu_4xx_wdt_cb(env);
-}
-
-static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
+static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq)
 {
     CPUState *env = opaque;
     ppc_tb_t *tb_env = env->tb_env;
@@ -1032,30 +996,30 @@  static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
     /* XXX: we should also update all timers */
 }
 
-clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq,
+clk_setup_cb ppc_40x_timers_init (CPUState *env, uint32_t freq,
                                   unsigned int decr_excp)
 {
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
 
     tb_env = qemu_mallocz(sizeof(ppc_tb_t));
     env->tb_env = tb_env;
-    ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
+    ppc40x_timer = qemu_mallocz(sizeof(ppc40x_timer_t));
     tb_env->tb_freq = freq;
     tb_env->decr_freq = freq;
-    tb_env->opaque = ppcemb_timer;
+    tb_env->opaque = ppc40x_timer;
     LOG_TB("%s freq %" PRIu32 "\n", __func__, freq);
-    if (ppcemb_timer != NULL) {
+    if (ppc40x_timer != NULL) {
         /* We use decr timer for PIT */
         tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_4xx_pit_cb, env);
-        ppcemb_timer->fit_timer =
+        ppc40x_timer->fit_timer =
             qemu_new_timer_ns(vm_clock, &cpu_4xx_fit_cb, env);
-        ppcemb_timer->wdt_timer =
+        ppc40x_timer->wdt_timer =
             qemu_new_timer_ns(vm_clock, &cpu_4xx_wdt_cb, env);
-        ppcemb_timer->decr_excp = decr_excp;
+        ppc40x_timer->decr_excp = decr_excp;
     }
 
-    return &ppc_emb_set_tb_clk;
+    return &ppc_40x_set_tb_clk;
 }
 
 /*****************************************************************************/
diff --git a/hw/ppc.h b/hw/ppc.h
index 3ccf134..16df16a 100644
--- a/hw/ppc.h
+++ b/hw/ppc.h
@@ -1,3 +1,5 @@ 
+void ppc_set_irq (CPUState *env, int n_IRQ, int level);
+
 /* PowerPC hardware exceptions management helpers */
 typedef void (*clk_setup_cb)(void *opaque, uint32_t freq);
 typedef struct clk_setup_t clk_setup_t;
@@ -11,6 +13,24 @@  static inline void clk_setup (clk_setup_t *clk, uint32_t freq)
         (*clk->cb)(clk->opaque, freq);
 }
 
+struct ppc_tb_t {
+    /* Time base management */
+    int64_t  tb_offset;    /* Compensation                    */
+    int64_t  atb_offset;   /* Compensation                    */
+    uint32_t tb_freq;      /* TB frequency                    */
+    /* Decrementer management */
+    uint64_t decr_next;    /* Tick for next decr interrupt    */
+    uint32_t decr_freq;    /* decrementer frequency           */
+    struct QEMUTimer *decr_timer;
+    /* Hypervisor decrementer management */
+    uint64_t hdecr_next;    /* Tick for next hdecr interrupt  */
+    struct QEMUTimer *hdecr_timer;
+    uint64_t purr_load;
+    uint64_t purr_start;
+    void *opaque;
+};
+
+uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
 clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq);
 /* Embedded PowerPC DCR management */
 typedef uint32_t (*dcr_read_cb)(void *opaque, int dcrn);
@@ -19,7 +39,7 @@  int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn),
                   int (*dcr_write_error)(int dcrn));
 int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
                       dcr_read_cb drc_read, dcr_write_cb dcr_write);
-clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq,
+clk_setup_cb ppc_40x_timers_init (CPUState *env, uint32_t freq,
                                   unsigned int decr_excp);
 
 /* Embedded PowerPC reset */
@@ -55,3 +75,6 @@  enum {
 #define FW_CFG_PPC_KVM_PID      (FW_CFG_ARCH_LOCAL + 0x07)
 
 #define PPC_SERIAL_MM_BAUDBASE 399193
+
+/* ppc_booke.c */
+void ppc_booke_timers_init (CPUState *env, uint32_t freq);
diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c
index 68bdfaa..073c6a2 100644
--- a/hw/ppc4xx_devs.c
+++ b/hw/ppc4xx_devs.c
@@ -55,7 +55,7 @@  CPUState *ppc4xx_init (const char *cpu_model,
     cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
     cpu_clk->opaque = env;
     /* Set time-base frequency to sysclk */
-    tb_clk->cb = ppc_emb_timers_init(env, sysclk, PPC_INTERRUPT_PIT);
+    tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT);
     tb_clk->opaque = env;
     ppc_dcr_init(env, NULL, NULL);
     /* Register qemu callbacks */
diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c
new file mode 100644
index 0000000..a49ff7b
--- /dev/null
+++ b/hw/ppc_booke.c
@@ -0,0 +1,266 @@ 
+/*
+ * QEMU PowerPC Booke hardware System Emulator
+ *
+ * Copyright (c) 2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "ppc.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "nvram.h"
+#include "qemu-log.h"
+#include "loader.h"
+
+
+/* Timer Control Register */
+
+#define TCR_WP_SHIFT  30        /* Watchdog Timer Period */
+#define TCR_WP_MASK   (0x3 << TCR_WP_SHIFT)
+#define TCR_WRC_SHIFT 28        /* Watchdog Timer Reset Control */
+#define TCR_WRC_MASK  (0x3 << TCR_WRC_SHIFT)
+#define TCR_WIE       (1 << 27) /* Watchdog Timer Interrupt Enable */
+#define TCR_DIE       (1 << 26) /* Decrementer Interrupt Enable */
+#define TCR_FP_SHIFT  24        /* Fixed-Interval Timer Period */
+#define TCR_FP_MASK   (0x3 << TCR_FP_SHIFT)
+#define TCR_FIE       (1 << 23) /* Fixed-Interval Timer Interrupt Enable */
+#define TCR_ARE       (1 << 22) /* Auto-Reload Enable */
+
+/* Timer Control Register (e500 specific fields) */
+
+#define TCR_E500_FPEXT_SHIFT 13 /* Fixed-Interval Timer Period Extension */
+#define TCR_E500_FPEXT_MASK  (0xf << TCR_E500_FPEXT_SHIFT)
+#define TCR_E500_WPEXT_SHIFT 17 /* Watchdog Timer Period Extension */
+#define TCR_E500_WPEXT_MASK  (0xf << TCR_E500_WPEXT_SHIFT)
+
+/* Timer Status Register  */
+
+#define TSR_FIS       (1 << 26) /* Fixed-Interval Timer Interrupt Status */
+#define TSR_DIS       (1 << 27) /* Decrementer Interrupt Status */
+#define TSR_WRS_SHIFT 28        /* Watchdog Timer Reset Status */
+#define TSR_WRS_MASK  (0x3 << TSR_WRS_SHIFT)
+#define TSR_WIS       (1 << 30) /* Watchdog Timer Interrupt Status */
+#define TSR_ENW       (1 << 31) /* Enable Next Watchdog Timer */
+
+typedef struct booke_timer_t booke_timer_t;
+struct booke_timer_t {
+
+    uint64_t fit_next;
+    struct QEMUTimer *fit_timer;
+
+    uint64_t wdt_next;
+    struct QEMUTimer *wdt_timer;
+};
+
+/* 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;
+}
+
+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);
+    }
+
+    *next = now + muldiv64(lapse, get_ticks_per_sec(), tb_env->tb_freq);
+
+    if (*next == now)
+        (*next)++;
+
+    qemu_mod_timer(timer, *next);
+}
+
+static void booke_decr_cb (void *opaque)
+{
+    CPUState *env;
+    ppc_tb_t *tb_env;
+    booke_timer_t *booke_timer;
+
+    env = opaque;
+    tb_env = env->tb_env;
+    booke_timer = tb_env->opaque;
+    env->spr[SPR_BOOKE_TSR] |= TSR_DIS;
+    if (env->spr[SPR_BOOKE_TCR] & TCR_DIE) {
+        ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
+    }
+
+    if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) {
+        /* Auto Reload */
+        cpu_ppc_store_decr(env, env->spr[SPR_BOOKE_DECAR]);
+    }
+}
+
+static void booke_fit_cb (void *opaque)
+{
+    CPUState *env;
+    ppc_tb_t *tb_env;
+    booke_timer_t *booke_timer;
+
+    env = opaque;
+    tb_env = env->tb_env;
+    booke_timer = tb_env->opaque;
+    env->spr[SPR_BOOKE_TSR] |= TSR_FIS;
+    if (env->spr[SPR_BOOKE_TCR] & TCR_FIE) {
+        ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
+    }
+
+    booke_update_fixed_timer(env,
+                             booke_get_fit_target(env),
+                             &booke_timer->fit_next,
+                             booke_timer->fit_timer);
+}
+
+static void booke_wdt_cb (void *opaque)
+{
+    CPUState *env;
+    ppc_tb_t *tb_env;
+    booke_timer_t *booke_timer;
+
+    env = opaque;
+    tb_env = env->tb_env;
+    booke_timer = tb_env->opaque;
+
+    /* TODO: There's lots of complicated stuff to do here */
+
+    booke_update_fixed_timer(env,
+                             booke_get_wdt_target(env),
+                             &booke_timer->wdt_next,
+                             booke_timer->wdt_timer);
+}
+
+void store_booke_tsr (CPUState *env, target_ulong val)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    booke_timer_t *booke_timer;
+
+    booke_timer = tb_env->opaque;
+
+    env->spr[SPR_BOOKE_TSR] &= ~val;
+
+    if (val & TSR_DIS) {
+        ppc_set_irq(env, PPC_INTERRUPT_DECR, 0);
+    }
+
+    if (val & TSR_FIS) {
+        ppc_set_irq(env, PPC_INTERRUPT_FIT, 0);
+    }
+
+    if (val & TSR_WIS) {
+        ppc_set_irq(env, PPC_INTERRUPT_WDT, 0);
+    }
+}
+
+void store_booke_tcr (CPUState *env, target_ulong val)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    booke_timer_t *booke_timer = tb_env->opaque;
+
+    tb_env = env->tb_env;
+    env->spr[SPR_BOOKE_TCR] = val;
+
+    booke_update_fixed_timer(env,
+                             booke_get_fit_target(env),
+                             &booke_timer->fit_next,
+                             booke_timer->fit_timer);
+
+    booke_update_fixed_timer(env,
+                             booke_get_wdt_target(env),
+                             &booke_timer->wdt_next,
+                             booke_timer->wdt_timer);
+
+    if (val & TCR_DIE && env->spr[SPR_BOOKE_TSR] & TSR_DIS) {
+        ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
+    }
+
+    if (val & TCR_FIE && env->spr[SPR_BOOKE_TSR] & TSR_FIS) {
+        ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
+    }
+
+    if (val & TCR_WIE && env->spr[SPR_BOOKE_TSR] & TSR_WIS) {
+        ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
+    }
+}
+
+void ppc_booke_timers_init (CPUState *env, uint32_t freq)
+{
+    ppc_tb_t *tb_env;
+    booke_timer_t *booke_timer;
+
+    tb_env      = qemu_mallocz(sizeof(ppc_tb_t));
+    booke_timer = qemu_mallocz(sizeof(booke_timer_t));
+
+    env->tb_env = tb_env;
+
+    tb_env->tb_freq    = freq;
+    tb_env->decr_freq  = freq;
+    tb_env->opaque     = booke_timer;
+    tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, env);
+
+    booke_timer->fit_timer =
+        qemu_new_timer_ns(vm_clock, &booke_fit_cb, env);
+    booke_timer->wdt_timer =
+        qemu_new_timer_ns(vm_clock, &booke_wdt_cb, env);
+}
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 6b57fbf..83672c9 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -237,9 +237,7 @@  static void mpc8544ds_init(ram_addr_t ram_size,
         exit(1);
     }
 
-    /* XXX register timer? */
-    ppc_emb_timers_init(env, 400000000, PPC_INTERRUPT_DECR);
-    ppc_dcr_init(env, NULL, NULL);
+    ppc_booke_timers_init(env, 400000000);
 
     /* Register reset handler */
     qemu_register_reset(mpc8544ds_cpu_reset, env);
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
index fa60515..1da478f 100644
--- a/hw/virtex_ml507.c
+++ b/hw/virtex_ml507.c
@@ -81,7 +81,6 @@  static void mmubooke_create_initial_mapping(CPUState *env,
 static CPUState *ppc440_init_xilinx(ram_addr_t *ram_size,
                                     int do_init,
                                     const char *cpu_model,
-                                    clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
                                     uint32_t sysclk)
 {
     CPUState *env;
@@ -93,11 +92,7 @@  static CPUState *ppc440_init_xilinx(ram_addr_t *ram_size,
         exit(1);
     }
 
-    cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
-    cpu_clk->opaque = env;
-    /* Set time-base frequency to sysclk */
-    tb_clk->cb = ppc_emb_timers_init(env, sysclk, PPC_INTERRUPT_DECR);
-    tb_clk->opaque = env;
+    ppc_booke_timers_init(env, sysclk);
 
     ppc_dcr_init(env, NULL, NULL);
 
@@ -198,7 +193,6 @@  static void virtex_init(ram_addr_t ram_size,
     ram_addr_t phys_ram;
     ram_addr_t phys_flash;
     qemu_irq irq[32], *cpu_irq;
-    clk_setup_t clk_setup[7];
     int kernel_size;
     int i;
 
@@ -208,8 +202,7 @@  static void virtex_init(ram_addr_t ram_size,
     }
 
     memset(clk_setup, 0, sizeof(clk_setup));
-    env = ppc440_init_xilinx(&ram_size, 1, cpu_model, &clk_setup[0],
-                             &clk_setup[1], 400000000);
+    env = ppc440_init_xilinx(&ram_size, 1, cpu_model, 400000000);
     qemu_register_reset(main_cpu_reset, env);
 
     phys_ram = qemu_ram_alloc(NULL, "ram", ram_size);
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 6d60d14..28c1d03 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -982,8 +982,28 @@  struct CPUPPCState {
 #if !defined(CONFIG_USER_ONLY)
     void *load_info;    /* Holds boot loading state.  */
 #endif
+
+    /* booke timers */
+
+    /* Specifies bit locations of the Time Base used to signal a fixed timer
+     * exception on a transition from 0 to 1. (watchdog or fixed-interval timer)
+     */
+    uint8_t fit_period[4];
+    uint8_t wdt_period[4];
 };
 
+#define SET_FIT_PERIOD(a_, b_, c_, d_)          \
+env->fit_period[0] = (a_);                      \
+ env->fit_period[1] = (b_);                     \
+ env->fit_period[2] = (c_);                     \
+ env->fit_period[3] = (d_);                     \
+
+#define SET_WDT_PERIOD(a_, b_, c_, d_)          \
+env->wdt_period[0] = (a_);                      \
+ env->wdt_period[1] = (b_);                     \
+ env->wdt_period[2] = (c_);                     \
+ env->wdt_period[3] = (d_);                     \
+
 #if !defined(CONFIG_USER_ONLY)
 /* Context used internally during MMU translations */
 typedef struct mmu_ctx_t mmu_ctx_t;
@@ -1774,6 +1794,8 @@  enum {
 
     /* BookE 2.06 PowerPC specification                                      */
     PPC2_BOOKE206      = 0x0000000000000001ULL,
+    /* e500 support                                                          */
+    PPC2_E500          = 0x0000000000000002ULL,
 };
 
 /*****************************************************************************/
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 395ea0e..6f0ad2d 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -2815,7 +2815,9 @@  void ppc_hw_interrupt (CPUPPCState *env)
     if (msr_ee != 0) {
         /* Watchdog timer on embedded PowerPC */
         if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
-            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
+            if (env->excp_model != POWERPC_EXCP_BOOKE) {
+                env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
+            }
             powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT);
             return;
         }
@@ -2826,7 +2828,9 @@  void ppc_hw_interrupt (CPUPPCState *env)
         }
         /* Fixed interval timer on embedded PowerPC */
         if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
-            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
+            if (env->excp_model != POWERPC_EXCP_BOOKE) {
+                env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
+            }
             powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT);
             return;
         }
@@ -2838,7 +2842,9 @@  void ppc_hw_interrupt (CPUPPCState *env)
         }
         /* Decrementer exception */
         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
-            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
+            if (env->excp_model != POWERPC_EXCP_BOOKE) {
+                env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
+            }
             powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR);
             return;
         }
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index fc50ae3..05be8b6 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -3251,6 +3251,9 @@  static void init_proc_401 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(13, 17, 21, 25);
+    SET_WDT_PERIOD(17, 21, 25, 29);
 }
 
 /* PowerPC 401x2                                                             */
@@ -3288,6 +3291,9 @@  static void init_proc_401x2 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(13, 17, 21, 25);
+    SET_WDT_PERIOD(17, 21, 25, 29);
 }
 
 /* PowerPC 401x3                                                             */
@@ -3321,6 +3327,9 @@  static void init_proc_401x3 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(13, 17, 21, 25);
+    SET_WDT_PERIOD(17, 21, 25, 29);
 }
 
 /* IOP480                                                                    */
@@ -3358,6 +3367,9 @@  static void init_proc_IOP480 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(9, 13, 17, 21);
+    SET_WDT_PERIOD(17, 21, 25, 29);
 }
 
 /* PowerPC 403                                                               */
@@ -3388,6 +3400,9 @@  static void init_proc_403 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(9, 13, 17, 21);
+    SET_WDT_PERIOD(17, 21, 25, 29);
 }
 
 /* PowerPC 403 GCX                                                           */
@@ -3437,6 +3452,9 @@  static void init_proc_403GCX (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(9, 13, 17, 21);
+    SET_WDT_PERIOD(17, 21, 25, 29);
 }
 
 /* PowerPC 405                                                               */
@@ -3485,6 +3503,9 @@  static void init_proc_405 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(9, 13, 17, 21);
+    SET_WDT_PERIOD(17, 21, 25, 29);
 }
 
 /* PowerPC 440 EP                                                            */
@@ -3566,6 +3587,9 @@  static void init_proc_440EP (CPUPPCState *env)
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(13, 17, 21, 25);
+    SET_WDT_PERIOD(21, 25, 29, 33);
 }
 
 /* PowerPC 440 GP                                                            */
@@ -3629,6 +3653,9 @@  static void init_proc_440GP (CPUPPCState *env)
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(13, 17, 21, 25);
+    SET_WDT_PERIOD(21, 25, 29, 33);
 }
 
 /* PowerPC 440x4                                                             */
@@ -3692,6 +3719,9 @@  static void init_proc_440x4 (CPUPPCState *env)
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(13, 17, 21, 25);
+    SET_WDT_PERIOD(21, 25, 29, 33);
 }
 
 /* PowerPC 440x5                                                             */
@@ -3772,6 +3802,9 @@  static void init_proc_440x5 (CPUPPCState *env)
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(13, 17, 21, 25);
+    SET_WDT_PERIOD(21, 25, 29, 33);
 }
 
 /* PowerPC 460 (guessed)                                                     */
@@ -3859,6 +3892,9 @@  static void init_proc_460 (CPUPPCState *env)
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(13, 17, 21, 25);
+    SET_WDT_PERIOD(21, 25, 29, 33);
 }
 
 /* PowerPC 460F (guessed)                                                    */
@@ -3949,6 +3985,9 @@  static void init_proc_460F (CPUPPCState *env)
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(13, 17, 21, 25);
+    SET_WDT_PERIOD(21, 25, 29, 33);
 }
 
 /* Freescale 5xx cores (aka RCPU) */
@@ -4317,7 +4356,7 @@  static void init_proc_e300 (CPUPPCState *env)
                                 PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
                                 PPC_CACHE_DCBZ | PPC_CACHE_DCBA |       \
                                 PPC_MEM_TLBSYNC | PPC_TLBIVAX)
-#define POWERPC_INSNS2_e500v1  (PPC2_BOOKE206)
+#define POWERPC_INSNS2_e500v1  (PPC2_BOOKE206 | PPC2_E500)
 #define POWERPC_MSRM_e500v1    (0x000000000606FF30ULL)
 #define POWERPC_MMU_e500v1     (POWERPC_MMU_BOOKE206)
 #define POWERPC_EXCP_e500v1    (POWERPC_EXCP_BOOKE)
@@ -4336,7 +4375,7 @@  static void init_proc_e300 (CPUPPCState *env)
                                 PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
                                 PPC_CACHE_DCBZ | PPC_CACHE_DCBA |       \
                                 PPC_MEM_TLBSYNC | PPC_TLBIVAX)
-#define POWERPC_INSNS2_e500v2  (PPC2_BOOKE206)
+#define POWERPC_INSNS2_e500v2  (PPC2_BOOKE206 | PPC2_E500)
 #define POWERPC_MSRM_e500v2    (0x000000000606FF30ULL)
 #define POWERPC_MMU_e500v2     (POWERPC_MMU_BOOKE206)
 #define POWERPC_EXCP_e500v2    (POWERPC_EXCP_BOOKE)