memory.c

Go to the documentation of this file.
00001 /*
00002  * $Id: memory.c,v 1.19 2004/05/19 23:02:11 troth Exp $
00003  *
00004  ****************************************************************************
00005  *
00006  * simulavr - A simulator for the Atmel AVR family of microcontrollers.
00007  * Copyright (C) 2001, 2002, 2003, 2004  Theodore A. Roth
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  ****************************************************************************
00024  */
00025 
00026 /**
00027  * \file memory.c
00028  * \brief Memory access functions.
00029  *
00030  * This module provides functions for reading and writing to simulated memory.
00031  * The Memory class is a subclass of AvrClass.
00032  */
00033 
00034 #include <config.h>
00035 
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <string.h>
00039 
00040 #include "avrerror.h"
00041 #include "avrmalloc.h"
00042 #include "avrclass.h"
00043 #include "utils.h"
00044 #include "callback.h"
00045 #include "op_names.h"
00046 
00047 #include "storage.h"
00048 #include "flash.h"
00049 
00050 #include "vdevs.h"
00051 #include "memory.h"
00052 #include "stack.h"
00053 #include "register.h"
00054 #include "sram.h"
00055 #include "eeprom.h"
00056 #include "timers.h"
00057 #include "ports.h"
00058 
00059 #include "avrcore.h"
00060 
00061 #include "display.h"
00062 
00063 /** \brief Allocates memory for a new memory object. */
00064 
00065 Memory *
00066 mem_new (int gpwr_end, int io_reg_end, int sram_end, int xram_end)
00067 {
00068     Memory *mem;
00069 
00070     mem = avr_new0 (Memory, 1);
00071     mem_construct (mem, gpwr_end, io_reg_end, sram_end, xram_end);
00072     class_overload_destroy ((AvrClass *)mem, mem_destroy);
00073 
00074     return mem;
00075 }
00076 
00077 /** \brief Constructor for the memory object. */
00078 
00079 void
00080 mem_construct (Memory *mem, int gpwr_end, int io_reg_end, int sram_end,
00081                int xram_end)
00082 {
00083     if (mem == NULL)
00084         avr_error ("passed null ptr");
00085 
00086     mem->gpwr_end = gpwr_end;
00087     mem->io_reg_end = io_reg_end;
00088     mem->sram_end = sram_end;
00089     mem->xram_end = xram_end;
00090 
00091     mem->cell = avr_new0 (MemoryCell, xram_end + 1);
00092 
00093     class_construct ((AvrClass *)mem);
00094 }
00095 
00096 /** \brief Descructor for the memory object. */
00097 
00098 void
00099 mem_destroy (void *mem)
00100 {
00101     int i;
00102 
00103     Memory *this = (Memory *)mem;
00104 
00105     if (mem == NULL)
00106         return;
00107 
00108     for (i = 0; i < this->xram_end; i++)
00109     {
00110         if (this->cell[i].vdev)
00111         {
00112             class_unref ((AvrClass *)this->cell[i].vdev);
00113         }
00114     }
00115 
00116     avr_free (this->cell);
00117 
00118     class_destroy (mem);
00119 }
00120 
00121 /** \brief Attach a device to the device list.
00122  
00123   Devices that are accessed more often should be attached
00124   last so that they will be at the front of the list.
00125  
00126   A default virtual device can be overridden by attaching
00127   a new device ahead of it in the list.  */
00128 
00129 void
00130 mem_attach (Memory *mem, int addr, char *name, VDevice *vdev, int flags,
00131             uint8_t reset_value, uint8_t rd_mask, uint8_t wr_mask)
00132 {
00133     MemoryCell *cell;
00134 
00135     if (mem == NULL)
00136         avr_error ("passed null ptr");
00137 
00138     if (vdev == NULL)
00139         avr_error ("attempt to attach null device");
00140 
00141     if ((addr < 0) || (addr >= mem->xram_end))
00142         avr_error ("address out of range");
00143 
00144     cell = &mem->cell[addr];
00145 
00146     cell->name = name;
00147     cell->flags = flags;
00148     cell->reset_value = reset_value;
00149     cell->rd_mask = rd_mask;
00150     cell->wr_mask = wr_mask;
00151 
00152     class_ref ((AvrClass *)vdev);
00153     cell->vdev = vdev;
00154 }
00155 
00156 /** \brief Find the VDevice associated with the given address. */
00157 
00158 VDevice *
00159 mem_get_vdevice_by_addr (Memory *mem, int addr)
00160 {
00161     return mem->cell[addr].vdev;
00162 }
00163 
00164 /** \brief Find the VDevice associated with the given name. 
00165 
00166     \deprecated */
00167 
00168 VDevice *
00169 mem_get_vdevice_by_name (Memory *mem, char *name)
00170 {
00171 #if 0
00172     return (VDevice *)dlist_lookup (mem->dev, (AvrClass *)name,
00173                                     vdev_name_cmp);
00174 #else
00175     avr_error ("use of deprecated interface");
00176     return NULL;
00177 #endif
00178 }
00179 
00180 static inline MemoryCell *
00181 mem_get_cell (Memory *mem, int addr)
00182 {
00183     return mem->cell + addr;
00184 }
00185 
00186 static inline int
00187 mem_is_io_reg (Memory *mem, int addr)
00188 {
00189     return ((addr > mem->gpwr_end) && (addr <= mem->io_reg_end));
00190 }
00191 
00192 static inline char *
00193 mem_get_name (Memory *mem, int addr)
00194 {
00195     return mem->cell[addr].name;
00196 }
00197 
00198 void
00199 mem_set_addr_name (Memory *mem, int addr, char *name)
00200 {
00201     mem->cell[addr].name = name;
00202 }
00203 
00204 /** \brief Reads byte from memory and sanity-checks for valid address. 
00205  * 
00206  * \param mem A pointer to the memory object
00207  * \param addr The address to be read 
00208  * \return The byte found at that address addr
00209  */
00210 
00211 uint8_t
00212 mem_read (Memory *mem, int addr)
00213 {
00214     MemoryCell *cell = mem_get_cell (mem, addr);
00215 
00216     if (cell->vdev == NULL)
00217     {
00218         char *name = mem_get_name (mem, addr);
00219 
00220         if (name)
00221         {
00222             avr_warning ("**** Attempt to read invalid %s: %s at 0x%04x\n",
00223                          mem_is_io_reg (mem, addr) ? "io reg" : "mem addr",
00224                          name, addr);
00225         }
00226         else
00227         {
00228             avr_warning ("**** Attempt to read invalid %s: 0x%04x\n",
00229                          mem_is_io_reg (mem, addr) ? "io reg" : "mem addr",
00230                          addr);
00231         }
00232 
00233         return 0;
00234     }
00235 
00236     return (vdev_read (cell->vdev, addr) & cell->rd_mask);
00237 }
00238 
00239 /** \brief Writes byte to memory and updates display for io registers. 
00240  * 
00241  * \param mem A pointer to a memory object
00242  * \param addr The address to be written to
00243  * \param val The value to be written there
00244  */
00245 
00246 void
00247 mem_write (Memory *mem, int addr, uint8_t val)
00248 {
00249     MemoryCell *cell = mem_get_cell (mem, addr);
00250 
00251     if (cell->vdev == NULL)
00252     {
00253         char *name = mem_get_name (mem, addr);
00254 
00255         if (name)
00256         {
00257             avr_warning ("**** Attempt to write invalid %s: %s at 0x%04x\n",
00258                          mem_is_io_reg (mem, addr) ? "io reg" : "mem addr",
00259                          name, addr);
00260         }
00261         else
00262         {
00263             avr_warning ("**** Attempt to write invalid %s: 0x%04x\n",
00264                          mem_is_io_reg (mem, addr) ? "io reg" : "mem addr",
00265                          addr);
00266         }
00267 
00268         return;
00269     }
00270 
00271     /* update the display for io registers here */
00272 
00273     if (mem_is_io_reg (mem, addr))
00274         display_io_reg (addr - (mem->gpwr_end + 1), val & cell->wr_mask);
00275 
00276     vdev_write (cell->vdev, addr, val & cell->wr_mask);
00277 }
00278 
00279 /** \brief Resets every device in the memory object.
00280  * \param mem A pointer to the memory object.
00281  */
00282 
00283 void
00284 mem_reset (Memory *mem)
00285 {
00286     int i;
00287 
00288     for (i = 0; i < mem->xram_end; i++)
00289     {
00290         MemoryCell *cell = mem_get_cell (mem, i);
00291 
00292         if (cell->vdev)
00293             vdev_reset (cell->vdev);
00294     }
00295 }
00296 
00297 static void
00298 mem_reg_dump_core (Memory *mem, FILE * f_core)
00299 {
00300     int i, j;
00301 
00302     fprintf (f_core, "General Purpose Register Dump:\n");
00303     for (i = 0; i < 32; i += 8)
00304     {
00305         for (j = i; j < (i + 8); j++)
00306             fprintf (f_core, "r%02d=%02x  ", j, mem_read (mem, j));
00307         fprintf (f_core, "\n");
00308     }
00309     fprintf (f_core, "\n");
00310 }
00311 
00312 /** \brief Fetch the name and value of the io register (addr). 
00313  *
00314  * \param mem A pointer to the memory object.
00315  * \param addr The address to fetch from.
00316  * \param val A pointer where the value of the register is to be copied.
00317  * \param buf A pointer to where the name of the register should be copied.
00318  * \param bufsiz The maximum size of the the buf string.
00319  */
00320 
00321 void
00322 mem_io_fetch (Memory *mem, int addr, uint8_t * val, char *buf, int bufsiz)
00323 {
00324     MemoryCell *cell;
00325 
00326     if (mem_is_io_reg (mem, addr))
00327     {
00328         cell = mem_get_cell (mem, addr);
00329 
00330         if (cell->name == NULL)
00331         {
00332             strncpy (buf, "Reserved", bufsiz);
00333             *val = 0;
00334         }
00335         else
00336         {
00337             strncpy (buf, cell->name, bufsiz);
00338 
00339             if (cell->vdev)
00340             {
00341                 /* FIXME: Add vdev_read_no_ext () interface to avoid calling
00342                    the external functions during a read. This will require a
00343                    reworking of how the vdev invokes the external read
00344                    method. */
00345 
00346                 *val = (vdev_read (cell->vdev, addr) & cell->rd_mask);
00347             }
00348             else
00349             {
00350                 *val = 0;
00351             }
00352         }
00353     }
00354     else
00355     {
00356         *val = 0;
00357         strncpy (buf, "NOT AN IO REG", bufsiz);
00358     }
00359 }
00360 
00361 static void
00362 mem_io_reg_dump_core (Memory *mem, FILE * f_core)
00363 {
00364     int i, j;
00365     char name[80];
00366     uint8_t val;
00367 
00368     int begin = mem->gpwr_end + 1;
00369     int end = mem->io_reg_end;
00370     int half = (end - begin) / 2;
00371     int mid = begin + half;
00372 
00373     fprintf (f_core, "IO Register Dump:\n");
00374     for (i = begin; i < mid; i++)
00375     {
00376         for (j = i; j < end; j += half)
00377         {
00378             memset (name, '\0', sizeof (name));
00379             mem_io_fetch (mem, j, &val, name, sizeof (name) - 1);
00380 
00381             fprintf (f_core, "%02x : %-10s : 0x%02x               ", j - half,
00382                      name, val);
00383         }
00384         fprintf (f_core, "\n");
00385     }
00386     fprintf (f_core, "\n");
00387 }
00388 
00389 static void
00390 mem_sram_display (Memory *mem, FILE * f_core, int base, int size)
00391 {
00392     int i;
00393     int dup = 0;
00394     int ndat = 16;
00395     char line[80];
00396     char last_line[80];
00397     char buf[80];
00398     line[0] = last_line[0] = '\0';
00399 
00400     for (i = base; i < (base + size); i++)
00401     {
00402         if (((i % ndat) == 0) && strlen (line))
00403         {
00404             if (strncmp (line, last_line, 80) == 0)
00405             {
00406                 dup++;
00407             }
00408             else
00409             {
00410                 if (dup > 0)
00411                     fprintf (f_core, "  -- last line repeats --\n");
00412                 fprintf (f_core, "%04x : %s\n", i - ndat, line);
00413                 dup = 0;
00414             }
00415             strncpy (last_line, line, 80);
00416             line[0] = '\0';
00417         }
00418         snprintf (buf, 80, "%02x ", mem_read (mem, i));
00419         strncat (line, buf, 80);
00420     }
00421     if (dup > 0)
00422     {
00423         fprintf (f_core, "  -- last line repeats --\n");
00424         fprintf (f_core, "%04x : %s\n", i - ndat, line);
00425     }
00426     fprintf (f_core, "\n");
00427 }
00428 
00429 static void
00430 mem_sram_dump_core (Memory *mem, FILE * f_core)
00431 {
00432     int size, base;
00433 
00434     /*
00435      * Dump the internal sram
00436      */
00437 
00438     if (mem->io_reg_end == mem->sram_end)
00439         return;                 /* device has no sram */
00440 
00441     fprintf (f_core, "Internal SRAM Memory Dump:\n");
00442     base = mem->io_reg_end + 1;
00443     size = mem->sram_end;
00444     mem_sram_display (mem, f_core, base, size);
00445 
00446     /*
00447      * If external sram present, dump it too.
00448      */
00449 
00450     if (mem->sram_end == mem->xram_end)
00451         return;                 /* device has no xram */
00452 
00453     fprintf (f_core, "External SRAM Memory Dump:\n");
00454     base = mem->sram_end + 1;
00455     size = mem->xram_end;
00456     mem_sram_display (mem, f_core, base, size);
00457 
00458 }
00459 
00460 #if 0
00461 
00462 /* FIXME: Still need to figure out a sane way to look up a specific type of
00463    vdev by generic name. */
00464 
00465 static void
00466 mem_eeprom_dump_core (Memory *mem, FILE * f_core)
00467 {
00468     VDevice *dev = mem_get_vdevice_by_name (mem, "EEProm");
00469 
00470     if (dev != NULL)
00471         eeprom_dump_core ((EEProm *)dev, f_core);
00472 }
00473 #endif
00474 
00475 /** \brief Dump all the various memory locations to a file descriptor 
00476  *         in text format.
00477  *
00478  *  \param mem A memory object.
00479  *  \param f_core An open file descriptor.
00480  */
00481 
00482 void
00483 mem_dump_core (Memory *mem, FILE * f_core)
00484 {
00485     mem_reg_dump_core (mem, f_core);
00486     mem_io_reg_dump_core (mem, f_core);
00487     mem_sram_dump_core (mem, f_core);
00488 /*     mem_eeprom_dump_core (mem, f_core); */
00489 }

Automatically generated by Doxygen 1.5.2 on 3 Dec 2007.