- Main Page
- Related Pages
- Files

# memory.c

Go to the documentation of this file.

    00001 /*
    00002  * $Id: memory.c,v 1.22 2008/01/06 22:38:19 joerg_wunsch 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 MemoryCell *
    00181 mem_get_cell (Memory *mem, int addr)
    00182 {
    00183     return mem->cell + addr;
    00184 }
    00185
    00186 static 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 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 - base + 1;
    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 - base + 1;
    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.5 on 7 Nov 2008.