sim: moxie: move arch-specific file compilation to top-level
[binutils-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 #include "m68hc11-sim.h"
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 struct m68hc11_sim_cpu *m68hc11_cpu;
245
246 controller = hw_data (me);
247 sd = hw_system (me);
248 cpu = STATE_CPU (sd, 0);
249 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
250 switch (my_port)
251 {
252 case RESET_PORT:
253 {
254 HW_TRACE ((me, "EEPROM reset"));
255
256 /* Re-read the EEPROM from the file. This gives the chance
257 to users to erase this file before doing a reset and have
258 a fresh EEPROM taken into account. */
259 m6811eepr_memory_rw (controller, O_RDONLY);
260
261 /* Reset the state of EEPROM programmer. The CONFIG register
262 is also initialized from the EEPROM/file content. */
263 m68hc11_cpu->ios[M6811_PPROG] = 0;
264 if (m68hc11_cpu->cpu_use_local_config)
265 m68hc11_cpu->ios[M6811_CONFIG] = m68hc11_cpu->cpu_config;
266 else
267 m68hc11_cpu->ios[M6811_CONFIG] = controller->eeprom[controller->size-1];
268 controller->eeprom_wmode = 0;
269 controller->eeprom_waddr = 0;
270 controller->eeprom_wbyte = 0;
271
272 /* Attach or detach to the bus depending on the EEPROM enable bit.
273 The EEPROM CONFIG register is still enabled and can be programmed
274 for a next configuration (taken into account only after a reset,
275 see Motorola spec). */
276 if (!(m68hc11_cpu->ios[M6811_CONFIG] & M6811_EEON))
277 {
278 if (controller->mapped)
279 hw_detach_address (hw_parent (me), M6811_EEPROM_LEVEL,
280 controller->attach_space,
281 controller->base_address,
282 controller->size - 1,
283 me);
284 controller->mapped = 0;
285 }
286 else
287 {
288 if (!controller->mapped)
289 hw_attach_address (hw_parent (me), M6811_EEPROM_LEVEL,
290 controller->attach_space,
291 controller->base_address,
292 controller->size - 1,
293 me);
294 controller->mapped = 1;
295 }
296 break;
297 }
298
299 default:
300 hw_abort (me, "Event on unknown port %d", my_port);
301 break;
302 }
303 }
304
305
306 static void
307 m68hc11eepr_finish (struct hw *me)
308 {
309 struct m68hc11eepr *controller;
310
311 controller = HW_ZALLOC (me, struct m68hc11eepr);
312 set_hw_data (me, controller);
313 set_hw_io_read_buffer (me, m68hc11eepr_io_read_buffer);
314 set_hw_io_write_buffer (me, m68hc11eepr_io_write_buffer);
315 set_hw_ports (me, m68hc11eepr_ports);
316 set_hw_port_event (me, m68hc11eepr_port_event);
317 #ifdef set_hw_ioctl
318 set_hw_ioctl (me, m68hc11eepr_ioctl);
319 #else
320 me->to_ioctl = m68hc11eepr_ioctl;
321 #endif
322
323 attach_m68hc11eepr_regs (me, controller);
324 }
325
326
327
328 static io_reg_desc pprog_desc[] = {
329 { M6811_BYTE, "BYTE ", "Byte Program Mode" },
330 { M6811_ROW, "ROW ", "Row Program Mode" },
331 { M6811_ERASE, "ERASE ", "Erase Mode" },
332 { M6811_EELAT, "EELAT ", "EEProm Latch Control" },
333 { M6811_EEPGM, "EEPGM ", "EEProm Programming Voltable Enable" },
334 { 0, 0, 0 }
335 };
336 extern io_reg_desc config_desc[];
337
338
339 /* Describe the state of the EEPROM device. */
340 static void
341 m68hc11eepr_info (struct hw *me)
342 {
343 SIM_DESC sd;
344 uint16_t base = 0;
345 sim_cpu *cpu;
346 struct m68hc11_sim_cpu *m68hc11_cpu;
347 struct m68hc11eepr *controller;
348 uint8_t val;
349
350 sd = hw_system (me);
351 cpu = STATE_CPU (sd, 0);
352 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
353 controller = hw_data (me);
354 base = cpu_get_io_base (cpu);
355
356 sim_io_printf (sd, "M68HC11 EEprom:\n");
357
358 val = m68hc11_cpu->ios[M6811_PPROG];
359 print_io_byte (sd, "PPROG ", pprog_desc, val, base + M6811_PPROG);
360 sim_io_printf (sd, "\n");
361
362 val = m68hc11_cpu->ios[M6811_CONFIG];
363 print_io_byte (sd, "CONFIG ", config_desc, val, base + M6811_CONFIG);
364 sim_io_printf (sd, "\n");
365
366 val = controller->eeprom[controller->size - 1];
367 print_io_byte (sd, "(*NEXT*) ", config_desc, val, base + M6811_CONFIG);
368 sim_io_printf (sd, "\n");
369
370 /* Describe internal state of EEPROM. */
371 if (controller->eeprom_wmode)
372 {
373 if (controller->eeprom_waddr == controller->size - 1)
374 sim_io_printf (sd, " Programming CONFIG register ");
375 else
376 sim_io_printf (sd, " Programming: 0x%04x ",
377 controller->eeprom_waddr + controller->base_address);
378
379 sim_io_printf (sd, "with 0x%02x\n",
380 controller->eeprom_wbyte);
381 }
382
383 sim_io_printf (sd, " EEProm file: %s\n",
384 controller->file_name);
385 }
386
387 static int
388 m68hc11eepr_ioctl (struct hw *me,
389 hw_ioctl_request request,
390 va_list ap)
391 {
392 m68hc11eepr_info (me);
393 return 0;
394 }
395
396 /* generic read/write */
397
398 static unsigned
399 m68hc11eepr_io_read_buffer (struct hw *me,
400 void *dest,
401 int space,
402 unsigned_word base,
403 unsigned nr_bytes)
404 {
405 SIM_DESC sd;
406 struct m68hc11eepr *controller;
407 sim_cpu *cpu;
408 struct m68hc11_sim_cpu *m68hc11_cpu;
409
410 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
411
412 sd = hw_system (me);
413 controller = hw_data (me);
414 cpu = STATE_CPU (sd, 0);
415 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
416
417 if (space == io_map)
418 {
419 unsigned cnt = 0;
420
421 while (nr_bytes != 0)
422 {
423 switch (base)
424 {
425 case M6811_PPROG:
426 case M6811_CONFIG:
427 *((uint8_t*) dest) = m68hc11_cpu->ios[base];
428 break;
429
430 default:
431 hw_abort (me, "reading wrong register 0x%04x", base);
432 }
433 dest = (uint8_t*) (dest) + 1;
434 base++;
435 nr_bytes--;
436 cnt++;
437 }
438 return cnt;
439 }
440
441 /* In theory, we can't read the EEPROM when it's being programmed. */
442 if ((m68hc11_cpu->ios[M6811_PPROG] & M6811_EELAT) != 0
443 && cpu_is_running (cpu))
444 {
445 sim_memory_error (cpu, SIM_SIGBUS, base,
446 "EEprom not configured for reading");
447 }
448
449 base = base - controller->base_address;
450 memcpy (dest, &controller->eeprom[base], nr_bytes);
451 return nr_bytes;
452 }
453
454
455 static unsigned
456 m68hc11eepr_io_write_buffer (struct hw *me,
457 const void *source,
458 int space,
459 unsigned_word base,
460 unsigned nr_bytes)
461 {
462 SIM_DESC sd;
463 struct m68hc11eepr *controller;
464 sim_cpu *cpu;
465 struct m68hc11_sim_cpu *m68hc11_cpu;
466 uint8_t val;
467
468 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
469
470 sd = hw_system (me);
471 controller = hw_data (me);
472 cpu = STATE_CPU (sd, 0);
473 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
474
475 /* Programming several bytes at a time is not possible. */
476 if (space != io_map && nr_bytes != 1)
477 {
478 sim_memory_error (cpu, SIM_SIGBUS, base,
479 "EEprom write error (only 1 byte can be programmed)");
480 return 0;
481 }
482
483 if (nr_bytes != 1)
484 hw_abort (me, "Cannot write more than 1 byte to EEPROM device at a time");
485
486 val = *((const uint8_t*) source);
487
488 /* Write to the EEPROM control register. */
489 if (space == io_map && base == M6811_PPROG)
490 {
491 uint8_t wrong_bits;
492 uint16_t addr;
493
494 addr = base + cpu_get_io_base (cpu);
495
496 /* Setting EELAT and EEPGM at the same time is an error.
497 Clearing them both is ok. */
498 wrong_bits = (m68hc11_cpu->ios[M6811_PPROG] ^ val) & val;
499 wrong_bits &= (M6811_EELAT | M6811_EEPGM);
500
501 if (wrong_bits == (M6811_EEPGM|M6811_EELAT))
502 {
503 sim_memory_error (cpu, SIM_SIGBUS, addr,
504 "Wrong eeprom programing value");
505 return 0;
506 }
507
508 if ((val & M6811_EELAT) == 0)
509 {
510 val = 0;
511 }
512 if ((val & M6811_EEPGM) && !(m68hc11_cpu->ios[M6811_PPROG] & M6811_EELAT))
513 {
514 sim_memory_error (cpu, SIM_SIGBUS, addr,
515 "EEProm high voltage applied after EELAT");
516 }
517 if ((val & M6811_EEPGM) && controller->eeprom_wmode == 0)
518 {
519 sim_memory_error (cpu, SIM_SIGSEGV, addr,
520 "EEProm high voltage applied without address");
521 }
522 if (val & M6811_EEPGM)
523 {
524 controller->eeprom_wcycle = cpu_current_cycle (cpu);
525 }
526 else if (m68hc11_cpu->ios[M6811_PPROG] & M6811_PPROG)
527 {
528 int i;
529 unsigned long t = cpu_current_cycle (cpu);
530
531 t -= controller->eeprom_wcycle;
532 if (t < controller->eeprom_min_cycles)
533 {
534 sim_memory_error (cpu, SIM_SIGILL, addr,
535 "EEprom programmed only for %lu cycles",
536 t);
537 }
538
539 /* Program the byte by clearing some bits. */
540 if (!(m68hc11_cpu->ios[M6811_PPROG] & M6811_ERASE))
541 {
542 controller->eeprom[controller->eeprom_waddr]
543 &= controller->eeprom_wbyte;
544 }
545
546 /* Erase a byte, row or the complete eeprom. Erased value is 0xFF.
547 Ignore row or complete eeprom erase when we are programming the
548 CONFIG register (last EEPROM byte). */
549 else if ((m68hc11_cpu->ios[M6811_PPROG] & M6811_BYTE)
550 || controller->eeprom_waddr == controller->size - 1)
551 {
552 controller->eeprom[controller->eeprom_waddr] = 0xff;
553 }
554 else if (m68hc11_cpu->ios[M6811_BYTE] & M6811_ROW)
555 {
556 size_t max_size;
557
558 /* Size of EEPROM (-1 because the last byte is the
559 CONFIG register. */
560 max_size = controller->size;
561 controller->eeprom_waddr &= 0xFFF0;
562 for (i = 0; i < 16
563 && controller->eeprom_waddr < max_size; i++)
564 {
565 controller->eeprom[controller->eeprom_waddr] = 0xff;
566 controller->eeprom_waddr ++;
567 }
568 }
569 else
570 {
571 size_t max_size;
572
573 max_size = controller->size;
574 for (i = 0; i < max_size; i++)
575 {
576 controller->eeprom[i] = 0xff;
577 }
578 }
579
580 /* Save the eeprom in a file. We have to save after each
581 change because the simulator can be stopped or crash... */
582 if (m6811eepr_memory_rw (controller, O_WRONLY | O_CREAT) != 0)
583 {
584 sim_memory_error (cpu, SIM_SIGABRT, addr,
585 "EEPROM programing failed: errno=%d", errno);
586 }
587 controller->eeprom_wmode = 0;
588 }
589 m68hc11_cpu->ios[M6811_PPROG] = val;
590 return 1;
591 }
592
593 /* The CONFIG IO register is mapped at end of EEPROM.
594 It's not visible. */
595 if (space == io_map && base == M6811_CONFIG)
596 {
597 base = controller->size - 1;
598 }
599 else
600 {
601 base = base - controller->base_address;
602 }
603
604 /* Writing the memory is allowed for the Debugger or simulator
605 (cpu not running). */
606 if (cpu_is_running (cpu))
607 {
608 if ((m68hc11_cpu->ios[M6811_PPROG] & M6811_EELAT) == 0)
609 {
610 sim_memory_error (cpu, SIM_SIGSEGV, base,
611 "EEprom not configured for writing");
612 return 0;
613 }
614 if (controller->eeprom_wmode != 0)
615 {
616 sim_memory_error (cpu, SIM_SIGSEGV, base,
617 "EEprom write error");
618 return 0;
619 }
620 controller->eeprom_wmode = 1;
621 controller->eeprom_waddr = base;
622 controller->eeprom_wbyte = val;
623 }
624 else
625 {
626 controller->eeprom[base] = val;
627 m6811eepr_memory_rw (controller, O_WRONLY);
628 }
629
630 return 1;
631 }
632
633 const struct hw_descriptor dv_m68hc11eepr_descriptor[] = {
634 { "m68hc11eepr", m68hc11eepr_finish },
635 { "m68hc12eepr", m68hc11eepr_finish },
636 { NULL },
637 };
638