misc: Point to correct simavr include dirs
[simavr] / simavr / sim / avr_eeprom.c
1 /*
2         avr_eeprom.c
3
4         IO module that simulates the AVR EEProm
5
6         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
7
8         This file is part of simavr.
9
10         simavr is free software: you can redistribute it and/or modify
11         it under the terms of the GNU General Public License as published by
12         the Free Software Foundation, either version 3 of the License, or
13         (at your option) any later version.
14
15         simavr is distributed in the hope that it will be useful,
16         but WITHOUT ANY WARRANTY; without even the implied warranty of
17         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18         GNU General Public License for more details.
19
20         You should have received a copy of the GNU General Public License
21         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "avr_eeprom.h"
28
29 static avr_cycle_count_t avr_eempe_clear(struct avr_t * avr, avr_cycle_count_t when, void * param)
30 {
31         avr_eeprom_t * p = (avr_eeprom_t *)param;
32         avr_regbit_clear(p->io.avr, p->eempe);
33         return 0;
34 }
35
36 static avr_cycle_count_t avr_eei_raise(struct avr_t * avr, avr_cycle_count_t when, void * param)
37 {
38         avr_eeprom_t * p = (avr_eeprom_t *)param;
39         avr_raise_interrupt(p->io.avr, &p->ready);
40         return 0;
41 }
42
43 static void avr_eeprom_write(avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
44 {
45         avr_eeprom_t * p = (avr_eeprom_t *)param;
46         uint8_t eempe = avr_regbit_get(avr, p->eempe);
47
48         avr_core_watch_write(avr, addr, v);
49
50         if (!eempe && avr_regbit_get(avr, p->eempe)) {
51                 avr_cycle_timer_register(avr, 4, avr_eempe_clear, p);
52         }
53
54         if (eempe && avr_regbit_get(avr, p->eepe)) {    // write operation
55                 uint16_t addr;
56                 if (p->r_eearh)
57                         addr = avr->data[p->r_eearl] | (avr->data[p->r_eearh] << 8);
58                 else
59                         addr = avr->data[p->r_eearl];
60         //      printf("eeprom write %04x <- %02x\n", addr, avr->data[p->r_eedr]);
61                 p->eeprom[addr] = avr->data[p->r_eedr]; 
62                 // Automatically clears that bit (?)
63                 avr_regbit_clear(avr, p->eempe);
64
65                 avr_cycle_timer_register_usec(avr, 3400, avr_eei_raise, p); // 3.4ms here
66         }
67         if (avr_regbit_get(avr, p->eere)) {     // read operation
68                 uint16_t addr;
69                 if (p->r_eearh)
70                         addr = avr->data[p->r_eearl] | (avr->data[p->r_eearh] << 8);
71                 else
72                         addr = avr->data[p->r_eearl];
73                 avr->data[p->r_eedr] = p->eeprom[addr];
74         //      printf("eeprom read %04x : %02x\n", addr, p->eeprom[addr]);
75         }
76
77         // autocleared
78         avr_regbit_clear(avr, p->eepe);
79         avr_regbit_clear(avr, p->eere);
80 }
81
82 static int avr_eeprom_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param)
83 {
84         avr_eeprom_t * p = (avr_eeprom_t *)port;
85         int res = -1;
86
87         switch(ctl) {
88                 case AVR_IOCTL_EEPROM_SET: {
89                         avr_eeprom_desc_t * desc = (avr_eeprom_desc_t*)io_param;
90                         if (!desc || !desc->size || !desc->ee || (desc->offset + desc->size) > p->size) {
91                                 AVR_LOG(port->avr, LOG_WARNING, "EEPROM: %s: AVR_IOCTL_EEPROM_SET Invalid argument\n",
92                                                 __FUNCTION__);
93                                 return -2;
94                         }
95                         memcpy(p->eeprom + desc->offset, desc->ee, desc->size);
96                         AVR_LOG(port->avr, LOG_TRACE, "EEPROM: %s: AVR_IOCTL_EEPROM_SET Loaded %d at offset %d\n",
97                                         __FUNCTION__, desc->size, desc->offset);
98                 }       break;
99                 case AVR_IOCTL_EEPROM_GET: {
100                         avr_eeprom_desc_t * desc = (avr_eeprom_desc_t*)io_param;
101                         if (!desc || (desc->offset + desc->size) > p->size) {
102                                 AVR_LOG(port->avr, LOG_WARNING, "EEPROM: %s: AVR_IOCTL_EEPROM_GET Invalid argument\n",
103                                                 __FUNCTION__);
104                                 return -2;
105                         }
106                         if (desc->ee)
107                                 memcpy(desc->ee, p->eeprom + desc->offset, desc->size);
108                         else    // allow to get access to the read data, for gdb support
109                                 desc->ee = p->eeprom + desc->offset;
110                 }       break;
111         }
112         
113         return res;
114 }
115
116 static void avr_eeprom_dealloc(struct avr_io_t * port)
117 {
118         avr_eeprom_t * p = (avr_eeprom_t *)port;
119         if (p->eeprom)
120                 free(p->eeprom);
121         p->eeprom = NULL;
122 }
123
124 static  avr_io_t        _io = {
125         .kind = "eeprom",
126         .ioctl = avr_eeprom_ioctl,
127         .dealloc = avr_eeprom_dealloc,
128 };
129
130 void avr_eeprom_init(avr_t * avr, avr_eeprom_t * p)
131 {
132         p->io = _io;
133 //      printf("%s init (%d bytes) EEL/H:%02x/%02x EED=%02x EEC=%02x\n",
134 //                      __FUNCTION__, p->size, p->r_eearl, p->r_eearh, p->r_eedr, p->r_eecr);
135
136         p->eeprom = malloc(p->size);
137         memset(p->eeprom, 0xff, p->size);
138         
139         avr_register_io(avr, &p->io);
140         avr_register_vector(avr, &p->ready);
141
142         avr_register_io_write(avr, p->r_eecr, avr_eeprom_write, p);
143 }
144