packaging: Add python3-base dependency
[platform/upstream/gdb.git] / sim / m68hc11 / dv-m68hc11eepr.c
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