- Main Page
- Related Pages
- Files

# memory.c

Go to the documentation of this file.

    00001 /*
    00002  * $Id: memory.c,v 1.24 2009/02/24 21:10:12 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     /*
    00184      * Just return *any* possible cell for illegal addresses,
    00185      * to avoid accessing cells that have not been allocated.
    00186      * Later on, the illegal address will be caught anyway.
    00187      */
    00188     if ((addr < 0) || (addr > mem->xram_end))
    00189         addr = mem->xram_end - 1;
    00190
    00191     return mem->cell + addr;
    00192 }
    00193
    00194 static int
    00195 mem_is_io_reg (Memory *mem, int addr)
    00196 {
    00197     return ((addr > mem->gpwr_end) && (addr <= mem->io_reg_end));
    00198 }
    00199
    00200 static char *
    00201 mem_get_name (Memory *mem, int addr)
    00202 {
    00203     return mem->cell[addr].name;
    00204 }
    00205
    00206 void
    00207 mem_set_addr_name (Memory *mem, int addr, char *name)
    00208 {
    00209     mem->cell[addr].name = name;
    00210 }
    00211
    00212 /** \brief Reads byte from memory and sanity-checks for valid address.
    00213  *
    00214  * \param mem A pointer to the memory object
    00215  * \param addr The address to be read
    00216  * \return The byte found at that address addr
    00217  */
    00218
    00219 uint8_t
    00220 mem_read (Memory *mem, int addr)
    00221 {
    00222     MemoryCell *cell = mem_get_cell (mem, addr);
    00223
    00224     if (cell->vdev == NULL)
    00225     {
    00226         char *name = mem_get_name (mem, addr);
    00227
    00228         if (name)
    00229         {
    00230             avr_warning ("**** Attempt to read invalid %s: %s at 0x%04x\n",
    00231                          mem_is_io_reg (mem, addr) ? "io reg" : "mem addr",
    00232                          name, addr);
    00233         }
    00234         else
    00235         {
    00236             avr_warning ("**** Attempt to read invalid %s: 0x%04x\n",
    00237                          mem_is_io_reg (mem, addr) ? "io reg" : "mem addr",
    00238                          addr);
    00239         }
    00240
    00241         return 0;
    00242     }
    00243
    00244     return (vdev_read (cell->vdev, addr) & cell->rd_mask);
    00245 }
    00246
    00247 /** \brief Writes byte to memory and updates display for io registers.
    00248  *
    00249  * \param mem A pointer to a memory object
    00250  * \param addr The address to be written to
    00251  * \param val The value to be written there
    00252  */
    00253
    00254 void
    00255 mem_write (Memory *mem, int addr, uint8_t val)
    00256 {
    00257     MemoryCell *cell = mem_get_cell (mem, addr);
    00258
    00259     if (cell->vdev == NULL)
    00260     {
    00261         char *name = mem_get_name (mem, addr);
    00262
    00263         if (name)
    00264         {
    00265             avr_warning ("**** Attempt to write invalid %s: %s at 0x%04x\n",
    00266                          mem_is_io_reg (mem, addr) ? "io reg" : "mem addr",
    00267                          name, addr);
    00268         }
    00269         else
    00270         {
    00271             avr_warning ("**** Attempt to write invalid %s: 0x%04x\n",
    00272                          mem_is_io_reg (mem, addr) ? "io reg" : "mem addr",
    00273                          addr);
    00274         }
    00275
    00276         return;
    00277     }
    00278
    00279     /* update the display for io registers here */
    00280
    00281     if (mem_is_io_reg (mem, addr))
    00282         display_io_reg (addr - (mem->gpwr_end + 1), val & cell->wr_mask);
    00283
    00284     vdev_write (cell->vdev, addr, val & cell->wr_mask);
    00285 }
    00286
    00287 /** \brief Resets every device in the memory object.
    00288  * \param mem A pointer to the memory object.
    00289  */
    00290
    00291 void
    00292 mem_reset (Memory *mem)
    00293 {
    00294     int i;
    00295
    00296     for (i = 0; i < mem->xram_end; i++)
    00297     {
    00298         MemoryCell *cell = mem_get_cell (mem, i);
    00299
    00300         if (cell->vdev)
    00301             vdev_reset (cell->vdev);
    00302     }
    00303 }
    00304
    00305 static void
    00306 mem_reg_dump_core (Memory *mem, FILE * f_core)
    00307 {
    00308     int i, j;
    00309
    00310     fprintf (f_core, "General Purpose Register Dump:\n");
    00311     for (i = 0; i < 32; i += 8)
    00312     {
    00313         for (j = i; j < (i + 8); j++)
    00314             fprintf (f_core, "r%02d=%02x  ", j, mem_read (mem, j));
    00315         fprintf (f_core, "\n");
    00316     }
    00317     fprintf (f_core, "\n");
    00318 }
    00319
    00320 /** \brief Fetch the name and value of the io register (addr).
    00321  *
    00322  * \param mem A pointer to the memory object.
    00323  * \param addr The address to fetch from.
    00324  * \param val A pointer where the value of the register is to be copied.
    00325  * \param buf A pointer to where the name of the register should be copied.
    00326  * \param bufsiz The maximum size of the the buf string.
    00327  */
    00328
    00329 void
    00330 mem_io_fetch (Memory *mem, int addr, uint8_t * val, char *buf, int bufsiz)
    00331 {
    00332     MemoryCell *cell;
    00333
    00334     if (mem_is_io_reg (mem, addr))
    00335     {
    00336         cell = mem_get_cell (mem, addr);
    00337
    00338         if (cell->name == NULL)
    00339         {
    00340             strncpy (buf, "Reserved", bufsiz);
    00341             *val = 0;
    00342         }
    00343         else
    00344         {
    00345             strncpy (buf, cell->name, bufsiz);
    00346
    00347             if (cell->vdev)
    00348             {
    00349                 /* FIXME: Add vdev_read_no_ext () interface to avoid calling
    00350                    the external functions during a read. This will require a
    00351                    reworking of how the vdev invokes the external read
    00352                    method. */
    00353
    00354                 *val = (vdev_read (cell->vdev, addr) & cell->rd_mask);
    00355             }
    00356             else
    00357             {
    00358                 *val = 0;
    00359             }
    00360         }
    00361     }
    00362     else
    00363     {
    00364         *val = 0;
    00365         strncpy (buf, "NOT AN IO REG", bufsiz);
    00366     }
    00367 }
    00368
    00369 static void
    00370 mem_io_reg_dump_core (Memory *mem, FILE * f_core)
    00371 {
    00372     unsigned int i, j;
    00373     char name[80];
    00374     uint8_t val;
    00375
    00376     unsigned int begin = (unsigned)mem->gpwr_end + 1;
    00377     unsigned int end = (unsigned)mem->io_reg_end;
    00378     unsigned int half = (end - begin + 1) / 2;
    00379     unsigned int mid = begin + half;
    00380
    00381     fprintf (f_core, "IO Register Dump:\n");
    00382     for (i = begin; i < mid; i++)
    00383     {
    00384         for (j = i; j <= end; j += half)
    00385         {
    00386             memset (name, '\0', sizeof (name));
    00387             mem_io_fetch (mem, j, &val, name, sizeof (name) - 1);
    00388
    00389             fprintf (f_core, "%02x : %-10s : 0x%02x               ", j,
    00390                      name, val);
    00391         }
    00392         fprintf (f_core, "\n");
    00393     }
    00394     fprintf (f_core, "\n");
    00395 }
    00396
    00397 static void
    00398 mem_sram_display (Memory *mem, FILE * f_core, int base, int size)
    00399 {
    00400     int i;
    00401     int dup = 0;
    00402     int ndat = 16;
    00403     char line[80];
    00404     char last_line[80];
    00405     char buf[80];
    00406     line[0] = last_line[0] = '\0';
    00407
    00408     for (i = base; i < (base + size); i++)
    00409     {
    00410         if (((i % ndat) == 0) && strlen (line))
    00411         {
    00412             if (strncmp (line, last_line, 80) == 0)
    00413             {
    00414                 dup++;
    00415             }
    00416             else
    00417             {
    00418                 if (dup > 0)
    00419                     fprintf (f_core, "  -- last line repeats --\n");
    00420                 fprintf (f_core, "%04x : %s\n", i - ndat, line);
    00421                 dup = 0;
    00422             }
    00423             strncpy (last_line, line, 80);
    00424             line[0] = '\0';
    00425         }
    00426         snprintf (buf, 80, "%02x ", mem_read (mem, i));
    00427         strncat (line, buf, 80);
    00428     }
    00429     if (dup > 0)
    00430     {
    00431         fprintf (f_core, "  -- last line repeats --\n");
    00432         fprintf (f_core, "%04x : %s\n", i - ndat, line);
    00433     }
    00434     fprintf (f_core, "\n");
    00435 }
    00436
    00437 static void
    00438 mem_sram_dump_core (Memory *mem, FILE * f_core)
    00439 {
    00440     int size, base;
    00441
    00442     /*
    00443      * Dump the internal sram
    00444      */
    00445
    00446     if (mem->io_reg_end == mem->sram_end)
    00447         return;                 /* device has no sram */
    00448
    00449     fprintf (f_core, "Internal SRAM Memory Dump:\n");
    00450     base = mem->io_reg_end + 1;
    00451     size = mem->sram_end - base + 1;
    00452     mem_sram_display (mem, f_core, base, size);
    00453
    00454     /*
    00455      * If external sram present, dump it too.
    00456      */
    00457
    00458     if (mem->sram_end == mem->xram_end)
    00459         return;                 /* device has no xram */
    00460
    00461     fprintf (f_core, "External SRAM Memory Dump:\n");
    00462     base = mem->sram_end + 1;
    00463     size = mem->xram_end - base + 1;
    00464     mem_sram_display (mem, f_core, base, size);
    00465
    00466 }
    00467
    00468 #if 0
    00469
    00470 /* FIXME: Still need to figure out a sane way to look up a specific type of
    00471    vdev by generic name. */
    00472
    00473 static void
    00474 mem_eeprom_dump_core (Memory *mem, FILE * f_core)
    00475 {
    00476     VDevice *dev = mem_get_vdevice_by_name (mem, "EEProm");
    00477
    00478     if (dev != NULL)
    00479         eeprom_dump_core ((EEProm *)dev, f_core);
    00480 }
    00481 #endif
    00482
    00483 /** \brief Dump all the various memory locations to a file descriptor
    00484  *         in text format.
    00485  *
    00486  *  \param mem A memory object.
    00487  *  \param f_core An open file descriptor.
    00488  */
    00489
    00490 void
    00491 mem_dump_core (Memory *mem, FILE * f_core)
    00492 {
    00493     mem_reg_dump_core (mem, f_core);
    00494     mem_io_reg_dump_core (mem, f_core);
    00495     mem_sram_dump_core (mem, f_core);
    00496 /*     mem_eeprom_dump_core (mem, f_core); */
    00497 }

Automatically generated by Doxygen 1.5.5 on 5 Mar 2009.