]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/m68hc11/dv-m68hc11eepr.c
a0d2b6110a3f8e24187508d4361ae4207c379b1d
[thirdparty/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11eepr.c
1 /* dv-m68hc11eepr.c -- Simulation of the 68HC11 Internal EEPROM.
2 Copyright (C) 1999-2020 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