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