Home | History | Annotate | Line # | Download | only in m68hc11
      1       1.1  christos /*  dv-m68hc11eepr.c -- Simulation of the 68HC11 Internal EEPROM.
      2  1.1.1.10  christos     Copyright (C) 1999-2024 Free Software Foundation, Inc.
      3       1.1  christos     Written by Stephane Carrez (stcarrez (at) nerim.fr)
      4       1.1  christos     (From a driver model Contributed by Cygnus Solutions.)
      5       1.1  christos 
      6       1.1  christos     This program is free software; you can redistribute it and/or modify
      7       1.1  christos     it under the terms of the GNU General Public License as published by
      8       1.1  christos     the Free Software Foundation; either version 3 of the License, or
      9       1.1  christos     (at your option) any later version.
     10       1.1  christos 
     11       1.1  christos     This program is distributed in the hope that it will be useful,
     12       1.1  christos     but WITHOUT ANY WARRANTY; without even the implied warranty of
     13       1.1  christos     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14       1.1  christos     GNU General Public License for more details.
     15       1.1  christos 
     16       1.1  christos     You should have received a copy of the GNU General Public License
     17       1.1  christos     along with this program.  If not, see <http://www.gnu.org/licenses/>.
     18       1.1  christos 
     19       1.1  christos     */
     20       1.1  christos 
     21   1.1.1.9  christos /* This must come before any other includes.  */
     22   1.1.1.9  christos #include "defs.h"
     23       1.1  christos 
     24       1.1  christos #include "sim-main.h"
     25       1.1  christos #include "hw-main.h"
     26       1.1  christos #include "sim-assert.h"
     27       1.1  christos #include "sim-events.h"
     28   1.1.1.9  christos #include "sim-signal.h"
     29       1.1  christos 
     30       1.1  christos #include <unistd.h>
     31       1.1  christos #include <fcntl.h>
     32       1.1  christos #include <errno.h>
     33       1.1  christos 
     34  1.1.1.10  christos #include "m68hc11-sim.h"
     35       1.1  christos 
     36       1.1  christos /* DEVICE
     37       1.1  christos 
     38       1.1  christos         m68hc11eepr - m68hc11 EEPROM
     39       1.1  christos 
     40       1.1  christos 
     41       1.1  christos    DESCRIPTION
     42       1.1  christos 
     43       1.1  christos         Implements the 68HC11 eeprom device described in the m68hc11
     44       1.1  christos         user guide (Chapter 4 in the pink book).
     45       1.1  christos 
     46       1.1  christos 
     47       1.1  christos    PROPERTIES
     48       1.1  christos 
     49       1.1  christos    reg <base> <length>
     50       1.1  christos 
     51       1.1  christos         Base of eeprom and its length.
     52       1.1  christos 
     53       1.1  christos    file <path>
     54       1.1  christos 
     55       1.1  christos         Path of the EEPROM file.  The default is 'm6811.eeprom'.
     56       1.1  christos 
     57       1.1  christos 
     58       1.1  christos    PORTS
     59       1.1  christos 
     60       1.1  christos         None
     61       1.1  christos 
     62       1.1  christos    */
     63       1.1  christos 
     64       1.1  christos 
     65       1.1  christos 
     66       1.1  christos /* static functions */
     67       1.1  christos 
     68       1.1  christos 
     69       1.1  christos /* port ID's */
     70       1.1  christos 
     71       1.1  christos enum
     72       1.1  christos {
     73       1.1  christos   RESET_PORT
     74       1.1  christos };
     75       1.1  christos 
     76       1.1  christos 
     77       1.1  christos static const struct hw_port_descriptor m68hc11eepr_ports[] =
     78       1.1  christos {
     79       1.1  christos   { "reset", RESET_PORT, 0, input_port, },
     80       1.1  christos   { NULL, },
     81       1.1  christos };
     82       1.1  christos 
     83       1.1  christos 
     84       1.1  christos 
     85       1.1  christos /* The timer/counter register internal state.  Note that we store
     86       1.1  christos    state using the control register images, in host endian order.  */
     87       1.1  christos 
     88       1.1  christos struct m68hc11eepr
     89       1.1  christos {
     90       1.1  christos   address_word  base_address; /* control register base */
     91       1.1  christos   int           attach_space;
     92       1.1  christos   unsigned      size;
     93       1.1  christos   int           mapped;
     94       1.1  christos 
     95       1.1  christos   /* Current state of the eeprom programing:
     96       1.1  christos      - eeprom_wmode indicates whether the EEPROM address and byte have
     97       1.1  christos        been latched.
     98       1.1  christos      - eeprom_waddr indicates the EEPROM address that was latched
     99       1.1  christos        and eeprom_wbyte is the byte that was latched.
    100       1.1  christos      - eeprom_wcycle indicates the CPU absolute cycle type when
    101       1.1  christos        the high voltage was applied (successfully) on the EEPROM.
    102       1.1  christos 
    103       1.1  christos      These data members are setup only when we detect good EEPROM programing
    104       1.1  christos      conditions (see Motorola EEPROM Programming and PPROG register usage).
    105       1.1  christos      When the high voltage is switched off, we look at the CPU absolute
    106       1.1  christos      cycle time to see if the EEPROM command must succeeds or not.
    107       1.1  christos      The EEPROM content is updated and saved only at that time.
    108       1.1  christos      (EEPROM command is: byte zero bits program, byte erase, row erase
    109       1.1  christos      and bulk erase).
    110       1.1  christos 
    111       1.1  christos      The CONFIG register is programmed in the same way.  It is physically
    112       1.1  christos      located at the end of the EEPROM (eeprom size + 1).  It is not mapped
    113       1.1  christos      in memory but it's saved in the EEPROM file.  */
    114       1.1  christos   unsigned long		eeprom_wcycle;
    115   1.1.1.9  christos   uint16_t		eeprom_waddr;
    116   1.1.1.9  christos   uint8_t			eeprom_wbyte;
    117   1.1.1.9  christos   uint8_t			eeprom_wmode;
    118       1.1  christos 
    119   1.1.1.9  christos   uint8_t*		eeprom;
    120       1.1  christos 
    121       1.1  christos   /* Minimum time in CPU cycles for programming the EEPROM.  */
    122       1.1  christos   unsigned long         eeprom_min_cycles;
    123       1.1  christos 
    124       1.1  christos   const char*           file_name;
    125       1.1  christos };
    126       1.1  christos 
    127       1.1  christos 
    128       1.1  christos 
    129       1.1  christos /* Finish off the partially created hw device.  Attach our local
    130       1.1  christos    callbacks.  Wire up our port names etc.  */
    131       1.1  christos 
    132       1.1  christos static hw_io_read_buffer_method m68hc11eepr_io_read_buffer;
    133       1.1  christos static hw_io_write_buffer_method m68hc11eepr_io_write_buffer;
    134       1.1  christos static hw_ioctl_method m68hc11eepr_ioctl;
    135       1.1  christos 
    136       1.1  christos /* Read or write the memory bank content from/to a file.
    137       1.1  christos    Returns 0 if the operation succeeded and -1 if it failed.  */
    138       1.1  christos static int
    139       1.1  christos m6811eepr_memory_rw (struct m68hc11eepr *controller, int mode)
    140       1.1  christos {
    141       1.1  christos   const char *name = controller->file_name;
    142       1.1  christos   int fd;
    143       1.1  christos   size_t size;
    144       1.1  christos 
    145       1.1  christos   size = controller->size;
    146       1.1  christos   fd = open (name, mode, 0644);
    147       1.1  christos   if (fd < 0)
    148       1.1  christos     {
    149       1.1  christos       if (mode == O_RDONLY)
    150       1.1  christos         {
    151       1.1  christos           memset (controller->eeprom, 0xFF, size);
    152       1.1  christos           /* Default value for CONFIG register (0xFF should be ok):
    153       1.1  christos              controller->eeprom[size - 1] = M6811_NOSEC | M6811_NOCOP
    154       1.1  christos                                             | M6811_ROMON | M6811_EEON;  */
    155       1.1  christos           return 0;
    156       1.1  christos         }
    157       1.1  christos       return -1;
    158       1.1  christos     }
    159       1.1  christos 
    160       1.1  christos   if (mode == O_RDONLY)
    161       1.1  christos     {
    162       1.1  christos       if (read (fd, controller->eeprom, size) != size)
    163       1.1  christos 	{
    164       1.1  christos 	  close (fd);
    165       1.1  christos 	  return -1;
    166       1.1  christos 	}
    167       1.1  christos     }
    168       1.1  christos   else
    169       1.1  christos     {
    170       1.1  christos       if (write (fd, controller->eeprom, size) != size)
    171       1.1  christos 	{
    172       1.1  christos 	  close (fd);
    173       1.1  christos 	  return -1;
    174       1.1  christos 	}
    175       1.1  christos     }
    176       1.1  christos   close (fd);
    177       1.1  christos 
    178       1.1  christos   return 0;
    179       1.1  christos }
    180       1.1  christos 
    181       1.1  christos 
    182       1.1  christos 
    183       1.1  christos 
    184       1.1  christos static void
    185       1.1  christos attach_m68hc11eepr_regs (struct hw *me,
    186       1.1  christos                          struct m68hc11eepr *controller)
    187       1.1  christos {
    188       1.1  christos   unsigned_word attach_address;
    189       1.1  christos   int attach_space;
    190       1.1  christos   unsigned attach_size;
    191       1.1  christos   reg_property_spec reg;
    192       1.1  christos 
    193       1.1  christos   if (hw_find_property (me, "reg") == NULL)
    194       1.1  christos     hw_abort (me, "Missing \"reg\" property");
    195       1.1  christos 
    196       1.1  christos   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    197       1.1  christos     hw_abort (me, "\"reg\" property must contain one addr/size entry");
    198       1.1  christos 
    199       1.1  christos   hw_unit_address_to_attach_address (hw_parent (me),
    200       1.1  christos 				     &reg.address,
    201       1.1  christos 				     &attach_space,
    202       1.1  christos 				     &attach_address,
    203       1.1  christos 				     me);
    204       1.1  christos   hw_unit_size_to_attach_size (hw_parent (me),
    205       1.1  christos 			       &reg.size,
    206       1.1  christos 			       &attach_size, me);
    207       1.1  christos 
    208       1.1  christos   /* Attach the two IO registers that control the EEPROM.
    209       1.1  christos      The EEPROM is only attached at reset time because it may
    210       1.1  christos      be enabled/disabled by the EEON bit in the CONFIG register.  */
    211       1.1  christos   hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
    212       1.1  christos                      io_map, M6811_PPROG, 1, me);
    213       1.1  christos   hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
    214       1.1  christos                      io_map, M6811_CONFIG, 1, me);
    215       1.1  christos 
    216       1.1  christos   if (hw_find_property (me, "file") == NULL)
    217       1.1  christos     controller->file_name = "m6811.eeprom";
    218       1.1  christos   else
    219       1.1  christos     controller->file_name = hw_find_string_property (me, "file");
    220       1.1  christos 
    221       1.1  christos   controller->attach_space = attach_space;
    222       1.1  christos   controller->base_address = attach_address;
    223   1.1.1.6  christos   controller->eeprom = hw_malloc (me, attach_size + 1);
    224       1.1  christos   controller->eeprom_min_cycles = 10000;
    225       1.1  christos   controller->size = attach_size + 1;
    226       1.1  christos   controller->mapped = 0;
    227       1.1  christos 
    228       1.1  christos   m6811eepr_memory_rw (controller, O_RDONLY);
    229       1.1  christos }
    230       1.1  christos 
    231       1.1  christos 
    232       1.1  christos /* An event arrives on an interrupt port.  */
    233       1.1  christos 
    234       1.1  christos static void
    235       1.1  christos m68hc11eepr_port_event (struct hw *me,
    236       1.1  christos                         int my_port,
    237       1.1  christos                         struct hw *source,
    238       1.1  christos                         int source_port,
    239       1.1  christos                         int level)
    240       1.1  christos {
    241       1.1  christos   SIM_DESC sd;
    242       1.1  christos   struct m68hc11eepr *controller;
    243       1.1  christos   sim_cpu *cpu;
    244  1.1.1.10  christos   struct m68hc11_sim_cpu *m68hc11_cpu;
    245       1.1  christos 
    246       1.1  christos   controller = hw_data (me);
    247       1.1  christos   sd         = hw_system (me);
    248       1.1  christos   cpu        = STATE_CPU (sd, 0);
    249  1.1.1.10  christos   m68hc11_cpu  = M68HC11_SIM_CPU (cpu);
    250       1.1  christos   switch (my_port)
    251       1.1  christos     {
    252       1.1  christos     case RESET_PORT:
    253       1.1  christos       {
    254       1.1  christos 	HW_TRACE ((me, "EEPROM reset"));
    255       1.1  christos 
    256       1.1  christos         /* Re-read the EEPROM from the file.  This gives the chance
    257       1.1  christos            to users to erase this file before doing a reset and have
    258       1.1  christos            a fresh EEPROM taken into account.  */
    259       1.1  christos         m6811eepr_memory_rw (controller, O_RDONLY);
    260       1.1  christos 
    261       1.1  christos         /* Reset the state of EEPROM programmer.  The CONFIG register
    262       1.1  christos            is also initialized from the EEPROM/file content.  */
    263  1.1.1.10  christos         m68hc11_cpu->ios[M6811_PPROG]    = 0;
    264  1.1.1.10  christos         if (m68hc11_cpu->cpu_use_local_config)
    265  1.1.1.10  christos           m68hc11_cpu->ios[M6811_CONFIG] = m68hc11_cpu->cpu_config;
    266       1.1  christos         else
    267  1.1.1.10  christos           m68hc11_cpu->ios[M6811_CONFIG]   = controller->eeprom[controller->size-1];
    268       1.1  christos         controller->eeprom_wmode = 0;
    269       1.1  christos         controller->eeprom_waddr = 0;
    270       1.1  christos         controller->eeprom_wbyte = 0;
    271       1.1  christos 
    272       1.1  christos         /* Attach or detach to the bus depending on the EEPROM enable bit.
    273       1.1  christos            The EEPROM CONFIG register is still enabled and can be programmed
    274       1.1  christos            for a next configuration (taken into account only after a reset,
    275       1.1  christos            see Motorola spec).  */
    276  1.1.1.10  christos         if (!(m68hc11_cpu->ios[M6811_CONFIG] & M6811_EEON))
    277       1.1  christos           {
    278       1.1  christos             if (controller->mapped)
    279       1.1  christos               hw_detach_address (hw_parent (me), M6811_EEPROM_LEVEL,
    280       1.1  christos                                  controller->attach_space,
    281       1.1  christos                                  controller->base_address,
    282       1.1  christos                                  controller->size - 1,
    283       1.1  christos                                  me);
    284       1.1  christos             controller->mapped = 0;
    285       1.1  christos           }
    286       1.1  christos         else
    287       1.1  christos           {
    288       1.1  christos             if (!controller->mapped)
    289       1.1  christos               hw_attach_address (hw_parent (me), M6811_EEPROM_LEVEL,
    290       1.1  christos                                  controller->attach_space,
    291       1.1  christos                                  controller->base_address,
    292       1.1  christos                                  controller->size - 1,
    293       1.1  christos                                  me);
    294       1.1  christos             controller->mapped = 1;
    295       1.1  christos           }
    296       1.1  christos         break;
    297       1.1  christos       }
    298       1.1  christos 
    299       1.1  christos     default:
    300       1.1  christos       hw_abort (me, "Event on unknown port %d", my_port);
    301       1.1  christos       break;
    302       1.1  christos     }
    303       1.1  christos }
    304       1.1  christos 
    305       1.1  christos 
    306       1.1  christos static void
    307       1.1  christos m68hc11eepr_finish (struct hw *me)
    308       1.1  christos {
    309       1.1  christos   struct m68hc11eepr *controller;
    310       1.1  christos 
    311       1.1  christos   controller = HW_ZALLOC (me, struct m68hc11eepr);
    312       1.1  christos   set_hw_data (me, controller);
    313       1.1  christos   set_hw_io_read_buffer (me, m68hc11eepr_io_read_buffer);
    314       1.1  christos   set_hw_io_write_buffer (me, m68hc11eepr_io_write_buffer);
    315       1.1  christos   set_hw_ports (me, m68hc11eepr_ports);
    316       1.1  christos   set_hw_port_event (me, m68hc11eepr_port_event);
    317       1.1  christos #ifdef set_hw_ioctl
    318       1.1  christos   set_hw_ioctl (me, m68hc11eepr_ioctl);
    319       1.1  christos #else
    320       1.1  christos   me->to_ioctl = m68hc11eepr_ioctl;
    321       1.1  christos #endif
    322       1.1  christos 
    323       1.1  christos   attach_m68hc11eepr_regs (me, controller);
    324       1.1  christos }
    325       1.1  christos 
    326       1.1  christos 
    327       1.1  christos 
    328       1.1  christos static io_reg_desc pprog_desc[] = {
    329       1.1  christos   { M6811_BYTE,  "BYTE  ", "Byte Program Mode" },
    330       1.1  christos   { M6811_ROW,   "ROW   ", "Row Program Mode" },
    331       1.1  christos   { M6811_ERASE, "ERASE ", "Erase Mode" },
    332       1.1  christos   { M6811_EELAT, "EELAT ", "EEProm Latch Control" },
    333       1.1  christos   { M6811_EEPGM, "EEPGM ", "EEProm Programming Voltable Enable" },
    334       1.1  christos   { 0,  0, 0 }
    335       1.1  christos };
    336       1.1  christos extern io_reg_desc config_desc[];
    337       1.1  christos 
    338       1.1  christos 
    339       1.1  christos /* Describe the state of the EEPROM device.  */
    340       1.1  christos static void
    341       1.1  christos m68hc11eepr_info (struct hw *me)
    342       1.1  christos {
    343       1.1  christos   SIM_DESC sd;
    344   1.1.1.9  christos   uint16_t base = 0;
    345       1.1  christos   sim_cpu *cpu;
    346  1.1.1.10  christos   struct m68hc11_sim_cpu *m68hc11_cpu;
    347       1.1  christos   struct m68hc11eepr *controller;
    348   1.1.1.9  christos   uint8_t val;
    349       1.1  christos 
    350       1.1  christos   sd         = hw_system (me);
    351       1.1  christos   cpu        = STATE_CPU (sd, 0);
    352  1.1.1.10  christos   m68hc11_cpu  = M68HC11_SIM_CPU (cpu);
    353       1.1  christos   controller = hw_data (me);
    354       1.1  christos   base       = cpu_get_io_base (cpu);
    355       1.1  christos 
    356       1.1  christos   sim_io_printf (sd, "M68HC11 EEprom:\n");
    357       1.1  christos 
    358  1.1.1.10  christos   val = m68hc11_cpu->ios[M6811_PPROG];
    359       1.1  christos   print_io_byte (sd, "PPROG  ", pprog_desc, val, base + M6811_PPROG);
    360       1.1  christos   sim_io_printf (sd, "\n");
    361       1.1  christos 
    362  1.1.1.10  christos   val = m68hc11_cpu->ios[M6811_CONFIG];
    363       1.1  christos   print_io_byte (sd, "CONFIG ", config_desc, val, base + M6811_CONFIG);
    364       1.1  christos   sim_io_printf (sd, "\n");
    365       1.1  christos 
    366       1.1  christos   val = controller->eeprom[controller->size - 1];
    367       1.1  christos   print_io_byte (sd, "(*NEXT*) ", config_desc, val, base + M6811_CONFIG);
    368       1.1  christos   sim_io_printf (sd, "\n");
    369       1.1  christos 
    370       1.1  christos   /* Describe internal state of EEPROM.  */
    371       1.1  christos   if (controller->eeprom_wmode)
    372       1.1  christos     {
    373       1.1  christos       if (controller->eeprom_waddr == controller->size - 1)
    374       1.1  christos         sim_io_printf (sd, "  Programming CONFIG register ");
    375       1.1  christos       else
    376       1.1  christos         sim_io_printf (sd, "  Programming: 0x%04x ",
    377       1.1  christos                        controller->eeprom_waddr + controller->base_address);
    378       1.1  christos 
    379       1.1  christos       sim_io_printf (sd, "with 0x%02x\n",
    380       1.1  christos 		     controller->eeprom_wbyte);
    381       1.1  christos     }
    382       1.1  christos 
    383       1.1  christos   sim_io_printf (sd, "  EEProm file: %s\n",
    384       1.1  christos                  controller->file_name);
    385       1.1  christos }
    386       1.1  christos 
    387       1.1  christos static int
    388       1.1  christos m68hc11eepr_ioctl (struct hw *me,
    389       1.1  christos 		   hw_ioctl_request request,
    390       1.1  christos 		   va_list ap)
    391       1.1  christos {
    392       1.1  christos   m68hc11eepr_info (me);
    393       1.1  christos   return 0;
    394       1.1  christos }
    395       1.1  christos 
    396       1.1  christos /* generic read/write */
    397       1.1  christos 
    398       1.1  christos static unsigned
    399       1.1  christos m68hc11eepr_io_read_buffer (struct hw *me,
    400       1.1  christos 			    void *dest,
    401       1.1  christos 			    int space,
    402       1.1  christos 			    unsigned_word base,
    403       1.1  christos 			    unsigned nr_bytes)
    404       1.1  christos {
    405       1.1  christos   SIM_DESC sd;
    406       1.1  christos   struct m68hc11eepr *controller;
    407       1.1  christos   sim_cpu *cpu;
    408  1.1.1.10  christos   struct m68hc11_sim_cpu *m68hc11_cpu;
    409       1.1  christos 
    410       1.1  christos   HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
    411       1.1  christos 
    412       1.1  christos   sd         = hw_system (me);
    413       1.1  christos   controller = hw_data (me);
    414       1.1  christos   cpu        = STATE_CPU (sd, 0);
    415  1.1.1.10  christos   m68hc11_cpu  = M68HC11_SIM_CPU (cpu);
    416       1.1  christos 
    417       1.1  christos   if (space == io_map)
    418       1.1  christos     {
    419       1.1  christos       unsigned cnt = 0;
    420       1.1  christos 
    421       1.1  christos       while (nr_bytes != 0)
    422       1.1  christos         {
    423       1.1  christos           switch (base)
    424       1.1  christos             {
    425       1.1  christos             case M6811_PPROG:
    426       1.1  christos             case M6811_CONFIG:
    427  1.1.1.10  christos               *((uint8_t*) dest) = m68hc11_cpu->ios[base];
    428       1.1  christos               break;
    429       1.1  christos 
    430       1.1  christos             default:
    431       1.1  christos               hw_abort (me, "reading wrong register 0x%04x", base);
    432       1.1  christos             }
    433   1.1.1.9  christos           dest = (uint8_t*) (dest) + 1;
    434       1.1  christos           base++;
    435       1.1  christos           nr_bytes--;
    436       1.1  christos           cnt++;
    437       1.1  christos         }
    438       1.1  christos       return cnt;
    439       1.1  christos     }
    440       1.1  christos 
    441       1.1  christos   /* In theory, we can't read the EEPROM when it's being programmed.  */
    442  1.1.1.10  christos   if ((m68hc11_cpu->ios[M6811_PPROG] & M6811_EELAT) != 0
    443       1.1  christos       && cpu_is_running (cpu))
    444       1.1  christos     {
    445       1.1  christos       sim_memory_error (cpu, SIM_SIGBUS, base,
    446       1.1  christos 			"EEprom not configured for reading");
    447       1.1  christos     }
    448       1.1  christos 
    449       1.1  christos   base = base - controller->base_address;
    450       1.1  christos   memcpy (dest, &controller->eeprom[base], nr_bytes);
    451       1.1  christos   return nr_bytes;
    452       1.1  christos }
    453       1.1  christos 
    454       1.1  christos 
    455       1.1  christos static unsigned
    456       1.1  christos m68hc11eepr_io_write_buffer (struct hw *me,
    457       1.1  christos 			     const void *source,
    458       1.1  christos 			     int space,
    459       1.1  christos 			     unsigned_word base,
    460       1.1  christos 			     unsigned nr_bytes)
    461       1.1  christos {
    462       1.1  christos   SIM_DESC sd;
    463       1.1  christos   struct m68hc11eepr *controller;
    464       1.1  christos   sim_cpu *cpu;
    465  1.1.1.10  christos   struct m68hc11_sim_cpu *m68hc11_cpu;
    466   1.1.1.9  christos   uint8_t val;
    467       1.1  christos 
    468       1.1  christos   HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
    469       1.1  christos 
    470       1.1  christos   sd         = hw_system (me);
    471       1.1  christos   controller = hw_data (me);
    472       1.1  christos   cpu        = STATE_CPU (sd, 0);
    473  1.1.1.10  christos   m68hc11_cpu  = M68HC11_SIM_CPU (cpu);
    474       1.1  christos 
    475       1.1  christos   /* Programming several bytes at a time is not possible.  */
    476       1.1  christos   if (space != io_map && nr_bytes != 1)
    477       1.1  christos     {
    478       1.1  christos       sim_memory_error (cpu, SIM_SIGBUS, base,
    479       1.1  christos 			"EEprom write error (only 1 byte can be programmed)");
    480       1.1  christos       return 0;
    481       1.1  christos     }
    482       1.1  christos 
    483       1.1  christos   if (nr_bytes != 1)
    484       1.1  christos     hw_abort (me, "Cannot write more than 1 byte to EEPROM device at a time");
    485       1.1  christos 
    486   1.1.1.9  christos   val = *((const uint8_t*) source);
    487       1.1  christos 
    488       1.1  christos   /* Write to the EEPROM control register.  */
    489       1.1  christos   if (space == io_map && base == M6811_PPROG)
    490       1.1  christos     {
    491   1.1.1.9  christos       uint8_t wrong_bits;
    492   1.1.1.9  christos       uint16_t addr;
    493       1.1  christos 
    494       1.1  christos       addr = base + cpu_get_io_base (cpu);
    495       1.1  christos 
    496       1.1  christos       /* Setting EELAT and EEPGM at the same time is an error.
    497       1.1  christos          Clearing them both is ok.  */
    498  1.1.1.10  christos       wrong_bits = (m68hc11_cpu->ios[M6811_PPROG] ^ val) & val;
    499       1.1  christos       wrong_bits &= (M6811_EELAT | M6811_EEPGM);
    500       1.1  christos 
    501       1.1  christos       if (wrong_bits == (M6811_EEPGM|M6811_EELAT))
    502       1.1  christos 	{
    503       1.1  christos 	  sim_memory_error (cpu, SIM_SIGBUS, addr,
    504       1.1  christos 			    "Wrong eeprom programing value");
    505       1.1  christos 	  return 0;
    506       1.1  christos 	}
    507       1.1  christos 
    508       1.1  christos       if ((val & M6811_EELAT) == 0)
    509       1.1  christos 	{
    510       1.1  christos 	  val = 0;
    511       1.1  christos 	}
    512  1.1.1.10  christos       if ((val & M6811_EEPGM) && !(m68hc11_cpu->ios[M6811_PPROG] & M6811_EELAT))
    513       1.1  christos 	{
    514       1.1  christos 	  sim_memory_error (cpu, SIM_SIGBUS, addr,
    515       1.1  christos 			    "EEProm high voltage applied after EELAT");
    516       1.1  christos 	}
    517       1.1  christos       if ((val & M6811_EEPGM) && controller->eeprom_wmode == 0)
    518       1.1  christos 	{
    519       1.1  christos 	  sim_memory_error (cpu, SIM_SIGSEGV, addr,
    520       1.1  christos 			    "EEProm high voltage applied without address");
    521       1.1  christos 	}
    522       1.1  christos       if (val & M6811_EEPGM)
    523       1.1  christos 	{
    524       1.1  christos 	  controller->eeprom_wcycle = cpu_current_cycle (cpu);
    525       1.1  christos 	}
    526  1.1.1.10  christos       else if (m68hc11_cpu->ios[M6811_PPROG] & M6811_PPROG)
    527       1.1  christos 	{
    528       1.1  christos 	  int i;
    529       1.1  christos 	  unsigned long t = cpu_current_cycle (cpu);
    530       1.1  christos 
    531       1.1  christos 	  t -= controller->eeprom_wcycle;
    532       1.1  christos 	  if (t < controller->eeprom_min_cycles)
    533       1.1  christos 	    {
    534       1.1  christos 	      sim_memory_error (cpu, SIM_SIGILL, addr,
    535       1.1  christos 				"EEprom programmed only for %lu cycles",
    536       1.1  christos 				t);
    537       1.1  christos 	    }
    538       1.1  christos 
    539       1.1  christos 	  /* Program the byte by clearing some bits.  */
    540  1.1.1.10  christos 	  if (!(m68hc11_cpu->ios[M6811_PPROG] & M6811_ERASE))
    541       1.1  christos 	    {
    542       1.1  christos 	      controller->eeprom[controller->eeprom_waddr]
    543       1.1  christos 		&= controller->eeprom_wbyte;
    544       1.1  christos 	    }
    545       1.1  christos 
    546       1.1  christos 	  /* Erase a byte, row or the complete eeprom.  Erased value is 0xFF.
    547       1.1  christos              Ignore row or complete eeprom erase when we are programming the
    548       1.1  christos              CONFIG register (last EEPROM byte).  */
    549  1.1.1.10  christos 	  else if ((m68hc11_cpu->ios[M6811_PPROG] & M6811_BYTE)
    550       1.1  christos                    || controller->eeprom_waddr == controller->size - 1)
    551       1.1  christos 	    {
    552       1.1  christos 	      controller->eeprom[controller->eeprom_waddr] = 0xff;
    553       1.1  christos 	    }
    554  1.1.1.10  christos 	  else if (m68hc11_cpu->ios[M6811_BYTE] & M6811_ROW)
    555       1.1  christos 	    {
    556       1.1  christos               size_t max_size;
    557       1.1  christos 
    558       1.1  christos               /* Size of EEPROM (-1 because the last byte is the
    559       1.1  christos                  CONFIG register.  */
    560       1.1  christos               max_size = controller->size;
    561       1.1  christos 	      controller->eeprom_waddr &= 0xFFF0;
    562       1.1  christos 	      for (i = 0; i < 16
    563       1.1  christos                      && controller->eeprom_waddr < max_size; i++)
    564       1.1  christos 		{
    565       1.1  christos 		  controller->eeprom[controller->eeprom_waddr] = 0xff;
    566       1.1  christos 		  controller->eeprom_waddr ++;
    567       1.1  christos 		}
    568       1.1  christos 	    }
    569       1.1  christos 	  else
    570       1.1  christos 	    {
    571       1.1  christos               size_t max_size;
    572       1.1  christos 
    573       1.1  christos               max_size = controller->size;
    574       1.1  christos 	      for (i = 0; i < max_size; i++)
    575       1.1  christos 		{
    576       1.1  christos 		  controller->eeprom[i] = 0xff;
    577       1.1  christos 		}
    578       1.1  christos 	    }
    579       1.1  christos 
    580       1.1  christos 	  /* Save the eeprom in a file.  We have to save after each
    581       1.1  christos 	     change because the simulator can be stopped or crash...  */
    582       1.1  christos 	  if (m6811eepr_memory_rw (controller, O_WRONLY | O_CREAT) != 0)
    583       1.1  christos 	    {
    584       1.1  christos 	      sim_memory_error (cpu, SIM_SIGABRT, addr,
    585       1.1  christos 				"EEPROM programing failed: errno=%d", errno);
    586       1.1  christos 	    }
    587       1.1  christos 	  controller->eeprom_wmode = 0;
    588       1.1  christos 	}
    589  1.1.1.10  christos       m68hc11_cpu->ios[M6811_PPROG] = val;
    590       1.1  christos       return 1;
    591       1.1  christos     }
    592       1.1  christos 
    593       1.1  christos   /* The CONFIG IO register is mapped at end of EEPROM.
    594       1.1  christos      It's not visible.  */
    595       1.1  christos   if (space == io_map && base == M6811_CONFIG)
    596       1.1  christos     {
    597       1.1  christos       base = controller->size - 1;
    598       1.1  christos     }
    599       1.1  christos   else
    600       1.1  christos     {
    601       1.1  christos       base = base - controller->base_address;
    602       1.1  christos     }
    603       1.1  christos 
    604       1.1  christos   /* Writing the memory is allowed for the Debugger or simulator
    605       1.1  christos      (cpu not running).  */
    606       1.1  christos   if (cpu_is_running (cpu))
    607       1.1  christos     {
    608  1.1.1.10  christos       if ((m68hc11_cpu->ios[M6811_PPROG] & M6811_EELAT) == 0)
    609       1.1  christos 	{
    610       1.1  christos 	  sim_memory_error (cpu, SIM_SIGSEGV, base,
    611       1.1  christos 			    "EEprom not configured for writing");
    612       1.1  christos 	  return 0;
    613       1.1  christos 	}
    614       1.1  christos       if (controller->eeprom_wmode != 0)
    615       1.1  christos 	{
    616       1.1  christos 	  sim_memory_error (cpu, SIM_SIGSEGV, base,
    617       1.1  christos 			    "EEprom write error");
    618       1.1  christos 	  return 0;
    619       1.1  christos 	}
    620       1.1  christos       controller->eeprom_wmode = 1;
    621       1.1  christos       controller->eeprom_waddr = base;
    622       1.1  christos       controller->eeprom_wbyte = val;
    623       1.1  christos     }
    624       1.1  christos   else
    625       1.1  christos     {
    626       1.1  christos       controller->eeprom[base] = val;
    627       1.1  christos       m6811eepr_memory_rw (controller, O_WRONLY);
    628       1.1  christos     }
    629       1.1  christos 
    630       1.1  christos   return 1;
    631       1.1  christos }
    632       1.1  christos 
    633       1.1  christos const struct hw_descriptor dv_m68hc11eepr_descriptor[] = {
    634       1.1  christos   { "m68hc11eepr", m68hc11eepr_finish },
    635       1.1  christos   { "m68hc12eepr", m68hc11eepr_finish },
    636       1.1  christos   { NULL },
    637       1.1  christos };
    638       1.1  christos 
    639