Automatic Copyright Year update after running gdb/copyright.py
[deliverable/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11eepr.c
CommitLineData
e0709f50 1/* dv-m68hc11eepr.c -- Simulation of the 68HC11 Internal EEPROM.
88b9d363 2 Copyright (C) 1999-2022 Free Software Foundation, Inc.
099d1b50 3 Written by Stephane Carrez (stcarrez@nerim.fr)
e0709f50
AC
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
4744ac1b 8 the Free Software Foundation; either version 3 of the License, or
e0709f50 9 (at your option) any later version.
4744ac1b 10
e0709f50
AC
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.
4744ac1b 15
e0709f50 16 You should have received a copy of the GNU General Public License
4744ac1b 17 along with this program. If not, see <http://www.gnu.org/licenses/>.
e0709f50
AC
18
19 */
20
6df01ab8
MF
21/* This must come before any other includes. */
22#include "defs.h"
e0709f50
AC
23
24#include "sim-main.h"
25#include "hw-main.h"
26#include "sim-assert.h"
27#include "sim-events.h"
1fef66b0 28#include "sim-signal.h"
e0709f50
AC
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
71enum
72{
73 RESET_PORT
74};
75
76
77static 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
88struct m68hc11eepr
89{
90 address_word base_address; /* control register base */
91 int attach_space;
92 unsigned size;
63348d04
SC
93 int mapped;
94
e0709f50
AC
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 eeprom_waddr;
116 uint8 eeprom_wbyte;
117 uint8 eeprom_wmode;
118
119 uint8* eeprom;
120
121 /* Minimum time in CPU cycles for programming the EEPROM. */
122 unsigned long eeprom_min_cycles;
123
099d1b50 124 const char* file_name;
e0709f50
AC
125};
126
127
128
129/* Finish off the partially created hw device. Attach our local
130 callbacks. Wire up our port names etc. */
131
132static hw_io_read_buffer_method m68hc11eepr_io_read_buffer;
133static hw_io_write_buffer_method m68hc11eepr_io_write_buffer;
134static 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. */
138static int
139m6811eepr_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
184static void
185attach_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. */
63348d04
SC
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);
e0709f50
AC
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;
527aaa4a 223 controller->eeprom = hw_malloc (me, attach_size + 1);
e0709f50
AC
224 controller->eeprom_min_cycles = 10000;
225 controller->size = attach_size + 1;
63348d04
SC
226 controller->mapped = 0;
227
e0709f50
AC
228 m6811eepr_memory_rw (controller, O_RDONLY);
229}
230
231
232/* An event arrives on an interrupt port. */
233
234static void
235m68hc11eepr_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). */
eefde351 274 if (!(cpu->ios[M6811_CONFIG] & M6811_EEON))
e0709f50 275 {
63348d04 276 if (controller->mapped)
eefde351 277 hw_detach_address (hw_parent (me), M6811_EEPROM_LEVEL,
63348d04
SC
278 controller->attach_space,
279 controller->base_address,
280 controller->size - 1,
281 me);
282 controller->mapped = 0;
e0709f50
AC
283 }
284 else
285 {
63348d04 286 if (!controller->mapped)
eefde351 287 hw_attach_address (hw_parent (me), M6811_EEPROM_LEVEL,
63348d04
SC
288 controller->attach_space,
289 controller->base_address,
290 controller->size - 1,
291 me);
292 controller->mapped = 1;
e0709f50
AC
293 }
294 break;
295 }
296
297 default:
298 hw_abort (me, "Event on unknown port %d", my_port);
299 break;
300 }
301}
302
303
304static void
305m68hc11eepr_finish (struct hw *me)
306{
307 struct m68hc11eepr *controller;
308
309 controller = HW_ZALLOC (me, struct m68hc11eepr);
e0709f50
AC
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
326static 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};
334extern io_reg_desc config_desc[];
335
336
337/* Describe the state of the EEPROM device. */
338static void
339m68hc11eepr_info (struct hw *me)
340{
341 SIM_DESC sd;
342 uint16 base = 0;
343 sim_cpu *cpu;
344 struct m68hc11eepr *controller;
345 uint8 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 ",
eefde351 373 controller->eeprom_waddr + controller->base_address);
e0709f50
AC
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
383static int
384m68hc11eepr_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
394static unsigned
395m68hc11eepr_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*) dest) = cpu->ios[base];
422 break;
423
424 default:
425 hw_abort (me, "reading wrong register 0x%04x", base);
426 }
427 dest = (uint8*) (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
449static unsigned
450m68hc11eepr_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 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*) source);
479
480 /* Write to the EEPROM control register. */
481 if (space == io_map && base == M6811_PPROG)
482 {
483 uint8 wrong_bits;
484 uint16 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
625const struct hw_descriptor dv_m68hc11eepr_descriptor[] = {
b93775f5
SC
626 { "m68hc11eepr", m68hc11eepr_finish },
627 { "m68hc12eepr", m68hc11eepr_finish },
e0709f50
AC
628 { NULL },
629};
630
This page took 1.266444 seconds and 4 git commands to generate.