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