From 9f4d3ddfe6b0582776ca68f97f8b92c7feca3f0b Mon Sep 17 00:00:00 2001 From: Devin Acker Date: Wed, 19 Oct 2022 07:08:24 -0400 Subject: [PATCH] ctk-530: New working machine (#10445) New working machine -------------------- Casio CTK-530 [Devin Acker] --- src/devices/cpu/h8/gt913.cpp | 6 + src/mame/casio/ctk551.cpp | 214 +++++++++++++++++-- src/mame/layout/ctk530.lay | 386 +++++++++++++++++++++++++++++++++++ src/mame/mame.lst | 1 + 4 files changed, 592 insertions(+), 15 deletions(-) create mode 100644 src/mame/layout/ctk530.lay diff --git a/src/devices/cpu/h8/gt913.cpp b/src/devices/cpu/h8/gt913.cpp index 6819ecb400f..c56c8ed94f3 100644 --- a/src/devices/cpu/h8/gt913.cpp +++ b/src/devices/cpu/h8/gt913.cpp @@ -50,6 +50,12 @@ void gt913_device::map(address_map &map) map(0x0000, 0x7fff).rom(); map(0x8000, 0xbfff).rw(FUNC(gt913_device::data_r), FUNC(gt913_device::data_w)); map(0xc000, 0xf7ff).rom(); + + /* ctk530 writes here to latch LED matrix data, which generates an active high strobe on pin 99 (PLE/P16) + there's otherwise no external address decoding (or the usual read/write strobes) used for the LED latches. + just treat as a 16-bit write-only port for now */ + map(0xe000, 0xe001).lw16(NAME([this](uint16_t data) { io.write_word(h8_device::PORT_4, data); })); + map(0xfac0, 0xffbf).ram(); /* ffc0-ffcb: sound */ diff --git a/src/mame/casio/ctk551.cpp b/src/mame/casio/ctk551.cpp index 7ce5a0ab2ea..4d10df8a95f 100644 --- a/src/mame/casio/ctk551.cpp +++ b/src/mame/casio/ctk551.cpp @@ -37,6 +37,31 @@ is supposed to trigger a NMI which updates the RAM checksum, but the NMI handler always proceeds to fully start up the system as if the power is being turned on +------------------------------------------------------------------------------- + + CTK-530/540 (1995) + + Main board (JCM460-MA1M): + LSI101: CPU (Casio/NEC uPD912GF) + LSI102: 8Mbit ROM (Macronix MX23C8100PC-12) + IC103: stereo DAC (NEC uPD6379GR) + X301: 20MHz crystal + + Service manual with schematics, pinouts, etc.: + https://revenant1.net/casio/manuals/upd91x/ctk530.pdf + + To access the test mode (not mentioned in the service manual): + Hold the keypad 0 button while turning on the keyboard, then release the button. + "TST" will appear on the LCD. Afterwards, press one of these buttons: + - Keypad 0: switch test (press all front panel buttons in each column, top to bottom and left to right) + - Keypad 1: key test + - Keypad 2: ROM test + - Keypad 4/5/6: sound volume test + - Keypad 7/8: stereo test + - Keypad 9: MIDI loopback test + - Keypad +: LED/display test + - Mode: power off + ------------------------------------------------------------------------------- General MIDI modules (1996) @@ -123,6 +148,10 @@ Adds velocity-sensitive keys - CTK-551, CTK-558, Radio Shack MD-1160 (2000) Adds pitch wheel and different selection of demo songs + - CT-588 (2001) + Chinese localized version of CTK-541 + - CT-688 (2001) + Chinese localized version of CTK-551 Main board (JCM453-MA1M / JCM456-MA1M): LSI1: CPU (Casio GT913F) @@ -160,11 +189,13 @@ #include "cpu/h8/gt913.h" #include "machine/nvram.h" #include "video/hd44780.h" +#include "video/pwm.h" #include "emupal.h" #include "screen.h" #include "speaker.h" #include "ap10.lh" +#include "ctk530.lh" namespace { @@ -174,6 +205,7 @@ public: ctk551_state(machine_config const &mconfig, device_type type, char const *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") + , m_pwm(*this, "pwm") , m_lcdc(*this, "lcdc") , m_inputs(*this, "IN%u", 0U) , m_outputs(*this, "%02x.%d.%d", 0U, 0U, 0U) @@ -184,14 +216,21 @@ public: } void ap10(machine_config& config); + void ctk530(machine_config& config); void gz70sp(machine_config& config); void ctk601(machine_config& config); void ctk551(machine_config &config); void init_ap10(); + void init_ctk530(); void init_gz70sp(); - DECLARE_CUSTOM_INPUT_MEMBER(lcd_r) { return m_lcdc->db_r() >> 4; } + TIMER_CALLBACK_MEMBER(nmi_clear) { m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); } + + DECLARE_WRITE_LINE_MEMBER(pwm_row_w) { m_pwm->write_my(state); } + DECLARE_WRITE_LINE_MEMBER(pwm_col_w) { m_pwm->write_mx(state ^ 0xff); } + + DECLARE_CUSTOM_INPUT_MEMBER(lcd_r) { return m_lcdc->db_r() >> 4; } DECLARE_WRITE_LINE_MEMBER(lcd_w) { m_lcd_data = state << 4; @@ -230,19 +269,23 @@ public: private: void ap10_map(address_map& map); + void ctk530_map(address_map& map); void gz70sp_map(address_map& map); void ctk601_map(address_map& map); - void ctk551_map(address_map& map); void ap10_io_map(address_map& map); + void ctk530_io_map(address_map& map); void gz70sp_io_map(address_map& map); void ctk551_io_map(address_map &map); virtual void driver_start() override; required_device m_maincpu; + optional_device m_pwm; optional_device m_lcdc; + emu_timer* m_nmi_timer = nullptr; + optional_ioport_array<4> m_inputs; output_finder<64, 8, 5> m_outputs; @@ -267,7 +310,17 @@ INPUT_CHANGED_MEMBER(ctk551_state::switch_w) INPUT_CHANGED_MEMBER(ctk551_state::power_w) { - m_maincpu->set_input_line(INPUT_LINE_NMI, newval ? ASSERT_LINE : CLEAR_LINE); + if (newval) + { + m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE); + m_nmi_timer->adjust(attotime::never); + } + else + { + // give the CPU enough time to switch NMI to active-high so it fires again + // otherwise, releasing the power button too quickly may be ignored + m_nmi_timer->adjust(attotime::from_msec(100)); + } } INPUT_CHANGED_MEMBER(ctk551_state::switch_power_w) @@ -315,8 +368,13 @@ WRITE_LINE_MEMBER(ctk551_state::apo_w) logerror("apo_w: %x\n", state); /* auto power off - disable the LCD and speakers the CPU will go to sleep until the power switch triggers a NMI */ - if (!state && m_lcdc.found()) - m_lcdc->reset(); + if (!state) + { + if (m_pwm.found()) + m_pwm->clear(); + if (m_lcdc.found()) + m_lcdc->reset(); + } m_led_power = state; m_maincpu->set_output_gain(ALL_OUTPUTS, state ? 1.0 : 0.0); } @@ -350,6 +408,11 @@ void ctk551_state::ap10_map(address_map& map) map(0x380003, 0x380003).w(FUNC(ctk551_state::led_console_w)); } +void ctk551_state::ctk530_map(address_map& map) +{ + map(0x000000, 0x0fffff).rom().region("maincpu", 0).mirror(0x100000); +} + void ctk551_state::gz70sp_map(address_map& map) { map(0x000000, 0x1fffff).rom().region("maincpu", 0); @@ -368,15 +431,18 @@ void ctk551_state::ctk601_map(address_map& map) map(0x380002, 0x380003).portr("PB").portw("PA").umask16(0x00ff); } -void ctk551_state::ctk551_map(address_map& map) -{ - map(0x000000, 0x0fffff).rom().region("maincpu", 0).mirror(0x100000); -} - void ctk551_state::ap10_io_map(address_map& map) +{ + map(h8_device::PORT_1, h8_device::PORT_1).portrw("P1").umask16(0x00ff); + map(h8_device::PORT_2, h8_device::PORT_4).noprw(); + map(h8_device::ADC_0, h8_device::ADC_1).nopr(); +} + +void ctk551_state::ctk530_io_map(address_map& map) { map(h8_device::PORT_1, h8_device::PORT_1).portrw("P1").umask16(0x00ff); map(h8_device::PORT_2, h8_device::PORT_3).noprw(); + map(h8_device::PORT_4, h8_device::PORT_4).portw("PLE"); map(h8_device::ADC_0, h8_device::ADC_1).nopr(); } @@ -384,7 +450,7 @@ void ctk551_state::gz70sp_io_map(address_map& map) { map(h8_device::PORT_1, h8_device::PORT_1).portrw("P1").umask16(0x00ff); map(h8_device::PORT_2, h8_device::PORT_2).portrw("P2").umask16(0x00ff); - map(h8_device::PORT_3, h8_device::PORT_3).noprw(); + map(h8_device::PORT_3, h8_device::PORT_4).noprw(); map(h8_device::ADC_0, h8_device::ADC_1).nopr(); } @@ -392,7 +458,7 @@ void ctk551_state::ctk551_io_map(address_map &map) { map(h8_device::PORT_1, h8_device::PORT_1).portr("P1_R").portw("P1_W").umask16(0x00ff); map(h8_device::PORT_2, h8_device::PORT_2).portrw("P2").umask16(0x00ff); - map(h8_device::PORT_3, h8_device::PORT_3).noprw(); // port 3 pins are shared w/ key matrix + map(h8_device::PORT_3, h8_device::PORT_4).noprw(); // port 3 pins are shared w/ key matrix map(h8_device::ADC_0, h8_device::ADC_0).portr("AN0"); map(h8_device::ADC_1, h8_device::ADC_1).portr("AN1"); } @@ -404,6 +470,8 @@ void ctk551_state::driver_start() m_led_power.resolve(); m_outputs.resolve(); + m_nmi_timer = timer_alloc(FUNC(ctk551_state::nmi_clear), this); + m_input_sel = 0xf; save_item(NAME(m_switch)); @@ -441,6 +509,34 @@ void ctk551_state::ap10(machine_config& config) config.set_default_layout(layout_ap10); } +void ctk551_state::ctk530(machine_config& config) +{ + // CPU + GT913(config, m_maincpu, 20_MHz_XTAL / 2); + m_maincpu->set_addrmap(AS_DATA, &ctk551_state::ctk530_map); + m_maincpu->set_addrmap(AS_IO, &ctk551_state::ctk530_io_map); + m_maincpu->add_route(0, "lspeaker", 1.0); + m_maincpu->add_route(1, "rspeaker", 1.0); + + // MIDI + auto& mdin(MIDI_PORT(config, "mdin")); + midiin_slot(mdin); + mdin.rxd_handler().set("maincpu:sci0", FUNC(h8_sci_device::rx_w)); + + auto& mdout(MIDI_PORT(config, "mdout")); + midiout_slot(mdout); + m_maincpu->subdevice("sci0")->tx_handler().set(mdout, FUNC(midi_port_device::write_txd)); + + PWM_DISPLAY(config, m_pwm, 0); + m_pwm->set_size(4, 8); + m_pwm->set_segmask(0x7, 0xff); + + SPEAKER(config, "lspeaker").front_left(); + SPEAKER(config, "rspeaker").front_right(); + + config.set_default_layout(layout_ctk530); +} + void ctk551_state::gz70sp(machine_config& config) { // CPU @@ -499,7 +595,7 @@ void ctk551_state::ctk551(machine_config &config) { // CPU GT913(config, m_maincpu, 30'000'000 / 2); - m_maincpu->set_addrmap(AS_DATA, &ctk551_state::ctk551_map); + m_maincpu->set_addrmap(AS_DATA, &ctk551_state::ctk530_map); m_maincpu->set_addrmap(AS_IO, &ctk551_state::ctk551_io_map); m_maincpu->add_route(0, "lspeaker", 1.0); m_maincpu->add_route(1, "rspeaker", 1.0); @@ -787,6 +883,75 @@ INPUT_PORTS_START(base_61key) PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED ) INPUT_PORTS_END +INPUT_PORTS_START(ctk530) + PORT_INCLUDE(base_61key) + + PORT_START("maincpu:kbd:FI8") + PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("maincpu:kbd:FI9") + PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("maincpu:kbd:FI10") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad +") PORT_CODE(KEYCODE_PLUS_PAD) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad -") PORT_CODE(KEYCODE_MINUS_PAD) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 0") PORT_CODE(KEYCODE_0_PAD) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Accomp Volume Up") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Main Volume Up") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Mode") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("maincpu:kbd:KI0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Demo") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_PAD) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Tempo Up") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Main Volume Down") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Intro / Fill In") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("maincpu:kbd:KI1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Transpose / Tune / MIDI") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Rhythm") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Accomp Volume Down") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Synchro / Ending") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("maincpu:kbd:KI2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Touch Response") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Tone") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Tempo Down") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Start / Stop") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("maincpu:kbd:VELOCITY") + PORT_BIT( 0x7f, 0x7f, IPT_POSITIONAL ) PORT_NAME("Key Velocity") PORT_SENSITIVITY(100) PORT_KEYDELTA(10) PORT_CENTERDELTA(0) + + PORT_START("SWITCH") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_POWER_ON ) PORT_NAME("Power") PORT_CHANGED_MEMBER(DEVICE_SELF, ctk551_state, power_w, 0) + + PORT_START("P1") + PORT_BIT( 0x03, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(ctk551_state, apo_w) + PORT_BIT( 0x78, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_CONFNAME( 0x80, 0x80, "Power Source" ) + PORT_CONFSETTING( 0x80, "AC Adapter" ) + PORT_CONFSETTING( 0x00, "Battery" ) + + PORT_START("PLE") + PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(ctk551_state, pwm_col_w) + PORT_BIT( 0x0f00, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(ctk551_state, pwm_row_w) + PORT_BIT( 0xf000, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + INPUT_PORTS_START(ctk601) PORT_INCLUDE(base_61key) @@ -1004,6 +1169,13 @@ ROM_START(ap10) ROM_LOAD16_WORD_SWAP("ap10.lsi303", 0x000000, 0x100000, CRC(39caa214) SHA1(3b484628c1e6f0ad7c11e2ec7eff664294f9ec83)) // MX23C8100MC-12CA27 ROM_END +ROM_START(ctk530) + ROM_REGION(0x100000, "maincpu", ROMREGION_ERASE00) + + ROM_REGION16_BE(0x100000, "lsi102", 0) + ROM_LOAD16_WORD_SWAP("ctk530.lsi102", 0x000000, 0x100000, CRC(961bff85) SHA1(adfd46ef96fb53981b1b66cb89e3d716b0792ef0)) // MX23C8100PC-12CA19 +ROM_END + ROM_START(gz70sp) ROM_REGION(0x200000, "maincpu", 0) ROM_LOAD("romsxgm.bin", 0x000000, 0x200000, CRC(c392cf89) SHA1(93ebe213ea7a085c67d88974ed39ac3e9bf8059b)) // from the SW-10 softsynth @@ -1033,6 +1205,17 @@ void ctk551_state::init_ap10() rom[addr] = bitswap(rom[addr], 15, 14, 13, 10, 11, 12, 9, 8, 7, 6, 2, 3, 4, 5, 1, 0); } +void ctk551_state::init_ctk530() +{ + uint16_t* dest = (uint16_t*)memregion("maincpu")->base(); + const uint16_t* src = (uint16_t*)memregion("lsi102")->base(); + for (uint32_t i = 0; i < 0x80000; i++) + { + const uint32_t addr = bitswap(i, 8, 9, 0, 2, 4, 6, 17, 16, 14, 12, 10, 11, 13, 15, 18, 7, 5, 3, 1); + dest[addr] = bitswap(src[i], 0, 2, 15, 13, 4, 6, 11, 9, 1, 3, 14, 12, 5, 7, 10, 8); + } +} + void ctk551_state::init_gz70sp() { /* @@ -1048,7 +1231,8 @@ void ctk551_state::init_gz70sp() // models with MACHINE_IMPERFECT_SOUND are missing DSP emulation // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -SYST( 1995, ap10, 0, 0, ap10, ap10, ctk551_state, init_ap10, "Casio", "Celviano AP-10", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_IMPERFECT_SOUND) +SYST( 1995, ap10, 0, 0, ap10, ap10, ctk551_state, init_ap10, "Casio", "Celviano AP-10", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_IMPERFECT_SOUND ) +SYST( 1995, ctk530, 0, 0, ctk530, ctk530, ctk551_state, init_ctk530, "Casio", "CTK-530", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) SYST( 1996, gz70sp, 0, 0, gz70sp, gz70sp, ctk551_state, init_gz70sp, "Casio", "GZ-70SP", MACHINE_SUPPORTS_SAVE ) -SYST( 1997, ctk601, 0, 0, ctk601, ctk601, ctk551_state, empty_init, "Casio", "CTK-601", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND) +SYST( 1997, ctk601, 0, 0, ctk601, ctk601, ctk551_state, empty_init, "Casio", "CTK-601", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND ) SYST( 2000, ctk551, 0, 0, ctk551, ctk551, ctk551_state, empty_init, "Casio", "CTK-551", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/layout/ctk530.lay b/src/mame/layout/ctk530.lay new file mode 100644 index 00000000000..7a55d7e3707 --- /dev/null +++ b/src/mame/layout/ctk530.lay @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 3684db3ff8c..a4ec876e62c 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -11680,6 +11680,7 @@ megatrix @source:casio/ctk551.cpp ap10 // +ctk530 // ctk551 // ctk601 // gz70sp //