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