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