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 Sat Mar 7 2015.