xref: /netbsd-src/external/gpl3/gdb/dist/sim/m68hc11/dv-m68hc11eepr.c (revision 796c32c94f6e154afc9de0f63da35c91bb739b45)
1 /*  dv-m68hc11eepr.c -- Simulation of the 68HC11 Internal EEPROM.
2     Copyright (C) 1999-2017 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 
68 enum
69 {
70   RESET_PORT
71 };
72 
73 
74 static 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 
85 struct 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 
129 static hw_io_read_buffer_method m68hc11eepr_io_read_buffer;
130 static hw_io_write_buffer_method m68hc11eepr_io_write_buffer;
131 static 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.  */
135 static int
136 m6811eepr_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 
181 static void
182 attach_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 = 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 
231 static void
232 m68hc11eepr_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 
301 static void
302 m68hc11eepr_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 
323 static 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 };
331 extern io_reg_desc config_desc[];
332 
333 
334 /* Describe the state of the EEPROM device.  */
335 static void
336 m68hc11eepr_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 
380 static int
381 m68hc11eepr_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 
391 static unsigned
392 m68hc11eepr_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 
446 static unsigned
447 m68hc11eepr_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 
622 const struct hw_descriptor dv_m68hc11eepr_descriptor[] = {
623   { "m68hc11eepr", m68hc11eepr_finish },
624   { "m68hc12eepr", m68hc11eepr_finish },
625   { NULL },
626 };
627 
628