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 }