- Main Page
- Related Pages
- Files

# eeprom.c

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

Automatically generated by Doxygen 1.5.5 on 5 Mar 2009.