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