1 /* dv-m68hc11.c -- CPU 68HC11&68HC12 as a device. 2 Copyright (C) 1999-2023 Free Software Foundation, Inc. 3 Written by Stephane Carrez (stcarrez@nerim.fr) 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 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 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. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 19 */ 20 21 /* This must come before any other includes. */ 22 #include "defs.h" 23 24 #include "sim-main.h" 25 #include "sim-hw.h" 26 #include "hw-main.h" 27 #include "sim-options.h" 28 #include "hw-base.h" 29 #include <limits.h> 30 #include <stdlib.h> 31 32 /* DEVICE 33 34 m68hc11cpu - m68hc11 cpu virtual device 35 m68hc12cpu - m68hc12 cpu virtual device 36 37 DESCRIPTION 38 39 Implements the external m68hc11/68hc12 functionality. This includes 40 the delivery of of interrupts generated from other devices and the 41 handling of device specific registers. 42 43 44 PROPERTIES 45 46 reg <base> <size> 47 48 Register base (should be 0x1000 0x03f for C11, 0x0000 0x3ff for HC12). 49 50 clock <hz> 51 52 Frequency of the quartz used by the processor. 53 54 mode [single | expanded | bootstrap | test] 55 56 Cpu operating mode (the MODA and MODB external pins). 57 58 59 PORTS 60 61 reset (input) 62 63 Reset the cpu and generates a cpu-reset event (used to reset 64 other devices). 65 66 nmi (input) 67 68 Deliver a non-maskable interrupt to the processor. 69 70 71 set-port-a (input) 72 set-port-c (input) 73 set-pord-d (input) 74 75 Allow an external device to set the value of port A, C or D inputs. 76 77 78 cpu-reset (output) 79 80 Event generated after the CPU performs a reset. 81 82 83 port-a (output) 84 port-b (output) 85 port-c (output) 86 port-d (output) 87 88 Event generated when the value of the output port A, B, C or D 89 changes. 90 91 92 BUGS 93 94 When delivering an interrupt, this code assumes that there is only 95 one processor (number 0). 96 97 */ 98 99 enum 100 { 101 OPTION_OSC_SET = OPTION_START, 102 OPTION_OSC_CLEAR, 103 OPTION_OSC_INFO 104 }; 105 106 static DECLARE_OPTION_HANDLER (m68hc11_option_handler); 107 108 static const OPTION m68hc11_options[] = 109 { 110 { {"osc-set", required_argument, NULL, OPTION_OSC_SET }, 111 '\0', "BIT,FREQ", "Set the oscillator on input port BIT", 112 m68hc11_option_handler }, 113 { {"osc-clear", required_argument, NULL, OPTION_OSC_CLEAR }, 114 '\0', "BIT", "Clear oscillator on input port BIT", 115 m68hc11_option_handler }, 116 { {"osc-info", no_argument, NULL, OPTION_OSC_INFO }, 117 '\0', NULL, "Print information about current input oscillators", 118 m68hc11_option_handler }, 119 120 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } 121 }; 122 123 struct input_osc 124 { 125 int64_t on_time; 126 int64_t off_time; 127 int64_t repeat; 128 struct hw_event *event; 129 const char *name; 130 uint8_t mask; 131 uint8_t value; 132 uint16_t addr; 133 }; 134 135 #define NR_PORT_A_OSC (4) 136 #define NR_PORT_B_OSC (0) 137 #define NR_PORT_C_OSC (8) 138 #define NR_PORT_D_OSC (6) 139 #define NR_OSC (NR_PORT_A_OSC + NR_PORT_B_OSC + NR_PORT_C_OSC + NR_PORT_D_OSC) 140 struct m68hc11cpu { 141 /* Pending interrupts for delivery by event handler. */ 142 int pending_reset; 143 int pending_nmi; 144 int pending_level; 145 struct hw_event *event; 146 unsigned_word attach_address; 147 unsigned int attach_size; 148 int attach_space; 149 int last_oscillator; 150 struct input_osc oscillators[NR_OSC]; 151 }; 152 153 154 155 /* input port ID's */ 156 157 enum { 158 RESET_PORT, 159 NMI_PORT, 160 IRQ_PORT, 161 CPU_RESET_PORT, 162 SET_PORT_A, 163 SET_PORT_C, 164 SET_PORT_D, 165 CPU_WRITE_PORT, 166 PORT_A, 167 PORT_B, 168 PORT_C, 169 PORT_D, 170 CAPTURE 171 }; 172 173 174 static const struct hw_port_descriptor m68hc11cpu_ports[] = { 175 176 /* Interrupt inputs. */ 177 { "reset", RESET_PORT, 0, input_port, }, 178 { "nmi", NMI_PORT, 0, input_port, }, 179 { "irq", IRQ_PORT, 0, input_port, }, 180 181 { "set-port-a", SET_PORT_A, 0, input_port, }, 182 { "set-port-c", SET_PORT_C, 0, input_port, }, 183 { "set-port-d", SET_PORT_D, 0, input_port, }, 184 185 { "cpu-write-port", CPU_WRITE_PORT, 0, input_port, }, 186 187 /* Events generated for connection to other devices. */ 188 { "cpu-reset", CPU_RESET_PORT, 0, output_port, }, 189 190 /* Events generated when the corresponding port is 191 changed by the program. */ 192 { "port-a", PORT_A, 0, output_port, }, 193 { "port-b", PORT_B, 0, output_port, }, 194 { "port-c", PORT_C, 0, output_port, }, 195 { "port-d", PORT_D, 0, output_port, }, 196 197 { "capture", CAPTURE, 0, output_port, }, 198 199 { NULL, }, 200 }; 201 202 static hw_io_read_buffer_method m68hc11cpu_io_read_buffer; 203 static hw_io_write_buffer_method m68hc11cpu_io_write_buffer; 204 static hw_ioctl_method m68hc11_ioctl; 205 206 /* Finish off the partially created hw device. Attach our local 207 callbacks. Wire up our port names etc. */ 208 209 static hw_port_event_method m68hc11cpu_port_event; 210 211 static void make_oscillator (struct m68hc11cpu *controller, 212 const char *id, uint16_t addr, uint8_t mask); 213 static struct input_osc *find_oscillator (struct m68hc11cpu *controller, 214 const char *id); 215 static void reset_oscillators (struct hw *me); 216 217 static void 218 dv_m6811_attach_address_callback (struct hw *me, 219 int level, 220 int space, 221 address_word addr, 222 address_word nr_bytes, 223 struct hw *client) 224 { 225 HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, sz=%ld, client=%s", 226 level, space, (unsigned long) addr, (unsigned long) nr_bytes, 227 hw_path (client))); 228 229 if (space != io_map) 230 { 231 sim_core_attach (hw_system (me), 232 NULL, /*cpu*/ 233 level, 234 access_read_write_exec, 235 space, addr, 236 nr_bytes, 237 0, /* modulo */ 238 client, 239 NULL); 240 } 241 else 242 { 243 /*printf("Attach from sub device: %d\n", (long) addr);*/ 244 sim_core_attach (hw_system (me), 245 NULL, /*cpu*/ 246 level, 247 access_io, 248 space, addr, 249 nr_bytes, 250 0, /* modulo */ 251 client, 252 NULL); 253 } 254 } 255 256 static void 257 dv_m6811_detach_address_callback (struct hw *me, 258 int level, 259 int space, 260 address_word addr, 261 address_word nr_bytes, 262 struct hw *client) 263 { 264 sim_core_detach (hw_system (me), NULL, /*cpu*/ 265 level, space, addr); 266 } 267 268 static void 269 m68hc11_delete (struct hw* me) 270 { 271 struct m68hc11cpu *controller; 272 273 controller = hw_data (me); 274 275 reset_oscillators (me); 276 hw_detach_address (me, M6811_IO_LEVEL, 277 controller->attach_space, 278 controller->attach_address, 279 controller->attach_size, me); 280 } 281 282 283 static void 284 attach_m68hc11_regs (struct hw *me, 285 struct m68hc11cpu *controller) 286 { 287 SIM_DESC sd; 288 sim_cpu *cpu; 289 reg_property_spec reg; 290 const char *cpu_mode; 291 292 if (hw_find_property (me, "reg") == NULL) 293 hw_abort (me, "Missing \"reg\" property"); 294 295 if (!hw_find_reg_array_property (me, "reg", 0, ®)) 296 hw_abort (me, "\"reg\" property must contain one addr/size entry"); 297 298 hw_unit_address_to_attach_address (hw_parent (me), 299 ®.address, 300 &controller->attach_space, 301 &controller->attach_address, 302 me); 303 hw_unit_size_to_attach_size (hw_parent (me), 304 ®.size, 305 &controller->attach_size, me); 306 307 hw_attach_address (hw_parent (me), M6811_IO_LEVEL, 308 controller->attach_space, 309 controller->attach_address, 310 controller->attach_size, 311 me); 312 set_hw_delete (me, m68hc11_delete); 313 314 /* Get cpu frequency. */ 315 sd = hw_system (me); 316 cpu = STATE_CPU (sd, 0); 317 if (hw_find_property (me, "clock") != NULL) 318 { 319 cpu->cpu_frequency = hw_find_integer_property (me, "clock"); 320 } 321 else 322 { 323 cpu->cpu_frequency = 8*1000*1000; 324 } 325 326 if (hw_find_property (me, "use_bank") != NULL) 327 hw_attach_address (hw_parent (me), 0, 328 exec_map, 329 cpu->bank_start, 330 cpu->bank_end - cpu->bank_start, 331 me); 332 333 cpu_mode = "expanded"; 334 if (hw_find_property (me, "mode") != NULL) 335 cpu_mode = hw_find_string_property (me, "mode"); 336 337 if (strcmp (cpu_mode, "test") == 0) 338 cpu->cpu_mode = M6811_MDA | M6811_SMOD; 339 else if (strcmp (cpu_mode, "bootstrap") == 0) 340 cpu->cpu_mode = M6811_SMOD; 341 else if (strcmp (cpu_mode, "single") == 0) 342 cpu->cpu_mode = 0; 343 else 344 cpu->cpu_mode = M6811_MDA; 345 346 controller->last_oscillator = 0; 347 348 /* Create oscillators for input port A. */ 349 make_oscillator (controller, "A7", M6811_PORTA, 0x80); 350 make_oscillator (controller, "A2", M6811_PORTA, 0x04); 351 make_oscillator (controller, "A1", M6811_PORTA, 0x02); 352 make_oscillator (controller, "A0", M6811_PORTA, 0x01); 353 354 /* port B is output only. */ 355 356 /* Create oscillators for input port C. */ 357 make_oscillator (controller, "C0", M6811_PORTC, 0x01); 358 make_oscillator (controller, "C1", M6811_PORTC, 0x02); 359 make_oscillator (controller, "C2", M6811_PORTC, 0x04); 360 make_oscillator (controller, "C3", M6811_PORTC, 0x08); 361 make_oscillator (controller, "C4", M6811_PORTC, 0x10); 362 make_oscillator (controller, "C5", M6811_PORTC, 0x20); 363 make_oscillator (controller, "C6", M6811_PORTC, 0x40); 364 make_oscillator (controller, "C7", M6811_PORTC, 0x80); 365 366 /* Create oscillators for input port D. */ 367 make_oscillator (controller, "D0", M6811_PORTD, 0x01); 368 make_oscillator (controller, "D1", M6811_PORTD, 0x02); 369 make_oscillator (controller, "D2", M6811_PORTD, 0x04); 370 make_oscillator (controller, "D3", M6811_PORTD, 0x08); 371 make_oscillator (controller, "D4", M6811_PORTD, 0x10); 372 make_oscillator (controller, "D5", M6811_PORTD, 0x20); 373 374 /* Add oscillator commands. */ 375 sim_add_option_table (sd, 0, m68hc11_options); 376 } 377 378 static void 379 m68hc11cpu_finish (struct hw *me) 380 { 381 struct m68hc11cpu *controller; 382 383 controller = HW_ZALLOC (me, struct m68hc11cpu); 384 set_hw_data (me, controller); 385 set_hw_io_read_buffer (me, m68hc11cpu_io_read_buffer); 386 set_hw_io_write_buffer (me, m68hc11cpu_io_write_buffer); 387 set_hw_ports (me, m68hc11cpu_ports); 388 set_hw_port_event (me, m68hc11cpu_port_event); 389 set_hw_attach_address (me, dv_m6811_attach_address_callback); 390 set_hw_detach_address (me, dv_m6811_detach_address_callback); 391 #ifdef set_hw_ioctl 392 set_hw_ioctl (me, m68hc11_ioctl); 393 #else 394 me->to_ioctl = m68hc11_ioctl; 395 #endif 396 397 /* Initialize the pending interrupt flags. */ 398 controller->pending_level = 0; 399 controller->pending_reset = 0; 400 controller->pending_nmi = 0; 401 controller->event = NULL; 402 403 attach_m68hc11_regs (me, controller); 404 } 405 406 /* An event arrives on an interrupt port. */ 407 408 static void 409 deliver_m68hc11cpu_interrupt (struct hw *me, void *data) 410 { 411 } 412 413 static void 414 make_oscillator (struct m68hc11cpu *controller, const char *name, 415 uint16_t addr, uint8_t mask) 416 { 417 struct input_osc *osc; 418 419 if (controller->last_oscillator >= NR_OSC) 420 hw_abort (0, "Too many oscillators"); 421 422 osc = &controller->oscillators[controller->last_oscillator]; 423 osc->name = name; 424 osc->addr = addr; 425 osc->mask = mask; 426 controller->last_oscillator++; 427 } 428 429 /* Find the oscillator given the input port name. */ 430 static struct input_osc * 431 find_oscillator (struct m68hc11cpu *controller, const char *name) 432 { 433 int i; 434 435 for (i = 0; i < controller->last_oscillator; i++) 436 if (strcasecmp (controller->oscillators[i].name, name) == 0) 437 return &controller->oscillators[i]; 438 439 return 0; 440 } 441 442 static void 443 oscillator_handler (struct hw *me, void *data) 444 { 445 struct input_osc *osc = (struct input_osc*) data; 446 SIM_DESC sd; 447 sim_cpu *cpu; 448 int64_t dt; 449 uint8_t val; 450 451 sd = hw_system (me); 452 cpu = STATE_CPU (sd, 0); 453 454 /* Change the input bit. */ 455 osc->value ^= osc->mask; 456 val = cpu->ios[osc->addr] & ~osc->mask; 457 val |= osc->value; 458 m68hc11cpu_set_port (me, cpu, osc->addr, val); 459 460 /* Setup event to toggle the bit. */ 461 if (osc->value) 462 dt = osc->on_time; 463 else 464 dt = osc->off_time; 465 466 if (dt && --osc->repeat >= 0) 467 { 468 sim_events *events = STATE_EVENTS (sd); 469 470 dt += events->nr_ticks_to_process; 471 osc->event = hw_event_queue_schedule (me, dt, oscillator_handler, osc); 472 } 473 else 474 osc->event = 0; 475 } 476 477 static void 478 reset_oscillators (struct hw *me) 479 { 480 struct m68hc11cpu *controller = hw_data (me); 481 int i; 482 483 for (i = 0; i < controller->last_oscillator; i++) 484 { 485 if (controller->oscillators[i].event) 486 { 487 hw_event_queue_deschedule (me, controller->oscillators[i].event); 488 controller->oscillators[i].event = 0; 489 } 490 } 491 } 492 493 static void 494 m68hc11cpu_port_event (struct hw *me, 495 int my_port, 496 struct hw *source, 497 int source_port, 498 int level) 499 { 500 struct m68hc11cpu *controller = hw_data (me); 501 SIM_DESC sd; 502 sim_cpu *cpu; 503 504 sd = hw_system (me); 505 cpu = STATE_CPU (sd, 0); 506 switch (my_port) 507 { 508 case RESET_PORT: 509 HW_TRACE ((me, "port-in reset")); 510 511 /* The reset is made in 3 steps: 512 - First, cleanup the current sim_cpu struct. 513 - Reset the devices. 514 - Restart the cpu for the reset (get the CPU mode from the 515 CONFIG register that gets initialized by EEPROM device). */ 516 cpu_reset (cpu); 517 reset_oscillators (me); 518 hw_port_event (me, CPU_RESET_PORT, 1); 519 cpu_restart (cpu); 520 break; 521 522 case NMI_PORT: 523 controller->pending_nmi = 1; 524 HW_TRACE ((me, "port-in nmi")); 525 break; 526 527 case IRQ_PORT: 528 /* level == 0 means that the interrupt was cleared. */ 529 if(level == 0) 530 controller->pending_level = -1; /* signal end of interrupt */ 531 else 532 controller->pending_level = level; 533 HW_TRACE ((me, "port-in level=%d", level)); 534 break; 535 536 case SET_PORT_A: 537 m68hc11cpu_set_port (me, cpu, M6811_PORTA, level); 538 break; 539 540 case SET_PORT_C: 541 m68hc11cpu_set_port (me, cpu, M6811_PORTC, level); 542 break; 543 544 case SET_PORT_D: 545 m68hc11cpu_set_port (me, cpu, M6811_PORTD, level); 546 break; 547 548 case CPU_WRITE_PORT: 549 break; 550 551 default: 552 hw_abort (me, "bad switch"); 553 break; 554 } 555 556 /* Schedule an event to be delivered immediately after current 557 instruction. */ 558 if(controller->event != NULL) 559 hw_event_queue_deschedule(me, controller->event); 560 controller->event = 561 hw_event_queue_schedule (me, 0, deliver_m68hc11cpu_interrupt, NULL); 562 } 563 564 565 io_reg_desc config_desc[] = { 566 { M6811_NOSEC, "NOSEC ", "Security Mode Disable" }, 567 { M6811_NOCOP, "NOCOP ", "COP System Disable" }, 568 { M6811_ROMON, "ROMON ", "Enable On-chip Rom" }, 569 { M6811_EEON, "EEON ", "Enable On-chip EEprom" }, 570 { 0, 0, 0 } 571 }; 572 573 io_reg_desc hprio_desc[] = { 574 { M6811_RBOOT, "RBOOT ", "Read Bootstrap ROM" }, 575 { M6811_SMOD, "SMOD ", "Special Mode" }, 576 { M6811_MDA, "MDA ", "Mode Select A" }, 577 { M6811_IRV, "IRV ", "Internal Read Visibility" }, 578 { 0, 0, 0 } 579 }; 580 581 io_reg_desc option_desc[] = { 582 { M6811_ADPU, "ADPU ", "A/D Powerup" }, 583 { M6811_CSEL, "CSEL ", "A/D/EE Charge pump clock source select" }, 584 { M6811_IRQE, "IRQE ", "IRQ Edge/Level sensitive" }, 585 { M6811_DLY, "DLY ", "Stop exit turn on delay" }, 586 { M6811_CME, "CME ", "Clock Monitor Enable" }, 587 { M6811_CR1, "CR1 ", "COP timer rate select (CR1)" }, 588 { M6811_CR0, "CR0 ", "COP timer rate select (CR0)" }, 589 { 0, 0, 0 } 590 }; 591 592 static void 593 m68hc11_info (struct hw *me) 594 { 595 SIM_DESC sd; 596 uint16_t base = 0; 597 sim_cpu *cpu; 598 struct m68hc11sio *controller; 599 uint8_t val; 600 601 sd = hw_system (me); 602 cpu = STATE_CPU (sd, 0); 603 controller = hw_data (me); 604 605 base = cpu_get_io_base (cpu); 606 sim_io_printf (sd, "M68HC11:\n"); 607 608 val = cpu->ios[M6811_HPRIO]; 609 print_io_byte (sd, "HPRIO ", hprio_desc, val, base + M6811_HPRIO); 610 switch (cpu->cpu_mode) 611 { 612 case M6811_MDA | M6811_SMOD: 613 sim_io_printf (sd, "[test]\n"); 614 break; 615 case M6811_SMOD: 616 sim_io_printf (sd, "[bootstrap]\n"); 617 break; 618 case M6811_MDA: 619 sim_io_printf (sd, "[extended]\n"); 620 break; 621 default: 622 sim_io_printf (sd, "[single]\n"); 623 break; 624 } 625 626 val = cpu->ios[M6811_CONFIG]; 627 print_io_byte (sd, "CONFIG", config_desc, val, base + M6811_CONFIG); 628 sim_io_printf (sd, "\n"); 629 630 val = cpu->ios[M6811_OPTION]; 631 print_io_byte (sd, "OPTION", option_desc, val, base + M6811_OPTION); 632 sim_io_printf (sd, "\n"); 633 634 val = cpu->ios[M6811_INIT]; 635 print_io_byte (sd, "INIT ", 0, val, base + M6811_INIT); 636 sim_io_printf (sd, "Ram = 0x%04x IO = 0x%04x\n", 637 (((uint16_t) (val & 0xF0)) << 8), 638 (((uint16_t) (val & 0x0F)) << 12)); 639 640 641 cpu_info (sd, cpu); 642 interrupts_info (sd, &cpu->cpu_interrupts); 643 } 644 645 static int 646 m68hc11_ioctl (struct hw *me, 647 hw_ioctl_request request, 648 va_list ap) 649 { 650 m68hc11_info (me); 651 return 0; 652 } 653 654 /* Setup an oscillator on an input port. 655 656 TON represents the time in seconds that the input port should be set to 1. 657 TOFF is the time in seconds for the input port to be set to 0. 658 659 The oscillator frequency is therefore 1 / (ton + toff). 660 661 REPEAT indicates the number of 1 <-> 0 transitions until the oscillator 662 stops. */ 663 int 664 m68hc11cpu_set_oscillator (SIM_DESC sd, const char *port, 665 double ton, double toff, int64_t repeat) 666 { 667 sim_cpu *cpu; 668 struct input_osc *osc; 669 double f; 670 671 cpu = STATE_CPU (sd, 0); 672 673 /* Find oscillator that corresponds to the input port. */ 674 osc = find_oscillator (hw_data (cpu->hw_cpu), port); 675 if (osc == 0) 676 return -1; 677 678 /* Compute the ON time in cpu cycles. */ 679 f = (double) (cpu->cpu_frequency) * ton; 680 osc->on_time = (int64_t) (f / 4.0); 681 if (osc->on_time < 1) 682 osc->on_time = 1; 683 684 /* Compute the OFF time in cpu cycles. */ 685 f = (double) (cpu->cpu_frequency) * toff; 686 osc->off_time = (int64_t) (f / 4.0); 687 if (osc->off_time < 1) 688 osc->off_time = 1; 689 690 osc->repeat = repeat; 691 if (osc->event) 692 hw_event_queue_deschedule (cpu->hw_cpu, osc->event); 693 694 osc->event = hw_event_queue_schedule (cpu->hw_cpu, 695 osc->value ? osc->on_time 696 : osc->off_time, 697 oscillator_handler, osc); 698 return 0; 699 } 700 701 /* Clear the oscillator. */ 702 int 703 m68hc11cpu_clear_oscillator (SIM_DESC sd, const char *port) 704 { 705 sim_cpu *cpu; 706 struct input_osc *osc; 707 708 cpu = STATE_CPU (sd, 0); 709 osc = find_oscillator (hw_data (cpu->hw_cpu), port); 710 if (osc == 0) 711 return -1; 712 713 if (osc->event) 714 hw_event_queue_deschedule (cpu->hw_cpu, osc->event); 715 osc->event = 0; 716 osc->repeat = 0; 717 return 0; 718 } 719 720 static int 721 get_frequency (const char *s, double *f) 722 { 723 char *p; 724 725 *f = strtod (s, &p); 726 if (s == p) 727 return -1; 728 729 if (*p) 730 { 731 if (strcasecmp (p, "khz") == 0) 732 *f = *f * 1000.0; 733 else if (strcasecmp (p, "mhz") == 0) 734 *f = *f * 1000000.0; 735 else if (strcasecmp (p, "hz") != 0) 736 return -1; 737 } 738 return 0; 739 } 740 741 static SIM_RC 742 m68hc11_option_handler (SIM_DESC sd, sim_cpu *cpu, 743 int opt, char *arg, int is_command) 744 { 745 struct m68hc11cpu *controller; 746 double f; 747 char *p; 748 int i; 749 int title_printed = 0; 750 751 if (cpu == 0) 752 cpu = STATE_CPU (sd, 0); 753 754 controller = hw_data (cpu->hw_cpu); 755 switch (opt) 756 { 757 case OPTION_OSC_SET: 758 p = strchr (arg, ','); 759 if (p) 760 *p++ = 0; 761 762 if (p == 0) 763 sim_io_eprintf (sd, "No frequency specified\n"); 764 else if (get_frequency (p, &f) < 0 || f < 1.0e-8) 765 sim_io_eprintf (sd, "Invalid frequency: '%s'\n", p); 766 else if (m68hc11cpu_set_oscillator (sd, arg, 767 1.0 / (f * 2.0), 768 1.0 / (f * 2.0), LONG_MAX)) 769 sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg); 770 break; 771 772 case OPTION_OSC_CLEAR: 773 if (m68hc11cpu_clear_oscillator (sd, arg) != 0) 774 sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg); 775 break; 776 777 case OPTION_OSC_INFO: 778 for (i = 0; i < controller->last_oscillator; i++) 779 { 780 int64_t t; 781 struct input_osc *osc; 782 783 osc = &controller->oscillators[i]; 784 if (osc->event) 785 { 786 double f; 787 int cur_value; 788 int next_value; 789 char freq[32]; 790 791 if (title_printed == 0) 792 { 793 title_printed = 1; 794 sim_io_printf (sd, " PORT Frequency Current" 795 " Next Transition time\n"); 796 } 797 798 f = (double) (osc->on_time + osc->off_time); 799 f = (double) (cpu->cpu_frequency / 4) / f; 800 t = hw_event_remain_time (cpu->hw_cpu, osc->event); 801 802 if (f > 10000.0) 803 sprintf (freq, "%6.2f", f / 1000.0); 804 else 805 sprintf (freq, "%6.2f", f); 806 cur_value = osc->value ? 1 : 0; 807 next_value = osc->value ? 0 : 1; 808 if (f > 10000.0) 809 sim_io_printf (sd, " %4.4s %8.8s khz" 810 " %d %d %35.35s\n", 811 osc->name, freq, 812 cur_value, next_value, 813 cycle_to_string (cpu, t, 814 PRINT_TIME | PRINT_CYCLE)); 815 else 816 sim_io_printf (sd, " %4.4s %8.8s hz " 817 " %d %d %35.35s\n", 818 osc->name, freq, 819 cur_value, next_value, 820 cycle_to_string (cpu, t, 821 PRINT_TIME | PRINT_CYCLE)); 822 } 823 } 824 break; 825 } 826 827 return SIM_RC_OK; 828 } 829 830 /* generic read/write */ 831 832 static unsigned 833 m68hc11cpu_io_read_buffer (struct hw *me, 834 void *dest, 835 int space, 836 unsigned_word base, 837 unsigned nr_bytes) 838 { 839 SIM_DESC sd; 840 struct m68hc11cpu *controller = hw_data (me); 841 sim_cpu *cpu; 842 unsigned byte = 0; 843 int result; 844 845 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); 846 847 sd = hw_system (me); 848 cpu = STATE_CPU (sd, 0); 849 850 if (base >= cpu->bank_start && base < cpu->bank_end) 851 { 852 address_word virt_addr = phys_to_virt (cpu, base); 853 if (virt_addr != base) 854 return sim_core_read_buffer (sd, cpu, space, dest, 855 virt_addr, nr_bytes); 856 } 857 858 /* Handle reads for the sub-devices. */ 859 base -= controller->attach_address; 860 result = sim_core_read_buffer (sd, cpu, 861 io_map, dest, base, nr_bytes); 862 if (result > 0) 863 return result; 864 865 while (nr_bytes) 866 { 867 if (base >= controller->attach_size) 868 break; 869 870 memcpy (dest, &cpu->ios[base], 1); 871 dest = (char*) dest + 1; 872 base++; 873 byte++; 874 nr_bytes--; 875 } 876 return byte; 877 } 878 879 void 880 m68hc11cpu_set_port (struct hw *me, sim_cpu *cpu, 881 unsigned addr, uint8_t val) 882 { 883 uint8_t mask; 884 uint8_t delta; 885 int check_interrupts = 0; 886 int i; 887 888 switch (addr) 889 { 890 case M6811_PORTA: 891 if (cpu->ios[M6811_PACTL] & M6811_DDRA7) 892 mask = 3; 893 else 894 mask = 0x83; 895 896 val = val & mask; 897 val |= cpu->ios[M6811_PORTA] & ~mask; 898 delta = val ^ cpu->ios[M6811_PORTA]; 899 cpu->ios[M6811_PORTA] = val; 900 if (delta & 0x80) 901 { 902 /* Pulse accumulator is enabled. */ 903 if ((cpu->ios[M6811_PACTL] & M6811_PAEN) 904 && !(cpu->ios[M6811_PACTL] & M6811_PAMOD)) 905 { 906 int inc; 907 908 /* Increment event counter according to rising/falling edge. */ 909 if (cpu->ios[M6811_PACTL] & M6811_PEDGE) 910 inc = (val & 0x80) ? 1 : 0; 911 else 912 inc = (val & 0x80) ? 0 : 1; 913 914 cpu->ios[M6811_PACNT] += inc; 915 916 /* Event counter overflowed. */ 917 if (inc && cpu->ios[M6811_PACNT] == 0) 918 { 919 cpu->ios[M6811_TFLG2] |= M6811_PAOVI; 920 check_interrupts = 1; 921 } 922 } 923 } 924 925 /* Scan IC3, IC2 and IC1. Bit number is 3 - i. */ 926 for (i = 0; i < 3; i++) 927 { 928 uint8_t mask = (1 << i); 929 930 if (delta & mask) 931 { 932 uint8_t edge; 933 int captured; 934 935 edge = cpu->ios[M6811_TCTL2]; 936 edge = (edge >> (2 * i)) & 0x3; 937 switch (edge) 938 { 939 case 0: 940 captured = 0; 941 break; 942 case 1: 943 captured = (val & mask) != 0; 944 break; 945 case 2: 946 captured = (val & mask) == 0; 947 break; 948 default: 949 captured = 1; 950 break; 951 } 952 if (captured) 953 { 954 cpu->ios[M6811_TFLG1] |= (1 << i); 955 hw_port_event (me, CAPTURE, M6811_TIC1 + 3 - i); 956 check_interrupts = 1; 957 } 958 } 959 } 960 break; 961 962 case M6811_PORTC: 963 mask = cpu->ios[M6811_DDRC]; 964 val = val & mask; 965 val |= cpu->ios[M6811_PORTC] & ~mask; 966 cpu->ios[M6811_PORTC] = val; 967 break; 968 969 case M6811_PORTD: 970 mask = cpu->ios[M6811_DDRD]; 971 val = val & mask; 972 val |= cpu->ios[M6811_PORTD] & ~mask; 973 cpu->ios[M6811_PORTD] = val; 974 break; 975 976 default: 977 break; 978 } 979 980 if (check_interrupts) 981 interrupts_update_pending (&cpu->cpu_interrupts); 982 } 983 984 static void 985 m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu, 986 unsigned_word addr, uint8_t val) 987 { 988 switch (addr) 989 { 990 case M6811_PORTA: 991 hw_port_event (me, PORT_A, val); 992 break; 993 994 case M6811_PIOC: 995 break; 996 997 case M6811_PORTC: 998 hw_port_event (me, PORT_C, val); 999 break; 1000 1001 case M6811_PORTB: 1002 hw_port_event (me, PORT_B, val); 1003 break; 1004 1005 case M6811_PORTCL: 1006 break; 1007 1008 case M6811_DDRC: 1009 break; 1010 1011 case M6811_PORTD: 1012 hw_port_event (me, PORT_D, val); 1013 break; 1014 1015 case M6811_DDRD: 1016 break; 1017 1018 case M6811_TMSK2: 1019 1020 break; 1021 1022 /* Change the RAM and I/O mapping. */ 1023 case M6811_INIT: 1024 { 1025 uint8_t old_bank = cpu->ios[M6811_INIT]; 1026 1027 cpu->ios[M6811_INIT] = val; 1028 1029 /* Update IO mapping. Detach from the old address 1030 and attach to the new one. */ 1031 if ((old_bank & 0x0F) != (val & 0x0F)) 1032 { 1033 struct m68hc11cpu *controller = hw_data (me); 1034 1035 hw_detach_address (hw_parent (me), M6811_IO_LEVEL, 1036 controller->attach_space, 1037 controller->attach_address, 1038 controller->attach_size, 1039 me); 1040 controller->attach_address = (val & 0x0F0) << 12; 1041 hw_attach_address (hw_parent (me), M6811_IO_LEVEL, 1042 controller->attach_space, 1043 controller->attach_address, 1044 controller->attach_size, 1045 me); 1046 } 1047 if ((old_bank & 0xF0) != (val & 0xF0)) 1048 { 1049 ; 1050 } 1051 return; 1052 } 1053 1054 /* Writing the config is similar to programing the eeprom. 1055 The config register value is the last byte of the EEPROM. 1056 This last byte is not mapped in memory (that's why we have 1057 to add '1' to 'end_addr'). */ 1058 case M6811_CONFIG: 1059 { 1060 return; 1061 } 1062 1063 1064 /* COP reset. */ 1065 case M6811_COPRST: 1066 if (val == 0xAA && cpu->ios[addr] == 0x55) 1067 { 1068 val = 0; 1069 /* COP reset here. */ 1070 } 1071 break; 1072 1073 default: 1074 break; 1075 1076 } 1077 cpu->ios[addr] = val; 1078 } 1079 1080 static unsigned 1081 m68hc11cpu_io_write_buffer (struct hw *me, 1082 const void *source, 1083 int space, 1084 unsigned_word base, 1085 unsigned nr_bytes) 1086 { 1087 SIM_DESC sd; 1088 struct m68hc11cpu *controller = hw_data (me); 1089 unsigned byte; 1090 sim_cpu *cpu; 1091 int result; 1092 1093 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); 1094 1095 sd = hw_system (me); 1096 cpu = STATE_CPU (sd, 0); 1097 1098 if (base >= cpu->bank_start && base < cpu->bank_end) 1099 { 1100 address_word virt_addr = phys_to_virt (cpu, base); 1101 if (virt_addr != base) 1102 return sim_core_write_buffer (sd, cpu, space, source, 1103 virt_addr, nr_bytes); 1104 } 1105 base -= controller->attach_address; 1106 result = sim_core_write_buffer (sd, cpu, 1107 io_map, source, base, nr_bytes); 1108 if (result > 0) 1109 return result; 1110 1111 byte = 0; 1112 while (nr_bytes) 1113 { 1114 uint8_t val; 1115 if (base >= controller->attach_size) 1116 break; 1117 1118 val = *((uint8_t*) source); 1119 m68hc11cpu_io_write (me, cpu, base, val); 1120 source = (char*) source + 1; 1121 base++; 1122 byte++; 1123 nr_bytes--; 1124 } 1125 return byte; 1126 } 1127 1128 const struct hw_descriptor dv_m68hc11_descriptor[] = { 1129 { "m68hc11", m68hc11cpu_finish }, 1130 { "m68hc12", m68hc11cpu_finish }, 1131 { NULL }, 1132 }; 1133 1134