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