Main Page

- Main Page
- Related Pages
- Files

- File List
- Globals

memory.c
Go to the documentation of this file.
1 /*
2 * $Id: memory.c,v 1.24 2009/02/24 21:10:12 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 /**
27 * \file memory.c
28 * \brief Memory access functions.
29 *
30 * This module provides functions for reading and writing to simulated memory.
31 * The Memory class is a subclass of AvrClass.
32 */
33
34 #include <config.h>
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "avrerror.h"
41 #include "avrmalloc.h"
42 #include "avrclass.h"
43 #include "utils.h"
44 #include "callback.h"
45 #include "op_names.h"
46
47 #include "storage.h"
48 #include "flash.h"
49
50 #include "vdevs.h"
51 #include "memory.h"
52 #include "stack.h"
53 #include "register.h"
54 #include "sram.h"
55 #include "eeprom.h"
56 #include "timers.h"
57 #include "ports.h"
58
59 #include "avrcore.h"
60
61 #include "display.h"
62
63 /** \brief Allocates memory for a new memory object. */
64
65 Memory *
66 mem_new (int gpwr_end, int io_reg_end, int sram_end, int xram_end)
67 {
68 Memory *mem;
69
70 mem = avr_new0 (Memory, 1);
71 mem_construct (mem, gpwr_end, io_reg_end, sram_end, xram_end);
72 class_overload_destroy ((AvrClass *)mem, mem_destroy);
73
74 return mem;
75 }
76
77 /** \brief Constructor for the memory object. */
78
79 void
80 mem_construct (Memory *mem, int gpwr_end, int io_reg_end, int sram_end,
81 int xram_end)
82 {
83 if (mem == NULL)
84 avr_error ("passed null ptr");
85
86 mem->gpwr_end = gpwr_end;
87 mem->io_reg_end = io_reg_end;
88 mem->sram_end = sram_end;
89 mem->xram_end = xram_end;
90
91 mem->cell = avr_new0 (MemoryCell, xram_end + 1);
92
93 class_construct ((AvrClass *)mem);
94 }
95
96 /** \brief Descructor for the memory object. */
97
98 void
99 mem_destroy (void *mem)
100 {
101 int i;
102
103 Memory *this = (Memory *)mem;
104
105 if (mem == NULL)
106 return;
107
108 for (i = 0; i < this->xram_end; i++)
109 {
110 if (this->cell[i].vdev)
111 {
112 class_unref ((AvrClass *)this->cell[i].vdev);
113 }
114 }
115
116 avr_free (this->cell);
117
118 class_destroy (mem);
119 }
120
121 /** \brief Attach a device to the device list.
122
123 Devices that are accessed more often should be attached
124 last so that they will be at the front of the list.
125
126 A default virtual device can be overridden by attaching
127 a new device ahead of it in the list. */
128
129 void
130 mem_attach (Memory *mem, int addr, char *name, VDevice *vdev, int flags,
131 uint8_t reset_value, uint8_t rd_mask, uint8_t wr_mask)
132 {
133 MemoryCell *cell;
134
135 if (mem == NULL)
136 avr_error ("passed null ptr");
137
138 if (vdev == NULL)
139 avr_error ("attempt to attach null device");
140
141 if ((addr < 0) || (addr > mem->xram_end))
142 avr_error ("address out of range");
143
144 cell = &mem->cell[addr];
145
146 cell->name = name;
147 cell->flags = flags;
148 cell->reset_value = reset_value;
149 cell->rd_mask = rd_mask;
150 cell->wr_mask = wr_mask;
151
152 class_ref ((AvrClass *)vdev);
153 cell->vdev = vdev;
154 }
155
156 /** \brief Find the VDevice associated with the given address. */
157
158 VDevice *
159 mem_get_vdevice_by_addr (Memory *mem, int addr)
160 {
161 return mem->cell[addr].vdev;
162 }
163
164 /** \brief Find the VDevice associated with the given name.
165
166 \deprecated */
167
168 VDevice *
169 mem_get_vdevice_by_name (Memory *mem, char *name)
170 {
171 #if 0
172 return (VDevice *)dlist_lookup (mem->dev, (AvrClass *)name,
173 vdev_name_cmp);
174 #else
175 avr_error ("use of deprecated interface");
176 return NULL;
177 #endif
178 }
179
180 static MemoryCell *
181 mem_get_cell (Memory *mem, int addr)
182 {
183 /*
184 * Just return *any* possible cell for illegal addresses,
185 * to avoid accessing cells that have not been allocated.
186 * Later on, the illegal address will be caught anyway.
187 */
188 if ((addr < 0) || (addr > mem->xram_end))
189 addr = mem->xram_end - 1;
190
191 return mem->cell + addr;
192 }
193
194 static int
195 mem_is_io_reg (Memory *mem, int addr)
196 {
197 return ((addr > mem->gpwr_end) && (addr <= mem->io_reg_end));
198 }
199
200 static char *
201 mem_get_name (Memory *mem, int addr)
202 {
203 return mem->cell[addr].name;
204 }
205
206 void
207 mem_set_addr_name (Memory *mem, int addr, char *name)
208 {
209 mem->cell[addr].name = name;
210 }
211
212 /** \brief Reads byte from memory and sanity-checks for valid address.
213 *
214 * \param mem A pointer to the memory object
215 * \param addr The address to be read
216 * \return The byte found at that address addr
217 */
218
219 uint8_t
220 mem_read (Memory *mem, int addr)
221 {
222 MemoryCell *cell = mem_get_cell (mem, addr);
223
224 if (cell->vdev == NULL)
225 {
226 char *name = mem_get_name (mem, addr);
227
228 if (name)
229 {
230 avr_warning ("**** Attempt to read invalid %s: %s at 0x%04x\n",
231 mem_is_io_reg (mem, addr) ? "io reg" : "mem addr",
232 name, addr);
233 }
234 else
235 {
236 avr_warning ("**** Attempt to read invalid %s: 0x%04x\n",
237 mem_is_io_reg (mem, addr) ? "io reg" : "mem addr",
238 addr);
239 }
240
241 return 0;
242 }
243
244 return (vdev_read (cell->vdev, addr) & cell->rd_mask);
245 }
246
247 /** \brief Writes byte to memory and updates display for io registers.
248 *
249 * \param mem A pointer to a memory object
250 * \param addr The address to be written to
251 * \param val The value to be written there
252 */
253
254 void
255 mem_write (Memory *mem, int addr, uint8_t val)
256 {
257 MemoryCell *cell = mem_get_cell (mem, addr);
258
259 if (cell->vdev == NULL)
260 {
261 char *name = mem_get_name (mem, addr);
262
263 if (name)
264 {
265 avr_warning ("**** Attempt to write invalid %s: %s at 0x%04x\n",
266 mem_is_io_reg (mem, addr) ? "io reg" : "mem addr",
267 name, addr);
268 }
269 else
270 {
271 avr_warning ("**** Attempt to write invalid %s: 0x%04x\n",
272 mem_is_io_reg (mem, addr) ? "io reg" : "mem addr",
273 addr);
274 }
275
276 return;
277 }
278
279 /* update the display for io registers here */
280
281 if (mem_is_io_reg (mem, addr))
282 display_io_reg (addr - (mem->gpwr_end + 1), val & cell->wr_mask);
283
284 vdev_write (cell->vdev, addr, val & cell->wr_mask);
285 }
286
287 /** \brief Resets every device in the memory object.
288 * \param mem A pointer to the memory object.
289 */
290
291 void
292 mem_reset (Memory *mem)
293 {
294 int i;
295
296 for (i = 0; i < mem->xram_end; i++)
297 {
298 MemoryCell *cell = mem_get_cell (mem, i);
299
300 if (cell->vdev)
301 vdev_reset (cell->vdev);
302 }
303 }
304
305 static void
306 mem_reg_dump_core (Memory *mem, FILE * f_core)
307 {
308 int i, j;
309
310 fprintf (f_core, "General Purpose Register Dump:\n");
311 for (i = 0; i < 32; i += 8)
312 {
313 for (j = i; j < (i + 8); j++)
314 fprintf (f_core, "r%02d=%02x ", j, mem_read (mem, j));
315 fprintf (f_core, "\n");
316 }
317 fprintf (f_core, "\n");
318 }
319
320 /** \brief Fetch the name and value of the io register (addr).
321 *
322 * \param mem A pointer to the memory object.
323 * \param addr The address to fetch from.
324 * \param val A pointer where the value of the register is to be copied.
325 * \param buf A pointer to where the name of the register should be copied.
326 * \param bufsiz The maximum size of the the buf string.
327 */
328
329 void
330 mem_io_fetch (Memory *mem, int addr, uint8_t * val, char *buf, int bufsiz)
331 {
332 MemoryCell *cell;
333
334 if (mem_is_io_reg (mem, addr))
335 {
336 cell = mem_get_cell (mem, addr);
337
338 if (cell->name == NULL)
339 {
340 strncpy (buf, "Reserved", bufsiz);
341 *val = 0;
342 }
343 else
344 {
345 strncpy (buf, cell->name, bufsiz);
346
347 if (cell->vdev)
348 {
349 /* FIXME: Add vdev_read_no_ext () interface to avoid calling
350 the external functions during a read. This will require a
351 reworking of how the vdev invokes the external read
352 method. */
353
354 *val = (vdev_read (cell->vdev, addr) & cell->rd_mask);
355 }
356 else
357 {
358 *val = 0;
359 }
360 }
361 }
362 else
363 {
364 *val = 0;
365 strncpy (buf, "NOT AN IO REG", bufsiz);
366 }
367 }
368
369 static void
370 mem_io_reg_dump_core (Memory *mem, FILE * f_core)
371 {
372 unsigned int i, j;
373 char name[80];
374 uint8_t val;
375
376 unsigned int begin = (unsigned)mem->gpwr_end + 1;
377 unsigned int end = (unsigned)mem->io_reg_end;
378 unsigned int half = (end - begin + 1) / 2;
379 unsigned int mid = begin + half;
380
381 fprintf (f_core, "IO Register Dump:\n");
382 for (i = begin; i < mid; i++)
383 {
384 for (j = i; j <= end; j += half)
385 {
386 memset (name, '\0', sizeof (name));
387 mem_io_fetch (mem, j, &val, name, sizeof (name) - 1);
388
389 fprintf (f_core, "%02x : %-10s : 0x%02x ", j,
390 name, val);
391 }
392 fprintf (f_core, "\n");
393 }
394 fprintf (f_core, "\n");
395 }
396
397 static void
398 mem_sram_display (Memory *mem, FILE * f_core, int base, int size)
399 {
400 int i;
401 int dup = 0;
402 int ndat = 16;
403 char line[80];
404 char last_line[80];
405 char buf[80];
406 line[0] = last_line[0] = '\0';
407
408 for (i = base; i < (base + size); i++)
409 {
410 if (((i % ndat) == 0) && strlen (line))
411 {
412 if (strncmp (line, last_line, 80) == 0)
413 {
414 dup++;
415 }
416 else
417 {
418 if (dup > 0)
419 fprintf (f_core, " -- last line repeats --\n");
420 fprintf (f_core, "%04x : %s\n", i - ndat, line);
421 dup = 0;
422 }
423 strncpy (last_line, line, 80);
424 line[0] = '\0';
425 }
426 snprintf (buf, 80, "%02x ", mem_read (mem, i));
427 strncat (line, buf, 80 - strlen(line) - 1);
428 }
429 if (dup > 0)
430 {
431 fprintf (f_core, " -- last line repeats --\n");
432 fprintf (f_core, "%04x : %s\n", i - ndat, line);
433 }
434 fprintf (f_core, "\n");
435 }
436
437 static void
438 mem_sram_dump_core (Memory *mem, FILE * f_core)
439 {
440 int size, base;
441
442 /*
443 * Dump the internal sram
444 */
445
446 if (mem->io_reg_end == mem->sram_end)
447 return; /* device has no sram */
448
449 fprintf (f_core, "Internal SRAM Memory Dump:\n");
450 base = mem->io_reg_end + 1;
451 size = mem->sram_end - base + 1;
452 mem_sram_display (mem, f_core, base, size);
453
454 /*
455 * If external sram present, dump it too.
456 */
457
458 if (mem->sram_end == mem->xram_end)
459 return; /* device has no xram */
460
461 fprintf (f_core, "External SRAM Memory Dump:\n");
462 base = mem->sram_end + 1;
463 size = mem->xram_end - base + 1;
464 mem_sram_display (mem, f_core, base, size);
465
466 }
467
468 #if 0
469
470 /* FIXME: Still need to figure out a sane way to look up a specific type of
471 vdev by generic name. */
472
473 static void
474 mem_eeprom_dump_core (Memory *mem, FILE * f_core)
475 {
476 VDevice *dev = mem_get_vdevice_by_name (mem, "EEProm");
477
478 if (dev != NULL)
479 eeprom_dump_core ((EEProm *)dev, f_core);
480 }
481 #endif
482
483 /** \brief Dump all the various memory locations to a file descriptor
484 * in text format.
485 *
486 * \param mem A memory object.
487 * \param f_core An open file descriptor.
488 */
489
490 void
491 mem_dump_core (Memory *mem, FILE * f_core)
492 {
493 mem_reg_dump_core (mem, f_core);
494 mem_io_reg_dump_core (mem, f_core);
495 mem_sram_dump_core (mem, f_core);
496 /* mem_eeprom_dump_core (mem, f_core); */
497 }

Automatically generated by Doxygen 1.8.2 on Mon Aug 18 2014.