trunk/src/mess/drivers/ti99_4x.c
| r26106 | r26107 | |
| 54 | 54 | #include "machine/ti99/joyport.h" |
| 55 | 55 | #include "machine/ti99/peribox.h" |
| 56 | 56 | |
| 57 | // Debugging |
| 58 | #define TRACE_READY 0 |
| 59 | #define TRACE_INTERRUPTS 0 |
| 60 | #define TRACE_CRU 0 |
| 57 | 61 | #define LOG logerror |
| 58 | | #define VERBOSE 1 |
| 59 | 62 | |
| 60 | 63 | /* |
| 61 | 64 | The console. |
| r26106 | r26107 | |
| 92 | 95 | DECLARE_WRITE_LINE_MEMBER( dbin_line ); |
| 93 | 96 | |
| 94 | 97 | // Connections from outside towards the CPU (callbacks) |
| 95 | | DECLARE_WRITE_LINE_MEMBER( console_ready ); |
| 96 | 98 | DECLARE_WRITE_LINE_MEMBER( console_ready_dmux ); |
| 99 | DECLARE_WRITE_LINE_MEMBER( console_ready_sound ); |
| 100 | DECLARE_WRITE_LINE_MEMBER( console_ready_pbox ); |
| 101 | DECLARE_WRITE_LINE_MEMBER( console_ready_cart ); |
| 102 | DECLARE_WRITE_LINE_MEMBER( console_ready_grom ); |
| 97 | 103 | DECLARE_WRITE_LINE_MEMBER( console_reset ); |
| 104 | DECLARE_WRITE_LINE_MEMBER( extint ); |
| 105 | DECLARE_WRITE_LINE_MEMBER( notconnected ); |
| 98 | 106 | |
| 99 | 107 | // Connections with the system interface chip 9901 |
| 100 | 108 | DECLARE_WRITE_LINE_MEMBER( set_tms9901_INT2 ); |
| 101 | 109 | DECLARE_WRITE_LINE_MEMBER( set_tms9901_INT12 ); |
| 102 | 110 | DECLARE_WRITE_LINE_MEMBER( set_tms9901_INT2_from_v9938); |
| 103 | | DECLARE_WRITE_LINE_MEMBER( extint ); |
| 104 | | DECLARE_WRITE_LINE_MEMBER( notconnected ); |
| 105 | 111 | |
| 106 | 112 | // Connections with the system interface TMS9901 |
| 107 | 113 | DECLARE_READ8_MEMBER(read_by_9901); |
| r26106 | r26107 | |
| 125 | 131 | int m_keyboard_column; |
| 126 | 132 | int m_check_alphalock; |
| 127 | 133 | |
| 128 | | int m_ready_prev; // for debugging purposes only |
| 134 | // READY handling |
| 135 | int m_nready_combined; |
| 136 | int m_nready_prev; |
| 137 | void console_ready_join(int id, int state); |
| 129 | 138 | |
| 130 | | // Latches the ready line from different sources |
| 131 | | int m_ready_line, m_ready_line_dmux; |
| 132 | | |
| 133 | 139 | // Console type |
| 134 | 140 | int m_console; |
| 135 | 141 | |
| r26106 | r26107 | |
| 156 | 162 | }; |
| 157 | 163 | |
| 158 | 164 | /* |
| 165 | READY bits. |
| 166 | */ |
| 167 | enum |
| 168 | { |
| 169 | READY_GROM = 1, |
| 170 | READY_DMUX = 2, |
| 171 | READY_PBOX = 4, |
| 172 | READY_SOUND = 8, |
| 173 | READY_CART = 16 |
| 174 | }; |
| 175 | |
| 176 | /* |
| 159 | 177 | Memory map. |
| 160 | 178 | Most of the work is done in the datamux (see datamux.c). We only keep ROM |
| 161 | 179 | and the small 256 byte PAD RAM here because they are directly connected |
| r26106 | r26107 | |
| 340 | 358 | |
| 341 | 359 | static GROM_CONFIG(grom0_config) |
| 342 | 360 | { |
| 343 | | false, 0, region_grom, 0x0000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, console_ready), GROMFREQ |
| 361 | false, 0, region_grom, 0x0000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, console_ready_grom), GROMFREQ |
| 344 | 362 | }; |
| 345 | 363 | |
| 346 | 364 | static GROM_CONFIG(grom1_config) |
| 347 | 365 | { |
| 348 | | false, 1, region_grom, 0x2000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, console_ready), GROMFREQ |
| 366 | false, 1, region_grom, 0x2000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, console_ready_grom), GROMFREQ |
| 349 | 367 | }; |
| 350 | 368 | |
| 351 | 369 | static GROM_CONFIG(grom2_config) |
| 352 | 370 | { |
| 353 | | false, 2, region_grom, 0x4000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, console_ready), GROMFREQ |
| 371 | false, 2, region_grom, 0x4000, 0x1800, DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, console_ready_grom), GROMFREQ |
| 354 | 372 | }; |
| 355 | 373 | |
| 356 | 374 | static GROMPORT_CONFIG(console_cartslot) |
| 357 | 375 | { |
| 358 | | DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, console_ready), |
| 376 | DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, console_ready_cart), |
| 359 | 377 | DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, console_reset) |
| 360 | 378 | }; |
| 361 | 379 | |
| r26106 | r26107 | |
| 363 | 381 | { |
| 364 | 382 | DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, extint), // INTA |
| 365 | 383 | DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, notconnected), // INTB |
| 366 | | DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, console_ready), // READY |
| 384 | DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, console_ready_pbox), // READY |
| 367 | 385 | 0x70000 // Address bus prefix (AMA/AMB/AMC) |
| 368 | 386 | }; |
| 369 | 387 | |
| 370 | 388 | static TI_SOUND_CONFIG( sound_conf ) |
| 371 | 389 | { |
| 372 | | DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, console_ready) // READY |
| 390 | DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, console_ready_sound) // READY |
| 373 | 391 | }; |
| 374 | 392 | |
| 375 | 393 | READ8_MEMBER( ti99_4x_state::cruread ) |
| 376 | 394 | { |
| 377 | | // if (VERBOSE>6) LOG("read access to CRU address %04x\n", offset << 4); |
| 395 | // if (TRACE_CRU) LOG("read access to CRU address %04x\n", offset << 4); |
| 378 | 396 | UINT8 value = 0; |
| 379 | 397 | |
| 380 | 398 | // Similar to the bus8z_devices, just let the gromport and the p-box |
| r26106 | r26107 | |
| 390 | 408 | |
| 391 | 409 | WRITE8_MEMBER( ti99_4x_state::cruwrite ) |
| 392 | 410 | { |
| 393 | | if (VERBOSE>6) LOG("ti99_4x: write access to CRU address %04x\n", offset << 1); |
| 411 | if (TRACE_CRU) LOG("ti99_4x: write access to CRU address %04x\n", offset << 1); |
| 394 | 412 | // The QI version does not propagate the CRU signals to the cartridge slot |
| 395 | 413 | if (m_console != MODEL_4QI) m_gromport->cruwrite(space, offset<<1, data); |
| 396 | 414 | m_peribox->cruwrite(space, offset<<1, data); |
| r26106 | r26107 | |
| 403 | 421 | if (offset == IDLE_OP) return; |
| 404 | 422 | else |
| 405 | 423 | { |
| 406 | | if (VERBOSE>1) LOG("ti99_4x: External operation %s not implemented on TI-99 board\n", extop[offset]); |
| 424 | LOG("ti99_4x: External operation %s not implemented on TI-99 board\n", extop[offset]); |
| 407 | 425 | } |
| 408 | 426 | } |
| 409 | 427 | |
| r26106 | r26107 | |
| 637 | 655 | */ |
| 638 | 656 | WRITE_LINE_MEMBER( ti99_4x_state::set_tms9901_INT2 ) |
| 639 | 657 | { |
| 640 | | if (VERBOSE>6) LOG("ti99_4x: VDP int 2 on tms9901, level=%d\n", state); |
| 658 | if (TRACE_INTERRUPTS) LOG("ti99_4x: VDP int 2 on tms9901, level=%d\n", state); |
| 641 | 659 | m_tms9901->set_single_int(2, state); |
| 642 | 660 | } |
| 643 | 661 | |
| 644 | 662 | WRITE_LINE_MEMBER(ti99_4x_state::set_tms9901_INT2_from_v9938) |
| 645 | 663 | { |
| 664 | if (TRACE_INTERRUPTS) LOG("ti99_4x: VDP int 2 on tms9901, level=%d\n", state); |
| 646 | 665 | m_tms9901->set_single_int(2, state); |
| 647 | 666 | } |
| 648 | 667 | |
| r26106 | r26107 | |
| 651 | 670 | */ |
| 652 | 671 | WRITE_LINE_MEMBER( ti99_4x_state::set_tms9901_INT12) |
| 653 | 672 | { |
| 673 | if (TRACE_INTERRUPTS) LOG("ti99_4x: joyport INT 12 on tms9901, level=%d\n", state); |
| 654 | 674 | m_tms9901->set_single_int(12, state); |
| 655 | 675 | } |
| 656 | 676 | |
| r26106 | r26107 | |
| 660 | 680 | */ |
| 661 | 681 | INPUT_CHANGED_MEMBER( ti99_4x_state::load_interrupt ) |
| 662 | 682 | { |
| 683 | LOG("ti99_4x: LOAD interrupt, level=%d\n", newval); |
| 663 | 684 | m_cpu->set_input_line(INT_9900_LOAD, (newval==0)? ASSERT_LINE : CLEAR_LINE); |
| 664 | 685 | } |
| 665 | 686 | |
| r26106 | r26107 | |
| 667 | 688 | Links to external devices |
| 668 | 689 | ***********************************************************/ |
| 669 | 690 | |
| 670 | | // FIXME: The sound chip is one of the devices that may operate the ready line |
| 671 | | // at some later time and thus mess up the READY handling (raises the READY |
| 672 | | // line without bothering about the rest). We need to do a proper AND here. |
| 673 | | |
| 674 | 691 | /* |
| 675 | | We may have lots of devices pulling down this line; so we should use a AND |
| 676 | | gate to do it right. On the other hand, when READY is down, there is just |
| 677 | | no chance to make another device pull down the same line; the CPU just |
| 678 | | won't access any other device in this time. |
| 692 | We combine the incoming READY signals and propagate them to the CPU. |
| 693 | An alternative would be to let the CPU get the READY state, but this would |
| 694 | be a much higher overhead, as this happens in each clock tick. |
| 679 | 695 | */ |
| 680 | | WRITE_LINE_MEMBER( ti99_4x_state::console_ready ) |
| 696 | void ti99_4x_state::console_ready_join(int id, int state) |
| 681 | 697 | { |
| 682 | | m_ready_line = state; |
| 683 | | int combined = (m_ready_line == ASSERT_LINE && m_ready_line_dmux == ASSERT_LINE)? ASSERT_LINE : CLEAR_LINE; |
| 698 | if (state==CLEAR_LINE) |
| 699 | m_nready_combined |= id; |
| 700 | else |
| 701 | m_nready_combined &= ~id; |
| 684 | 702 | |
| 685 | | if (VERBOSE>6) |
| 703 | if (TRACE_READY) |
| 686 | 704 | { |
| 687 | | if (m_ready_prev != combined) LOG("ti99_4x: READY level = %d\n", combined); |
| 705 | if (m_nready_prev != m_nready_combined) LOG("ti99_4x: READY bits = %04x\n", ~m_nready_combined); |
| 688 | 706 | } |
| 689 | | m_ready_prev = combined; |
| 690 | | m_cpu->set_ready(combined); |
| 707 | |
| 708 | m_nready_prev = m_nready_combined; |
| 709 | m_cpu->set_ready(m_nready_combined==0); |
| 691 | 710 | } |
| 692 | 711 | |
| 693 | 712 | /* |
| 694 | | The RESET line leading to a reset of the CPU. |
| 713 | Connections to the READY line. This might look a bit ugly; we need an |
| 714 | implementation of a "Wired AND" device. |
| 695 | 715 | */ |
| 696 | | WRITE_LINE_MEMBER( ti99_4x_state::console_reset ) |
| 716 | WRITE_LINE_MEMBER( ti99_4x_state::console_ready_grom ) |
| 697 | 717 | { |
| 698 | | if (machine().phase() != MACHINE_PHASE_INIT) |
| 699 | | { |
| 700 | | m_cpu->set_input_line(INT_9900_RESET, state); |
| 701 | | m_video->reset_vdp(state); |
| 702 | | } |
| 718 | console_ready_join(READY_GROM, state); |
| 703 | 719 | } |
| 704 | 720 | |
| 721 | WRITE_LINE_MEMBER( ti99_4x_state::console_ready_dmux ) |
| 722 | { |
| 723 | console_ready_join(READY_DMUX, state); |
| 724 | } |
| 725 | |
| 726 | WRITE_LINE_MEMBER( ti99_4x_state::console_ready_pbox ) |
| 727 | { |
| 728 | console_ready_join(READY_PBOX, state); |
| 729 | } |
| 730 | |
| 731 | WRITE_LINE_MEMBER( ti99_4x_state::console_ready_sound ) |
| 732 | { |
| 733 | console_ready_join(READY_SOUND, state); |
| 734 | } |
| 735 | |
| 736 | WRITE_LINE_MEMBER( ti99_4x_state::console_ready_cart ) |
| 737 | { |
| 738 | console_ready_join(READY_CART, state); |
| 739 | } |
| 740 | |
| 705 | 741 | /* |
| 706 | | The exception of the above rule. Memory access over the datamux also operates |
| 707 | | the READY line, and the datamux raises READY depending on the clock pulse. |
| 708 | | So we must make sure this does not interfere. |
| 742 | The RESET line leading to a reset of the CPU. This is asserted when a |
| 743 | cartridge is plugged in. |
| 709 | 744 | */ |
| 710 | | WRITE_LINE_MEMBER( ti99_4x_state::console_ready_dmux ) |
| 745 | WRITE_LINE_MEMBER( ti99_4x_state::console_reset ) |
| 711 | 746 | { |
| 712 | | m_ready_line_dmux = state; |
| 713 | | int combined = (m_ready_line == ASSERT_LINE && m_ready_line_dmux == ASSERT_LINE)? ASSERT_LINE : CLEAR_LINE; |
| 714 | | |
| 715 | | if (VERBOSE>7) |
| 747 | if (machine().phase() != MACHINE_PHASE_INIT) |
| 716 | 748 | { |
| 717 | | if (m_ready_prev != combined) LOG("ti99_4x: READY dmux level = %d\n", state); |
| 749 | m_cpu->set_input_line(INT_9900_RESET, state); |
| 750 | m_video->reset_vdp(state); |
| 718 | 751 | } |
| 719 | | m_ready_prev = combined; |
| 720 | | m_cpu->set_ready(combined); |
| 721 | 752 | } |
| 722 | 753 | |
| 723 | 754 | WRITE_LINE_MEMBER( ti99_4x_state::extint ) |
| 724 | 755 | { |
| 725 | | if (VERBOSE>6) LOG("ti99_4x: EXTINT level = %02x\n", state); |
| 756 | if (TRACE_INTERRUPTS) LOG("ti99_4x: EXTINT level = %02x\n", state); |
| 726 | 757 | if (m_tms9901 != NULL) |
| 727 | 758 | m_tms9901->set_single_int(1, state); |
| 728 | 759 | } |
| 729 | 760 | |
| 730 | 761 | WRITE_LINE_MEMBER( ti99_4x_state::notconnected ) |
| 731 | 762 | { |
| 732 | | if (VERBOSE>6) LOG("ti99_4x: Setting a not connected line ... ignored\n"); |
| 763 | if (TRACE_INTERRUPTS) LOG("ti99_4x: Setting a not connected line ... ignored\n"); |
| 733 | 764 | } |
| 734 | 765 | |
| 735 | 766 | /*****************************************************************************/ |
| r26106 | r26107 | |
| 892 | 923 | { |
| 893 | 924 | m_peribox->senila(CLEAR_LINE); |
| 894 | 925 | m_peribox->senilb(CLEAR_LINE); |
| 895 | | m_ready_line = m_ready_line_dmux = ASSERT_LINE; |
| 896 | | |
| 926 | m_nready_combined = 0; |
| 897 | 927 | m_console = MODEL_4; |
| 898 | 928 | } |
| 899 | 929 | |
| r26106 | r26107 | |
| 997 | 1027 | { |
| 998 | 1028 | m_peribox->senila(CLEAR_LINE); |
| 999 | 1029 | m_peribox->senilb(CLEAR_LINE); |
| 1000 | | m_ready_line = m_ready_line_dmux = ASSERT_LINE; |
| 1030 | m_nready_combined = 0; |
| 1001 | 1031 | m_console = MODEL_4A; |
| 1002 | 1032 | } |
| 1003 | 1033 | |
| r26106 | r26107 | |
| 1104 | 1134 | { |
| 1105 | 1135 | m_peribox->senila(CLEAR_LINE); |
| 1106 | 1136 | m_peribox->senilb(CLEAR_LINE); |
| 1107 | | m_ready_line = m_ready_line_dmux = ASSERT_LINE; |
| 1108 | 1137 | m_console = MODEL_4QI; |
| 1138 | m_nready_combined = 0; |
| 1109 | 1139 | } |
| 1110 | 1140 | |
| 1111 | 1141 | static MACHINE_CONFIG_START( ti99_4qi_60hz, ti99_4x_state ) |