Polished gdb support, etc
[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 void avr_eeprom_run(avr_io_t * port)
30 {
31         avr_eeprom_t * p = (avr_eeprom_t *)port;
32         avr_t * avr = p->io.avr;
33         //printf("%s\n", __FUNCTION__);
34         if (p->eempe_clear_timer) {
35                 p->eempe_clear_timer--;
36                 if (p->eempe_clear_timer == 0) {
37                         avr_regbit_clear(avr, p->eempe);
38                 }
39         }
40         if (p->ready_raise_timer) {
41                 p->ready_raise_timer--;
42                 if (p->ready_raise_timer == 0) {
43                         avr_raise_interrupt(avr, &p->ready);
44                 }
45         }
46 }
47
48 static void avr_eeprom_write(avr_t * avr, uint8_t addr, uint8_t v, void * param)
49 {
50         avr_eeprom_t * p = (avr_eeprom_t *)param;
51         uint8_t eempe = avr_regbit_get(avr, p->eempe);
52
53         avr_core_watch_write(avr, addr, v);
54
55         if (!eempe && avr_regbit_get(avr, p->eempe)) {
56                 p->eempe_clear_timer = 4;       // auto clear, later
57         }
58         
59         if (eempe && avr_regbit_get(avr, p->eepe)) {    // write operation
60                 uint16_t addr = avr->data[p->r_eearl] | (avr->data[p->r_eearh] << 8);
61         //      printf("eeprom write %04x <- %02x\n", addr, avr->data[p->r_eedr]);
62                 p->eeprom[addr] = avr->data[p->r_eedr]; 
63                 // Automatically clears that bit (?)
64                 p->eempe_clear_timer = 0;
65                 avr_regbit_clear(avr, p->eempe);
66
67                 p->ready_raise_timer = 1024; // make a avr_milliseconds_to_cycle(...) 3.4ms here
68         }
69         if (avr_regbit_get(avr, p->eere)) {     // read operation
70                 uint16_t addr = avr->data[p->r_eearl] | (avr->data[p->r_eearh] << 8);
71                 avr->data[p->r_eedr] = p->eeprom[addr];
72         //      printf("eeprom read %04x : %02x\n", addr, p->eeprom[addr]);
73         }
74
75         // autocleared
76         avr_regbit_clear(avr, p->eepe);
77         avr_regbit_clear(avr, p->eere);
78 }
79
80 static int avr_eeprom_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param)
81 {
82         avr_eeprom_t * p = (avr_eeprom_t *)port;
83         int res = -1;
84
85         switch(ctl) {
86                 case AVR_IOCTL_EEPROM_SET: {
87                         avr_eeprom_desc_t * desc = (avr_eeprom_desc_t*)io_param;
88                         if (!desc || !desc->size || !desc->ee || (desc->offset + desc->size) >= p->size) {
89                                 printf("%s: AVR_IOCTL_EEPROM_SET Invalid argument\n",
90                                                 __FUNCTION__);
91                                 return -2;
92                         }
93                         memcpy(p->eeprom + desc->offset, desc->ee, desc->size);
94                         printf("%s: AVR_IOCTL_EEPROM_SET Loaded %d at offset %d\n",
95                                         __FUNCTION__, desc->size, desc->offset);
96                 }       break;
97                 case AVR_IOCTL_EEPROM_GET: {
98                         avr_eeprom_desc_t * desc = (avr_eeprom_desc_t*)io_param;
99                         if (!desc || (desc->offset + desc->size) >= p->size) {
100                                 printf("%s: AVR_IOCTL_EEPROM_GET Invalid argument\n",
101                                                 __FUNCTION__);
102                                 return -2;
103                         }
104                         if (desc->ee)
105                                 memcpy(desc->ee, p->eeprom + desc->offset, desc->size);
106                         else    // allow to get access to the read data, for gdb support
107                                 desc->ee = p->eeprom + desc->offset;
108                 }       break;
109         }
110         
111         return res;
112 }
113
114 static  avr_io_t        _io = {
115         .kind = "eeprom",
116         .run = avr_eeprom_run,
117         .ioctl = avr_eeprom_ioctl,
118 };
119
120 void avr_eeprom_init(avr_t * avr, avr_eeprom_t * p)
121 {
122         p->io = _io;
123 //      printf("%s init (%d bytes) EEL/H:%02x/%02x EED=%02x EEC=%02x\n",
124 //                      __FUNCTION__, p->size, p->r_eearl, p->r_eearh, p->r_eedr, p->r_eecr);
125
126         p->eeprom = malloc(p->size);
127         memset(p->eeprom, 0xff, p->size);
128         
129         avr_register_io(avr, &p->io);
130         avr_register_vector(avr, &p->ready);
131
132         avr_register_io_write(avr, p->r_eecr, avr_eeprom_write, p);
133 }
134