misc: Point to correct simavr include dirs
[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         AVR_LOG(avr, LOG_TRACE, "WATCHDOG: timer fired.\n");
32         avr_raise_interrupt(avr, &p->watchdog);
33
34         if (!avr_regbit_get(avr, p->watchdog.enable)) {
35                 AVR_LOG(avr, LOG_ERROR, "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                         AVR_LOG(avr, LOG_TRACE, "WATCHDOG: reset to %d cycles @ 128kz (* %d) = %d CPU cycles)\n",
75                                         2048 << wdp, 1 << wdp, (int)p->cycle_count);
76                         avr_cycle_timer_register(avr, p->cycle_count, avr_watchdog_timer, p);
77                 } else {
78                         AVR_LOG(avr, LOG_TRACE, "WATCHDOG: disabled\n");
79                         avr_cycle_timer_cancel(avr, avr_watchdog_timer, p);
80                 }
81         } else {
82                 // reset old values
83                 avr_regbit_setto(avr, p->wde, wde_o);
84                 for (int i = 0; i < 4; i++)
85                         avr_regbit_setto(avr, p->wdp[i], wdp_o[i]);
86                 v = avr->data[p->wdce.reg];
87         }
88         avr_core_watch_write(avr, addr, v);
89 }
90
91 /*
92  * called by the core when a WTD instruction is found
93  */
94 static int avr_watchdog_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param)
95 {
96         avr_watchdog_t * p = (avr_watchdog_t *)port;
97         int res = -1;
98
99         if (ctl == AVR_IOCTL_WATCHDOG_RESET) {
100                 if (avr_regbit_get(p->io.avr, p->wde))
101                         avr_cycle_timer_register(p->io.avr, p->cycle_count, avr_watchdog_timer, p);
102                 res = 0;
103         }
104
105         return res;
106 }
107
108 static void avr_watchdog_reset(avr_io_t * port)
109 {
110 //      avr_watchdog_t * p = (avr_watchdog_t *)port;
111
112 }
113
114 static  avr_io_t        _io = {
115         .kind = "watchdog",
116         .reset = avr_watchdog_reset,
117         .ioctl = avr_watchdog_ioctl,
118 };
119
120 void avr_watchdog_init(avr_t * avr, avr_watchdog_t * p)
121 {
122         p->io = _io;
123
124         avr_register_io(avr, &p->io);
125         avr_register_vector(avr, &p->watchdog);
126
127         avr_register_io_write(avr, p->wdce.reg, avr_watchdog_write, p);
128 }
129