- Main Page
- Related Pages
- Files

# 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.5.5 on 7 Nov 2008.