twi: Move avr_twi_irq_msg to avr_twi.c
[simavr] / simavr / sim / avr_watchdog.c
1 /*
2         avr_watchdog.c
3
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include "avr_watchdog.h"
26
27 static avr_cycle_count_t avr_watchdog_timer(struct avr_t * avr, avr_cycle_count_t when, void * param)
28 {
29         avr_watchdog_t * p = (avr_watchdog_t *)param;
30
31         printf("WATCHDOG timer fired.\n");
32         avr_raise_interrupt(avr, &p->watchdog);
33
34         if (!avr_regbit_get(avr, p->watchdog.enable)) {
35                 printf("WATCHDOG timer fired and interrupt is not enabled. Quitting\n");
36                 avr_sadly_crashed(avr, 10);
37         }
38
39         return 0;
40 }
41
42 static avr_cycle_count_t avr_wdce_clear(struct avr_t * avr, avr_cycle_count_t when, void * param)
43 {
44         avr_watchdog_t * p = (avr_watchdog_t *)param;
45         avr_regbit_clear(p->io.avr, p->wdce);
46         return 0;
47 }
48
49 static void avr_watchdog_write(avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
50 {
51         avr_watchdog_t * p = (avr_watchdog_t *)param;
52         // backup the registers
53         // uint8_t wd = avr->data[p->wdce.reg];
54         uint8_t wdce_o = avr_regbit_get(avr, p->wdce);  // old
55         uint8_t wde_o = avr_regbit_get(avr, p->wde);
56         uint8_t wdp_o[4];
57
58 //      printf("avr_watchdog_write %02x\n", v);
59         for (int i = 0; i < 4; i++)
60                 wdp_o[i] = avr_regbit_get(avr, p->wdp[i]);
61
62         avr->data[p->wdce.reg] = v;
63         uint8_t wdce_n = avr_regbit_get(avr, p->wdce);  // new
64
65         if (wdce_o /* || wdce_n */) {
66                 // make sure bit gets reset eventually
67                 if (wdce_n)
68                         avr_cycle_timer_register(avr, 4, avr_wdce_clear, p);
69
70                 uint8_t wdp = avr_regbit_get_array(avr, p->wdp, 4);
71                 p->cycle_count = 2048 << wdp;
72                 p->cycle_count = (p->cycle_count * avr->frequency) / 128000;
73                 if (avr_regbit_get(avr, p->wde)) {
74                         printf("Watchdog reset to %d cycles @ 128kz (* %d) = %d CPU cycles)\n", 2048 << wdp, 1 << wdp, (int)p->cycle_count);
75                         avr_cycle_timer_register(avr, p->cycle_count, avr_watchdog_timer, p);
76                 } else {
77                         printf("Watchdog disabled\n");
78                         avr_cycle_timer_cancel(avr, avr_watchdog_timer, p);
79                 }
80         } else {
81                 // reset old values
82                 avr_regbit_setto(avr, p->wde, wde_o);
83                 for (int i = 0; i < 4; i++)
84                         avr_regbit_setto(avr, p->wdp[i], wdp_o[i]);
85                 v = avr->data[p->wdce.reg];
86         }
87         avr_core_watch_write(avr, addr, v);
88 }
89
90 /*
91  * called by the core when a WTD instruction is found
92  */
93 static int avr_watchdog_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param)
94 {
95         avr_watchdog_t * p = (avr_watchdog_t *)port;
96         int res = -1;
97
98         if (ctl == AVR_IOCTL_WATCHDOG_RESET) {
99                 if (avr_regbit_get(p->io.avr, p->wde))
100                         avr_cycle_timer_register(p->io.avr, p->cycle_count, avr_watchdog_timer, p);
101                 res = 0;
102         }
103
104         return res;
105 }
106
107 static void avr_watchdog_reset(avr_io_t * port)
108 {
109 //      avr_watchdog_t * p = (avr_watchdog_t *)port;
110
111 }
112
113 static  avr_io_t        _io = {
114         .kind = "watchdog",
115         .reset = avr_watchdog_reset,
116         .ioctl = avr_watchdog_ioctl,
117 };
118
119 void avr_watchdog_init(avr_t * avr, avr_watchdog_t * p)
120 {
121         p->io = _io;
122
123         avr_register_io(avr, &p->io);
124         avr_register_vector(avr, &p->watchdog);
125
126         avr_register_io_write(avr, p->wdce.reg, avr_watchdog_write, p);
127 }
128