Main Page

eeprom.c
1 /*
2 * $Id: eeprom.c,v 1.21 2008/03/19 22:39:02 joerg_wunsch Exp $
3 *
4 ****************************************************************************
5 *
6 * simulavr - A simulator for the Atmel AVR family of microcontrollers.
7 * Copyright (C) 2001, 2002, 2003, 2004 Theodore A. Roth
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 ****************************************************************************
24 */
25
26 #include <config.h>
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <unistd.h>
33
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37
38 #include "avrerror.h"
39 #include "avrmalloc.h"
40 #include "avrclass.h"
41 #include "utils.h"
42 #include "callback.h"
43 #include "op_names.h"
44
45 #include "storage.h"
46 #include "flash.h"
47
48 #include "vdevs.h"
49 #include "memory.h"
50 #include "stack.h"
51 #include "register.h"
52 #include "sram.h"
53 #include "eeprom.h"
54 #include "timers.h"
55 #include "ports.h"
56
57 #include "avrcore.h"
58
59 #include "display.h"
60
61 static uint8_t eeprom_reg_read (VDevice *dev, int addr);
62 static void eeprom_reg_write (VDevice *dev, int addr, uint8_t val);
63 static void eeprom_reg_reset (VDevice *dev);
64 static void eeprom_wr_eecr (EEProm *ee, uint8_t val);
65
66 static int eeprom_wr_op_cb (uint64_t time, AvrClass *data);
67 static int eeprom_mwe_clr_cb (uint64_t time, AvrClass *data);
68
69 /* XXX */
70 static VDevice *global_eeprom;
71
72 /**
73 * \brief Create a new EEPROM control register set instance.
74 *
75 * This should only be used in DevSuppDefn initializers.
76 */
77
78 VDevice *
79 eeprom_create (int addr, char *name, int rel_addr, void *data)
80 {
81 if (rel_addr == 0 && addr != EECR_ADDR)
82 avr_error("Attempt to create EEPROM control register at unknown address: 0x%02x != 0x%02x",
83 addr, EECR_ADDR);
84
85 return global_eeprom;
86 }
87
88 EEProm *
89 eeprom_new (int size, uint8_t eecr_mask)
90 {
91 EEProm *eeprom;
92
93 if (global_eeprom != NULL)
94 avr_error("Global EEPROM does already exist");
95
96 eeprom = avr_new (EEProm, 1);
97 eeprom_construct (eeprom, size, eecr_mask);
98 class_overload_destroy ((AvrClass *)eeprom, eeprom_destroy);
99
100 global_eeprom = (VDevice *)eeprom;
101
102 return eeprom;
103 }
104
105 void
106 eeprom_construct (EEProm *eeprom, int size, uint8_t eecr_mask)
107 {
108 int i;
109
110 if (eeprom == NULL)
111 avr_error ("passed null ptr");
112
113 eeprom->stor = storage_new (0 /*base */ , size);
114
115 /* init eeprom to ones */
116 for (i = 0; i < size; i++)
117 storage_writeb (eeprom->stor, i, 0xff);
118
119 eeprom->eecr_mask = eecr_mask;
120
121 eeprom_reg_reset ((VDevice *)eeprom);
122
123 vdev_construct ((VDevice *)eeprom, eeprom_reg_read, eeprom_reg_write,
124 eeprom_reg_reset, vdev_def_AddAddr);
125 }
126
127 void
128 eeprom_destroy (void *eeprom)
129 {
130 EEProm *_eeprom = (EEProm *)eeprom;
131
132 if (eeprom == NULL)
133 return;
134
135 class_unref ((AvrClass *)_eeprom->stor);
136
137 vdev_destroy (eeprom);
138 }
139
140 int
141 eeprom_get_size (EEProm *eeprom)
142 {
143 return storage_get_size (eeprom->stor);
144 }
145
146 static uint8_t
147 eeprom_reg_read (VDevice *dev, int addr)
148 {
149 EEProm *ee = (EEProm *)dev;
150
151 switch (addr)
152 {
153 case EECR_ADDR:
154 return ee->eecr;
155 case EEDR_ADDR:
156 return ee->eedr;
157 case EEARL_ADDR:
158 return ee->eearl;
159 case EEARH_ADDR:
160 return ee->eearh;
161 }
162 avr_error ("Bad address: %d", addr);
163 return 0;
164 }
165
166 static void
167 eeprom_reg_write (VDevice *dev, int addr, uint8_t val)
168 {
169 EEProm *ee = (EEProm *)dev;
170
171 if (ee->eecr & mask_EEWE)
172 {
173 /*
174 * From the 8515 data sheet: The user should poll the EEWE bit before
175 * starting the read operaton. If a write operation is in progress
176 * when new data or address is written to the EEPROM I/O registers,
177 * the write operation will be interrupted, and the result is
178 * undefined.
179 */
180 avr_error ("Attempt to write to EEPROM I/O reg during write "
181 "operation");
182 }
183
184 switch (addr)
185 {
186 case EECR_ADDR:
187 eeprom_wr_eecr (ee, val);
188 return;
189 case EEDR_ADDR:
190 ee->eedr = val;
191 return;
192 case EEARL_ADDR:
193 ee->eearl = val;
194 return;
195 case EEARH_ADDR:
196 ee->eearh = val;
197 return;
198 }
199 avr_error ("Bad address: %d", addr);
200 }
201
202 static void
203 eeprom_reg_reset (VDevice *dev)
204 {
205 EEProm *ee = (EEProm *)dev;
206
207 ee->wr_op_cb = NULL;
208 ee->wr_op_clk = 0;
209
210 ee->mwe_clr_cb = NULL;
211 ee->mwe_clk = 0;
212
213 ee->eecr = ee->eedr = ee->eearl = ee->eearh = 0;
214 }
215
216 static void
217 eeprom_wr_eecr (EEProm *ee, uint8_t val)
218 {
219 int addr = (ee->eearh << 8) | ee->eearl;
220
221 CallBack *cb;
222
223 switch (val & ee->eecr_mask)
224 {
225 case mask_EERE:
226 /*
227 * we never need to set EERE bit one,
228 * just more data from eeprom array into eedr.
229 */
230 ee->eedr = storage_readb (ee->stor, addr);
231 break;
232
233 case mask_EEWE:
234 if (((ee->eecr_mask & mask_EEMWE) == 0) /* device has no MWE
235 function */
236 || (ee->eecr & ee->eecr_mask & mask_EEMWE)) /* or MWE bit is
237 set */
238 {
239 ee->eecr |= mask_EEWE;
240 ee->wr_op_clk = EEPROM_WR_OP_CLKS;
241
242 /* start write operation */
243 if (ee->wr_op_cb == NULL)
244 {
245 cb = callback_new (eeprom_wr_op_cb, (AvrClass *)ee);
246 ee->wr_op_cb = cb;
247 avr_core_async_cb_add ((AvrCore *)
248 vdev_get_core ((VDevice *)ee), cb);
249 }
250 }
251 break;
252
253 case mask_EEMWE:
254 ee->eecr |= mask_EEMWE;
255 ee->mwe_clk = EEPROM_MWE_CLKS;
256
257 if (ee->mwe_clr_cb == NULL)
258 {
259 cb = callback_new (eeprom_mwe_clr_cb, (AvrClass *)ee);
260 ee->mwe_clr_cb = cb;
261 avr_core_clk_cb_add ((AvrCore *)vdev_get_core ((VDevice *)ee),
262 cb);
263 }
264 break;
265
266 case (mask_EEMWE | mask_EEWE):
267 /* just call this function again, but without EEMWE set in val */
268 eeprom_wr_eecr (ee, mask_EEWE);
269 break;
270
271 default:
272 avr_error ("Unknown eeprom control register write operation: "
273 "0x%02x", val);
274 }
275 }
276
277 /*
278 * The data sheets say that a write operation takes 2.5 to 4.0 ms to complete
279 * depending on Vcc voltage. Since the get_program_time() function only has
280 * 10 ms resolution, we'll just simulate a timer with counting down from
281 * EEPROM_WR_OP_CLKS to zero. 2500 clocks would be 2.5 ms if simulator is
282 * running at 1 MHz. I really don't think that this variation should be
283 * critical in most apps, but I'd wouldn't mind being proven wrong.
284 */
285 static int
286 eeprom_wr_op_cb (uint64_t time, AvrClass *data)
287 {
288 EEProm *ee = (EEProm *)data;
289 int addr;
290
291 /*
292 * FIXME: At some point in the future, we might need to check if
293 * any of the I/O registers have been written to during the write
294 * operation which would cause the write op to be interrupted.
295 * Right now, the simulator is aborted in that situation.
296 */
297
298 if (ee->wr_op_clk > 0)
299 {
300 /* write is not complete yet */
301 ee->wr_op_clk--;
302 return CB_RET_RETAIN;
303 }
304
305 /* write the data in eedr into eeprom at addr */
306 addr = (ee->eearh << 8) | ee->eearl;
307 //avr_warning ("writing 0x%02x to eeprom at 0x%04x\n", ee->eedr, addr);
308 display_eeprom (addr, 1, &ee->eedr);
309 storage_writeb (ee->stor, addr, ee->eedr);
310
311 /* Now it's ok to start another write operation */
312 ee->eecr &= ~(mask_EEWE); /* clear the write enable bit */
313 ee->wr_op_cb = NULL; /* remove callback */
314
315 return CB_RET_REMOVE;
316 }
317
318 /*
319 * Once set, the hardware will automatically clear the EEMWE bit
320 * after EEPROM_MWE_CLKS clock cycles.
321 */
322 static int
323 eeprom_mwe_clr_cb (uint64_t time, AvrClass *data)
324 {
325 EEProm *ee = (EEProm *)data;
326
327 if (ee->mwe_clk > 0)
328 {
329 ee->mwe_clk--;
330 return CB_RET_RETAIN;
331 }
332
333 ee->eecr &= ~(mask_EEMWE); /* clear the EEMWE bit */
334 ee->mwe_clr_cb = NULL; /* remove callback */
335
336 return CB_RET_REMOVE;
337 }
338
339 static int
340 eeprom_load_from_bin_file (EEProm *eeprom, char *file)
341 {
342 int fd, res;
343 int addr = 0;
344 uint8_t datum;
345
346 fd = open (file, O_RDONLY);
347 if (fd < 0)
348 avr_error ("Couldn't open binary eeprom image file: %s: %s", file,
349 strerror (errno));
350
351 while ((res = read (fd, &datum, sizeof (datum))) != 0)
352 {
353 if (res == -1)
354 avr_error ("Error reading binary eeprom image file: %s: %s", file,
355 strerror (errno));
356
357 storage_writeb (eeprom->stor, addr, datum);
358
359 addr++;
360 }
361
362 close (fd);
363
364 return 0;
365 }
366
367 /** \brief Load data into eeprom from a file. */
368
369 int
370 eeprom_load_from_file (EEProm *eeprom, char *file, int format)
371 {
372 switch (format)
373 {
374 case FFMT_BIN:
375 return eeprom_load_from_bin_file (eeprom, file);
376 case FFMT_IHEX:
377 case FFMT_ELF:
378 default:
379 avr_warning ("Unsupported file format\n");
380 }
381
382 return -1;
383 }
384
385 void
386 eeprom_dump_core (EEProm *eeprom, FILE * f_core)
387 {
388 int i;
389 int dup = 0;
390 int ndat = 16;
391 char line[80];
392 char last_line[80];
393 char buf[80];
394 int size = storage_get_size (eeprom->stor);
395
396 fprintf (f_core, "EEPROM Memory Dump:\n");
397
398 line[0] = last_line[0] = '\0';
399
400 for (i = 0; i < size; i++)
401 {
402 if (((i % ndat) == 0) && strlen (line))
403 {
404 if (strncmp (line, last_line, 80) == 0)
405 {
406 dup++;
407 }
408 else
409 {
410 if (dup > 0)
411 fprintf (f_core, " -- last line repeats --\n");
412 fprintf (f_core, "%04x : %s\n", i - ndat, line);
413 dup = 0;
414 }
415 strncpy (last_line, line, 80);
416 line[0] = '\0';
417 }
418 snprintf (buf, 80, "%02x ", storage_readb (eeprom->stor, i));
419 strncat (line, buf, 80 - strlen(line) - 1);
420 }
421 if (dup > 0)
422 {
423 fprintf (f_core, " -- last line repeats --\n");
424 fprintf (f_core, "%04x : %s\n", i - ndat, line);
425 }
426 fprintf (f_core, "\n");
427 }
avr_new
#define avr_new(type, count)
Macro for allocating memory.
Definition: avrmalloc.c:57
avr_core_async_cb_add
void avr_core_async_cb_add(AvrCore *core, CallBack *cb)
Add a new asynchronous callback to list.
vdev_def_AddAddr
void vdev_def_AddAddr(VDevice *dev, int addr, char *name, int related_addr, void *data)
Default AddAddr method.
Definition: device.c:80
vdev_destroy
void vdev_destroy(void *dev)
Destructor for a VDevice.
Definition: device.c:105
vdev_get_core
AvrClass * vdev_get_core(VDevice *dev)
Get the core field.
avr_warning
#define avr_warning(fmt, args...)
Print a warning message to stderr.
Definition: avrerror.c:46
class_unref
void class_unref(AvrClass *klass)
Decrements the reference count for the klass object.
Definition: avrclass.c:120
vdev_construct
void vdev_construct(VDevice *dev, VDevFP_Read rd, VDevFP_Write wr, VDevFP_Reset reset, VDevFP_AddAddr add_addr)
Constructor for a VDevice.
Definition: device.c:89
avr_error
#define avr_error(fmt, args...)
Print an error message to stderr and terminate program.
Definition: avrerror.c:50
avr_core_clk_cb_add
void avr_core_clk_cb_add(AvrCore *core, CallBack *cb)
Add a new clock callback to list.
class_overload_destroy
void class_overload_destroy(AvrClass *klass, AvrClassFP_Destroy destroy)
Overload the default destroy method.
Definition: avrclass.c:92
display_eeprom
void display_eeprom(int addr, int len, uint8_t *vals)
Update a block of eeprom addresses in the display.
Definition: display.c:404

Automatically generated by Doxygen 1.8.12 on Sun Apr 2 2017.