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