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