Updated copyright notices for most files.
[deliverable/binutils-gdb.git] / sim / ppc / hw_eeprom.c
index 8a52e9dc41d684d8abbeb87ef7b01e00c9bd7d59..5092984369e1e3d603e92231351947626828e537 100644 (file)
 #ifndef _HW_EEPROM_C_
 #define _HW_EEPROM_C_
 
-#ifndef STATIC_INLINE_HW_EEPROM
-#define STATIC_INLINE_HW_EEPROM STATIC_INLINE
-#endif
-
 #include "device_table.h"
 
 #ifdef HAVE_STRING_H
 #endif
 #endif
 
-/* EEPROM - electricaly erasable programable memory
 
-   Description:
+/* DEVICE
+
+
+   eeprom - JEDEC? compatible electricaly erasable programable device
+
+
+   DESCRIPTION
+
 
    This device implements a small byte addressable EEPROM.
    Programming is performed using the same write sequences as used by
-   modern EEPROM components.  Writes occure in real time, the device
-   returning a progress value until the programing has been completed.
+   standard modern EEPROM components.  Writes occure in real time, the
+   device returning a progress value until the programing has been
+   completed.
+
+   It is based on the AMD 29F040 component.
+
+
+   PROPERTIES
+
+
+   reg = <address> <size> (required)
+
+   Determine where the device lives in the parents address space.
+
+
+   nr-sectors = <integer> (required)
+
+   When erasing an entire sector is cleared at a time.  This specifies
+   the number of sectors in the EEPROM component.
+
+
+   sector-size = <integer> (required)
+
+   The number of bytes in a sector.  When erasing, memory chunks of
+   this size are cleared.
+
+   NOTE: The product nr-sectors * sector-size does not need to map the
+   size specified in the reg property.  If the specified size is
+   smaller part of the eeprom will not be accessible while if it is
+   larger the addresses will wrap.
+
+
+   byte-write-delay = <integer> (required)
+
+   Number of clock ticks before the programming of a single byte
+   completes.
+
+
+   sector-start-delay = <integer> (required)
+
+   When erasing sectors, the number of clock ticks after the sector
+   has been specified that the actual erase process commences.
+
+
+   erase-delay = <intger> (required)
+
+   Number of clock ticks before an erase program completes
+
+
+   manufacture-code = <integer> (required)
+
+   The one byte value returned when the auto-select manufacturer code
+   is read.
+
+
+   device-code = <integer> (required)
+
+   The one byte value returned when the auto-select device code is
+   read.
+
+
+   input-file = <file-name> (optional)
+
+   Initialize the eeprom using the specified binary file.
+
+
+   output-file = <file-name> (optional)
 
-   Properties:
+   When ever the eeprom is updated, save the modified image into the
+   specified file.
 
-   reg = <address> <size>.  Determine where the device lives in the
-   parents address space.
 
-   nr-sectors = <integer>.  When erasing an entire sector is cleared
-   at a time.  This specifies the number of sectors in the EEPROM
-   component.
+   EXAMPLES
 
-   byte-write-delay = <integer>.  Number of clock ticks before the
-   programming of a single byte completes.
 
-   sector-start-delay = <integer>.  When erasing sectors, the number
-   of clock ticks after the sector has been specified and the actual
-   erase process commences.
+   Enable tracing of the eeprom:
 
-   erase-delay = <intger>.  Number of clock ticks before an erase
-   program completes. */
+   |  bash$ psim -t eeprom-device \
+
+
+   Configure something very like the Amd Am29F040 - 512byte EEPROM
+   (but a bit faster):
+
+   |  -o '/eeprom@0xfff00000/reg 0xfff00000 0x80000' \
+   |  -o '/eeprom@0xfff00000/nr-sectors 8' \
+   |  -o '/eeprom@0xfff00000/sector-size 0x10000' \
+   |  -o '/eeprom@0xfff00000/byte-write-delay 1000' \
+   |  -o '/eeprom@0xfff00000/sector-start-delay 100' \
+   |  -o '/eeprom@0xfff00000/erase-delay 1000' \
+   |  -o '/eeprom@0xfff00000/manufacture-code 0x01' \
+   |  -o '/eeprom@0xfff00000/device-code 0xa4' \
+
+
+   Initialize the eeprom from the file <</dev/zero>>:
+
+   |  -o '/eeprom@0xfff00000/input-file /dev/zero'
+
+
+   BUGS
+
+
+   */
 
 typedef enum {
   read_reset,
@@ -73,216 +156,683 @@ typedef enum {
   write_nr_6,
   byte_program,
   byte_programming,
-  chip_erase, chip_erasing,
-  sector_erase, sector_erasing,
+  chip_erase,
+  sector_erase,
   sector_erase_suspend,
-  sector_erase_resume,
-} eeprom_states;
+  autoselect,
+} hw_eeprom_states;
 
-typedef struct _eeprom_device {
+static const char *
+state2a(hw_eeprom_states state)
+{
+  switch (state) {
+  case read_reset: return "read_reset";
+  case write_nr_2: return "write_nr_2";
+  case write_nr_3: return "write_nr_3";
+  case write_nr_4: return "write_nr_4";
+  case write_nr_5: return "write_nr_5";
+  case write_nr_6: return "write_nr_6";
+  case byte_program: return "byte_program";
+  case byte_programming: return "byte_programming";
+  case chip_erase: return "chip_erase";
+  case sector_erase: return "sector_erase";
+  case sector_erase_suspend: return "sector_erase_suspend";
+  case autoselect: return "autoselect";
+  }
+  return NULL;
+}
+
+typedef struct _hw_eeprom_device {
+  /* general */
+  hw_eeprom_states state;
   unsigned8 *memory;
   unsigned sizeof_memory;
-  unsigned sector_size;
+  unsigned erase_delay;
+  signed64 program_start_time;
+  signed64 program_finish_time;
+  unsigned8 manufacture_code;
+  unsigned8 device_code;
+  unsigned8 toggle_bit;
+  /* initialization */
+  const char *input_file_name;
+  const char *output_file_name;
+  /* for sector and sector programming */
+  hw_eeprom_states sector_state;
+  unsigned8 *sectors;
   unsigned nr_sectors;
-  unsigned byte_write_delay;
+  unsigned sizeof_sector;
   unsigned sector_start_delay;
-  unsigned erase_delay;
-  signed64 programme_start_time;
-  unsigned program_byte_address;
-  eeprom_states state;
-} eeprom_device;
-
-static void *
-eeprom_create(const char *name,
-            const device_unit *unit_address,
-            const char *args,
-            device *parent)
-{
-  eeprom_device *eeprom = ZALLOC(eeprom_device);
-  return eeprom;
-}
+  unsigned sector_start_time;
+  /* byte and byte programming */
+  unsigned byte_write_delay;
+  unsigned_word byte_program_address;
+  unsigned8 byte_program_byte;
+} hw_eeprom_device;
 
-typedef struct _eeprom_reg_spec {
+typedef struct _hw_eeprom_reg_spec {
   unsigned32 base;
   unsigned32 size;
-} eeprom_reg_spec;
+} hw_eeprom_reg_spec;
 
 static void
-eeprom_init_address(device *me,
-                  psim *system)
+hw_eeprom_init_data(device *me)
 {
-  eeprom_device *eeprom = (eeprom_device*)device_data(me);
-  const device_property *reg = device_find_array_property(me, "reg");
-  const eeprom_reg_spec *spec = reg->array;
-  int nr_entries = reg->sizeof_array / sizeof(*spec);
+  hw_eeprom_device *eeprom = (hw_eeprom_device*)device_data(me);
+
+  /* have we any input or output files */
+  if (device_find_property(me, "input-file") != NULL)
+    eeprom->input_file_name = device_find_string_property(me, "input-file");
+  if (device_find_property(me, "output-file") != NULL)
+    eeprom->input_file_name = device_find_string_property(me, "output-file");
 
-  if ((reg->sizeof_array % sizeof(*spec)) != 0)
-    error("devices/%s reg property of incorrect size\n", device_name(me));
-  if (nr_entries > 1)
-    error("devices/%s reg property contains multiple specs\n",
-         device_name(me));
+  /* figure out the sectors in the eeprom */
+  if (eeprom->sectors == NULL) {
+    eeprom->nr_sectors = device_find_integer_property(me, "nr-sectors");
+    eeprom->sizeof_sector = device_find_integer_property(me, "sector-size");
+    eeprom->sectors = zalloc(eeprom->nr_sectors);
+  }
+  else
+    memset(eeprom->sectors, 0, eeprom->nr_sectors);
 
   /* initialize the eeprom */
   if (eeprom->memory == NULL) {
-    eeprom->sizeof_memory = BE2H_4(spec->size);
+    eeprom->sizeof_memory = eeprom->sizeof_sector * eeprom->nr_sectors;
     eeprom->memory = zalloc(eeprom->sizeof_memory);
   }
   else
-    memset(eeprom->memory, eeprom->sizeof_memory, 0);
-
-  /* figure out the sectors in the eeprom */
-  eeprom->nr_sectors = device_find_integer_property(me, "nr-sectors");
-  eeprom->sector_size = eeprom->sizeof_memory / eeprom->nr_sectors;
-  if (eeprom->sector_size * eeprom->nr_sectors != eeprom->sizeof_memory)
-    error("device/%s nr-sectors does not evenly divide eeprom\n",
-         device_name(me));
+    memset(eeprom->memory, 0, eeprom->sizeof_memory);
+  if (eeprom->input_file_name != NULL) {
+    int i;
+    FILE *input_file = fopen(eeprom->input_file_name, "r");
+    if (input_file == NULL) {
+      perror("eeprom");
+      device_error(me, "Failed to open input file %s\n", eeprom->input_file_name);
+    }
+    for (i = 0; i < eeprom->sizeof_memory; i++) {
+      if (fread(&eeprom->memory[i], 1, 1, input_file) != 1)
+       break;
+    }
+    fclose(input_file);
+  }
 
   /* timing */
   eeprom->byte_write_delay = device_find_integer_property(me, "byte-write-delay");
   eeprom->sector_start_delay = device_find_integer_property(me, "sector-start-delay");
   eeprom->erase_delay = device_find_integer_property(me, "erase-delay");
 
-  device_attach_address(device_parent(me),
-                       device_name(me),
-                       attach_callback,
-                       0 /*address space*/,
-                       BE2H_4(spec->base),
-                       eeprom->sizeof_memory,
-                       access_read_write_exec,
-                       me);
+  /* misc */
+  eeprom->manufacture_code = device_find_integer_property(me, "manufacture-code");
+  eeprom->device_code = device_find_integer_property(me, "device-code");
+}
+
+
+static void
+invalid_read(device *me,
+            hw_eeprom_states state,
+            unsigned_word address,
+            const char *reason)
+{
+  DTRACE(eeprom, ("Invalid read to 0x%lx while in state %s (%s)\n",
+                 (unsigned long)address,
+                 state2a(state),
+                 reason));
 }
 
+static void
+invalid_write(device *me,
+             hw_eeprom_states state,
+             unsigned_word address,
+             unsigned8 data,
+             const char *reason)
+{
+  DTRACE(eeprom, ("Invalid write of 0x%lx to 0x%lx while in state %s (%s)\n",
+                 (unsigned long)data,
+                 (unsigned long)address,
+                 state2a(state),
+                 reason));
+}
 
+static void
+dump_eeprom(device *me,
+           hw_eeprom_device *eeprom)
+{
+  if (eeprom->output_file_name != NULL) {
+    int i;
+    FILE *output_file = fopen(eeprom->output_file_name, "w");
+    if (output_file == NULL) {
+      perror("eeprom");
+      device_error(me, "Failed to open output file %s\n",
+                  eeprom->output_file_name);
+    }
+    for (i = 0; i < eeprom->sizeof_memory; i++) {
+      if (fwrite(&eeprom->memory[i], 1, 1, output_file) != 1)
+       break;
+    }
+    fclose(output_file);
+  }
+}
+
+
+/* program a single byte of eeprom */
+
+static void
+start_programming_byte(device *me,
+                      hw_eeprom_device *eeprom,
+                      unsigned_word address,
+                      unsigned8 new_byte)
+{
+  unsigned8 old_byte = eeprom->memory[address];
+  DTRACE(eeprom, ("start-programing-byte - address 0x%lx, new 0x%lx, old 0x%lx\n",
+                 (unsigned long)address,
+                 (unsigned long)new_byte,
+                 (unsigned long)old_byte));
+  eeprom->byte_program_address = address;
+  /* : old new : ~old : new&~old
+     :  0   0  :   1  :    0
+     :  0   1  :   1  :    1     -- can not set a bit
+     :  1   0  :   0  :    0
+     :  1   1  :   0  :    0 */
+  if (~old_byte & new_byte)
+    invalid_write(me, eeprom->state, address, new_byte, "setting cleared bit");
+  /* : old new : old&new
+     :  0   0  :    0
+     :  0   1  :    0
+     :  1   0  :    0
+     :  1   1  :    1 */
+  eeprom->byte_program_byte = new_byte & old_byte;
+  eeprom->memory[address] = ~new_byte & ~0x24; /* LE-bits 5:3 zero */
+  eeprom->program_start_time = device_event_queue_time(me);
+  eeprom->program_finish_time = (eeprom->program_start_time
+                                + eeprom->byte_write_delay);
+}
+
+static void
+finish_programming_byte(device *me,
+                       hw_eeprom_device *eeprom)
+{
+  DTRACE(eeprom, ("finish-programming-byte - address 0x%lx, byte 0x%lx\n",
+                 (unsigned long)eeprom->byte_program_address,
+                 (unsigned long)eeprom->byte_program_byte));
+  eeprom->memory[eeprom->byte_program_address] = eeprom->byte_program_byte;
+  dump_eeprom(me, eeprom);
+}
+
+
+/* erase the eeprom completly */
+
+static void
+start_erasing_chip(device *me,
+                  hw_eeprom_device *eeprom)
+{
+  DTRACE(eeprom, ("start-erasing-chip\n"));
+  memset(eeprom->memory, 0, eeprom->sizeof_memory);
+  eeprom->program_start_time = device_event_queue_time(me);
+  eeprom->program_finish_time = (eeprom->program_start_time
+                                + eeprom->erase_delay);
+}
+
+static void
+finish_erasing_chip(device *me,
+                   hw_eeprom_device *eeprom)
+{
+  DTRACE(eeprom, ("finish-erasing-chip\n"));
+  memset(eeprom->memory, 0xff, eeprom->sizeof_memory);
+  dump_eeprom(me, eeprom);
+}
+
+
+/* erase a single sector of the eeprom */
+
+static void
+start_erasing_sector(device *me,
+                    hw_eeprom_device *eeprom,
+                    unsigned_word address)
+{
+  int sector = address / eeprom->sizeof_sector;
+  DTRACE(eeprom, ("start-erasing-sector - address 0x%lx, sector %d\n",
+                 (unsigned long)address, sector));
+  ASSERT(sector < eeprom->nr_sectors);
+  eeprom->sectors[sector] = 1;
+  memset(eeprom->memory + sector * eeprom->sizeof_sector,
+        0x4, eeprom->sizeof_sector);
+  eeprom->program_start_time = device_event_queue_time(me);
+  eeprom->sector_start_time = (eeprom->program_start_time
+                              + eeprom->sector_start_delay);
+  eeprom->program_finish_time = (eeprom->sector_start_time
+                                + eeprom->erase_delay);
+
+}
+
+static void
+finish_erasing_sector(device *me,
+                     hw_eeprom_device *eeprom)
+{
+  int sector;
+  DTRACE(eeprom, ("finish-erasing-sector\n"));
+  for (sector = 0; sector < eeprom->nr_sectors; sector++) {
+    if (eeprom->sectors[sector]) {
+      eeprom->sectors[sector] = 0;
+      memset(eeprom->memory + sector * eeprom->sizeof_sector,
+            0xff, eeprom->sizeof_sector);
+    }
+  }
+  dump_eeprom(me, eeprom);
+}
+
+
+/* eeprom reads */
+
+static unsigned8
+toggle(hw_eeprom_device *eeprom,
+       unsigned8 byte)
+{
+  eeprom->toggle_bit = eeprom->toggle_bit ^ 0x40; /* le-bit 6 */
+  return eeprom->toggle_bit ^ byte;
+}
+
+static unsigned8
+read_byte(device *me,
+         hw_eeprom_device *eeprom,
+         unsigned_word address)
+{
+  /* may need multiple iterations of this */
+  while (1) {
+    switch (eeprom->state) {
+
+    case read_reset:
+      return eeprom->memory[address];
+
+    case autoselect:
+      if ((address & 0xff) == 0x00)
+       return eeprom->manufacture_code;
+      else if ((address & 0xff) == 0x01)
+       return eeprom->device_code;
+      else
+       return 0; /* not certain about this */
+
+    case byte_programming:
+      if (device_event_queue_time(me) > eeprom->program_finish_time) {
+       finish_programming_byte(me, eeprom);
+       eeprom->state = read_reset;
+       continue;
+      }
+      else if (address == eeprom->byte_program_address) {
+       return toggle(eeprom, eeprom->memory[address]);
+      }
+      else {
+       /* trash that memory location */
+       invalid_read(me, eeprom->state, address, "not byte program address");
+       eeprom->memory[address] = (eeprom->memory[address]
+                                  & eeprom->byte_program_byte);
+       return toggle(eeprom, eeprom->memory[eeprom->byte_program_address]);
+      }
+
+    case chip_erase:
+      if (device_event_queue_time(me) > eeprom->program_finish_time) {
+       finish_erasing_chip(me, eeprom);
+       eeprom->state = read_reset;
+       continue;
+      }
+      else {
+       return toggle(eeprom, eeprom->memory[address]);
+      }
+
+    case sector_erase:
+      if (device_event_queue_time(me) > eeprom->program_finish_time) {
+       finish_erasing_sector(me, eeprom);
+       eeprom->state = read_reset;
+       continue;
+      }
+      else if (!eeprom->sectors[address / eeprom->sizeof_sector]) {
+       /* read to wrong sector */
+       invalid_read(me, eeprom->state, address, "sector not being erased");
+       return toggle(eeprom, eeprom->memory[address]) & ~0x8;
+      }
+      else if (device_event_queue_time(me) > eeprom->sector_start_time) {
+       return toggle(eeprom, eeprom->memory[address]) | 0x8;
+      }
+      else {
+       return toggle(eeprom, eeprom->memory[address]) & ~0x8;
+      }
+
+    case sector_erase_suspend:
+      if (!eeprom->sectors[address / eeprom->sizeof_sector]) {
+       return eeprom->memory[address];
+      }
+      else {
+       invalid_read(me, eeprom->state, address, "sector being erased");
+       return eeprom->memory[address];
+      }
+
+    default:
+      invalid_read(me, eeprom->state, address, "invalid state");
+      return eeprom->memory[address];
+
+    }
+  }
+  return 0;
+}
+                      
 static unsigned
-eeprom_io_read_buffer(device *me,
-                     void *dest,
-                     int space,
-                     unsigned_word addr,
-                     unsigned nr_bytes,
-                     cpu *processor,
-                     unsigned_word cia)
+hw_eeprom_io_read_buffer(device *me,
+                        void *dest,
+                        int space,
+                        unsigned_word addr,
+                        unsigned nr_bytes,
+                        cpu *processor,
+                        unsigned_word cia)
 {
-  eeprom_device *eeprom = (eeprom_device*)device_data(me);
+  hw_eeprom_device *eeprom = (hw_eeprom_device*)device_data(me);
   int i;
   for (i = 0; i < nr_bytes; i++) {
-    unsigned_word address = (addr + nr_bytes) % eeprom->sizeof_memory;
-    eeprom->memory[address] = eeprom_io_read_byte(address);
+    unsigned_word address = (addr + i) % eeprom->sizeof_memory;
+    unsigned8 byte = read_byte(me, eeprom, address);
+    ((unsigned8*)dest)[i] = byte;
   }
   return nr_bytes;
 }
 
+
+/* eeprom writes */
+
 static void
-eeprom_io_write_byte()
+write_byte(device *me,
+          hw_eeprom_device *eeprom,
+          unsigned_word address,
+          unsigned8 data)
 {
-  switch (state) {
-  case read_reset:
-    if (address == 0x5555 && data = 0xaa)
-      state = first_write;
-    else
-      state = read_reset;
-    break;
-  case first_write:
-    if (address == 0x2aaa && data == 0x55)
-      state = second_write;
-    else
-      state = read_reset; /* issue warning */
-    break;
-  case second_write:
-    if (address == 0x5555 && data == 0xf0)
-      state = read_reset;
-    else if (address == 0x5555 && data == 0x90)
-      state = auto_select;
-    else if (address == 0x5555 && data == 0xa0)
-      state = byte_program;
-    else if (address == 0x5555 && data == 0x80)
-      state = third_write;
-    else
-      state = read_reset;
-    break;
-  case fourth_write:
-    if (address == 0x5555 && data == 0xaa)
-      state = fith_write;
-    else
-      state = read_reset;
-    break;
-  case fith_write:
-    if (address == 0x2aaa && data == 0x55)
-      state = sixth_write;
-    else
-      state = read_reset;
-    break;
-  case sixth_write:
-    if (address == 0x5555 && data == 0x10)
-      state = chip_erase;
-    else
-      sector_erase();
-    break;
-  case auto_select:
-    if (data == 0xf0)
-      state = read_reset;
-    else if (address == 0x5555 && data == 0xaa)
-      state = second_write;
-    else
-      state = read_reset; /* issue warning */
-    break;
-  case sector_erase:
-    if (data == 0xb0)
-      state = sector_erase_suspend;
-    else
-      state = sector_erase; /* ignore */
-    break;
-  case sector_erase_suspend:
-    if (data == 0x30)
-      state = sector_erase;
-    else
-      state = sector_erase_suspend; /* ignore */
-    break;
-  case byte_program:
-    /* perform the byte program */
-    program_address = address;
-    program_start = some_time();
-    toggle = 0;
-    /* but only make things `0' and never 1 */
-    byte[address] = data;
-    state = byte_programming;
-    break;
-  case byte_programming:
-    if (finished)
-      state = read_reset;
-    else
-      state = byte_programming;
-    break;
+  /* may need multiple transitions to process a write */
+  while (1) {
+    switch (eeprom->state) {
+
+    case read_reset:
+      if (address == 0x5555 && data == 0xaa)
+       eeprom->state = write_nr_2;
+      else if (data == 0xf0)
+       eeprom->state = read_reset;
+      else {
+       invalid_write(me, eeprom->state, address, data, "unexpected");
+       eeprom->state = read_reset;
+      }
+      return;
+
+    case write_nr_2:
+      if (address == 0x2aaa && data == 0x55)
+       eeprom->state = write_nr_3;
+      else {
+       invalid_write(me, eeprom->state, address, data, "unexpected");
+       eeprom->state = read_reset;
+      }
+      return;
+
+    case write_nr_3:
+      if (address == 0x5555 && data == 0xf0)
+       eeprom->state = read_reset;
+      else if (address == 0x5555 && data == 0x90)
+       eeprom->state = autoselect;
+      else if (address == 0x5555 && data == 0xa0) {
+       eeprom->state = byte_program;
+      }
+      else if (address == 0x5555 && data == 0x80)
+       eeprom->state = write_nr_4;
+      else {
+       invalid_write(me, eeprom->state, address, data, "unexpected");
+       eeprom->state = read_reset;
+      }
+      return;
+
+    case write_nr_4:
+      if (address == 0x5555 && data == 0xaa)
+       eeprom->state = write_nr_5;
+      else {
+       invalid_write(me, eeprom->state, address, data, "unexpected");
+       eeprom->state = read_reset;
+      }
+      return;
+
+    case write_nr_5:
+      if (address == 0x2aaa && data == 0x55)
+       eeprom->state = write_nr_6;
+      else {
+       invalid_write(me, eeprom->state, address, data, "unexpected");
+       eeprom->state = read_reset;
+      }
+      return;
+
+    case write_nr_6:
+      if (address == 0x5555 && data == 0x10) {
+       start_erasing_chip(me, eeprom);
+       eeprom->state = chip_erase;
+      }
+      else {
+       start_erasing_sector(me, eeprom, address);
+       eeprom->sector_state = read_reset;
+       eeprom->state = sector_erase;
+      }
+      return;
+
+    case autoselect:
+      if (data == 0xf0)
+       eeprom->state = read_reset;
+      else if (address == 0x5555 && data == 0xaa)
+       eeprom->state = write_nr_2;
+      else {
+       invalid_write(me, eeprom->state, address, data, "unsupported address");
+       eeprom->state = read_reset;
+      }
+      return;
+
+    case byte_program:
+      start_programming_byte(me, eeprom, address, data);
+      eeprom->state = byte_programming;
+      return;
+
+    case byte_programming:
+      if (device_event_queue_time(me) > eeprom->program_finish_time) {
+       finish_programming_byte(me, eeprom);
+       eeprom->state = read_reset;
+       continue;
+      }
+      /* ignore it */
+      return;
+
+    case chip_erase:
+      if (device_event_queue_time(me) > eeprom->program_finish_time) {
+       finish_erasing_chip(me, eeprom);
+       eeprom->state = read_reset;
+       continue;
+      }
+      /* ignore it */
+      return;
+
+    case sector_erase:
+      if (device_event_queue_time(me) > eeprom->program_finish_time) {
+       finish_erasing_sector(me, eeprom);
+       eeprom->state = eeprom->sector_state;
+       continue;
+      }
+      else if (device_event_queue_time(me) > eeprom->sector_start_time
+              && data == 0xb0) {
+       eeprom->sector_state = read_reset;
+       eeprom->state = sector_erase_suspend;
+      }
+      else {
+       if (eeprom->sector_state == read_reset
+           && address == 0x5555 && data == 0xaa)
+         eeprom->sector_state = write_nr_2;
+       else if (eeprom->sector_state == write_nr_2
+                && address == 0x2aaa && data == 0x55)
+         eeprom->sector_state = write_nr_3;
+       else if (eeprom->sector_state == write_nr_3
+                && address == 0x5555 && data == 0x80)
+         eeprom->sector_state = write_nr_4;
+       else if (eeprom->sector_state == write_nr_4
+                && address == 0x5555 && data == 0xaa)
+         eeprom->sector_state = write_nr_5;
+       else if (eeprom->sector_state == write_nr_5
+                && address == 0x2aaa && data == 0x55)
+         eeprom->sector_state = write_nr_6;
+       else if (eeprom->sector_state == write_nr_6
+                && address != 0x5555 && data == 0x30) {
+         if (device_event_queue_time(me) > eeprom->sector_start_time) {
+           DTRACE(eeprom, ("sector erase command after window closed\n"));
+           eeprom->sector_state = read_reset;
+         }
+         else {
+           start_erasing_sector(me, eeprom, address);
+           eeprom->sector_state = read_reset;
+         }
+       }
+       else {
+         invalid_write(me, eeprom->state, address, data, state2a(eeprom->sector_state));
+         eeprom->state = read_reset;
+       }
+      }
+      return;
+
+    case sector_erase_suspend:
+      if (data == 0x30)
+       eeprom->state = sector_erase;
+      else {
+       invalid_write(me, eeprom->state, address, data, "not resume command");
+       eeprom->state = read_reset;
+      }
+      return;
+
+    }
   }
 }
 
 static unsigned
-eeprom_io_write_buffer(device *me,
-                      const void *source,
-                      int space,
-                      unsigned_word addr,
-                      unsigned nr_bytes,
-                      cpu *processor,
-                      unsigned_word cia)
+hw_eeprom_io_write_buffer(device *me,
+                         const void *source,
+                         int space,
+                         unsigned_word addr,
+                         unsigned nr_bytes,
+                         cpu *processor,
+                         unsigned_word cia)
 {
-  eeprom_device *eeprom = (eeprom_device*)device_data(me);
+  hw_eeprom_device *eeprom = (hw_eeprom_device*)device_data(me);
   int i;
   for (i = 0; i < nr_bytes; i++) {
-    unsigned_word address = (addr + nr_bytes) % eeprom->sizeof_memory;
-    eeprom_io_read_byte(address, eeprom->memory[address]);
+    unsigned_word address = (addr + i) % eeprom->sizeof_memory;
+    unsigned8 byte = ((unsigned8*)source)[i];
+    write_byte(me, eeprom, address, byte);
   }
   return nr_bytes;
 }
 
 
+/* An instance of the eeprom */
+
+typedef struct _hw_eeprom_instance {
+  unsigned_word pos;
+  hw_eeprom_device *eeprom;
+  device *me;
+} hw_eeprom_instance;
+
+static void
+hw_eeprom_instance_delete(device_instance *instance)
+{
+  hw_eeprom_instance *data = device_instance_data(instance);
+  zfree(data);
+}
+
+static int
+hw_eeprom_instance_read(device_instance *instance,
+                       void *buf,
+                       unsigned_word len)
+{
+  hw_eeprom_instance *data = device_instance_data(instance);
+  int i;
+  if (data->eeprom->state != read_reset)
+    DITRACE(eeprom, ("eeprom not idle during instance read\n"));
+  for (i = 0; i < len; i++) {
+    ((unsigned8*)buf)[i] = data->eeprom->memory[data->pos];
+    data->pos = (data->pos + 1) % data->eeprom->sizeof_memory;
+  }
+  return len;
+}
 
-static device_callbacks const eeprom_callbacks = {
-  { eeprom_init_address, },
+static int
+hw_eeprom_instance_write(device_instance *instance,
+                        const void *buf,
+                        unsigned_word len)
+{
+  hw_eeprom_instance *data = device_instance_data(instance);
+  int i;
+  if (data->eeprom->state != read_reset)
+    DITRACE(eeprom, ("eeprom not idle during instance write\n"));
+  for (i = 0; i < len; i++) {
+    data->eeprom->memory[data->pos] = ((unsigned8*)buf)[i];
+    data->pos = (data->pos + 1) % data->eeprom->sizeof_memory;
+  }
+  dump_eeprom(data->me, data->eeprom);
+  return len;
+}
+
+static int
+hw_eeprom_instance_seek(device_instance *instance,
+                     unsigned_word pos_hi,
+                     unsigned_word pos_lo)
+{
+  hw_eeprom_instance *data = device_instance_data(instance);
+  if (pos_lo >= data->eeprom->sizeof_memory)
+    device_error(data->me, "seek value 0x%lx out of range\n",
+                (unsigned long)pos_lo);
+  data->pos = pos_lo;
+  return 0;
+}
+
+static const device_instance_callbacks hw_eeprom_instance_callbacks = {
+  hw_eeprom_instance_delete,
+  hw_eeprom_instance_read,
+  hw_eeprom_instance_write,
+  hw_eeprom_instance_seek,
+};
+
+static device_instance *
+hw_eeprom_create_instance(device *me,
+                         const char *path,
+                         const char *args)
+{
+  hw_eeprom_device *eeprom = device_data(me);
+  hw_eeprom_instance *data = ZALLOC(hw_eeprom_instance);
+  data->eeprom = eeprom;
+  data->me = me;
+  return device_create_instance_from(me, NULL,
+                                    data,
+                                    path, args,
+                                    &hw_eeprom_instance_callbacks);
+}
+
+
+
+static device_callbacks const hw_eeprom_callbacks = {
+  { generic_device_init_address,
+    hw_eeprom_init_data },
   { NULL, }, /* address */
-  { eeprom_io_read_buffer, eeprom_io_write_buffer }, /* IO */
+  { hw_eeprom_io_read_buffer,
+    hw_eeprom_io_write_buffer }, /* IO */
+  { NULL, }, /* DMA */
+  { NULL, }, /* interrupt */
+  { NULL, }, /* unit */
+  hw_eeprom_create_instance,
 };
 
-const device_descriptor eeprom_device_descriptor[] = {
-  { "eeprom", eeprom_create, &eeprom_callbacks },
+static void *
+hw_eeprom_create(const char *name,
+                const device_unit *unit_address,
+                const char *args)
+{
+  hw_eeprom_device *eeprom = ZALLOC(hw_eeprom_device);
+  return eeprom;
+}
+
+
+
+const device_descriptor hw_eeprom_device_descriptor[] = {
+  { "eeprom", hw_eeprom_create, &hw_eeprom_callbacks },
   { NULL },
 };
 
This page took 0.033341 seconds and 4 git commands to generate.