Re: [RFC 1/1] Implement AVR watchdog timer

2021-05-15 Thread Philippe Mathieu-Daudé
+Pavel/Alex

On 5/3/21 10:08 PM, Michael Rolnik wrote:
> Hi all,
> 
> I was about to make icount work. but, there is something I still don't
> understand. I have this code 
> 
> timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, avr_wdt_interrupt, s);
> 
> and then
> 
> void avr_wdt_interrupt(/* some arguments */) {
> #define MS2NS(n)        ((n) * 100ull)
>     timer_mod_ns(timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + MS2NS(15));
> }
> 
> when running with --icount shift=0, *avr_wdt_interrupt* is called about
> every 1K instructions, however it should have been called 15M
> instructions as shift=0 makes every instruction to be executed in 1
> virtual ns.
> 
> What am I doing wrong?
> 
> Thank you,
> Michael Rolnik
> 
> 
> On Mon, May 3, 2021 at 4:36 PM Michael Rolnik  > wrote:
> 
> Hi Fred.
> 
> 1. thanks
> 2. It seems I have forgotten to set those flags.
> 3. 15ms is easy to test 8s will take 533 times longer, so in my case
> 3200 instructions which is totally incorrect. I don't understand why
> as I program the timer in virtual nanoseconds and not host time.
> 4. I hope Richard could help with icount.
> 
> best regards,
> Michael Rolnik
> 
> On Mon, May 3, 2021 at 4:15 PM Fred Konrad  > wrote:
> 
> 
> 
> Le 5/2/21 à 10:10 PM, Michael Rolnik a écrit :
> > Signed-off-by: Michael Rolnik  >
> > ---
> >   hw/avr/Kconfig                |   1 +
> >   hw/avr/atmega.c               |  15 ++-
> >   hw/avr/atmega.h               |   2 +
> >   hw/watchdog/Kconfig           |   3 +
> >   hw/watchdog/avr_wdt.c         | 190
> ++
> >   hw/watchdog/meson.build       |   2 +
> >   hw/watchdog/trace-events      |   5 +
> >   include/hw/watchdog/avr_wdt.h |  47 +
> >   target/avr/cpu.c              |   3 +
> >   target/avr/cpu.h              |   1 +
> >   target/avr/helper.c           |   7 +-
> >   11 files changed, 271 insertions(+), 5 deletions(-)
> >   create mode 100644 hw/watchdog/avr_wdt.c
> >   create mode 100644 include/hw/watchdog/avr_wdt.h
> >
> > diff --git a/hw/avr/Kconfig b/hw/avr/Kconfig
> > index d31298c3cc..9939e4902f 100644
> > --- a/hw/avr/Kconfig
> > +++ b/hw/avr/Kconfig
> > @@ -3,6 +3,7 @@ config AVR_ATMEGA_MCU
> >       select AVR_TIMER16
> >       select AVR_USART
> >       select AVR_POWER
> > +    select AVR_WDT
> >   
> >   config ARDUINO
> >       select AVR_ATMEGA_MCU
> > diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c
> > index 44c6afebbb..31ceb1c21c 100644
> > --- a/hw/avr/atmega.c
> > +++ b/hw/avr/atmega.c
> > @@ -28,6 +28,7 @@ enum AtmegaPeripheral {
> >       GPIOG, GPIOH, GPIOI, GPIOJ, GPIOK, GPIOL,
> >       USART0, USART1, USART2, USART3,
> >       TIMER0, TIMER1, TIMER2, TIMER3, TIMER4, TIMER5,
> > +    WDT,
> >       PERIFMAX
> >   };
> >   
> > @@ -75,6 +76,7 @@ static const peripheral_cfg
> dev168_328[PERIFMAX] = {
> >       [GPIOD]         = {  0x29 },
> >       [GPIOC]         = {  0x26 },
> >       [GPIOB]         = {  0x23 },
> > +    [WDT]           = {  0x60 },
> >   }, dev1280_2560[PERIFMAX] = {
> >       [USART3]        = { 0x130, POWER1, 2 },
> >       [TIMER5]        = { 0x120, POWER1, 5, 0x73, 0x3a, true },
> > @@ -99,6 +101,7 @@ static const peripheral_cfg
> dev168_328[PERIFMAX] = {
> >       [GPIOC]         = {  0x26 },
> >       [GPIOB]         = {  0x23 },
> >       [GPIOA]         = {  0x20 },
> > +    [WDT]           = {  0x60 },
> >   };
> >   
> >   enum AtmegaIrq {
> > @@ -118,6 +121,7 @@ enum AtmegaIrq {
> >           TIMER4_COMPC_IRQ, TIMER4_OVF_IRQ,
> >       TIMER5_CAPT_IRQ, TIMER5_COMPA_IRQ, TIMER5_COMPB_IRQ,
> >           TIMER5_COMPC_IRQ, TIMER5_OVF_IRQ,
> > +    WATCHDOG_TIMER_IRQ,
> >       IRQ_COUNT
> >   };
> >   
> > @@ -133,6 +137,7 @@ enum AtmegaIrq {
> >   #define TIMER_OVF_IRQ(n)    (n * TIMER_IRQ_COUNT +
> TIMER0_OVF_IRQ)
> >   
> >   static const uint8_t irq168_328[IRQ_COUNT] = {
> > +    [WATCHDOG_TIMER_IRQ]    = 7,
> >       [TIMER2_COMPA_IRQ]      = 8,
> >       [TIMER2_COMPB_IRQ]      = 9,
> >       [TIMER2_OVF_IRQ]        = 10,
> > @@ -147,6 +152,7 @@ static const uint8_t irq168_328[IRQ_COUNT] = {
> >       [USART0_DRE_IRQ]        = 20,
> >       [USART0_TXC_IRQ]        = 21,
> >   }, irq1280_2560[IRQ_COUNT] = {
> > +    [WATC

Re: [RFC 1/1] Implement AVR watchdog timer

2021-05-14 Thread Michael Rolnik
Ok, thanks.

Sent from my cell phone, please ignore typos

On Thu, May 13, 2021, 3:27 PM Pavel Dovgalyuk 
wrote:

> On 06.05.2021 00:18, Michael Rolnik wrote:
> > Signed-off-by: Michael Rolnik 
> > ---
> >   MAINTAINERS   |   2 +
> >   hw/avr/Kconfig|   1 +
> >   hw/avr/atmega.c   |  15 +-
> >   hw/avr/atmega.h   |   2 +
> >   hw/watchdog/Kconfig   |   3 +
> >   hw/watchdog/avr_wdt.c | 274 ++
> >   hw/watchdog/meson.build   |   2 +
> >   hw/watchdog/trace-events  |   5 +
> >   include/hw/watchdog/avr_wdt.h |  47 ++
> >   target/avr/cpu.c  |   3 +
> >   target/avr/cpu.h  |   1 +
> >   target/avr/helper.c   |   7 +-
> >   target/avr/translate.c|  38 -
> >   13 files changed, 391 insertions(+), 9 deletions(-)
> >   create mode 100644 hw/watchdog/avr_wdt.c
> >   create mode 100644 include/hw/watchdog/avr_wdt.h
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 4c05ff8bba..e1fce736d2 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1052,6 +1052,8 @@ F: include/hw/timer/avr_timer16.h
> >   F: hw/timer/avr_timer16.c
> >   F: include/hw/misc/avr_power.h
> >   F: hw/misc/avr_power.c
> > +F: include/hw/watchdog/avr_wdt.h
> > +F: hw/watchdog/avr_wdt.c
> >
> >   Arduino
> >   M: Philippe Mathieu-Daudé 
> > diff --git a/hw/avr/Kconfig b/hw/avr/Kconfig
> > index d31298c3cc..9939e4902f 100644
> > --- a/hw/avr/Kconfig
> > +++ b/hw/avr/Kconfig
> > @@ -3,6 +3,7 @@ config AVR_ATMEGA_MCU
> >   select AVR_TIMER16
> >   select AVR_USART
> >   select AVR_POWER
> > +select AVR_WDT
> >
> >   config ARDUINO
> >   select AVR_ATMEGA_MCU
> > diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c
> > index 44c6afebbb..31ceb1c21c 100644
> > --- a/hw/avr/atmega.c
> > +++ b/hw/avr/atmega.c
> > @@ -28,6 +28,7 @@ enum AtmegaPeripheral {
> >   GPIOG, GPIOH, GPIOI, GPIOJ, GPIOK, GPIOL,
> >   USART0, USART1, USART2, USART3,
> >   TIMER0, TIMER1, TIMER2, TIMER3, TIMER4, TIMER5,
> > +WDT,
> >   PERIFMAX
> >   };
> >
> > @@ -75,6 +76,7 @@ static const peripheral_cfg dev168_328[PERIFMAX] = {
> >   [GPIOD] = {  0x29 },
> >   [GPIOC] = {  0x26 },
> >   [GPIOB] = {  0x23 },
> > +[WDT]   = {  0x60 },
> >   }, dev1280_2560[PERIFMAX] = {
> >   [USART3]= { 0x130, POWER1, 2 },
> >   [TIMER5]= { 0x120, POWER1, 5, 0x73, 0x3a, true },
> > @@ -99,6 +101,7 @@ static const peripheral_cfg dev168_328[PERIFMAX] = {
> >   [GPIOC] = {  0x26 },
> >   [GPIOB] = {  0x23 },
> >   [GPIOA] = {  0x20 },
> > +[WDT]   = {  0x60 },
> >   };
> >
> >   enum AtmegaIrq {
> > @@ -118,6 +121,7 @@ enum AtmegaIrq {
> >   TIMER4_COMPC_IRQ, TIMER4_OVF_IRQ,
> >   TIMER5_CAPT_IRQ, TIMER5_COMPA_IRQ, TIMER5_COMPB_IRQ,
> >   TIMER5_COMPC_IRQ, TIMER5_OVF_IRQ,
> > +WATCHDOG_TIMER_IRQ,
> >   IRQ_COUNT
> >   };
> >
> > @@ -133,6 +137,7 @@ enum AtmegaIrq {
> >   #define TIMER_OVF_IRQ(n)(n * TIMER_IRQ_COUNT + TIMER0_OVF_IRQ)
> >
> >   static const uint8_t irq168_328[IRQ_COUNT] = {
> > +[WATCHDOG_TIMER_IRQ]= 7,
> >   [TIMER2_COMPA_IRQ]  = 8,
> >   [TIMER2_COMPB_IRQ]  = 9,
> >   [TIMER2_OVF_IRQ]= 10,
> > @@ -147,6 +152,7 @@ static const uint8_t irq168_328[IRQ_COUNT] = {
> >   [USART0_DRE_IRQ]= 20,
> >   [USART0_TXC_IRQ]= 21,
> >   }, irq1280_2560[IRQ_COUNT] = {
> > +[WATCHDOG_TIMER_IRQ]= 13,
> >   [TIMER2_COMPA_IRQ]  = 14,
> >   [TIMER2_COMPB_IRQ]  = 15,
> >   [TIMER2_OVF_IRQ]= 16,
> > @@ -344,10 +350,17 @@ static void atmega_realize(DeviceState *dev, Error
> **errp)
> >   g_free(devname);
> >   }
> >
> > +/* Watchdog Timer */
> > +object_initialize_child(OBJECT(dev), "wdt", &s->wdt, TYPE_AVR_WDT);
> > +sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &error_abort);
> > +sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0,
> > +OFFSET_DATA + mc->dev[WDT].addr);
> > +qdev_connect_gpio_out_named(cpudev, "wdr", 0,
> > +qdev_get_gpio_in_named(DEVICE(&s->wdt), "wdr", 0));
> > +
> >   create_unimplemented_device("avr-twi",  OFFSET_DATA +
> 0x0b8, 6);
> >   create_unimplemented_device("avr-adc",  OFFSET_DATA +
> 0x078, 8);
> >   create_unimplemented_device("avr-ext-mem-ctrl", OFFSET_DATA +
> 0x074, 2);
> > -create_unimplemented_device("avr-watchdog", OFFSET_DATA +
> 0x060, 1);
> >   create_unimplemented_device("avr-spi",  OFFSET_DATA +
> 0x04c, 3);
> >   create_unimplemented_device("avr-eeprom",   OFFSET_DATA +
> 0x03f, 3);
> >   }
> > diff --git a/hw/avr/atmega.h b/hw/avr/atmega.h
> > index a99ee15c7e..60bbd44bdd 100644
> > --- a/hw/avr/atmega.h
> > +++ b/hw/avr/atmega.h
> > @@ -13,6 +13,7 @@
> >
> >   #include "hw/char/avr_usart.h"
> >   #include "

Re: [RFC 1/1] Implement AVR watchdog timer

2021-05-13 Thread Pavel Dovgalyuk

On 06.05.2021 00:18, Michael Rolnik wrote:

Signed-off-by: Michael Rolnik 
---
  MAINTAINERS   |   2 +
  hw/avr/Kconfig|   1 +
  hw/avr/atmega.c   |  15 +-
  hw/avr/atmega.h   |   2 +
  hw/watchdog/Kconfig   |   3 +
  hw/watchdog/avr_wdt.c | 274 ++
  hw/watchdog/meson.build   |   2 +
  hw/watchdog/trace-events  |   5 +
  include/hw/watchdog/avr_wdt.h |  47 ++
  target/avr/cpu.c  |   3 +
  target/avr/cpu.h  |   1 +
  target/avr/helper.c   |   7 +-
  target/avr/translate.c|  38 -
  13 files changed, 391 insertions(+), 9 deletions(-)
  create mode 100644 hw/watchdog/avr_wdt.c
  create mode 100644 include/hw/watchdog/avr_wdt.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 4c05ff8bba..e1fce736d2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1052,6 +1052,8 @@ F: include/hw/timer/avr_timer16.h
  F: hw/timer/avr_timer16.c
  F: include/hw/misc/avr_power.h
  F: hw/misc/avr_power.c
+F: include/hw/watchdog/avr_wdt.h
+F: hw/watchdog/avr_wdt.c
  
  Arduino

  M: Philippe Mathieu-Daudé 
diff --git a/hw/avr/Kconfig b/hw/avr/Kconfig
index d31298c3cc..9939e4902f 100644
--- a/hw/avr/Kconfig
+++ b/hw/avr/Kconfig
@@ -3,6 +3,7 @@ config AVR_ATMEGA_MCU
  select AVR_TIMER16
  select AVR_USART
  select AVR_POWER
+select AVR_WDT
  
  config ARDUINO

  select AVR_ATMEGA_MCU
diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c
index 44c6afebbb..31ceb1c21c 100644
--- a/hw/avr/atmega.c
+++ b/hw/avr/atmega.c
@@ -28,6 +28,7 @@ enum AtmegaPeripheral {
  GPIOG, GPIOH, GPIOI, GPIOJ, GPIOK, GPIOL,
  USART0, USART1, USART2, USART3,
  TIMER0, TIMER1, TIMER2, TIMER3, TIMER4, TIMER5,
+WDT,
  PERIFMAX
  };
  
@@ -75,6 +76,7 @@ static const peripheral_cfg dev168_328[PERIFMAX] = {

  [GPIOD] = {  0x29 },
  [GPIOC] = {  0x26 },
  [GPIOB] = {  0x23 },
+[WDT]   = {  0x60 },
  }, dev1280_2560[PERIFMAX] = {
  [USART3]= { 0x130, POWER1, 2 },
  [TIMER5]= { 0x120, POWER1, 5, 0x73, 0x3a, true },
@@ -99,6 +101,7 @@ static const peripheral_cfg dev168_328[PERIFMAX] = {
  [GPIOC] = {  0x26 },
  [GPIOB] = {  0x23 },
  [GPIOA] = {  0x20 },
+[WDT]   = {  0x60 },
  };
  
  enum AtmegaIrq {

@@ -118,6 +121,7 @@ enum AtmegaIrq {
  TIMER4_COMPC_IRQ, TIMER4_OVF_IRQ,
  TIMER5_CAPT_IRQ, TIMER5_COMPA_IRQ, TIMER5_COMPB_IRQ,
  TIMER5_COMPC_IRQ, TIMER5_OVF_IRQ,
+WATCHDOG_TIMER_IRQ,
  IRQ_COUNT
  };
  
@@ -133,6 +137,7 @@ enum AtmegaIrq {

  #define TIMER_OVF_IRQ(n)(n * TIMER_IRQ_COUNT + TIMER0_OVF_IRQ)
  
  static const uint8_t irq168_328[IRQ_COUNT] = {

+[WATCHDOG_TIMER_IRQ]= 7,
  [TIMER2_COMPA_IRQ]  = 8,
  [TIMER2_COMPB_IRQ]  = 9,
  [TIMER2_OVF_IRQ]= 10,
@@ -147,6 +152,7 @@ static const uint8_t irq168_328[IRQ_COUNT] = {
  [USART0_DRE_IRQ]= 20,
  [USART0_TXC_IRQ]= 21,
  }, irq1280_2560[IRQ_COUNT] = {
+[WATCHDOG_TIMER_IRQ]= 13,
  [TIMER2_COMPA_IRQ]  = 14,
  [TIMER2_COMPB_IRQ]  = 15,
  [TIMER2_OVF_IRQ]= 16,
@@ -344,10 +350,17 @@ static void atmega_realize(DeviceState *dev, Error **errp)
  g_free(devname);
  }
  
+/* Watchdog Timer */

+object_initialize_child(OBJECT(dev), "wdt", &s->wdt, TYPE_AVR_WDT);
+sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &error_abort);
+sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0,
+OFFSET_DATA + mc->dev[WDT].addr);
+qdev_connect_gpio_out_named(cpudev, "wdr", 0,
+qdev_get_gpio_in_named(DEVICE(&s->wdt), "wdr", 0));
+
  create_unimplemented_device("avr-twi",  OFFSET_DATA + 0x0b8, 6);
  create_unimplemented_device("avr-adc",  OFFSET_DATA + 0x078, 8);
  create_unimplemented_device("avr-ext-mem-ctrl", OFFSET_DATA + 0x074, 2);
-create_unimplemented_device("avr-watchdog", OFFSET_DATA + 0x060, 1);
  create_unimplemented_device("avr-spi",  OFFSET_DATA + 0x04c, 3);
  create_unimplemented_device("avr-eeprom",   OFFSET_DATA + 0x03f, 3);
  }
diff --git a/hw/avr/atmega.h b/hw/avr/atmega.h
index a99ee15c7e..60bbd44bdd 100644
--- a/hw/avr/atmega.h
+++ b/hw/avr/atmega.h
@@ -13,6 +13,7 @@
  
  #include "hw/char/avr_usart.h"

  #include "hw/timer/avr_timer16.h"
+#include "hw/watchdog/avr_wdt.h"
  #include "hw/misc/avr_power.h"
  #include "target/avr/cpu.h"
  #include "qom/object.h"
@@ -45,6 +46,7 @@ struct AtmegaMcuState {
  AVRMaskState pwr[POWER_MAX];
  AVRUsartState usart[USART_MAX];
  AVRTimer16State timer[TIMER_MAX];
+AVRWatchdogState wdt;
  uint64_t xtal_freq_hz;
  };
  
diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig

index 66e1d029e3..e0f89d2fe0 100644
--- a/hw/watchdog/Kconfig
+++ b/hw/watchdog/Kconfig
@@ -20,3 +20,6 @@ config WDT_IMX2
  
  config WDT_SBSA

  bool
+
+config 

[RFC 1/1] Implement AVR watchdog timer

2021-05-05 Thread Michael Rolnik
Signed-off-by: Michael Rolnik 
---
 MAINTAINERS   |   2 +
 hw/avr/Kconfig|   1 +
 hw/avr/atmega.c   |  15 +-
 hw/avr/atmega.h   |   2 +
 hw/watchdog/Kconfig   |   3 +
 hw/watchdog/avr_wdt.c | 274 ++
 hw/watchdog/meson.build   |   2 +
 hw/watchdog/trace-events  |   5 +
 include/hw/watchdog/avr_wdt.h |  47 ++
 target/avr/cpu.c  |   3 +
 target/avr/cpu.h  |   1 +
 target/avr/helper.c   |   7 +-
 target/avr/translate.c|  38 -
 13 files changed, 391 insertions(+), 9 deletions(-)
 create mode 100644 hw/watchdog/avr_wdt.c
 create mode 100644 include/hw/watchdog/avr_wdt.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 4c05ff8bba..e1fce736d2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1052,6 +1052,8 @@ F: include/hw/timer/avr_timer16.h
 F: hw/timer/avr_timer16.c
 F: include/hw/misc/avr_power.h
 F: hw/misc/avr_power.c
+F: include/hw/watchdog/avr_wdt.h
+F: hw/watchdog/avr_wdt.c
 
 Arduino
 M: Philippe Mathieu-Daudé 
diff --git a/hw/avr/Kconfig b/hw/avr/Kconfig
index d31298c3cc..9939e4902f 100644
--- a/hw/avr/Kconfig
+++ b/hw/avr/Kconfig
@@ -3,6 +3,7 @@ config AVR_ATMEGA_MCU
 select AVR_TIMER16
 select AVR_USART
 select AVR_POWER
+select AVR_WDT
 
 config ARDUINO
 select AVR_ATMEGA_MCU
diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c
index 44c6afebbb..31ceb1c21c 100644
--- a/hw/avr/atmega.c
+++ b/hw/avr/atmega.c
@@ -28,6 +28,7 @@ enum AtmegaPeripheral {
 GPIOG, GPIOH, GPIOI, GPIOJ, GPIOK, GPIOL,
 USART0, USART1, USART2, USART3,
 TIMER0, TIMER1, TIMER2, TIMER3, TIMER4, TIMER5,
+WDT,
 PERIFMAX
 };
 
@@ -75,6 +76,7 @@ static const peripheral_cfg dev168_328[PERIFMAX] = {
 [GPIOD] = {  0x29 },
 [GPIOC] = {  0x26 },
 [GPIOB] = {  0x23 },
+[WDT]   = {  0x60 },
 }, dev1280_2560[PERIFMAX] = {
 [USART3]= { 0x130, POWER1, 2 },
 [TIMER5]= { 0x120, POWER1, 5, 0x73, 0x3a, true },
@@ -99,6 +101,7 @@ static const peripheral_cfg dev168_328[PERIFMAX] = {
 [GPIOC] = {  0x26 },
 [GPIOB] = {  0x23 },
 [GPIOA] = {  0x20 },
+[WDT]   = {  0x60 },
 };
 
 enum AtmegaIrq {
@@ -118,6 +121,7 @@ enum AtmegaIrq {
 TIMER4_COMPC_IRQ, TIMER4_OVF_IRQ,
 TIMER5_CAPT_IRQ, TIMER5_COMPA_IRQ, TIMER5_COMPB_IRQ,
 TIMER5_COMPC_IRQ, TIMER5_OVF_IRQ,
+WATCHDOG_TIMER_IRQ,
 IRQ_COUNT
 };
 
@@ -133,6 +137,7 @@ enum AtmegaIrq {
 #define TIMER_OVF_IRQ(n)(n * TIMER_IRQ_COUNT + TIMER0_OVF_IRQ)
 
 static const uint8_t irq168_328[IRQ_COUNT] = {
+[WATCHDOG_TIMER_IRQ]= 7,
 [TIMER2_COMPA_IRQ]  = 8,
 [TIMER2_COMPB_IRQ]  = 9,
 [TIMER2_OVF_IRQ]= 10,
@@ -147,6 +152,7 @@ static const uint8_t irq168_328[IRQ_COUNT] = {
 [USART0_DRE_IRQ]= 20,
 [USART0_TXC_IRQ]= 21,
 }, irq1280_2560[IRQ_COUNT] = {
+[WATCHDOG_TIMER_IRQ]= 13,
 [TIMER2_COMPA_IRQ]  = 14,
 [TIMER2_COMPB_IRQ]  = 15,
 [TIMER2_OVF_IRQ]= 16,
@@ -344,10 +350,17 @@ static void atmega_realize(DeviceState *dev, Error **errp)
 g_free(devname);
 }
 
+/* Watchdog Timer */
+object_initialize_child(OBJECT(dev), "wdt", &s->wdt, TYPE_AVR_WDT);
+sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &error_abort);
+sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0,
+OFFSET_DATA + mc->dev[WDT].addr);
+qdev_connect_gpio_out_named(cpudev, "wdr", 0,
+qdev_get_gpio_in_named(DEVICE(&s->wdt), "wdr", 0));
+
 create_unimplemented_device("avr-twi",  OFFSET_DATA + 0x0b8, 6);
 create_unimplemented_device("avr-adc",  OFFSET_DATA + 0x078, 8);
 create_unimplemented_device("avr-ext-mem-ctrl", OFFSET_DATA + 0x074, 2);
-create_unimplemented_device("avr-watchdog", OFFSET_DATA + 0x060, 1);
 create_unimplemented_device("avr-spi",  OFFSET_DATA + 0x04c, 3);
 create_unimplemented_device("avr-eeprom",   OFFSET_DATA + 0x03f, 3);
 }
diff --git a/hw/avr/atmega.h b/hw/avr/atmega.h
index a99ee15c7e..60bbd44bdd 100644
--- a/hw/avr/atmega.h
+++ b/hw/avr/atmega.h
@@ -13,6 +13,7 @@
 
 #include "hw/char/avr_usart.h"
 #include "hw/timer/avr_timer16.h"
+#include "hw/watchdog/avr_wdt.h"
 #include "hw/misc/avr_power.h"
 #include "target/avr/cpu.h"
 #include "qom/object.h"
@@ -45,6 +46,7 @@ struct AtmegaMcuState {
 AVRMaskState pwr[POWER_MAX];
 AVRUsartState usart[USART_MAX];
 AVRTimer16State timer[TIMER_MAX];
+AVRWatchdogState wdt;
 uint64_t xtal_freq_hz;
 };
 
diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig
index 66e1d029e3..e0f89d2fe0 100644
--- a/hw/watchdog/Kconfig
+++ b/hw/watchdog/Kconfig
@@ -20,3 +20,6 @@ config WDT_IMX2
 
 config WDT_SBSA
 bool
+
+config AVR_WDT
+bool
diff --git a/hw/watchdog/avr_wdt.c b/hw/watchdog/avr_wdt.c
new file mode 100644
index 00..cbd6457c8b
--- /dev/null
++

Re: [RFC 1/1] Implement AVR watchdog timer

2021-05-03 Thread Michael Rolnik
Hi all,

I was about to make icount work. but, there is something I still don't
understand. I have this code

timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, avr_wdt_interrupt, s);

and then

void avr_wdt_interrupt(/* some arguments */) {
#define MS2NS(n)((n) * 100ull)
timer_mod_ns(timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + MS2NS(15));
}

when running with --icount shift=0, *avr_wdt_interrupt* is called about
every 1K instructions, however it should have been called 15M instructions
as shift=0 makes every instruction to be executed in 1 virtual ns.

What am I doing wrong?

Thank you,
Michael Rolnik


On Mon, May 3, 2021 at 4:36 PM Michael Rolnik  wrote:

> Hi Fred.
>
> 1. thanks
> 2. It seems I have forgotten to set those flags.
> 3. 15ms is easy to test 8s will take 533 times longer, so in my case 3200
> instructions which is totally incorrect. I don't understand why as
> I program the timer in virtual nanoseconds and not host time.
> 4. I hope Richard could help with icount.
>
> best regards,
> Michael Rolnik
>
> On Mon, May 3, 2021 at 4:15 PM Fred Konrad  wrote:
>
>>
>>
>> Le 5/2/21 à 10:10 PM, Michael Rolnik a écrit :
>> > Signed-off-by: Michael Rolnik 
>> > ---
>> >   hw/avr/Kconfig|   1 +
>> >   hw/avr/atmega.c   |  15 ++-
>> >   hw/avr/atmega.h   |   2 +
>> >   hw/watchdog/Kconfig   |   3 +
>> >   hw/watchdog/avr_wdt.c | 190 ++
>> >   hw/watchdog/meson.build   |   2 +
>> >   hw/watchdog/trace-events  |   5 +
>> >   include/hw/watchdog/avr_wdt.h |  47 +
>> >   target/avr/cpu.c  |   3 +
>> >   target/avr/cpu.h  |   1 +
>> >   target/avr/helper.c   |   7 +-
>> >   11 files changed, 271 insertions(+), 5 deletions(-)
>> >   create mode 100644 hw/watchdog/avr_wdt.c
>> >   create mode 100644 include/hw/watchdog/avr_wdt.h
>> >
>> > diff --git a/hw/avr/Kconfig b/hw/avr/Kconfig
>> > index d31298c3cc..9939e4902f 100644
>> > --- a/hw/avr/Kconfig
>> > +++ b/hw/avr/Kconfig
>> > @@ -3,6 +3,7 @@ config AVR_ATMEGA_MCU
>> >   select AVR_TIMER16
>> >   select AVR_USART
>> >   select AVR_POWER
>> > +select AVR_WDT
>> >
>> >   config ARDUINO
>> >   select AVR_ATMEGA_MCU
>> > diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c
>> > index 44c6afebbb..31ceb1c21c 100644
>> > --- a/hw/avr/atmega.c
>> > +++ b/hw/avr/atmega.c
>> > @@ -28,6 +28,7 @@ enum AtmegaPeripheral {
>> >   GPIOG, GPIOH, GPIOI, GPIOJ, GPIOK, GPIOL,
>> >   USART0, USART1, USART2, USART3,
>> >   TIMER0, TIMER1, TIMER2, TIMER3, TIMER4, TIMER5,
>> > +WDT,
>> >   PERIFMAX
>> >   };
>> >
>> > @@ -75,6 +76,7 @@ static const peripheral_cfg dev168_328[PERIFMAX] = {
>> >   [GPIOD] = {  0x29 },
>> >   [GPIOC] = {  0x26 },
>> >   [GPIOB] = {  0x23 },
>> > +[WDT]   = {  0x60 },
>> >   }, dev1280_2560[PERIFMAX] = {
>> >   [USART3]= { 0x130, POWER1, 2 },
>> >   [TIMER5]= { 0x120, POWER1, 5, 0x73, 0x3a, true },
>> > @@ -99,6 +101,7 @@ static const peripheral_cfg dev168_328[PERIFMAX] = {
>> >   [GPIOC] = {  0x26 },
>> >   [GPIOB] = {  0x23 },
>> >   [GPIOA] = {  0x20 },
>> > +[WDT]   = {  0x60 },
>> >   };
>> >
>> >   enum AtmegaIrq {
>> > @@ -118,6 +121,7 @@ enum AtmegaIrq {
>> >   TIMER4_COMPC_IRQ, TIMER4_OVF_IRQ,
>> >   TIMER5_CAPT_IRQ, TIMER5_COMPA_IRQ, TIMER5_COMPB_IRQ,
>> >   TIMER5_COMPC_IRQ, TIMER5_OVF_IRQ,
>> > +WATCHDOG_TIMER_IRQ,
>> >   IRQ_COUNT
>> >   };
>> >
>> > @@ -133,6 +137,7 @@ enum AtmegaIrq {
>> >   #define TIMER_OVF_IRQ(n)(n * TIMER_IRQ_COUNT + TIMER0_OVF_IRQ)
>> >
>> >   static const uint8_t irq168_328[IRQ_COUNT] = {
>> > +[WATCHDOG_TIMER_IRQ]= 7,
>> >   [TIMER2_COMPA_IRQ]  = 8,
>> >   [TIMER2_COMPB_IRQ]  = 9,
>> >   [TIMER2_OVF_IRQ]= 10,
>> > @@ -147,6 +152,7 @@ static const uint8_t irq168_328[IRQ_COUNT] = {
>> >   [USART0_DRE_IRQ]= 20,
>> >   [USART0_TXC_IRQ]= 21,
>> >   }, irq1280_2560[IRQ_COUNT] = {
>> > +[WATCHDOG_TIMER_IRQ]= 13,
>> >   [TIMER2_COMPA_IRQ]  = 14,
>> >   [TIMER2_COMPB_IRQ]  = 15,
>> >   [TIMER2_OVF_IRQ]= 16,
>> > @@ -344,10 +350,17 @@ static void atmega_realize(DeviceState *dev,
>> Error **errp)
>> >   g_free(devname);
>> >   }
>> >
>> > +/* Watchdog Timer */
>> > +object_initialize_child(OBJECT(dev), "wdt", &s->wdt, TYPE_AVR_WDT);
>> > +sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &error_abort);
>> > +sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0,
>> > +OFFSET_DATA + mc->dev[WDT].addr);
>> > +qdev_connect_gpio_out_named(cpudev, "wdr", 0,
>> > +qdev_get_gpio_in_named(DEVICE(&s->wdt), "wdr", 0));
>> > +
>> >   create_unimplemented_device("avr-twi",  OFFSET_DATA +
>> 0x0b8, 6);
>> >   create_unimplemented_device("avr-adc",   

Re: [RFC 1/1] Implement AVR watchdog timer

2021-05-03 Thread Michael Rolnik
Hi Fred.

1. thanks
2. It seems I have forgotten to set those flags.
3. 15ms is easy to test 8s will take 533 times longer, so in my case 3200
instructions which is totally incorrect. I don't understand why as
I program the timer in virtual nanoseconds and not host time.
4. I hope Richard could help with icount.

best regards,
Michael Rolnik

On Mon, May 3, 2021 at 4:15 PM Fred Konrad  wrote:

>
>
> Le 5/2/21 à 10:10 PM, Michael Rolnik a écrit :
> > Signed-off-by: Michael Rolnik 
> > ---
> >   hw/avr/Kconfig|   1 +
> >   hw/avr/atmega.c   |  15 ++-
> >   hw/avr/atmega.h   |   2 +
> >   hw/watchdog/Kconfig   |   3 +
> >   hw/watchdog/avr_wdt.c | 190 ++
> >   hw/watchdog/meson.build   |   2 +
> >   hw/watchdog/trace-events  |   5 +
> >   include/hw/watchdog/avr_wdt.h |  47 +
> >   target/avr/cpu.c  |   3 +
> >   target/avr/cpu.h  |   1 +
> >   target/avr/helper.c   |   7 +-
> >   11 files changed, 271 insertions(+), 5 deletions(-)
> >   create mode 100644 hw/watchdog/avr_wdt.c
> >   create mode 100644 include/hw/watchdog/avr_wdt.h
> >
> > diff --git a/hw/avr/Kconfig b/hw/avr/Kconfig
> > index d31298c3cc..9939e4902f 100644
> > --- a/hw/avr/Kconfig
> > +++ b/hw/avr/Kconfig
> > @@ -3,6 +3,7 @@ config AVR_ATMEGA_MCU
> >   select AVR_TIMER16
> >   select AVR_USART
> >   select AVR_POWER
> > +select AVR_WDT
> >
> >   config ARDUINO
> >   select AVR_ATMEGA_MCU
> > diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c
> > index 44c6afebbb..31ceb1c21c 100644
> > --- a/hw/avr/atmega.c
> > +++ b/hw/avr/atmega.c
> > @@ -28,6 +28,7 @@ enum AtmegaPeripheral {
> >   GPIOG, GPIOH, GPIOI, GPIOJ, GPIOK, GPIOL,
> >   USART0, USART1, USART2, USART3,
> >   TIMER0, TIMER1, TIMER2, TIMER3, TIMER4, TIMER5,
> > +WDT,
> >   PERIFMAX
> >   };
> >
> > @@ -75,6 +76,7 @@ static const peripheral_cfg dev168_328[PERIFMAX] = {
> >   [GPIOD] = {  0x29 },
> >   [GPIOC] = {  0x26 },
> >   [GPIOB] = {  0x23 },
> > +[WDT]   = {  0x60 },
> >   }, dev1280_2560[PERIFMAX] = {
> >   [USART3]= { 0x130, POWER1, 2 },
> >   [TIMER5]= { 0x120, POWER1, 5, 0x73, 0x3a, true },
> > @@ -99,6 +101,7 @@ static const peripheral_cfg dev168_328[PERIFMAX] = {
> >   [GPIOC] = {  0x26 },
> >   [GPIOB] = {  0x23 },
> >   [GPIOA] = {  0x20 },
> > +[WDT]   = {  0x60 },
> >   };
> >
> >   enum AtmegaIrq {
> > @@ -118,6 +121,7 @@ enum AtmegaIrq {
> >   TIMER4_COMPC_IRQ, TIMER4_OVF_IRQ,
> >   TIMER5_CAPT_IRQ, TIMER5_COMPA_IRQ, TIMER5_COMPB_IRQ,
> >   TIMER5_COMPC_IRQ, TIMER5_OVF_IRQ,
> > +WATCHDOG_TIMER_IRQ,
> >   IRQ_COUNT
> >   };
> >
> > @@ -133,6 +137,7 @@ enum AtmegaIrq {
> >   #define TIMER_OVF_IRQ(n)(n * TIMER_IRQ_COUNT + TIMER0_OVF_IRQ)
> >
> >   static const uint8_t irq168_328[IRQ_COUNT] = {
> > +[WATCHDOG_TIMER_IRQ]= 7,
> >   [TIMER2_COMPA_IRQ]  = 8,
> >   [TIMER2_COMPB_IRQ]  = 9,
> >   [TIMER2_OVF_IRQ]= 10,
> > @@ -147,6 +152,7 @@ static const uint8_t irq168_328[IRQ_COUNT] = {
> >   [USART0_DRE_IRQ]= 20,
> >   [USART0_TXC_IRQ]= 21,
> >   }, irq1280_2560[IRQ_COUNT] = {
> > +[WATCHDOG_TIMER_IRQ]= 13,
> >   [TIMER2_COMPA_IRQ]  = 14,
> >   [TIMER2_COMPB_IRQ]  = 15,
> >   [TIMER2_OVF_IRQ]= 16,
> > @@ -344,10 +350,17 @@ static void atmega_realize(DeviceState *dev, Error
> **errp)
> >   g_free(devname);
> >   }
> >
> > +/* Watchdog Timer */
> > +object_initialize_child(OBJECT(dev), "wdt", &s->wdt, TYPE_AVR_WDT);
> > +sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &error_abort);
> > +sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0,
> > +OFFSET_DATA + mc->dev[WDT].addr);
> > +qdev_connect_gpio_out_named(cpudev, "wdr", 0,
> > +qdev_get_gpio_in_named(DEVICE(&s->wdt), "wdr", 0));
> > +
> >   create_unimplemented_device("avr-twi",  OFFSET_DATA +
> 0x0b8, 6);
> >   create_unimplemented_device("avr-adc",  OFFSET_DATA +
> 0x078, 8);
> >   create_unimplemented_device("avr-ext-mem-ctrl", OFFSET_DATA +
> 0x074, 2);
> > -create_unimplemented_device("avr-watchdog", OFFSET_DATA +
> 0x060, 1);
> >   create_unimplemented_device("avr-spi",  OFFSET_DATA +
> 0x04c, 3);
> >   create_unimplemented_device("avr-eeprom",   OFFSET_DATA +
> 0x03f, 3);
> >   }
> > diff --git a/hw/avr/atmega.h b/hw/avr/atmega.h
> > index a99ee15c7e..60bbd44bdd 100644
> > --- a/hw/avr/atmega.h
> > +++ b/hw/avr/atmega.h
> > @@ -13,6 +13,7 @@
> >
> >   #include "hw/char/avr_usart.h"
> >   #include "hw/timer/avr_timer16.h"
> > +#include "hw/watchdog/avr_wdt.h"
> >   #include "hw/misc/avr_power.h"
> >   #include "target/avr/cpu.h"
> >   #include "qom/object.h"
> > @@ -45,6 +46,7 @@ struct AtmegaMcu

Re: [RFC 1/1] Implement AVR watchdog timer

2021-05-03 Thread Fred Konrad




Le 5/2/21 à 10:10 PM, Michael Rolnik a écrit :

Signed-off-by: Michael Rolnik 
---
  hw/avr/Kconfig|   1 +
  hw/avr/atmega.c   |  15 ++-
  hw/avr/atmega.h   |   2 +
  hw/watchdog/Kconfig   |   3 +
  hw/watchdog/avr_wdt.c | 190 ++
  hw/watchdog/meson.build   |   2 +
  hw/watchdog/trace-events  |   5 +
  include/hw/watchdog/avr_wdt.h |  47 +
  target/avr/cpu.c  |   3 +
  target/avr/cpu.h  |   1 +
  target/avr/helper.c   |   7 +-
  11 files changed, 271 insertions(+), 5 deletions(-)
  create mode 100644 hw/watchdog/avr_wdt.c
  create mode 100644 include/hw/watchdog/avr_wdt.h

diff --git a/hw/avr/Kconfig b/hw/avr/Kconfig
index d31298c3cc..9939e4902f 100644
--- a/hw/avr/Kconfig
+++ b/hw/avr/Kconfig
@@ -3,6 +3,7 @@ config AVR_ATMEGA_MCU
  select AVR_TIMER16
  select AVR_USART
  select AVR_POWER
+select AVR_WDT
  
  config ARDUINO

  select AVR_ATMEGA_MCU
diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c
index 44c6afebbb..31ceb1c21c 100644
--- a/hw/avr/atmega.c
+++ b/hw/avr/atmega.c
@@ -28,6 +28,7 @@ enum AtmegaPeripheral {
  GPIOG, GPIOH, GPIOI, GPIOJ, GPIOK, GPIOL,
  USART0, USART1, USART2, USART3,
  TIMER0, TIMER1, TIMER2, TIMER3, TIMER4, TIMER5,
+WDT,
  PERIFMAX
  };
  
@@ -75,6 +76,7 @@ static const peripheral_cfg dev168_328[PERIFMAX] = {

  [GPIOD] = {  0x29 },
  [GPIOC] = {  0x26 },
  [GPIOB] = {  0x23 },
+[WDT]   = {  0x60 },
  }, dev1280_2560[PERIFMAX] = {
  [USART3]= { 0x130, POWER1, 2 },
  [TIMER5]= { 0x120, POWER1, 5, 0x73, 0x3a, true },
@@ -99,6 +101,7 @@ static const peripheral_cfg dev168_328[PERIFMAX] = {
  [GPIOC] = {  0x26 },
  [GPIOB] = {  0x23 },
  [GPIOA] = {  0x20 },
+[WDT]   = {  0x60 },
  };
  
  enum AtmegaIrq {

@@ -118,6 +121,7 @@ enum AtmegaIrq {
  TIMER4_COMPC_IRQ, TIMER4_OVF_IRQ,
  TIMER5_CAPT_IRQ, TIMER5_COMPA_IRQ, TIMER5_COMPB_IRQ,
  TIMER5_COMPC_IRQ, TIMER5_OVF_IRQ,
+WATCHDOG_TIMER_IRQ,
  IRQ_COUNT
  };
  
@@ -133,6 +137,7 @@ enum AtmegaIrq {

  #define TIMER_OVF_IRQ(n)(n * TIMER_IRQ_COUNT + TIMER0_OVF_IRQ)
  
  static const uint8_t irq168_328[IRQ_COUNT] = {

+[WATCHDOG_TIMER_IRQ]= 7,
  [TIMER2_COMPA_IRQ]  = 8,
  [TIMER2_COMPB_IRQ]  = 9,
  [TIMER2_OVF_IRQ]= 10,
@@ -147,6 +152,7 @@ static const uint8_t irq168_328[IRQ_COUNT] = {
  [USART0_DRE_IRQ]= 20,
  [USART0_TXC_IRQ]= 21,
  }, irq1280_2560[IRQ_COUNT] = {
+[WATCHDOG_TIMER_IRQ]= 13,
  [TIMER2_COMPA_IRQ]  = 14,
  [TIMER2_COMPB_IRQ]  = 15,
  [TIMER2_OVF_IRQ]= 16,
@@ -344,10 +350,17 @@ static void atmega_realize(DeviceState *dev, Error **errp)
  g_free(devname);
  }
  
+/* Watchdog Timer */

+object_initialize_child(OBJECT(dev), "wdt", &s->wdt, TYPE_AVR_WDT);
+sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &error_abort);
+sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0,
+OFFSET_DATA + mc->dev[WDT].addr);
+qdev_connect_gpio_out_named(cpudev, "wdr", 0,
+qdev_get_gpio_in_named(DEVICE(&s->wdt), "wdr", 0));
+
  create_unimplemented_device("avr-twi",  OFFSET_DATA + 0x0b8, 6);
  create_unimplemented_device("avr-adc",  OFFSET_DATA + 0x078, 8);
  create_unimplemented_device("avr-ext-mem-ctrl", OFFSET_DATA + 0x074, 2);
-create_unimplemented_device("avr-watchdog", OFFSET_DATA + 0x060, 1);
  create_unimplemented_device("avr-spi",  OFFSET_DATA + 0x04c, 3);
  create_unimplemented_device("avr-eeprom",   OFFSET_DATA + 0x03f, 3);
  }
diff --git a/hw/avr/atmega.h b/hw/avr/atmega.h
index a99ee15c7e..60bbd44bdd 100644
--- a/hw/avr/atmega.h
+++ b/hw/avr/atmega.h
@@ -13,6 +13,7 @@
  
  #include "hw/char/avr_usart.h"

  #include "hw/timer/avr_timer16.h"
+#include "hw/watchdog/avr_wdt.h"
  #include "hw/misc/avr_power.h"
  #include "target/avr/cpu.h"
  #include "qom/object.h"
@@ -45,6 +46,7 @@ struct AtmegaMcuState {
  AVRMaskState pwr[POWER_MAX];
  AVRUsartState usart[USART_MAX];
  AVRTimer16State timer[TIMER_MAX];
+AVRWatchdogState wdt;
  uint64_t xtal_freq_hz;
  };
  
diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig

index 66e1d029e3..e0f89d2fe0 100644
--- a/hw/watchdog/Kconfig
+++ b/hw/watchdog/Kconfig
@@ -20,3 +20,6 @@ config WDT_IMX2
  
  config WDT_SBSA

  bool
+
+config AVR_WDT
+bool
diff --git a/hw/watchdog/avr_wdt.c b/hw/watchdog/avr_wdt.c
new file mode 100644
index 00..4ce1029a64
--- /dev/null
+++ b/hw/watchdog/avr_wdt.c
@@ -0,0 +1,190 @@
+/*
+ * AVR watchdog
+ *
+ * Copyright (c) 2018 Michael Rolnik


2021?


+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free

[RFC 1/1] Implement AVR watchdog timer

2021-05-02 Thread Michael Rolnik
Signed-off-by: Michael Rolnik 
---
 hw/avr/Kconfig|   1 +
 hw/avr/atmega.c   |  15 ++-
 hw/avr/atmega.h   |   2 +
 hw/watchdog/Kconfig   |   3 +
 hw/watchdog/avr_wdt.c | 190 ++
 hw/watchdog/meson.build   |   2 +
 hw/watchdog/trace-events  |   5 +
 include/hw/watchdog/avr_wdt.h |  47 +
 target/avr/cpu.c  |   3 +
 target/avr/cpu.h  |   1 +
 target/avr/helper.c   |   7 +-
 11 files changed, 271 insertions(+), 5 deletions(-)
 create mode 100644 hw/watchdog/avr_wdt.c
 create mode 100644 include/hw/watchdog/avr_wdt.h

diff --git a/hw/avr/Kconfig b/hw/avr/Kconfig
index d31298c3cc..9939e4902f 100644
--- a/hw/avr/Kconfig
+++ b/hw/avr/Kconfig
@@ -3,6 +3,7 @@ config AVR_ATMEGA_MCU
 select AVR_TIMER16
 select AVR_USART
 select AVR_POWER
+select AVR_WDT
 
 config ARDUINO
 select AVR_ATMEGA_MCU
diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c
index 44c6afebbb..31ceb1c21c 100644
--- a/hw/avr/atmega.c
+++ b/hw/avr/atmega.c
@@ -28,6 +28,7 @@ enum AtmegaPeripheral {
 GPIOG, GPIOH, GPIOI, GPIOJ, GPIOK, GPIOL,
 USART0, USART1, USART2, USART3,
 TIMER0, TIMER1, TIMER2, TIMER3, TIMER4, TIMER5,
+WDT,
 PERIFMAX
 };
 
@@ -75,6 +76,7 @@ static const peripheral_cfg dev168_328[PERIFMAX] = {
 [GPIOD] = {  0x29 },
 [GPIOC] = {  0x26 },
 [GPIOB] = {  0x23 },
+[WDT]   = {  0x60 },
 }, dev1280_2560[PERIFMAX] = {
 [USART3]= { 0x130, POWER1, 2 },
 [TIMER5]= { 0x120, POWER1, 5, 0x73, 0x3a, true },
@@ -99,6 +101,7 @@ static const peripheral_cfg dev168_328[PERIFMAX] = {
 [GPIOC] = {  0x26 },
 [GPIOB] = {  0x23 },
 [GPIOA] = {  0x20 },
+[WDT]   = {  0x60 },
 };
 
 enum AtmegaIrq {
@@ -118,6 +121,7 @@ enum AtmegaIrq {
 TIMER4_COMPC_IRQ, TIMER4_OVF_IRQ,
 TIMER5_CAPT_IRQ, TIMER5_COMPA_IRQ, TIMER5_COMPB_IRQ,
 TIMER5_COMPC_IRQ, TIMER5_OVF_IRQ,
+WATCHDOG_TIMER_IRQ,
 IRQ_COUNT
 };
 
@@ -133,6 +137,7 @@ enum AtmegaIrq {
 #define TIMER_OVF_IRQ(n)(n * TIMER_IRQ_COUNT + TIMER0_OVF_IRQ)
 
 static const uint8_t irq168_328[IRQ_COUNT] = {
+[WATCHDOG_TIMER_IRQ]= 7,
 [TIMER2_COMPA_IRQ]  = 8,
 [TIMER2_COMPB_IRQ]  = 9,
 [TIMER2_OVF_IRQ]= 10,
@@ -147,6 +152,7 @@ static const uint8_t irq168_328[IRQ_COUNT] = {
 [USART0_DRE_IRQ]= 20,
 [USART0_TXC_IRQ]= 21,
 }, irq1280_2560[IRQ_COUNT] = {
+[WATCHDOG_TIMER_IRQ]= 13,
 [TIMER2_COMPA_IRQ]  = 14,
 [TIMER2_COMPB_IRQ]  = 15,
 [TIMER2_OVF_IRQ]= 16,
@@ -344,10 +350,17 @@ static void atmega_realize(DeviceState *dev, Error **errp)
 g_free(devname);
 }
 
+/* Watchdog Timer */
+object_initialize_child(OBJECT(dev), "wdt", &s->wdt, TYPE_AVR_WDT);
+sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &error_abort);
+sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0,
+OFFSET_DATA + mc->dev[WDT].addr);
+qdev_connect_gpio_out_named(cpudev, "wdr", 0,
+qdev_get_gpio_in_named(DEVICE(&s->wdt), "wdr", 0));
+
 create_unimplemented_device("avr-twi",  OFFSET_DATA + 0x0b8, 6);
 create_unimplemented_device("avr-adc",  OFFSET_DATA + 0x078, 8);
 create_unimplemented_device("avr-ext-mem-ctrl", OFFSET_DATA + 0x074, 2);
-create_unimplemented_device("avr-watchdog", OFFSET_DATA + 0x060, 1);
 create_unimplemented_device("avr-spi",  OFFSET_DATA + 0x04c, 3);
 create_unimplemented_device("avr-eeprom",   OFFSET_DATA + 0x03f, 3);
 }
diff --git a/hw/avr/atmega.h b/hw/avr/atmega.h
index a99ee15c7e..60bbd44bdd 100644
--- a/hw/avr/atmega.h
+++ b/hw/avr/atmega.h
@@ -13,6 +13,7 @@
 
 #include "hw/char/avr_usart.h"
 #include "hw/timer/avr_timer16.h"
+#include "hw/watchdog/avr_wdt.h"
 #include "hw/misc/avr_power.h"
 #include "target/avr/cpu.h"
 #include "qom/object.h"
@@ -45,6 +46,7 @@ struct AtmegaMcuState {
 AVRMaskState pwr[POWER_MAX];
 AVRUsartState usart[USART_MAX];
 AVRTimer16State timer[TIMER_MAX];
+AVRWatchdogState wdt;
 uint64_t xtal_freq_hz;
 };
 
diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig
index 66e1d029e3..e0f89d2fe0 100644
--- a/hw/watchdog/Kconfig
+++ b/hw/watchdog/Kconfig
@@ -20,3 +20,6 @@ config WDT_IMX2
 
 config WDT_SBSA
 bool
+
+config AVR_WDT
+bool
diff --git a/hw/watchdog/avr_wdt.c b/hw/watchdog/avr_wdt.c
new file mode 100644
index 00..4ce1029a64
--- /dev/null
+++ b/hw/watchdog/avr_wdt.c
@@ -0,0 +1,190 @@
+/*
+ * AVR watchdog
+ *
+ * Copyright (c) 2018 Michael Rolnik
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope tha