1/* interp.c -- Simulator for Motorola 68HC11/68HC12 2 Copyright (C) 1999-2023 Free Software Foundation, Inc. 3 Written by Stephane Carrez (stcarrez@nerim.fr) 4 5This file is part of GDB, the GNU debugger. 6 7This program is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 3 of the License, or 10(at your option) any later version. 11 12This program is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20/* This must come before any other includes. */ 21#include "defs.h" 22 23#include "sim-main.h" 24#include "sim-assert.h" 25#include "sim-hw.h" 26#include "sim-options.h" 27#include "hw-tree.h" 28#include "hw-device.h" 29#include "hw-ports.h" 30#include "elf32-m68hc1x.h" 31 32#ifndef MONITOR_BASE 33# define MONITOR_BASE (0x0C000) 34# define MONITOR_SIZE (0x04000) 35#endif 36 37static void sim_get_info (SIM_DESC sd, char *cmd); 38 39struct sim_info_list 40{ 41 const char *name; 42 const char *device; 43}; 44 45struct sim_info_list dev_list_68hc11[] = { 46 {"cpu", "/m68hc11"}, 47 {"timer", "/m68hc11/m68hc11tim"}, 48 {"sio", "/m68hc11/m68hc11sio"}, 49 {"spi", "/m68hc11/m68hc11spi"}, 50 {"eeprom", "/m68hc11/m68hc11eepr"}, 51 {0, 0} 52}; 53 54struct sim_info_list dev_list_68hc12[] = { 55 {"cpu", "/m68hc12"}, 56 {"timer", "/m68hc12/m68hc12tim"}, 57 {"sio", "/m68hc12/m68hc12sio"}, 58 {"spi", "/m68hc12/m68hc12spi"}, 59 {"eeprom", "/m68hc12/m68hc12eepr"}, 60 {0, 0} 61}; 62 63/* Cover function of sim_state_free to free the cpu buffers as well. */ 64 65static void 66free_state (SIM_DESC sd) 67{ 68 if (STATE_MODULES (sd) != NULL) 69 sim_module_uninstall (sd); 70 71 sim_state_free (sd); 72} 73 74/* Give some information about the simulator. */ 75static void 76sim_get_info (SIM_DESC sd, char *cmd) 77{ 78 sim_cpu *cpu; 79 80 cpu = STATE_CPU (sd, 0); 81 if (cmd != 0 && (cmd[0] == ' ' || cmd[0] == '-')) 82 { 83 int i; 84 struct hw *hw_dev; 85 struct sim_info_list *dev_list; 86 const struct bfd_arch_info *arch; 87 88 arch = STATE_ARCHITECTURE (sd); 89 cmd++; 90 91 if (arch->arch == bfd_arch_m68hc11) 92 dev_list = dev_list_68hc11; 93 else 94 dev_list = dev_list_68hc12; 95 96 for (i = 0; dev_list[i].name; i++) 97 if (strcmp (cmd, dev_list[i].name) == 0) 98 break; 99 100 if (dev_list[i].name == 0) 101 { 102 sim_io_eprintf (sd, "Device '%s' not found.\n", cmd); 103 sim_io_eprintf (sd, "Valid devices: cpu timer sio eeprom\n"); 104 return; 105 } 106 hw_dev = sim_hw_parse (sd, "%s", dev_list[i].device); 107 if (hw_dev == 0) 108 { 109 sim_io_eprintf (sd, "Device '%s' not found\n", dev_list[i].device); 110 return; 111 } 112 hw_ioctl (hw_dev, 23, 0); 113 return; 114 } 115 116 cpu_info (sd, cpu); 117 interrupts_info (sd, &cpu->cpu_interrupts); 118} 119 120 121void 122sim_board_reset (SIM_DESC sd) 123{ 124 struct hw *hw_cpu; 125 sim_cpu *cpu; 126 const struct bfd_arch_info *arch; 127 const char *cpu_type; 128 129 cpu = STATE_CPU (sd, 0); 130 arch = STATE_ARCHITECTURE (sd); 131 132 /* hw_cpu = sim_hw_parse (sd, "/"); */ 133 if (arch->arch == bfd_arch_m68hc11) 134 { 135 cpu->cpu_type = CPU_M6811; 136 cpu_type = "/m68hc11"; 137 } 138 else 139 { 140 cpu->cpu_type = CPU_M6812; 141 cpu_type = "/m68hc12"; 142 } 143 144 hw_cpu = sim_hw_parse (sd, "%s", cpu_type); 145 if (hw_cpu == 0) 146 { 147 sim_io_eprintf (sd, "%s cpu not found in device tree.", cpu_type); 148 return; 149 } 150 151 cpu_reset (cpu); 152 hw_port_event (hw_cpu, 3, 0); 153 cpu_restart (cpu); 154} 155 156static int 157sim_hw_configure (SIM_DESC sd) 158{ 159 const struct bfd_arch_info *arch; 160 struct hw *device_tree; 161 sim_cpu *cpu; 162 163 arch = STATE_ARCHITECTURE (sd); 164 if (arch == 0) 165 return 0; 166 167 cpu = STATE_CPU (sd, 0); 168 cpu->cpu_configured_arch = arch; 169 device_tree = sim_hw_parse (sd, "/"); 170 if (arch->arch == bfd_arch_m68hc11) 171 { 172 cpu->cpu_interpretor = cpu_interp_m6811; 173 if (hw_tree_find_property (device_tree, "/m68hc11/reg") == 0) 174 { 175 /* Allocate core managed memory */ 176 177 /* the monitor */ 178 sim_do_commandf (sd, "memory region 0x%x@%d,0x%x", 179 /* MONITOR_BASE, MONITOR_SIZE */ 180 0x8000, M6811_RAM_LEVEL, 0x8000); 181 sim_do_commandf (sd, "memory region 0x000@%d,0x8000", 182 M6811_RAM_LEVEL); 183 sim_hw_parse (sd, "/m68hc11/reg 0x1000 0x03F"); 184 if (cpu->bank_start < cpu->bank_end) 185 { 186 sim_do_commandf (sd, "memory region 0x%x@%d,0x100000", 187 cpu->bank_virtual, M6811_RAM_LEVEL); 188 sim_hw_parse (sd, "/m68hc11/use_bank 1"); 189 } 190 } 191 if (cpu->cpu_start_mode) 192 { 193 sim_hw_parse (sd, "/m68hc11/mode %s", cpu->cpu_start_mode); 194 } 195 if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11sio/reg") == 0) 196 { 197 sim_hw_parse (sd, "/m68hc11/m68hc11sio/reg 0x2b 0x5"); 198 sim_hw_parse (sd, "/m68hc11/m68hc11sio/backend stdio"); 199 sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11sio"); 200 } 201 if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11tim/reg") == 0) 202 { 203 /* M68hc11 Timer configuration. */ 204 sim_hw_parse (sd, "/m68hc11/m68hc11tim/reg 0x1b 0x5"); 205 sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11tim"); 206 sim_hw_parse (sd, "/m68hc11 > capture capture /m68hc11/m68hc11tim"); 207 } 208 209 /* Create the SPI device. */ 210 if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11spi/reg") == 0) 211 { 212 sim_hw_parse (sd, "/m68hc11/m68hc11spi/reg 0x28 0x3"); 213 sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11spi"); 214 } 215 if (hw_tree_find_property (device_tree, "/m68hc11/nvram/reg") == 0) 216 { 217 /* M68hc11 persistent ram configuration. */ 218 sim_hw_parse (sd, "/m68hc11/nvram/reg 0x0 256"); 219 sim_hw_parse (sd, "/m68hc11/nvram/file m68hc11.ram"); 220 sim_hw_parse (sd, "/m68hc11/nvram/mode save-modified"); 221 /*sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/pram"); */ 222 } 223 if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11eepr/reg") == 0) 224 { 225 sim_hw_parse (sd, "/m68hc11/m68hc11eepr/reg 0xb000 512"); 226 sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11eepr"); 227 } 228 sim_hw_parse (sd, "/m68hc11 > port-a cpu-write-port /m68hc11"); 229 sim_hw_parse (sd, "/m68hc11 > port-b cpu-write-port /m68hc11"); 230 sim_hw_parse (sd, "/m68hc11 > port-c cpu-write-port /m68hc11"); 231 sim_hw_parse (sd, "/m68hc11 > port-d cpu-write-port /m68hc11"); 232 cpu->hw_cpu = sim_hw_parse (sd, "/m68hc11"); 233 } 234 else 235 { 236 cpu->cpu_interpretor = cpu_interp_m6812; 237 if (hw_tree_find_property (device_tree, "/m68hc12/reg") == 0) 238 { 239 /* Allocate core external memory. */ 240 sim_do_commandf (sd, "memory region 0x%x@%d,0x%x", 241 0x8000, M6811_RAM_LEVEL, 0x8000); 242 sim_do_commandf (sd, "memory region 0x000@%d,0x8000", 243 M6811_RAM_LEVEL); 244 if (cpu->bank_start < cpu->bank_end) 245 { 246 sim_do_commandf (sd, "memory region 0x%x@%d,0x100000", 247 cpu->bank_virtual, M6811_RAM_LEVEL); 248 sim_hw_parse (sd, "/m68hc12/use_bank 1"); 249 } 250 sim_hw_parse (sd, "/m68hc12/reg 0x0 0x3FF"); 251 } 252 253 if (!hw_tree_find_property (device_tree, "/m68hc12/m68hc12sio@1/reg")) 254 { 255 sim_hw_parse (sd, "/m68hc12/m68hc12sio@1/reg 0xC0 0x8"); 256 sim_hw_parse (sd, "/m68hc12/m68hc12sio@1/backend stdio"); 257 sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12sio@1"); 258 } 259 if (hw_tree_find_property (device_tree, "/m68hc12/m68hc12tim/reg") == 0) 260 { 261 /* M68hc11 Timer configuration. */ 262 sim_hw_parse (sd, "/m68hc12/m68hc12tim/reg 0x1b 0x5"); 263 sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12tim"); 264 sim_hw_parse (sd, "/m68hc12 > capture capture /m68hc12/m68hc12tim"); 265 } 266 267 /* Create the SPI device. */ 268 if (hw_tree_find_property (device_tree, "/m68hc12/m68hc12spi/reg") == 0) 269 { 270 sim_hw_parse (sd, "/m68hc12/m68hc12spi/reg 0x28 0x3"); 271 sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12spi"); 272 } 273 if (hw_tree_find_property (device_tree, "/m68hc12/nvram/reg") == 0) 274 { 275 /* M68hc11 persistent ram configuration. */ 276 sim_hw_parse (sd, "/m68hc12/nvram/reg 0x2000 8192"); 277 sim_hw_parse (sd, "/m68hc12/nvram/file m68hc12.ram"); 278 sim_hw_parse (sd, "/m68hc12/nvram/mode save-modified"); 279 } 280 if (hw_tree_find_property (device_tree, "/m68hc12/m68hc12eepr/reg") == 0) 281 { 282 sim_hw_parse (sd, "/m68hc12/m68hc12eepr/reg 0x0800 2048"); 283 sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12eepr"); 284 } 285 286 sim_hw_parse (sd, "/m68hc12 > port-a cpu-write-port /m68hc12"); 287 sim_hw_parse (sd, "/m68hc12 > port-b cpu-write-port /m68hc12"); 288 sim_hw_parse (sd, "/m68hc12 > port-c cpu-write-port /m68hc12"); 289 sim_hw_parse (sd, "/m68hc12 > port-d cpu-write-port /m68hc12"); 290 cpu->hw_cpu = sim_hw_parse (sd, "/m68hc12"); 291 } 292 return 1; 293} 294 295/* Get the memory bank parameters by looking at the global symbols 296 defined by the linker. */ 297static int 298sim_get_bank_parameters (SIM_DESC sd) 299{ 300 sim_cpu *cpu; 301 unsigned size; 302 bfd_vma addr; 303 304 cpu = STATE_CPU (sd, 0); 305 306 addr = trace_sym_value (sd, BFD_M68HC11_BANK_START_NAME); 307 if (addr != -1) 308 cpu->bank_start = addr; 309 310 size = trace_sym_value (sd, BFD_M68HC11_BANK_SIZE_NAME); 311 if (size == -1) 312 size = 0; 313 314 addr = trace_sym_value (sd, BFD_M68HC11_BANK_VIRTUAL_NAME); 315 if (addr != -1) 316 cpu->bank_virtual = addr; 317 318 cpu->bank_end = cpu->bank_start + size; 319 cpu->bank_shift = 0; 320 for (; size > 1; size >>= 1) 321 cpu->bank_shift++; 322 323 return 0; 324} 325 326static int 327sim_prepare_for_program (SIM_DESC sd, bfd* abfd) 328{ 329 sim_cpu *cpu; 330 int elf_flags = 0; 331 332 cpu = STATE_CPU (sd, 0); 333 334 if (abfd != NULL) 335 { 336 asection *s; 337 338 if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) 339 elf_flags = elf_elfheader (abfd)->e_flags; 340 341 cpu->cpu_elf_start = bfd_get_start_address (abfd); 342 /* See if any section sets the reset address */ 343 cpu->cpu_use_elf_start = 1; 344 for (s = abfd->sections; s && cpu->cpu_use_elf_start; s = s->next) 345 { 346 if (s->flags & SEC_LOAD) 347 { 348 bfd_size_type size; 349 350 size = bfd_section_size (s); 351 if (size > 0) 352 { 353 bfd_vma lma; 354 355 if (STATE_LOAD_AT_LMA_P (sd)) 356 lma = bfd_section_lma (s); 357 else 358 lma = bfd_section_vma (s); 359 360 if (lma <= 0xFFFE && lma+size >= 0x10000) 361 cpu->cpu_use_elf_start = 0; 362 } 363 } 364 } 365 366 if (elf_flags & E_M68HC12_BANKS) 367 { 368 if (sim_get_bank_parameters (sd) != 0) 369 sim_io_eprintf (sd, "Memory bank parameters are not initialized\n"); 370 } 371 } 372 373 if (!sim_hw_configure (sd)) 374 return SIM_RC_FAIL; 375 376 /* reset all state information */ 377 sim_board_reset (sd); 378 379 return SIM_RC_OK; 380} 381 382static sim_cia 383m68hc11_pc_get (sim_cpu *cpu) 384{ 385 return cpu_get_pc (cpu); 386} 387 388static void 389m68hc11_pc_set (sim_cpu *cpu, sim_cia pc) 390{ 391 cpu_set_pc (cpu, pc); 392} 393 394static int m68hc11_reg_fetch (SIM_CPU *, int, void *, int); 395static int m68hc11_reg_store (SIM_CPU *, int, const void *, int); 396 397SIM_DESC 398sim_open (SIM_OPEN_KIND kind, host_callback *callback, 399 bfd *abfd, char * const *argv) 400{ 401 int i; 402 SIM_DESC sd; 403 sim_cpu *cpu; 404 405 sd = sim_state_alloc (kind, callback); 406 407 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); 408 409 /* Set default options before parsing user options. */ 410 current_target_byte_order = BFD_ENDIAN_BIG; 411 412 /* The cpu data is kept in a separately allocated chunk of memory. */ 413 if (sim_cpu_alloc_all (sd, 1) != SIM_RC_OK) 414 { 415 free_state (sd); 416 return 0; 417 } 418 419 cpu = STATE_CPU (sd, 0); 420 421 cpu_initialize (sd, cpu); 422 423 if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK) 424 { 425 free_state (sd); 426 return 0; 427 } 428 429 /* The parser will print an error message for us, so we silently return. */ 430 if (sim_parse_args (sd, argv) != SIM_RC_OK) 431 { 432 /* Uninstall the modules to avoid memory leaks, 433 file descriptor leaks, etc. */ 434 free_state (sd); 435 return 0; 436 } 437 438 /* Check for/establish the a reference program image. */ 439 if (sim_analyze_program (sd, STATE_PROG_FILE (sd), abfd) != SIM_RC_OK) 440 { 441 free_state (sd); 442 return 0; 443 } 444 445 /* Establish any remaining configuration options. */ 446 if (sim_config (sd) != SIM_RC_OK) 447 { 448 free_state (sd); 449 return 0; 450 } 451 452 if (sim_post_argv_init (sd) != SIM_RC_OK) 453 { 454 /* Uninstall the modules to avoid memory leaks, 455 file descriptor leaks, etc. */ 456 free_state (sd); 457 return 0; 458 } 459 if (sim_prepare_for_program (sd, abfd) != SIM_RC_OK) 460 { 461 free_state (sd); 462 return 0; 463 } 464 465 /* CPU specific initialization. */ 466 for (i = 0; i < MAX_NR_PROCESSORS; ++i) 467 { 468 SIM_CPU *cpu = STATE_CPU (sd, i); 469 470 CPU_REG_FETCH (cpu) = m68hc11_reg_fetch; 471 CPU_REG_STORE (cpu) = m68hc11_reg_store; 472 CPU_PC_FETCH (cpu) = m68hc11_pc_get; 473 CPU_PC_STORE (cpu) = m68hc11_pc_set; 474 } 475 476 return sd; 477} 478 479/* Generic implementation of sim_engine_run that works within the 480 sim_engine setjmp/longjmp framework. */ 481 482void 483sim_engine_run (SIM_DESC sd, 484 int next_cpu_nr, /* ignore */ 485 int nr_cpus, /* ignore */ 486 int siggnal) /* ignore */ 487{ 488 sim_cpu *cpu; 489 490 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); 491 cpu = STATE_CPU (sd, 0); 492 while (1) 493 { 494 cpu_single_step (cpu); 495 496 /* process any events */ 497 if (sim_events_tickn (sd, cpu->cpu_current_cycle)) 498 { 499 sim_events_process (sd); 500 } 501 } 502} 503 504void 505sim_info (SIM_DESC sd, int verbose) 506{ 507 const char *cpu_type; 508 const struct bfd_arch_info *arch; 509 510 /* Nothing to do if there is no verbose flag set. */ 511 if (verbose == 0 && STATE_VERBOSE_P (sd) == 0) 512 return; 513 514 arch = STATE_ARCHITECTURE (sd); 515 if (arch->arch == bfd_arch_m68hc11) 516 cpu_type = "68HC11"; 517 else 518 cpu_type = "68HC12"; 519 520 sim_io_eprintf (sd, "Simulator info:\n"); 521 sim_io_eprintf (sd, " CPU Motorola %s\n", cpu_type); 522 sim_get_info (sd, 0); 523 sim_module_info (sd, verbose || STATE_VERBOSE_P (sd)); 524} 525 526SIM_RC 527sim_create_inferior (SIM_DESC sd, struct bfd *abfd, 528 char * const *argv, char * const *env) 529{ 530 return sim_prepare_for_program (sd, abfd); 531} 532 533static int 534m68hc11_reg_fetch (SIM_CPU *cpu, int rn, void *buf, int length) 535{ 536 unsigned char *memory = buf; 537 uint16_t val; 538 int size = 2; 539 540 switch (rn) 541 { 542 case A_REGNUM: 543 val = cpu_get_a (cpu); 544 size = 1; 545 break; 546 547 case B_REGNUM: 548 val = cpu_get_b (cpu); 549 size = 1; 550 break; 551 552 case D_REGNUM: 553 val = cpu_get_d (cpu); 554 break; 555 556 case X_REGNUM: 557 val = cpu_get_x (cpu); 558 break; 559 560 case Y_REGNUM: 561 val = cpu_get_y (cpu); 562 break; 563 564 case SP_REGNUM: 565 val = cpu_get_sp (cpu); 566 break; 567 568 case PC_REGNUM: 569 val = cpu_get_pc (cpu); 570 break; 571 572 case PSW_REGNUM: 573 val = cpu_get_ccr (cpu); 574 size = 1; 575 break; 576 577 case PAGE_REGNUM: 578 val = cpu_get_page (cpu); 579 size = 1; 580 break; 581 582 default: 583 val = 0; 584 break; 585 } 586 if (size == 1) 587 { 588 memory[0] = val; 589 } 590 else 591 { 592 memory[0] = val >> 8; 593 memory[1] = val & 0x0FF; 594 } 595 return size; 596} 597 598static int 599m68hc11_reg_store (SIM_CPU *cpu, int rn, const void *buf, int length) 600{ 601 const unsigned char *memory = buf; 602 uint16_t val; 603 604 val = *memory++; 605 if (length == 2) 606 val = (val << 8) | *memory; 607 608 switch (rn) 609 { 610 case D_REGNUM: 611 cpu_set_d (cpu, val); 612 break; 613 614 case A_REGNUM: 615 cpu_set_a (cpu, val); 616 return 1; 617 618 case B_REGNUM: 619 cpu_set_b (cpu, val); 620 return 1; 621 622 case X_REGNUM: 623 cpu_set_x (cpu, val); 624 break; 625 626 case Y_REGNUM: 627 cpu_set_y (cpu, val); 628 break; 629 630 case SP_REGNUM: 631 cpu_set_sp (cpu, val); 632 break; 633 634 case PC_REGNUM: 635 cpu_set_pc (cpu, val); 636 break; 637 638 case PSW_REGNUM: 639 cpu_set_ccr (cpu, val); 640 return 1; 641 642 case PAGE_REGNUM: 643 cpu_set_page (cpu, val); 644 return 1; 645 646 default: 647 break; 648 } 649 650 return 2; 651} 652