Main Page | Directories | File List | Globals | Related Pages

eeprom.c

00001 /*
00002  * $Id: eeprom.c,v 1.20 2004/01/30 07:09:56 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 #include <config.h>
00027 
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include <errno.h>
00032 #include <unistd.h>
00033 
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <fcntl.h>
00037 
00038 #include "avrerror.h"
00039 #include "avrmalloc.h"
00040 #include "avrclass.h"
00041 #include "utils.h"
00042 #include "callback.h"
00043 #include "op_names.h"
00044 
00045 #include "storage.h"
00046 #include "flash.h"
00047 
00048 #include "vdevs.h"
00049 #include "memory.h"
00050 #include "stack.h"
00051 #include "register.h"
00052 #include "sram.h"
00053 #include "eeprom.h"
00054 #include "timers.h"
00055 #include "ports.h"
00056 
00057 #include "avrcore.h"
00058 
00059 #include "display.h"
00060 
00061 static uint8_t eeprom_reg_read (VDevice *dev, int addr);
00062 static void eeprom_reg_write (VDevice *dev, int addr, uint8_t val);
00063 static void eeprom_reg_reset (VDevice *dev);
00064 static void eeprom_wr_eecr (EEProm *ee, uint8_t val);
00065 
00066 static int eeprom_wr_op_cb (uint64_t time, AvrClass *data);
00067 static int eeprom_mwe_clr_cb (uint64_t time, AvrClass *data);
00068 
00069 EEProm *
00070 eeprom_new (int size, uint8_t eecr_mask)
00071 {
00072     EEProm *eeprom;
00073 
00074     eeprom = avr_new (EEProm, 1);
00075     eeprom_construct (eeprom, size, eecr_mask);
00076     class_overload_destroy ((AvrClass *)eeprom, eeprom_destroy);
00077 
00078     return eeprom;
00079 }
00080 
00081 void
00082 eeprom_construct (EEProm *eeprom, int size, uint8_t eecr_mask)
00083 {
00084     int i;
00085 
00086     if (eeprom == NULL)
00087         avr_error ("passed null ptr");
00088 
00089     eeprom->stor = storage_new (0 /*base */ , size);
00090 
00091     /* init eeprom to ones */
00092     for (i = 0; i < size; i++)
00093         storage_writeb (eeprom->stor, i, 0xff);
00094 
00095     eeprom->eecr_mask = eecr_mask;
00096 
00097     eeprom_reg_reset ((VDevice *)eeprom);
00098 
00099     vdev_construct ((VDevice *)eeprom, eeprom_reg_read, eeprom_reg_write,
00100                     eeprom_reg_reset, vdev_def_AddAddr);
00101 }
00102 
00103 void
00104 eeprom_destroy (void *eeprom)
00105 {
00106     EEProm *_eeprom = (EEProm *)eeprom;
00107 
00108     if (eeprom == NULL)
00109         return;
00110 
00111     class_unref ((AvrClass *)_eeprom->stor);
00112 
00113     vdev_destroy (eeprom);
00114 }
00115 
00116 int
00117 eeprom_get_size (EEProm *eeprom)
00118 {
00119     return storage_get_size (eeprom->stor);
00120 }
00121 
00122 static uint8_t
00123 eeprom_reg_read (VDevice *dev, int addr)
00124 {
00125     EEProm *ee = (EEProm *)dev;
00126 
00127     switch (addr)
00128     {
00129         case EECR_ADDR:
00130             return ee->eecr;
00131         case EEDR_ADDR:
00132             return ee->eedr;
00133         case EEARL_ADDR:
00134             return ee->eearl;
00135         case EEARH_ADDR:
00136             return ee->eearh;
00137     }
00138     avr_error ("Bad address: %d", addr);
00139     return 0;
00140 }
00141 
00142 static void
00143 eeprom_reg_write (VDevice *dev, int addr, uint8_t val)
00144 {
00145     EEProm *ee = (EEProm *)dev;
00146 
00147     if (ee->eecr & mask_EEWE)
00148     {
00149         /*
00150          * From the 8515 data sheet: The user should poll the EEWE bit before
00151          * starting the read operaton. If a write operation is in progress
00152          * when new data or address is written to the EEPROM I/O registers,
00153          * the write operation will be interrupted, and the result is
00154          * undefined.
00155          */
00156         avr_error ("Attempt to write to EEPROM I/O reg during write "
00157                    "operation");
00158     }
00159 
00160     switch (addr)
00161     {
00162         case EECR_ADDR:
00163             eeprom_wr_eecr (ee, val);
00164             return;
00165         case EEDR_ADDR:
00166             ee->eedr = val;
00167             return;
00168         case EEARL_ADDR:
00169             ee->eearl = val;
00170             return;
00171         case EEARH_ADDR:
00172             ee->eearh = val;
00173             return;
00174     }
00175     avr_error ("Bad address: %d", addr);
00176 }
00177 
00178 static void
00179 eeprom_reg_reset (VDevice *dev)
00180 {
00181     EEProm *ee = (EEProm *)dev;
00182 
00183     ee->wr_op_cb = NULL;
00184     ee->wr_op_clk = 0;
00185 
00186     ee->mwe_clr_cb = NULL;
00187     ee->mwe_clk = 0;
00188 
00189     ee->eecr = ee->eedr = ee->eearl = ee->eearh = 0;
00190 }
00191 
00192 static void
00193 eeprom_wr_eecr (EEProm *ee, uint8_t val)
00194 {
00195     int addr = (ee->eearh << 8) | ee->eearl;
00196 
00197     CallBack *cb;
00198 
00199     switch (val & ee->eecr_mask)
00200     {
00201         case mask_EERE:
00202             /*
00203              * we never need to set EERE bit one,
00204              * just more data from eeprom array into eedr.
00205              */
00206             ee->eedr = storage_readb (ee->stor, addr);
00207             break;
00208 
00209         case mask_EEWE:
00210             if (((ee->eecr_mask & mask_EEMWE) == 0) /* device has no MWE
00211                                                        function */
00212                 || (ee->eecr & ee->eecr_mask & mask_EEMWE)) /* or MWE bit is
00213                                                                set */
00214             {
00215                 ee->eecr |= mask_EEWE;
00216                 ee->wr_op_clk = EEPROM_WR_OP_CLKS;
00217 
00218                 /* start write operation */
00219                 if (ee->wr_op_cb == NULL)
00220                 {
00221                     cb = callback_new (eeprom_wr_op_cb, (AvrClass *)ee);
00222                     ee->wr_op_cb = cb;
00223                     avr_core_async_cb_add ((AvrCore *)
00224                                            vdev_get_core ((VDevice *)ee), cb);
00225                 }
00226             }
00227             break;
00228 
00229         case mask_EEMWE:
00230             ee->eecr |= mask_EEMWE;
00231             ee->mwe_clk = EEPROM_MWE_CLKS;
00232 
00233             if (ee->mwe_clr_cb == NULL)
00234             {
00235                 cb = callback_new (eeprom_mwe_clr_cb, (AvrClass *)ee);
00236                 ee->mwe_clr_cb = cb;
00237                 avr_core_clk_cb_add ((AvrCore *)vdev_get_core ((VDevice *)ee),
00238                                      cb);
00239             }
00240             break;
00241 
00242         case (mask_EEMWE | mask_EEWE):
00243             /* just call this function again, but without EEMWE set in val */
00244             eeprom_wr_eecr (ee, mask_EEWE);
00245             break;
00246 
00247         default:
00248             avr_error ("Unknown eeprom control register write operation: "
00249                        "0x%02x", val);
00250     }
00251 }
00252 
00253 /*
00254  * The data sheets say that a write operation takes 2.5 to 4.0 ms to complete
00255  * depending on Vcc voltage. Since the get_program_time() function only has
00256  * 10 ms resolution, we'll just simulate a timer with counting down from
00257  * EEPROM_WR_OP_CLKS to zero. 2500 clocks would be 2.5 ms if simulator is
00258  * running at 1 MHz. I really don't think that this variation should be 
00259  * critical in most apps, but I'd wouldn't mind being proven wrong.
00260  */
00261 static int
00262 eeprom_wr_op_cb (uint64_t time, AvrClass *data)
00263 {
00264     EEProm *ee = (EEProm *)data;
00265     int addr;
00266 
00267     /*
00268      * FIXME: At some point in the future, we might need to check if
00269      * any of the I/O registers have been written to during the write
00270      * operation which would cause the write op to be interrupted.
00271      * Right now, the simulator is aborted in that situation.
00272      */
00273 
00274     if (ee->wr_op_clk > 0)
00275     {
00276         /* write is not complete yet */
00277         ee->wr_op_clk--;
00278         return CB_RET_RETAIN;
00279     }
00280 
00281     /* write the data in eedr into eeprom at addr */
00282     addr = (ee->eearh << 8) | ee->eearl;
00283     avr_warning ("writing 0x%02x to eeprom at 0x%04x\n", ee->eedr, addr);
00284     display_eeprom (addr, 1, &ee->eedr);
00285     storage_writeb (ee->stor, addr, ee->eedr);
00286 
00287     /* Now it's ok to start another write operation */
00288     ee->eecr &= ~(mask_EEWE);   /* clear the write enable bit */
00289     ee->wr_op_cb = NULL;        /* remove callback */
00290 
00291     return CB_RET_REMOVE;
00292 }
00293 
00294 /*
00295  * Once set, the hardware will automatically clear the EEMWE bit
00296  * after EEPROM_MWE_CLKS clock cycles.
00297  */
00298 static int
00299 eeprom_mwe_clr_cb (uint64_t time, AvrClass *data)
00300 {
00301     EEProm *ee = (EEProm *)data;
00302 
00303     if (ee->mwe_clk > 0)
00304     {
00305         ee->mwe_clk--;
00306         return CB_RET_RETAIN;
00307     }
00308 
00309     ee->eecr &= ~(mask_EEMWE);  /* clear the EEMWE bit */
00310     ee->mwe_clr_cb = NULL;      /* remove callback */
00311 
00312     return CB_RET_REMOVE;
00313 }
00314 
00315 static int
00316 eeprom_load_from_bin_file (EEProm *eeprom, char *file)
00317 {
00318     int fd, res;
00319     int addr = 0;
00320     uint8_t datum;
00321 
00322     fd = open (file, O_RDONLY);
00323     if (fd < 0)
00324         avr_error ("Couldn't open binary eeprom image file: %s: %s", file,
00325                    strerror (errno));
00326 
00327     while ((res = read (fd, &datum, sizeof (datum))) != 0)
00328     {
00329         if (res == -1)
00330             avr_error ("Error reading binary eeprom image file: %s: %s", file,
00331                        strerror (errno));
00332 
00333         storage_writeb (eeprom->stor, addr, datum);
00334 
00335         addr++;
00336     }
00337 
00338     close (fd);
00339 
00340     return 0;
00341 }
00342 
00343 /** \brief Load data into eeprom from a file. */
00344 
00345 int
00346 eeprom_load_from_file (EEProm *eeprom, char *file, int format)
00347 {
00348     switch (format)
00349     {
00350         case FFMT_BIN:
00351             return eeprom_load_from_bin_file (eeprom, file);
00352         case FFMT_IHEX:
00353         case FFMT_ELF:
00354         default:
00355             avr_warning ("Unsupported file format\n");
00356     }
00357 
00358     return -1;
00359 }
00360 
00361 void
00362 eeprom_dump_core (EEProm *eeprom, FILE * f_core)
00363 {
00364     int i;
00365     int dup = 0;
00366     int ndat = 16;
00367     char line[80];
00368     char last_line[80];
00369     char buf[80];
00370     int size = storage_get_size (eeprom->stor);
00371 
00372     fprintf (f_core, "EEPROM Memory Dump:\n");
00373 
00374     line[0] = last_line[0] = '\0';
00375 
00376     for (i = 0; i < size; i++)
00377     {
00378         if (((i % ndat) == 0) && strlen (line))
00379         {
00380             if (strncmp (line, last_line, 80) == 0)
00381             {
00382                 dup++;
00383             }
00384             else
00385             {
00386                 if (dup > 0)
00387                     fprintf (f_core, "  -- last line repeats --\n");
00388                 fprintf (f_core, "%04x : %s\n", i - ndat, line);
00389                 dup = 0;
00390             }
00391             strncpy (last_line, line, 80);
00392             line[0] = '\0';
00393         }
00394         snprintf (buf, 80, "%02x ", storage_readb (eeprom->stor, i));
00395         strncat (line, buf, 80);
00396     }
00397     if (dup > 0)
00398     {
00399         fprintf (f_core, "  -- last line repeats --\n");
00400         fprintf (f_core, "%04x : %s\n", i - ndat, line);
00401     }
00402     fprintf (f_core, "\n");
00403 }

Automatically generated by Doxygen 1.4.1 on 18 Oct 2005.