From 41e1c7d3a267c050d6b5cd9418e2cfa0e0d7d777 Mon Sep 17 00:00:00 2001 From: Devin Acker Date: Fri, 12 Aug 2022 19:30:06 -0400 Subject: ctk551.cpp: New working machines (#9929) * New working machines: --------------------------------------- Casio Celviano AP-10 [Devin Acker] Casio CTK-601 [Devin Acker, Gabriel Miceli] Casio GZ-70SP [Devin Acker] --- src/devices/cpu/h8/gt913.cpp | 175 +++++++-- src/devices/cpu/h8/gt913.h | 41 +- src/devices/cpu/h8/gt913.lst | 185 +++++++-- src/devices/cpu/h8/h8.cpp | 8 +- src/devices/cpu/h8/h8_intc.cpp | 31 +- src/devices/cpu/h8/h8_intc.h | 4 + src/devices/cpu/h8/h8d.cpp | 12 +- src/devices/cpu/h8/h8d.h | 6 +- src/devices/cpu/h8/h8make.py | 2 +- src/devices/machine/gt913_snd.cpp | 169 ++++---- src/devices/machine/gt913_snd.h | 4 +- src/mame/casio/ctk551.cpp | 791 +++++++++++++++++++++++++++++++++++--- src/mame/layout/ap10.lay | 284 ++++++++++++++ src/mame/mame.lst | 3 + 14 files changed, 1499 insertions(+), 216 deletions(-) create mode 100644 src/mame/layout/ap10.lay diff --git a/src/devices/cpu/h8/gt913.cpp b/src/devices/cpu/h8/gt913.cpp index ef432333d96..17930da3006 100644 --- a/src/devices/cpu/h8/gt913.cpp +++ b/src/devices/cpu/h8/gt913.cpp @@ -1,20 +1,21 @@ // license:BSD-3-Clause // copyright-holders:Devin Acker /*************************************************************************** - Casio GT913 + Casio GT913 (uPD913) This chip powers several late-90s/early-2000s Casio keyboards. It's based on the H8/300 instruction set, but with different encoding for many opcodes, as well as: - - Dedicated bank switching instructions (20-bit external address bus) + - Dedicated bank switching instructions + (20-bit external address bus + 3 chip select outputs, can address a total of 4MB) - Two timers, three 8-bit ports, two 8-bit ADCs - Keyboard controller w/ key velocity detection - MIDI UART - 24-voice DPCM sound - Earlier and later Casio keyboard models contain "uPD912" and "uPD914" chips, - which are presumably similar. + Variants include the uPD912 and GT915/uPD915. + These were later succeeded by the uPD914. ***************************************************************************/ @@ -28,12 +29,12 @@ gt913_device::gt913_device(const machine_config &mconfig, const char *tag, devic h8_device(mconfig, GT913, tag, owner, clock, address_map_constructor(FUNC(gt913_device::map), this)), device_mixer_interface(mconfig, *this, 2), m_rom(*this, DEVICE_SELF), - m_bank(*this, "bank"), + data_config("data", ENDIANNESS_BIG, 16, 22, 0), m_intc(*this, "intc"), m_sound(*this, "gt_sound"), m_kbd(*this, "kbd"), m_io_hle(*this, "io_hle"), - m_sci(*this, "sci"), + m_sci(*this, "sci%u", 0), m_port(*this, "port%u", 1) { has_hc = false; @@ -46,11 +47,10 @@ std::unique_ptr gt913_device::create_disassembler() void gt913_device::map(address_map &map) { -// map.unmap_value_high(); - map(0x0000, 0x7fff).rom(); - map(0x8000, 0xbfff).bankr("bank"); - map(0xfac0, 0xffbf).ram(); // CTK-551 zeroes out this range at $0418 + map(0x8000, 0xbfff).rw(FUNC(gt913_device::data_r), FUNC(gt913_device::data_w)); + map(0xc000, 0xf7ff).rom(); + map(0xfac0, 0xffbf).ram(); /* ffc0-ffcb: sound */ map(0xffc0, 0xffc5).rw(m_sound, FUNC(gt913_sound_device::data_r), FUNC(gt913_sound_device::data_w)); @@ -66,11 +66,13 @@ void gt913_device::map(address_map &map) map(0xffdc, 0xffdd).w(m_io_hle, FUNC(gt913_io_hle_device::timer_rate0_w)); map(0xffdf, 0xffdf).w(m_io_hle, FUNC(gt913_io_hle_device::timer_rate1_w)); - /* ffe0-ffe3: serial */ + /* ffe0-ffe7: serial */ map(0xffe0, 0xffe0).w(FUNC(gt913_device::uart_rate_w)); - map(0xffe1, 0xffe1).w(m_sci, FUNC(h8_sci_device::tdr_w)); - map(0xffe2, 0xffe2).rw(FUNC(gt913_device::uart_control_r), FUNC(gt913_device::uart_control_w)); - map(0xffe3, 0xffe3).r(m_sci, FUNC(h8_sci_device::rdr_r)); + map(0xffe1, 0xffe1).w(m_sci[0], FUNC(h8_sci_device::tdr_w)); + map(0xffe2, 0xffe2).select(0x04).rw(FUNC(gt913_device::uart_control_r), FUNC(gt913_device::uart_control_w)); + map(0xffe3, 0xffe3).r(m_sci[0], FUNC(h8_sci_device::rdr_r)); + map(0xffe5, 0xffe5).w(m_sci[1], FUNC(h8_sci_device::tdr_w)); + map(0xffe7, 0xffe7).r(m_sci[1], FUNC(h8_sci_device::rdr_r)); /* ffe9-ffea: ADC */ map(0xffe9, 0xffe9).rw(m_io_hle, FUNC(gt913_io_hle_device::adc_control_r), FUNC(gt913_io_hle_device::adc_control_w)); @@ -78,14 +80,13 @@ void gt913_device::map(address_map &map) /* fff0-fff5: I/O ports */ map(0xfff0, 0xfff0).rw(m_port[0], FUNC(h8_port_device::ddr_r), FUNC(h8_port_device::ddr_w)); - map(0xfff1, 0xfff1).rw(m_port[1], FUNC(h8_port_device::ddr_r), FUNC(h8_port_device::ddr_w)); + // port 2 DDR - ctk601 and gz70sp both seem to use only bit 0 to indicate either all inputs or all outputs +// map(0xfff1, 0xfff1).rw(m_port[1], FUNC(h8_port_device::ddr_r), FUNC(h8_port_device::ddr_w)); + map(0xfff1, 0xfff1).lw8(NAME([this](uint8_t data) { m_port[1]->ddr_w(BIT(data, 0) ? 0xff : 0x00); })); map(0xfff2, 0xfff2).rw(m_port[0], FUNC(h8_port_device::port_r), FUNC(h8_port_device::dr_w)); map(0xfff3, 0xfff3).rw(m_port[1], FUNC(h8_port_device::port_r), FUNC(h8_port_device::dr_w)); - // likely port 3 - pins are shared with input matrix, ctk551 clears this register on boot and nothing else - // (specifically, the pins are also used for key velocity detection, so port 3 is probably used by very few models, if any at all) map(0xfff4, 0xfff4).rw(m_port[2], FUNC(h8_port_device::port_r), FUNC(h8_port_device::dr_w)); - // unknown - ctk551 sets/clears a few bits on boot and before going to sleep -// map(0xfff5, 0xfff5).noprw(); + map(0xfff5, 0xfff5).rw(FUNC(gt913_device::syscr_r), FUNC(gt913_device::syscr_w)); } void gt913_device::device_add_mconfig(machine_config &config) @@ -98,34 +99,126 @@ void gt913_device::device_add_mconfig(machine_config &config) m_sound->add_route(1, *this, 1.0, AUTO_ALLOC_INPUT, 1); GT913_KBD_HLE(config, m_kbd, 0); - m_kbd->irq_cb().set([this] (int val) { if (val) m_intc->internal_interrupt(5); }); + m_kbd->irq_cb().set([this] (int val) + { + if (val) + m_intc->internal_interrupt(5); + else + m_intc->clear_interrupt(5); + }); GT913_IO_HLE(config, m_io_hle, "intc", 6, 7); - H8_SCI(config, m_sci, "intc", 8, 9, 10, 0); + H8_SCI(config, m_sci[0], "intc", 8, 9, 10, 0); + H8_SCI(config, m_sci[1], "intc", 11, 12, 13, 0); - H8_PORT(config, m_port[0], h8_device::PORT_1, 0xff, 0x00); - H8_PORT(config, m_port[1], h8_device::PORT_2, 0xff, 0x00); - H8_PORT(config, m_port[2], h8_device::PORT_3, 0xff, 0x00); + H8_PORT(config, m_port[0], h8_device::PORT_1, 0x00, 0x00); + H8_PORT(config, m_port[1], h8_device::PORT_2, 0x00, 0x00); + H8_PORT(config, m_port[2], h8_device::PORT_3, 0x00, 0x00); } void gt913_device::uart_rate_w(uint8_t data) { - m_sci->brr_w(data >> 2); + // TODO: how is SCI1 baud rate actually selected? + // gz70sp writes 0x7e to ffe4 to select 31250 baud for MIDI, which doesn't seem right + m_sci[0]->brr_w(data >> 2); + m_sci[1]->brr_w(data >> 2); } -void gt913_device::uart_control_w(uint8_t data) +void gt913_device::uart_control_w(offs_t offset, uint8_t data) { + const unsigned num = BIT(offset, 2); /* upper 4 bits seem to correspond to the upper bits of SSR (Tx/Rx/error status) lower 4 bits seem to correspond to the upper bits of SCR (Tx/Rx IRQ enable, Tx/Rx enable(?)) */ - m_sci->ssr_w(data & 0xf0); - m_sci->scr_w((data & 0x0f) << 4); + m_sci[num]->ssr_w(data & 0xf0); + m_sci[num]->scr_w((data & 0x0f) << 4); +} + +uint8_t gt913_device::uart_control_r(offs_t offset) +{ + const unsigned num = BIT(offset, 2); + return (m_sci[num]->ssr_r() & 0xf0) | (m_sci[num]->scr_r() >> 4); +} + +void gt913_device::syscr_w(uint8_t data) +{ + if (BIT(m_syscr ^ data, 2)) + // NMI active edge has changed + m_intc->set_input(INPUT_LINE_NMI, CLEAR_LINE); + + m_syscr = data; +} + +uint8_t gt913_device::syscr_r() +{ + return m_syscr; +} + +void gt913_device::data_w(offs_t offset, uint8_t data) +{ + m_data.write_byte(offset | (m_banknum & 0xff) << 14, data); +} + +uint8_t gt913_device::data_r(offs_t offset) +{ + return m_data.read_byte(offset | (m_banknum & 0xff) << 14); } -uint8_t gt913_device::uart_control_r() +uint8_t gt913_device::read8ib(uint32_t adr) { - return (m_sci->ssr_r() & 0xf0) | (m_sci->scr_r() >> 4); + if (BIT(m_syscr, 0)) + // indirect bank disabled + return program.read_byte(adr); + else if ((IR[0] & 0x0070) == 0) + // indirect bank enabled, using bankh for r0 + return m_data.read_byte(adr | ((m_banknum >> 6) << 16)); + else + // indirect bank enabled, using bankl for other regs + return m_data.read_byte(adr | ((m_banknum & 0x3f) << 16)); +} + +void gt913_device::write8ib(uint32_t adr, uint8_t data) +{ + if (BIT(m_syscr, 0)) + // indirect bank disabled + program.write_byte(adr, data); + else if ((IR[0] & 0x0070) == 0) + // indirect bank enabled, using bankh for r0 + m_data.write_byte(adr | ((m_banknum >> 6) << 16), data); + else + // indirect bank enabled, using bankl for other regs + m_data.write_byte(adr | ((m_banknum & 0x3f) << 16), data); +} + +uint16_t gt913_device::read16ib(uint32_t adr) +{ + adr &= ~1; + + if (BIT(m_syscr, 0)) + // indirect bank disabled + return program.read_word(adr); + else if ((IR[0] & 0x0070) == 0) + // indirect bank enabled, using bankh for r0 + return m_data.read_word(adr | ((m_banknum >> 6) << 16)); + else + // indirect bank enabled, using bankl for other regs + return m_data.read_word(adr | ((m_banknum & 0x3f) << 16)); +} + +void gt913_device::write16ib(uint32_t adr, uint16_t data) +{ + adr &= ~1; + + if (BIT(m_syscr, 0)) + // indirect bank disabled + program.write_word(adr, data); + else if ((IR[0] & 0x0070) == 0) + // indirect bank enabled, using bankh for r0 + m_data.write_word(adr | ((m_banknum >> 6) << 16), data); + else + // indirect bank enabled, using bankl for other regs + m_data.write_word(adr | ((m_banknum & 0x3f) << 16), data); } void gt913_device::irq_setup() @@ -150,23 +243,40 @@ void gt913_device::internal_update(uint64_t current_time) { uint64_t event_time = 0; - add_event(event_time, m_sci->internal_update(current_time)); + add_event(event_time, m_sci[0]->internal_update(current_time)); + add_event(event_time, m_sci[1]->internal_update(current_time)); recompute_bcount(event_time); } void gt913_device::execute_set_input(int inputnum, int state) { + if (inputnum == INPUT_LINE_NMI) + { + if (BIT(m_syscr, 2)) + state ^= ASSERT_LINE; + } + m_intc->set_input(inputnum, state); } +device_memory_interface::space_config_vector gt913_device::memory_space_config() const +{ + return space_config_vector{ + std::make_pair(AS_PROGRAM, &program_config), + std::make_pair(AS_IO, &io_config), + std::make_pair(AS_DATA, &data_config) + }; +} + void gt913_device::device_start() { h8_device::device_start(); - m_bank->configure_entries(0, m_rom->bytes() >> 12, m_rom->base(), 1 << 12); + space(AS_DATA).specific(m_data); save_item(NAME(m_banknum)); + save_item(NAME(m_syscr)); } void gt913_device::device_reset() @@ -174,6 +284,7 @@ void gt913_device::device_reset() h8_device::device_reset(); m_banknum = 0; + m_syscr = 0; } #include "cpu/h8/gt913.hxx" diff --git a/src/devices/cpu/h8/gt913.h b/src/devices/cpu/h8/gt913.h index 50072a4a3ca..1582baaa542 100644 --- a/src/devices/cpu/h8/gt913.h +++ b/src/devices/cpu/h8/gt913.h @@ -28,17 +28,30 @@ public: virtual std::unique_ptr create_disassembler() override; void uart_rate_w(uint8_t data); - void uart_control_w(uint8_t data); - uint8_t uart_control_r(); + void uart_control_w(offs_t offset, uint8_t data); + uint8_t uart_control_r(offs_t offset); -protected: + void data_w(offs_t offset, uint8_t data); + uint8_t data_r(offs_t offset); + + void syscr_w(uint8_t data); + uint8_t syscr_r(); +protected: + /* indirect reads/writes with banking support */ + uint8_t read8ib(uint32_t adr); + void write8ib(uint32_t adr, uint8_t data); + uint16_t read16ib(uint32_t adr); + void write16ib(uint32_t adr, uint16_t data); + virtual void update_irq_filter() override; virtual void interrupt_taken() override; virtual void internal_update(uint64_t current_time) override; virtual void irq_setup() override; virtual void execute_set_input(int inputnum, int state) override; + virtual space_config_vector memory_space_config() const override; + virtual void device_add_mconfig(machine_config &config) override; void map(address_map &map); @@ -49,15 +62,27 @@ protected: virtual void do_exec_partial() override; #define O(o) void o ## _full(); void o ## _partial() - O(ldbank_imm2l_bankl); O(ldbank_imm4l_bankh); O(ldbank_r8l_bankl); O(ldbank_r8l_bankh); + O(ldc_imm6l_ccr); + O(ldbank_imm6l_bankl); O(ldbank_imm6l_bankh); O(ldbank_r8l_bankl); O(ldbank_r8l_bankh); + + O(jmp_abs22e); + + O(mov_b_r16ih_r8l); O(mov_w_r16ih_r16l); O(mov_b_r16ph_r8l); O(mov_w_r16ph_r16l); + O(mov_b_r8l_r16ih); O(mov_w_r16l_r16ih); O(mov_b_r8l_pr16h); O(mov_w_r16l_pr16h); + O(mov_b_r16d16h_r8l); O(mov_w_r16d16h_r16l); O(mov_b_r8l_r16d16h); O(mov_w_r16l_r16d16h); - O(dispatch_6600); O(dispatch_7000); O(dispatch_7200); + O(dispatch_6000); O(dispatch_6100); O(dispatch_6200); O(dispatch_6300); + O(dispatch_6400); O(dispatch_6500); O(dispatch_6600); O(dispatch_6700); + O(dispatch_7000); O(dispatch_7100); O(dispatch_7200); O(dispatch_7300); + O(dispatch_7400); O(dispatch_7500); O(dispatch_7600); O(dispatch_7700); #undef O required_memory_region m_rom; - required_memory_bank m_bank; - uint16_t m_banknum; + address_space_config data_config; + memory_access<32, 1, 0, ENDIANNESS_BIG>::specific m_data; + uint16_t m_banknum; + uint8_t m_syscr; required_device m_intc; @@ -71,7 +96,7 @@ protected: required_device m_io_hle; /* serial port */ - required_device m_sci; + required_device_array m_sci; /* 3x 8-bit I/O ports */ required_device_array m_port; diff --git a/src/devices/cpu/h8/gt913.lst b/src/devices/cpu/h8/gt913.lst index 45f1ddc995c..7365bd2d3e1 100644 --- a/src/devices/cpu/h8/gt913.lst +++ b/src/devices/cpu/h8/gt913.lst @@ -9,30 +9,31 @@ 0240 fff0 0 stc ccr r8l 0340 fff0 0 ldc r8l ccr -0380 fff0 0 ldbank r8l bankh g - TMP1 = r8_r(IR[0]); - m_banknum = (TMP1 << 2) | (m_banknum & 0x3); - m_bank->set_entry(m_banknum); +0380 fff0 0 ldbank r8l bankl g + TMP1 = r8_r(IR[0]) & 0x3f; + m_banknum = (m_banknum & 0xffc0) | TMP1; prefetch(); -03c0 fff0 0 ldbank r8l bankl g - TMP1 = r8_r(IR[0]); - m_banknum = (m_banknum & 0xfffc) | (TMP1 & 0x3); - m_bank->set_entry(m_banknum); +03c0 fff0 0 ldbank r8l bankh g + TMP1 = r8_r(IR[0]) & 0x3f; + m_banknum = (TMP1 << 6) | (m_banknum & 0x3f); prefetch(); 0400 ff00 0 orc imm8 ccr 0500 ff00 0 xorc imm8 ccr 0600 ff00 0 andc imm8 ccr -0780 fff0 0 ldbank imm4l bankh g - m_banknum = ((IR[0] & 0xf) << 2) | (m_banknum & 0x3); - m_bank->set_entry(m_banknum); +0740 ffc0 0 ldc imm6l ccr g + CCR = IR[0] & 0x3f; + update_irq_filter(); + prefetch_noirq(); + +0780 ffc0 0 ldbank imm6l bankl g + m_banknum = (m_banknum & 0xffc0) | (IR[0] & 0x3f); prefetch(); -07c0 fff0 0 ldbank imm2l bankl g - m_banknum = (m_banknum & 0xfffc) | (IR[0] & 0x3); - m_bank->set_entry(m_banknum); +07c0 ffc0 0 ldbank imm6l bankh g + m_banknum = ((IR[0] & 0x3f) << 6) | (m_banknum & 0x3f); prefetch(); 0800 ff00 0 add.b r8h r8l @@ -101,34 +102,162 @@ 5980 ffff 0 rte - - 5a00 ff8f 0 jmp r16h - 5a80 ffff 0 jmp abs16e - -5b00 ff00 0 jmp abs8i - + +# TODO: how is this instruction actually supposed to work? +# gz70sp has an unused instance of it (probably used in whatever keyboard the ROM is based on) +# located where a 'sleep' instruction would normally be. +# the lower 22 bits of the address point to a lone 'sleep' instruction at the end of the ROM, +# but given the 16-bit program counter, it's not really clear what exactly is meant to happen. +# for now, just setting bankl/bankh and jumping into the bankswitched memory area should be ok +# (the NMI from the power switch will get things going afterwards). +5b80 ffc0 0 jmp abs22e - g + internal(1); + m_banknum = ((IR[0] & 0x3f) << 2) | (IR[1] >> 14); + PC = 0x8000 | (IR[1] & 0x3fff); + prefetch(); + 5c00 ff8f 0 jsr r16h - 5c80 ffff 0 jsr abs16e - 5e00 ff00 0 bsr rel8 - 5f00 fff0 0 mov.w imm16 r16l -66000000 ff00ff8f 0 btst imm3 r16ihh +60000000 ff8fff8f 0 bset imm3 r16ihh +61000000 ff8fff0f 0 bset r8h r16ihh +62000000 ff8fff8f 0 bclr imm3 r16ihh +63000000 ff8fff0f 0 bclr r8h r16ihh +64000000 ff8fff8f 0 bnot imm3 r16ihh +65000000 ff8fff0f 0 bnot r8h r16ihh +66000000 ff8fff8f 0 btst imm3 r16ihh +67000000 ff8fff0f 0 btst r8h r16ihh + +6800 ff80 0 mov.b r16ih r8l g + prefetch_start(); + internal(1); + TMP1 = read8ib(r16_r(IR[0] >> 4)); + set_nzv8(TMP1); + r8_w(IR[0], TMP1); + prefetch_done(); + +6900 ff88 0 mov.w r16ih r16l g + prefetch_start(); + internal(1); + TMP1 = read16ib(r16_r(IR[0] >> 4)); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch_done(); + +6a00 ff80 0 mov.b r16ph r8l g + TMP2 = r16_r(IR[0] >> 4); + prefetch_start(); + internal(2); + TMP1 = read8ib(TMP2); + TMP2 += 1; + r16_w(IR[0] >> 4, TMP2); + set_nzv8(TMP1); + r8_w(IR[0], TMP1); + prefetch_done(); + +6b00 ff88 0 mov.w r16ph r16l g + TMP2 = r16_r(IR[0] >> 4); + prefetch_start(); + internal(2); + TMP1 = read16ib(TMP2); + TMP2 += 2; + r16_w(IR[0] >> 4, TMP2); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch_done(); -6800 ff80 0 mov.b r16ih r8l -6900 ff88 0 mov.w r16ih r16l -6a00 ff80 0 mov.b r16ph r8l -6b00 ff88 0 mov.w r16ph r16l 6c00 fff0 0 mov.b abs16 r8l 6d00 fff0 0 mov.w abs16 r16l -6e00 ff80 0 mov.b r16d16h r8l -6f00 ff80 0 mov.w r16d16h r16l + +6e00 ff80 0 mov.b r16d16h r8l g + prefetch_start(); + TMP1 = uint16_t(r16_r(IR[0] >> 4) + IR[1]); + internal(1); + TMP2 = read8ib(TMP1); + set_nzv8(TMP2); + r8_w(IR[0], TMP2); + prefetch_done(); + +6f00 ff80 0 mov.w r16d16h r16l g + prefetch_start(); + TMP1 = uint16_t(r16_r(IR[0] >> 4) + IR[1]); + internal(1); + TMP2 = read16ib(TMP1); + set_nzv16(TMP2); + r16_w(IR[0], TMP2); + prefetch_done(); 70000000 ff00ff8f 0 bset imm3 abs8 +71000000 ff00ff0f 0 bset r8h abs8 72000000 ff00ff8f 0 bclr imm3 abs8 +73000000 ff00ff0f 0 bclr r8h abs8 +74000000 ff00ff8f 0 bnot imm3 abs8 +75000000 ff00ff0f 0 bnot r8h abs8 +76000000 ff00ff8f 0 btst imm3 abs8 +77000000 ff00ff0f 0 btst r8h abs8 + +7800 ff80 0 mov.b r8l r16ih g + prefetch_start(); + TMP1 = r8_r(IR[0]); + set_nzv8(TMP1); + internal(1); + write8ib(r16_r(IR[0] >> 4), TMP1); + prefetch_done(); + +7900 ff88 0 mov.w r16l r16ih g + prefetch_start(); + TMP1 = r16_r(IR[0]); + set_nzv16(TMP1); + internal(1); + write16ib(r16_r(IR[0] >> 4), TMP1); + prefetch_done(); + +7a00 ff80 0 mov.b r8l pr16h g + TMP1 = r8_r(IR[0]); + TMP2 = r16_r(IR[0] >> 4); + prefetch_start(); + internal(1); + TMP2 -= 1; + r16_w(IR[0] >> 4, TMP2); + set_nzv8(TMP1); + internal(1); + write8ib(TMP2, TMP1); + prefetch_done(); + +7b00 ff88 0 mov.w r16l pr16h g + TMP1 = r16_r(IR[0]); + TMP2 = r16_r(IR[0] >> 4); + prefetch_start(); + internal(1); + TMP2 -= 2; + r16_w(IR[0] >> 4, TMP2); + set_nzv16(TMP1); + internal(1); + write16ib(TMP2, TMP1); + prefetch_done(); -7800 ff80 0 mov.b r8l r16ih -7900 ff88 0 mov.w r16l r16ih -7a00 ff80 0 mov.b r8l pr16h -7b00 ff88 0 mov.w r16l pr16h 7c00 fff0 0 mov.b r8l abs16 7d00 fff0 0 mov.w r16l abs16 -7e00 ff80 0 mov.b r8l r16d16h -7f00 ff80 0 mov.w r16l r16d16h + +7e00 ff80 0 mov.b r8l r16d16h g + prefetch_start(); + TMP1 = uint16_t(r16_r(IR[0] >> 4) + IR[1]); + TMP2 = r8_r(IR[0]); + set_nzv8(TMP2); + internal(1); + write8ib(TMP1, TMP2); + prefetch_done(); + +7f00 ff80 0 mov.w r16l r16d16h g + prefetch_start(); + TMP1 = uint16_t(r16_r(IR[0] >> 4) + IR[1]); + TMP2 = r16_r(IR[0]); + set_nzv16(TMP2); + internal(1); + write16ib(TMP1, TMP2); + prefetch_done(); 8000 f000 0 add.b imm8 r8u 9000 f000 0 addx.b imm8 r8u diff --git a/src/devices/cpu/h8/h8.cpp b/src/devices/cpu/h8/h8.cpp index a571fe2367c..cd40624586c 100644 --- a/src/devices/cpu/h8/h8.cpp +++ b/src/devices/cpu/h8/h8.cpp @@ -482,16 +482,16 @@ uint8_t h8_device::do_addx8(uint8_t v1, uint8_t v2) uint8_t h8_device::do_subx8(uint8_t v1, uint8_t v2) { uint16_t res = v1 - v2 - (CCR & F_C ? 1 : 0); - CCR &= ~(F_N|F_V|F_Z|F_C); + CCR &= ~(F_N|F_V|F_C); if (has_hc) { CCR &= ~F_H; if (((v1 & 0xf) - (v2 & 0xf) - (CCR & F_C ? 1 : 0)) & 0x10) CCR |= F_H; } - if(!uint8_t(res)) - CCR |= F_Z; - else if(int8_t(res) < 0) + if(uint8_t(res)) + CCR &= ~F_Z; + if(int8_t(res) < 0) CCR |= F_N; if((v1^v2) & (v1^res) & 0x80) CCR |= F_V; diff --git a/src/devices/cpu/h8/h8_intc.cpp b/src/devices/cpu/h8/h8_intc.cpp index c27ceacfd06..f2a7b192164 100644 --- a/src/devices/cpu/h8/h8_intc.cpp +++ b/src/devices/cpu/h8/h8_intc.cpp @@ -12,11 +12,12 @@ h8_intc_device::h8_intc_device(const machine_config &mconfig, const char *tag, d h8_intc_device(mconfig, H8_INTC, tag, owner, clock) { irq_vector_base = 4; + irq_vector_count = 8; irq_vector_nmi = 3; } h8_intc_device::h8_intc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, type, tag, owner, clock), irq_vector_base(0), irq_vector_nmi(0), + device_t(mconfig, type, tag, owner, clock), irq_vector_base(0), irq_vector_count(0), irq_vector_nmi(0), cpu(*this, DEVICE_SELF_OWNER), nmi_input(false), irq_input(0), ier(0), isr(0), iscr(0), icr_filter(0), ipr_filter(0) { } @@ -48,7 +49,7 @@ int h8_intc_device::interrupt_taken(int vector) if(0) logerror("taking internal interrupt %d\n", vector); pending_irqs[vector >> 5] &= ~(1 << (vector & 31)); - if(irq_vector_base >= 0 && vector >= irq_vector_base && vector < irq_vector_base + 8) { + if(vector >= irq_vector_base && vector < irq_vector_base + irq_vector_count) { int irq = vector - irq_vector_base; if(irq_type[irq] != IRQ_LEVEL || !(irq_input & (1 << irq))) isr &= ~(1 << irq); @@ -160,10 +161,12 @@ void h8_intc_device::update_irq_types() void h8_intc_device::update_irq_state() { - if (irq_vector_base >= 0) + if (irq_vector_count > 0) { - pending_irqs[0] &= ~(255 << irq_vector_base); - pending_irqs[0] |= (isr & ier) << irq_vector_base; + const unsigned mask = (1 << irq_vector_count) - 1; + + pending_irqs[0] &= ~(mask << irq_vector_base); + pending_irqs[0] |= (isr & ier & mask) << irq_vector_base; } int cur_vector = 0; @@ -199,7 +202,8 @@ void h8_intc_device::get_priority(int vect, int &icr_pri, int &ipr_pri) const gt913_intc_device::gt913_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : gt913_intc_device(mconfig, GT913_INTC, tag, owner, clock) { - irq_vector_base = -1; // no external IRQs + irq_vector_base = 4; + irq_vector_count = 1; irq_vector_nmi = 3; } @@ -208,11 +212,25 @@ gt913_intc_device::gt913_intc_device(const machine_config &mconfig, device_type { } +void gt913_intc_device::device_reset() +{ + h8_intc_device::device_reset(); + + ier = 0x01; +} + +void gt913_intc_device::clear_interrupt(int vector) +{ + pending_irqs[vector >> 5] &= ~(1 << (vector & 31)); + update_irq_state(); +} + h8h_intc_device::h8h_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : h8h_intc_device(mconfig, H8H_INTC, tag, owner, clock) { irq_vector_base = 12; + irq_vector_count = 8; irq_vector_nmi = 7; } @@ -339,6 +357,7 @@ h8s_intc_device::h8s_intc_device(const machine_config &mconfig, const char *tag, h8h_intc_device(mconfig, H8S_INTC, tag, owner, clock) { irq_vector_base = 16; + irq_vector_count = 8; irq_vector_nmi = 7; } diff --git a/src/devices/cpu/h8/h8_intc.h b/src/devices/cpu/h8/h8_intc.h index 2fd1280c432..43569dc3b9b 100644 --- a/src/devices/cpu/h8/h8_intc.h +++ b/src/devices/cpu/h8/h8_intc.h @@ -36,6 +36,7 @@ protected: enum { MAX_VECTORS = 256 }; int irq_vector_base; + int irq_vector_count; int irq_vector_nmi; required_device cpu; @@ -64,8 +65,11 @@ class gt913_intc_device : public h8_intc_device { public: gt913_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + void clear_interrupt(int vector); protected: gt913_intc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_reset() override; }; class h8h_intc_device : public h8_intc_device { diff --git a/src/devices/cpu/h8/h8d.cpp b/src/devices/cpu/h8/h8d.cpp index 11a823c4b26..0009ec189fa 100644 --- a/src/devices/cpu/h8/h8d.cpp +++ b/src/devices/cpu/h8/h8d.cpp @@ -179,6 +179,10 @@ void h8_disassembler::disassemble_am(std::ostream &stream, int am, offs_t pc, co util::stream_format(stream, "h'%04x", opcodes.r16(pc+2)); break; + case DASM_abs22e: + util::stream_format(stream, "h'%06x", opcodes.r32(pc) & 0x3fffff); + break; + case DASM_abs24e: util::stream_format(stream, "h'%06x", opcodes.r32(pc) & 0xffffff); break; @@ -213,16 +217,12 @@ void h8_disassembler::disassemble_am(std::ostream &stream, int am, offs_t pc, co util::stream_format(stream, "#%x", (opcode >> 4) & 3); break; - case DASM_imm2l: - util::stream_format(stream, "#%x", opcode & 3); - break; - case DASM_imm3: util::stream_format(stream, "#%x", (opcode >> 4) & 7); break; - case DASM_imm4l: - util::stream_format(stream, "#%x", opcode & 15); + case DASM_imm6l: + util::stream_format(stream, "#%x", opcode & 0x3f); break; case DASM_imm8: diff --git a/src/devices/cpu/h8/h8d.h b/src/devices/cpu/h8/h8d.h index f6625fd9022..bd28feff96c 100644 --- a/src/devices/cpu/h8/h8d.h +++ b/src/devices/cpu/h8/h8d.h @@ -70,6 +70,7 @@ protected: DASM_abs32, /* 32-bit address present at end of instruction */ DASM_abs8i, /* 8-bit indirect jump address present at +1 */ DASM_abs16e, /* 16-bit jump address present at +2 */ + DASM_abs22e, /* 22-bit jump address present at +1 (GT913) */ DASM_abs24e, /* 24-bit jump address present at +1 */ DASM_rel8, /* 8-bit pc-relative jump address at +1, offset=2 */ @@ -80,9 +81,8 @@ protected: DASM_four, /* immediate value 4 */ DASM_imm2, /* 2-bit immediate in bits 4-5 (trapa) */ - DASM_imm2l, /* 2-bit immediate in bits 0-1 (GT913) */ DASM_imm3, /* 3-bit immediate in bits 4-6 (bit selection */ - DASM_imm4l, /* 4-bit immediate in bits 0-3 (GT913) */ + DASM_imm6l, /* 6-bit immediate in bits 0-5 (GT913) */ DASM_imm8, /* 8-bit immediate at +1 */ DASM_imm16, /* 16-bit immediate at +2 */ DASM_imm32, /* 32-bit immediate at +2 */ @@ -90,7 +90,7 @@ protected: DASM_ccr, /* internal register ccr */ DASM_exr, /* internal register exr */ DASM_bankl, /* internal register bankl (GT913) */ - DASM_bankh, /* internal register bankl (GT913) */ + DASM_bankh, /* internal register bankh (GT913) */ DASM_macl, /* internal register macl */ DASM_mach /* internal register mach */ }; diff --git a/src/devices/cpu/h8/h8make.py b/src/devices/cpu/h8/h8make.py index e16e5edf766..a2d131bcfa1 100644 --- a/src/devices/cpu/h8/h8make.py +++ b/src/devices/cpu/h8/h8make.py @@ -145,7 +145,7 @@ class Opcode: if dtype == 0 and (am1 == "r16h" or am2 == "r16h"): self.mask[len(self.mask) - 1] |= 0x80 extra_words = 0 - if (am1 == "abs16" or am2 == "abs16" or am1 == "abs16e" or am1 == "abs24e") and self.skip == 0: + if (am1 == "abs16" or am2 == "abs16" or am1 == "abs16e" or am1 == "abs22e" or am1 == "abs24e") and self.skip == 0: extra_words += 1 if (am1 == "abs32" or am2 == "abs32") and self.skip == 0: extra_words += 2 diff --git a/src/devices/machine/gt913_snd.cpp b/src/devices/machine/gt913_snd.cpp index eef16d8b494..b1c1b098d2b 100644 --- a/src/devices/machine/gt913_snd.cpp +++ b/src/devices/machine/gt913_snd.cpp @@ -44,6 +44,14 @@ const s8 gt913_sound_device::sample_7_to_8[128] = -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1 }; +// based on SW-10 softsynth +const u16 gt913_sound_device::volume_ramp[17] = +{ + 0x0000, 0x00fa, 0x0231, 0x03b5, 0x0596, 0x07ee, 0x0ad8, 0x0e78, + 0x12fa, 0x1897, 0x1f93, 0x2843, 0x3313, 0x4087, 0x5143, 0x6617, + 0x8000 +}; + gt913_sound_device::gt913_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, GT913_SOUND, tag, owner, clock) , device_sound_interface(mconfig, *this) @@ -77,10 +85,10 @@ void gt913_sound_device::device_start() save_item(STRUCT_MEMBER(m_voices, m_sample_next)); save_item(STRUCT_MEMBER(m_voices, m_exp)); + save_item(STRUCT_MEMBER(m_voices, m_volume_data)); save_item(STRUCT_MEMBER(m_voices, m_volume_current)); save_item(STRUCT_MEMBER(m_voices, m_volume_target)); save_item(STRUCT_MEMBER(m_voices, m_volume_rate)); - save_item(STRUCT_MEMBER(m_voices, m_volume_end)); save_item(STRUCT_MEMBER(m_voices, m_balance)); save_item(STRUCT_MEMBER(m_voices, m_gain)); @@ -102,12 +110,13 @@ void gt913_sound_device::sound_stream_update(sound_stream& stream, std::vector> 26, 32678); - outputs[1].put_int_clamp(i, (right * m_gain) >> 26, 32768); + outputs[0].put_int_clamp(i, (left * m_gain) >> 27, 32678); + outputs[1].put_int_clamp(i, (right * m_gain) >> 27, 32768); } } @@ -120,13 +129,27 @@ void gt913_sound_device::mix_sample(voice_t& voice, s64& left, s64& right) { // update sample position voice.m_addr_frac += voice.m_pitch; - while (voice.m_addr_frac >= (1 << 25)) + while (voice.m_enable && voice.m_addr_frac >= (1 << 25)) { voice.m_addr_frac -= (1 << 25); update_sample(voice); } - // update volume envelope + // interpolate, apply envelope + channel gain, and mix into output + const u8 step = (voice.m_addr_frac >> 22) & 7; + + const u8 env = (voice.m_volume_current >> 27); + const u16 env_step = (voice.m_volume_current >> 16) & 0x7ff; + const u32 env_level = (u32)volume_ramp[env] + (((volume_ramp[env + 1] - volume_ramp[env]) * env_step) >> 11); + + const s64 sample = ((s64)voice.m_sample + (voice.m_sample_next * step / 8)) * voice.m_gain * env_level; + + left += sample * voice.m_balance[0]; + right += sample * voice.m_balance[1]; +} + +void gt913_sound_device::update_envelope(voice_t& voice) +{ if (voice.m_volume_target > voice.m_volume_current && (voice.m_volume_target - voice.m_volume_current) > voice.m_volume_rate) { @@ -141,37 +164,42 @@ void gt913_sound_device::mix_sample(voice_t& voice, s64& left, s64& right) { voice.m_volume_current = voice.m_volume_target; } - - // interpolate, apply envelope + channel gain, and mix into output - const u8 step = (voice.m_addr_frac >> 22) & 7; - const u8 env = (voice.m_volume_current >> 24); - /* - the current envelope level effects amplitude non-linearly, just apply the value twice - (this hardware family is branded as "A² (A-Square) Sound Source" in some of Casio's - promotional materials, possibly for this reason?) - */ - const s64 sample = ((s64)voice.m_sample + (voice.m_sample_next * step / 8)) * voice.m_gain * env * env; - - left += sample * voice.m_balance[0]; - right += sample * voice.m_balance[1]; } void gt913_sound_device::update_sample(voice_t& voice) { voice.m_sample += voice.m_sample_next; - if (voice.m_addr_current == (voice.m_addr_loop | 1)) + if (voice.m_addr_current >= voice.m_addr_end) { + if (voice.m_addr_loop == voice.m_addr_end) + { + voice.m_enable = false; + return; + } + + voice.m_addr_current = voice.m_addr_loop; /* The last 12 bytes of each sample are a table containing five sample and exponent value pairs for the data words immediately after the loop point. The first pair corresponds to what the - sample and exponent value will be _after_ processing the first word after the loop, + sample and exponent value will be _after_ processing the first 16-bit word after the loop, so once we've reached that point, use those values to reload the current sample and exponent */ const u32 addr_loop_data = (voice.m_addr_end + 1) & ~1; voice.m_sample_next = read_word(addr_loop_data) - voice.m_sample; voice.m_exp = read_word(addr_loop_data + 10) & 7; + + if (!BIT(voice.m_addr_current, 0)) + { + /* + the loop data represents the state after applying both samples in a 16-bit word, + so if we're looping to the first of the two samples, compensate for the second one + */ + const u16 word = read_word(voice.m_addr_current); + const s16 delta = sample_7_to_8[word >> 9]; + voice.m_sample_next -= delta * (1 << voice.m_exp); + } } else { @@ -192,18 +220,10 @@ void gt913_sound_device::update_sample(voice_t& voice) { delta = sample_7_to_8[word >> 9]; } - voice.m_sample_next = delta * (1 << voice.m_exp); } voice.m_addr_current++; - if (voice.m_addr_current == voice.m_addr_end) - { - voice.m_addr_current = voice.m_addr_loop; - - if (voice.m_addr_loop == voice.m_addr_end) - voice.m_enable = false; - } } void gt913_sound_device::data_w(offs_t offset, u16 data) @@ -236,7 +256,7 @@ void gt913_sound_device::command_w(u16 data) } auto& voice = m_voices[voicenum]; - if (voicecmd == 0x0008) + if (voicecmd == 0x0008) // voice data write commands { /* sample start addresses seem to need to be word-aligned to decode properly @@ -245,19 +265,19 @@ void gt913_sound_device::command_w(u16 data) may loop badly or even become noticeably detuned TODO: is the LSB of start addresses supposed to indicate something else, then? */ - voice.m_addr_start = (m_data[1] | (m_data[2] << 16)) & 0x1ffffe; + voice.m_addr_start = (m_data[1] | (m_data[2] << 16)) & 0x3ffffe; } else if (voicecmd == 0x0000) { - voice.m_addr_end = (m_data[0] | (m_data[1] << 16)) & 0x1fffff; + voice.m_addr_end = (m_data[0] | (m_data[1] << 16)) & 0x3fffff; } else if (voicecmd == 0x2000) { - voice.m_addr_loop = (m_data[0] | (m_data[1] << 16)) & 0x1fffff; + voice.m_addr_loop = (m_data[0] | (m_data[1] << 16)) & 0x3fffff; } else if (voicecmd == 0x200a) { - /* TODO: what does bit 4 of data[2] do? ctk551 sets it unconditionally */ + /* TODO: what does bit 3 of data[2] do? ctk551 sets it unconditionally */ voice.m_exp = m_data[2] & 7; } else if (voicecmd == 0x200b) @@ -267,11 +287,11 @@ void gt913_sound_device::command_w(u16 data) { voice.m_addr_current = voice.m_addr_start; voice.m_addr_frac = 0; - voice.m_sample = 0; + voice.m_volume_current = 0; + voice.m_sample = voice.m_sample_next = 0; } voice.m_enable = enable; - voice.m_volume_end &= enable; } else if (voicecmd == 0x4004) { @@ -296,55 +316,58 @@ void gt913_sound_device::command_w(u16 data) } else if (voicecmd == 0x6007) { - logerror("voice %u volume %u rate %u\n", voicenum, (m_data[0] >> 8), m_data[0] & 0xff); - /* - only set a new volume level/rate if we haven't previously indicated the end of an envelope, - unless the new level also has the high bit set. otherwise, a timer irq may try to update the - normal envelope while other code is trying to force a note off - */ - const bool end = BIT(m_data[0], 15); - if (!voice.m_volume_end || end) - { - voice.m_volume_end = end; + // logerror("voice %u volume %u rate %u\n", voicenum, (m_data[0] >> 8), m_data[0] & 0xff); - voice.m_volume_target = (m_data[0] & 0x7f00) << 16; - /* - In addition to volume levels applying non-linearly, envelope rates - are also non-linear. Unfortunately, with the ctk-551's limited patch set and - lack of editing features, figuring out the correct behavior isn't easy. - This is essentially a rough estimate until a higher-end model (ctk-601 series, etc) - can be dumped and used for more detailed testing. - */ - const u8 x = m_data[0] & 0xff; - if (x >= 127) - voice.m_volume_rate = x << 21; - else if (x >= 63) - voice.m_volume_rate = x << 16; - else if (x >= 47) - voice.m_volume_rate = x << 14; - else if (x >= 31) - voice.m_volume_rate = x << 11; - else if (x >= 23) - voice.m_volume_rate = x << 9; - else if (x >= 15) - voice.m_volume_rate = x << 7; - else - voice.m_volume_rate = x << 5; + voice.m_volume_data = m_data[0]; + voice.m_volume_target = (m_data[0] & 0x7f00) << 16; + + // referenced from the SW-10 softsynth + u8 base = m_data[0] & 0xff; + u8 shift = base >> 5; + switch (shift) + { + case 0: + shift = base >> 2; + base &= 3; + break; + + case 1: + shift = 8; + base &= 0x1f; + break; + + default: + shift += 6; + base = (base & 0x1f) | 0x20; + break; } + /* + this part is less certain - the overall rate needs adjusting based on + the sample rate difference between this and the softsynth. + it's probably not exact, but it sounds okay + */ + voice.m_volume_rate = (base * 3) << (shift + 5); } - else if (voicecmd == 0x2028) + else if (voicecmd == 0x2028) // voice data read commands { /* - ctk551 issues this command and then reads the voice's current volume from data0 - to determine if it's time to start the next part of the volume envelope or not. + data0 is used to determine if it's time to start the next part of the volume envelope or not */ - m_data[0] = voice.m_enable ? (voice.m_volume_current >> 16) : 0; + m_data[0] = voice.m_volume_current >> 16; /* - data1 is used to read consecutive output sample and detect zero crossings when + data1 is used to read consecutive output samples and detect zero crossings when applying volume or expression changes to a MIDI channel */ m_data[1] = voice.m_sample; } + else if (voicecmd == 0x6020) + { + /* + AP-10 sometimes issues this command, then clears the low byte of data0, + and then issues command 0x6007 with the result (to pause an envelope?) + */ + m_data[0] = voice.m_volume_data; + } else { logerror("unknown sound write %04x (data: %04x %04x %04x)\n", data, m_data[0], m_data[1], m_data[2]); diff --git a/src/devices/machine/gt913_snd.h b/src/devices/machine/gt913_snd.h index 5e0912ae5d2..54eecfa72d0 100644 --- a/src/devices/machine/gt913_snd.h +++ b/src/devices/machine/gt913_snd.h @@ -51,6 +51,7 @@ private: static const u8 exp_2_to_3[4]; static const s8 sample_7_to_8[128]; + static const u16 volume_ramp[17]; struct voice_t { @@ -66,15 +67,16 @@ private: s16 m_sample, m_sample_next; u8 m_exp; + u16 m_volume_data; u32 m_volume_current, m_volume_target; u32 m_volume_rate; - bool m_volume_end; u8 m_balance[2]; u8 m_gain; }; void mix_sample(voice_t& voice, s64& left, s64& right); + void update_envelope(voice_t& voice); void update_sample(voice_t& voice); voice_t m_voices[24]; diff --git a/src/mame/casio/ctk551.cpp b/src/mame/casio/ctk551.cpp index 0eacfd96fea..d21b22d50d4 100644 --- a/src/mame/casio/ctk551.cpp +++ b/src/mame/casio/ctk551.cpp @@ -1,10 +1,121 @@ // license:BSD-3-Clause // copyright-holders:Devin Acker /* - Casio CTK-551 keyboard (and related models) - - Casio released several keyboard models with the same main board. - As usual, some of them were also rebranded by Radio Shack. + Casio GT913-based keyboards and MIDI modules + +------------------------------------------------------------------------------- + + Celviano AP-10 digital piano (1995) + + Main board (JCM358-MA1M): + LSI301: CPU (Casio/NEC uPD912GF) + LSI302: DSP (Hitachi HG51B277FB) + LSI303: 8Mbit ROM (Macronix MX23C8100MC-12) + LSI304: 64kbit SRAM for CPU (Sanyo LC3564SM-85), battery backed + LSI305: 256kbit SRAM for DSP (Sanyo LC333832M-70) + LSI306: stereo DAC (NEC uPD6379GR) + X301: 24MHz crystal for CPU + X302: 16MHz ceramic for DSP + + Service manual with schematics, pinouts, etc.: + https://revenant1.net/casio/manuals/upd91x/ap10.pdf + + To access the test mode (not mentioned in the service manual): + Hold both pedals and "Transpose/Tune/MIDI" while turning on the keyboard, then release the button. + Afterwards, press one of these buttons: + - Transpose: LED test + - Effect: switch test (press all front panel buttons left to right) + - Piano: key test (press all keys left to right) + - E.Piano: ROM test + - Organ/Strings/Song: sound volume test + - Record/Start/Stop: stereo test + - Demo: MIDI loopback test + - Harpsichord: exit test mode + + TODO: fix backup RAM getting re-initialized on every boot. + Depends on the power switch being implemented correctly - turning the power off + 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 + +------------------------------------------------------------------------------- + + General MIDI modules (1996) + + - GZ-30M + Basic model, small desktop module + No 5-pin MIDI jack, only mini-DIN for RS-232 or RS-422 + - GZ-70SP + MIDI module built into a pair of speakers w/ karaoke mic input + Provides both standard MIDI and mini-DIN connectors + - WG-130 + WaveBlaster-style PC daughterboard + + WG-130 board: + LSI101: stereo DAC (NEC uPD6379GR) + LSI102: CPU (Casio GT913F) + LSI103: 16Mbit ROM (Casio GM16000N-C40) + LSI104: 64kbit SRAM (Sanyo LC3564SM-85) + LSI105: unpopulated, for DSP SRAM + LSI106: unpopulated, for DSP + X101: 30MHz crystal + X102: unpopulated, for DSP + + All three of these apparently use the same mask ROM. + This ROM was also distributed as part of Casio's SW-10 softsynth for Windows, + which it released in early 1997 as part of the "LANA Lite" karaoke system. + http://web.archive.org/web/20011122112757/www.casio.co.jp/lanalite/LanaSw10.exe + + The WG-130 (and possibly others) have unpopulated footprints for the same DSP + used in some keyboards (e.g. the CTK-601). The ROM does actually support + using the DSP if it's present, and responds to the same sysex message used to + enable reverb on the CTK-601 and similar models (F0 44 0E 09 0x F7). + + Pulling CPU pin 53 (KI0/P24) low starts a ROM checksum test. + The result is indicated both by sound as well as output on pin 55 (KI2/P11). + + More info and photos: + https://piano.tyonmage.com/casio/gz-30m.html + https://piano.tyonmage.com/casio/gz-70sp.html + http://www.yjfy.com/museum/sound/WG-130.htm + +------------------------------------------------------------------------------- + + CTK-601/611 / Concertmate 990 (1997) + + Main board (JCM462-MA1M): + LSI1: CPU (Casio GT913F) + LSI2: DSP (Casio GD277F / Hitachi HG51B277FB) + LSI3: 16Mbit ROM (Macronix MX23C1610MC-12) + LSI4: 256kbit SRAM for CPU (Toshiba TC55257DFL-70L) + LSI5: 256kbit SRAM for DSP (same as LSI4) + LSI6: stereo DAC (NEC uPD6379GR) + X1: 30MHz crystal for CPU + X2: 20MHz ceramic for DSP + + Display board (JCM462-LCD1M): + LSI401: LCD controller (Epson SED1278F2A) + + Service manuals with schematics, pinouts, etc.: + https://revenant1.net/casio/manuals/upd91x/ctk601.pdf + https://revenant1.net/casio/manuals/upd91x/ctk611.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 a specific order, generally left to right) + - Keypad 1: pedal and key test + - Keypad 2: ROM test + - Keypad 4/5/6: sound volume test + - Keypad 7/8: stereo test + - Keypad 9: MIDI loopback test + - Keypad +: power source test + - Cursor Left: LCD test (all segments at once) + - Cursor Right: LCD test (all segments individually) + - Cursor Down: power off + +------------------------------------------------------------------------------- + + CTK-551 (and related models) - CTK-531, CTK-533 (1999) Basic 61-key model @@ -13,24 +124,21 @@ - CTK-551, CTK-558, Radio Shack MD-1160 (2000) Adds pitch wheel and different selection of demo songs - Main board (JCM456-MA1M): - - LSI1: CPU (Casio GT913F) - Custom chip based on H8/300 instruction set, built in peripheral controllers & sound generator - - LSI2: 8Mbit ROM (OKI MSM538002E) - - LSI3: LCD controller (HD44780 compatible) - May be either a Samsung KS0066U-10B or Epson SED1278F2A. + Main board (JCM453-MA1M / JCM456-MA1M): + LSI1: CPU (Casio GT913F) + LSI2: 8Mbit ROM (OKI MSM538002E) + LSI3: LCD controller (HD44780 compatible) + May be either a Samsung KS0066U-10B or Epson SED1278F2A. + IC1: stereo DAC (NEC uPD6379GR) + X1: 30MHz ceramic - IC1: stereo DAC (NEC uPD6379GR) - - CTK-541 service manual with schematics, pinouts, etc.: - https://revenant1.net/ctk541.pdf + Service manuals with schematics, pinouts, etc.: + https://revenant1.net/casio/manuals/upd91x/ctk531.pdf + https://revenant1.net/casio/manuals/upd91x/ctk541.pdf To access the test mode (not mentioned in the service manual): Hold the "Start/Stop" and keypad 0 buttons together when turning on the keyboard. - Afterwards, press one of these buttons: + "215dTEST" will appear on the LCD. Afterwards, press one of these buttons: - Tone: LCD test (press repeatedly) - Keypad 0: switch test (press all front panel buttons in a specific order, generally left to right) - Keypad 1 or Rhythm: pedal and key test @@ -50,11 +158,14 @@ #include "bus/midi/midiinport.h" #include "bus/midi/midioutport.h" #include "cpu/h8/gt913.h" +#include "machine/nvram.h" #include "video/hd44780.h" #include "emupal.h" #include "screen.h" #include "speaker.h" +#include "ap10.lh" + namespace { class ctk551_state : public driver_device @@ -64,42 +175,102 @@ public: : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") , m_lcdc(*this, "lcdc") + , m_inputs(*this, "IN%u", 0U) , m_outputs(*this, "%02x.%d.%d", 0U, 0U, 0U) , m_led_touch(*this, "led_touch") + , m_led_console(*this, "led_console_%d", 0U) , m_led_power(*this, "led_power") { } + void ap10(machine_config& config); + void gz70sp(machine_config& config); + void ctk601(machine_config& config); void ctk551(machine_config &config); + void init_ap10(); + void init_gz70sp(); + DECLARE_CUSTOM_INPUT_MEMBER(lcd_r) { return m_lcdc->db_r() >> 4; } - DECLARE_WRITE_LINE_MEMBER(lcd_w) { m_lcdc->db_w(state << 4); } + DECLARE_WRITE_LINE_MEMBER(lcd_w) + { + m_lcd_data = state << 4; + m_lcdc->db_w(m_lcd_data); + } + + // some models have all 4 LCD bits wired to adjacent port bits, but some don't + // (and even those don't always have them wired the same way - + // in some cases they're not even all connected to the same port) + template + DECLARE_CUSTOM_INPUT_MEMBER(lcd_bit_r) { return BIT(m_lcdc->db_r(), Bit); } + template + DECLARE_WRITE_LINE_MEMBER(lcd_bit_w) + { + m_lcd_data = (m_lcd_data & ~(1 << Bit)) | (state << Bit); + m_lcdc->db_w(m_lcd_data); + } + // handle the 4-position mode switch + // some models treat this as 3 modes plus power off, + // while others have 4 modes and move power to a separate button instead DECLARE_CUSTOM_INPUT_MEMBER(switch_r) { return m_switch; } DECLARE_INPUT_CHANGED_MEMBER(switch_w); + DECLARE_INPUT_CHANGED_MEMBER(power_w); + DECLARE_INPUT_CHANGED_MEMBER(switch_power_w); + + DECLARE_WRITE_LINE_MEMBER(inputs_w) { m_input_sel = state; } + DECLARE_CUSTOM_INPUT_MEMBER(inputs_r); + + void dsp_data_w(uint8_t data); + void dsp_cmd_w(uint8_t cmd); DECLARE_WRITE_LINE_MEMBER(led_touch_w) { m_led_touch = state; } + void led_console_w(uint8_t state); DECLARE_WRITE_LINE_MEMBER(apo_w); private: + void ap10_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 gz70sp_io_map(address_map& map); void ctk551_io_map(address_map &map); virtual void driver_start() override; required_device m_maincpu; - required_device m_lcdc; + optional_device m_lcdc; + + optional_ioport_array<4> m_inputs; output_finder<64, 8, 5> m_outputs; output_finder<> m_led_touch; + output_finder<6> m_led_console; output_finder<> m_led_power; ioport_value m_switch{}; + ioport_value m_input_sel{}; + + uint8_t m_lcd_data{}; + uint32_t m_dsp_data{}; DECLARE_WRITE_LINE_MEMBER(render_w); }; - INPUT_CHANGED_MEMBER(ctk551_state::switch_w) +{ + if (!oldval && newval) + m_switch = param; +} + +INPUT_CHANGED_MEMBER(ctk551_state::power_w) +{ + m_maincpu->set_input_line(INPUT_LINE_NMI, newval ? ASSERT_LINE : CLEAR_LINE); +} + +INPUT_CHANGED_MEMBER(ctk551_state::switch_power_w) { if (!oldval && newval) { @@ -112,12 +283,39 @@ INPUT_CHANGED_MEMBER(ctk551_state::switch_w) } } +CUSTOM_INPUT_MEMBER(ctk551_state::inputs_r) +{ + uint8_t result = 0xff; + for (unsigned i = 0U; i < m_inputs.size(); i++) + if (!BIT(m_input_sel, i)) + result &= m_inputs[i].read_safe(0xff); + + return result; +} + +void ctk551_state::dsp_data_w(uint8_t data) +{ + m_dsp_data >>= 8; + m_dsp_data |= (data << 24); +} + +void ctk551_state::dsp_cmd_w(uint8_t data) +{ + logerror("dsp_cmd_w: addr = %02x, data = %08x\n", data, m_dsp_data); +} + +void ctk551_state::led_console_w(uint8_t state) +{ + for (unsigned i = 0; i < 6; i++) + m_led_console[i] = !BIT(state, i); +} + 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) + if (!state && m_lcdc.found()) m_lcdc->reset(); m_led_power = state; m_maincpu->set_output_gain(ALL_OUTPUTS, state ? 1.0 : 0.0); @@ -140,6 +338,56 @@ WRITE_LINE_MEMBER(ctk551_state::render_w) } } + +void ctk551_state::ap10_map(address_map& map) +{ + map(0x000000, 0x0fffff).rom().region("maincpu", 0).mirror(0x100000); + map(0x300000, 0x301fff).ram().share("nvram").mirror(0x07e000); + // TODO: DSP + map(0x380000, 0x380000).w(FUNC(ctk551_state::dsp_data_w)); + map(0x380001, 0x380001).w(FUNC(ctk551_state::dsp_cmd_w)); + map(0x380002, 0x380003).noprw(); + map(0x380003, 0x380003).w(FUNC(ctk551_state::led_console_w)); +} + +void ctk551_state::gz70sp_map(address_map& map) +{ + map(0x000000, 0x1fffff).rom().region("maincpu", 0); + map(0x300000, 0x301fff).ram().mirror(0x07e000); + map(0x380000, 0x380003).noprw(); // DSP is mapped here, but not actually present +} + +void ctk551_state::ctk601_map(address_map& map) +{ + map(0x000000, 0x1fffff).rom().region("maincpu", 0); + map(0x300000, 0x307fff).ram().mirror(0x078000); + // TODO: DSP + map(0x380000, 0x380000).w(FUNC(ctk551_state::dsp_data_w)); + map(0x380001, 0x380001).w(FUNC(ctk551_state::dsp_cmd_w)); + map(0x380002, 0x380003).noprw(); + 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_3).noprw(); + map(h8_device::ADC_0, h8_device::ADC_1).nopr(); +} + +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::ADC_0, h8_device::ADC_1).nopr(); +} + 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); @@ -152,19 +400,106 @@ void ctk551_state::ctk551_io_map(address_map &map) void ctk551_state::driver_start() { m_led_touch.resolve(); + m_led_console.resolve(); m_led_power.resolve(); m_outputs.resolve(); - m_switch = 0x2; + m_input_sel = 0xf; save_item(NAME(m_switch)); + save_item(NAME(m_input_sel)); + save_item(NAME(m_lcd_data)); + save_item(NAME(m_dsp_data)); +} + + +void ctk551_state::ap10(machine_config& config) +{ + // CPU + GT913(config, m_maincpu, 24_MHz_XTAL / 2); + m_maincpu->set_addrmap(AS_DATA, &ctk551_state::ap10_map); + m_maincpu->set_addrmap(AS_IO, &ctk551_state::ap10_io_map); + m_maincpu->add_route(0, "lspeaker", 1.0); + m_maincpu->add_route(1, "rspeaker", 1.0); + + NVRAM(config, "nvram"); + + // TODO: DSP + + // 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)); + + SPEAKER(config, "lspeaker").front_left(); + SPEAKER(config, "rspeaker").front_right(); + + config.set_default_layout(layout_ap10); +} + +void ctk551_state::gz70sp(machine_config& config) +{ + // CPU + GT913(config, m_maincpu, 30_MHz_XTAL / 2); + m_maincpu->set_addrmap(AS_DATA, &ctk551_state::gz70sp_map); + m_maincpu->set_addrmap(AS_IO, &ctk551_state::gz70sp_io_map); + m_maincpu->add_route(0, "lspeaker", 1.0); + m_maincpu->add_route(1, "rspeaker", 1.0); + + // MIDI (sci0 for RS232/422, sci1 for standard MIDI) + auto& mdin(MIDI_PORT(config, "mdin")); + midiin_slot(mdin); + mdin.rxd_handler().set("maincpu:sci1", FUNC(h8_sci_device::rx_w)); + + SPEAKER(config, "lspeaker").front_left(); + SPEAKER(config, "rspeaker").front_right(); +} + +void ctk551_state::ctk601(machine_config& config) +{ + // CPU + GT913(config, m_maincpu, 30_MHz_XTAL / 2); + m_maincpu->set_addrmap(AS_DATA, &ctk551_state::ctk601_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); + + // TODO: DSP + + // 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)); + + // LCD + HD44780(config, m_lcdc, 0); + m_lcdc->set_lcd_size(2, 8); + + auto& screen = SCREEN(config, "screen", SCREEN_TYPE_SVG); + screen.set_refresh_hz(60); + screen.set_size(1000, 424); + screen.set_visarea_full(); + screen.screen_vblank().set(FUNC(ctk551_state::render_w)); + + SPEAKER(config, "lspeaker").front_left(); + SPEAKER(config, "rspeaker").front_right(); + + m_switch = 0x8; } void ctk551_state::ctk551(machine_config &config) { // CPU - // 30MHz oscillator, divided down internally (otherwise the test mode's OK/NG sounds play at double speed) GT913(config, m_maincpu, 30'000'000 / 2); + m_maincpu->set_addrmap(AS_DATA, &ctk551_state::ctk551_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); @@ -172,11 +507,11 @@ void ctk551_state::ctk551(machine_config &config) // MIDI auto &mdin(MIDI_PORT(config, "mdin")); midiin_slot(mdin); - mdin.rxd_handler().set("maincpu:sci", FUNC(h8_sci_device::rx_w)); + mdin.rxd_handler().set("maincpu:sci0", FUNC(h8_sci_device::rx_w)); auto &mdout(MIDI_PORT(config, "mdout")); midiout_slot(mdout); - m_maincpu->subdevice("sci")->tx_handler().set(mdout, FUNC(midi_port_device::write_txd)); + m_maincpu->subdevice("sci0")->tx_handler().set(mdout, FUNC(midi_port_device::write_txd)); // LCD HD44780(config, m_lcdc, 0); @@ -190,9 +525,189 @@ void ctk551_state::ctk551(machine_config &config) SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); + + m_switch = 0x2; } -INPUT_PORTS_START(ctk551) +INPUT_PORTS_START(ap10) + PORT_START("maincpu:kbd:FI0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A0") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A0#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B0") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C1") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C1#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D1") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D1#") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E1") + + PORT_START("maincpu:kbd:FI1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F1") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F1#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G1") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G1#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A1") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A1#") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B1") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2") + + PORT_START("maincpu:kbd:FI2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D2") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D2#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E2") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2#") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2#") + + PORT_START("maincpu:kbd:FI3") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B2") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3#") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E3") + + PORT_START("maincpu:kbd:FI4") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3#") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B3") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4") + + PORT_START("maincpu:kbd:FI5") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E4") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4#") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4#") + + PORT_START("maincpu:kbd:FI6") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B4") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C5") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C5#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D5") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D5#") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E5") + + PORT_START("maincpu:kbd:FI7") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F5") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F5#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G5") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G5#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A5") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A5#") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B5") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C6") + + PORT_START("maincpu:kbd:FI8") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C6#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D6") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D6#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E6") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F6") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F6#") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G6") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G6#") + + PORT_START("maincpu:kbd:FI9") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A6") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A6#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B6") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C7") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C7#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D7") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D7#") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E7") + + PORT_START("maincpu:kbd:FI10") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F7") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F7#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G7") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G7#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A7") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A7#") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B7") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C8") + + PORT_START("maincpu:kbd:KI0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Transpose / Tune / MIDI") PORT_CODE(KEYCODE_1) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Digital Effect") PORT_CODE(KEYCODE_2) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Piano") PORT_CODE(KEYCODE_3) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("E. Piano") PORT_CODE(KEYCODE_4) + PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("maincpu:kbd:KI1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Harpsichord") PORT_CODE(KEYCODE_5) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Pipe Organ") PORT_CODE(KEYCODE_6) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Strings") PORT_CODE(KEYCODE_7) + PORT_BIT( 0xf8, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("maincpu:kbd:KI2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Song") PORT_CODE(KEYCODE_8) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Record") PORT_CODE(KEYCODE_9) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Start / Stop") PORT_CODE(KEYCODE_0) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Demo") PORT_CODE(KEYCODE_MINUS) + PORT_BIT( 0xf0, 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("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( 0x38, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Damper Pedal") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Soft/Sostenuto Pedal") +INPUT_PORTS_END + +INPUT_PORTS_START(gz70sp) + PORT_START("maincpu:kbd:FI0") + PORT_START("maincpu:kbd:FI1") + PORT_START("maincpu:kbd:FI2") + PORT_START("maincpu:kbd:FI3") + PORT_START("maincpu:kbd:FI4") + PORT_START("maincpu:kbd:FI5") + PORT_START("maincpu:kbd:FI6") + PORT_START("maincpu:kbd:FI7") + PORT_START("maincpu:kbd:FI8") + PORT_START("maincpu:kbd:FI9") + PORT_START("maincpu:kbd:FI10") + PORT_START("maincpu:kbd:KI0") + PORT_START("maincpu:kbd:KI1") + PORT_START("maincpu:kbd:KI2") + + PORT_START("P1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OUTPUT ) // test mode output (1 = in progress / OK, 0 = error) + PORT_BIT( 0xfc, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("P2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_POWER_ON ) PORT_NAME("Demo") PORT_TOGGLE + PORT_BIT( 0x0e, IP_ACTIVE_LOW, IPT_UNUSED ) + /* + this is actually a serial mode switch for the mini-DIN connector + PORT_CONFNAME( 0x0e, 0x0e, "Connection to Host" ) + PORT_CONFSETTING( 0x06, "PC 1 (RS-232, 31250 baud)" ) + PORT_CONFSETTING( 0x0a, "PC 2 (RS-232, 38400 baud)" ) + PORT_CONFSETTING( 0x0c, "Mac (RS-422, 31250 baud)" ) + PORT_CONFSETTING( 0x0e, "MIDI" ) + */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_NAME("ROM Test") + PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + +INPUT_PORTS_START(base_61key) PORT_START("maincpu:kbd:FI0") PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2") PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2#") @@ -270,16 +785,144 @@ INPUT_PORTS_START(ctk551) PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B6") PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C7") PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +INPUT_PORTS_START(ctk601) + 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_KEYPAD ) PORT_NAME("Drum Pad 3") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Drum Pad 1") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Pitch Bend Down") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Cursor Down / Enter") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad +") PORT_CODE(KEYCODE_PLUS_PAD) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Tone") + + PORT_START("maincpu:kbd:KI0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Drum Pad 4") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Drum Pad 2") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Pitch Bend Up") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Start / Stop") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad -") PORT_CODE(KEYCODE_MINUS_PAD) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Rhythm") + + PORT_START("maincpu:kbd:KI1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Drum Pad 5") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Step") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Tempo Down") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Cursor Right") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 0") PORT_CODE(KEYCODE_0_PAD) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Demo") + + PORT_START("maincpu:kbd:KI2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Drum Pad 6") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Memory") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Tempo Up") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Cursor Left") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_PAD) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Transpose / Tune / MIDI") + + 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("P1_R") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(ctk551_state, lcd_bit_r<4>) + PORT_BIT( 0x06, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(ctk551_state, lcd_bit_r<5>) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(ctk551_state, lcd_bit_r<6>) + PORT_BIT( 0x60, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(ctk551_state, lcd_bit_r<7>) + + PORT_START("P1_W") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(ctk551_state, lcd_bit_w<4>) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(ctk551_state, apo_w) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(ctk551_state, lcd_bit_w<5>) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(ctk551_state, lcd_bit_w<6>) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OUTPUT ) // DSP reset + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(ctk551_state, lcd_bit_w<7>) + + PORT_START("P2") + PORT_BIT( 0x07, IP_ACTIVE_HIGH, IPT_UNKNOWN ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER("lcdc", hd44780_device, e_w) + PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNKNOWN ) + + PORT_START("AN0") + PORT_CONFNAME( 0xff, 0x00, "Power Source" ) + PORT_CONFSETTING( 0x00, "AC Adapter" ) + PORT_CONFSETTING( 0xff, "Battery" ) + + PORT_START("AN1") + PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) + + // DSP ports + PORT_START("PA") + PORT_BIT( 0x0f, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(ctk551_state, inputs_w) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER("lcdc", hd44780_device, rs_w) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER("lcdc", hd44780_device, rw_w) + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("PB") + PORT_BIT( 0x0f, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(ctk551_state, inputs_r) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Pedal") + PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("SWITCH") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Full Range Chord)") PORT_CHANGED_MEMBER(DEVICE_SELF, ctk551_state, switch_w, 0x1) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Fingered)") PORT_CHANGED_MEMBER(DEVICE_SELF, ctk551_state, switch_w, 0x2) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Casio Chord)") PORT_CHANGED_MEMBER(DEVICE_SELF, ctk551_state, switch_w, 0x4) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Normal)") PORT_CHANGED_MEMBER(DEVICE_SELF, ctk551_state, switch_w, 0x8) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_POWER_ON ) PORT_NAME("Power") PORT_CHANGED_MEMBER(DEVICE_SELF, ctk551_state, power_w, 0) + + PORT_START("IN0") + PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(ctk551_state, switch_r) + + PORT_START("IN1") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Intro") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Normal / Fill In") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Synchro / Ending") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Variation / Fill In") + + PORT_START("IN2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Touch Response") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Free Session") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Layer") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Split") + + PORT_START("IN3") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Reverb") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Accomp Volume") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Synth") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Mixer") +INPUT_PORTS_END + +INPUT_PORTS_START(ctk551) + PORT_INCLUDE(base_61key) PORT_START("maincpu:kbd:FI8") PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD) PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD) PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD) PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad +") PORT_CODE(KEYCODE_PLUS_PAD) - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Touch Response") - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Song Bank") - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Rhythm") - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Tone") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Touch Response") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Song Bank") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Rhythm") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Tone") PORT_START("maincpu:kbd:FI9") PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD) @@ -287,29 +930,29 @@ INPUT_PORTS_START(ctk551) PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD) PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad -") PORT_CODE(KEYCODE_MINUS_PAD) PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Accomp Volume") - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Transpose / Tune / MIDI") - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Chord Book") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Accomp Volume") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Transpose / Tune / MIDI") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Chord Book") PORT_START("maincpu:kbd:FI10") PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD) PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD) PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_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_OTHER ) PORT_NAME("Play / Pause") - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Rewind") - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Start / Stop") - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Sync / Fill In") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Play / Pause") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Rewind") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Start / Stop") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Sync / Fill In") PORT_START("maincpu:kbd:KI0") - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Right Hand On/Off") - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Left Hand On/Off") - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Fast Forward") - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Stop") - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Tempo Down") - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Volume Down") - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Tempo Up") - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Volume Up") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Right Hand On/Off") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Left Hand On/Off") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Fast Forward") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Stop") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Tempo Down") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Volume Down") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Tempo Up") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Volume Up") PORT_START("maincpu:kbd:KI1") PORT_BIT( 0x0f, IP_ACTIVE_HIGH, IPT_UNUSED ) @@ -322,10 +965,10 @@ INPUT_PORTS_START(ctk551) 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_OTHER ) PORT_NAME("Power Off") PORT_CHANGED_MEMBER(DEVICE_SELF, ctk551_state, switch_w, 0x1) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Normal") PORT_CHANGED_MEMBER(DEVICE_SELF, ctk551_state, switch_w, 0x2) - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Casio Chord") PORT_CHANGED_MEMBER(DEVICE_SELF, ctk551_state, switch_w, 0x4) - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Fingered") PORT_CHANGED_MEMBER(DEVICE_SELF, ctk551_state, switch_w, 0x8) + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Power Off") PORT_CHANGED_MEMBER(DEVICE_SELF, ctk551_state, switch_power_w, 0x1) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Normal)") PORT_CHANGED_MEMBER(DEVICE_SELF, ctk551_state, switch_power_w, 0x2) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Casio Chord)") PORT_CHANGED_MEMBER(DEVICE_SELF, ctk551_state, switch_power_w, 0x4) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Fingered)") PORT_CHANGED_MEMBER(DEVICE_SELF, ctk551_state, switch_power_w, 0x8) PORT_START("P1_R") PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) @@ -353,19 +996,59 @@ INPUT_PORTS_START(ctk551) PORT_START("AN1") PORT_BIT( 0xff, 0x7f, IPT_PADDLE ) PORT_NAME("Pitch Wheel") PORT_SENSITIVITY(100) PORT_KEYDELTA(10) PORT_MINMAX(0x00, 0xff) - INPUT_PORTS_END + +ROM_START(ap10) + ROM_REGION(0x100000, "maincpu", 0) + ROM_LOAD16_WORD_SWAP("ap10.lsi303", 0x000000, 0x100000, CRC(39caa214) SHA1(3b484628c1e6f0ad7c11e2ec7eff664294f9ec83)) // MX23C8100MC-12CA27 +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 +ROM_END + +ROM_START(ctk601) + ROM_REGION(0x200000, "maincpu", 0) + ROM_LOAD16_WORD_SWAP("ctk601.lsi3", 0x000000, 0x200000, CRC(23ae6ab1) SHA1(c1a8a1b9af19888360b56587c58602c26ad5029e)) // MX23C1610MC-12CA62 + + ROM_REGION(366949, "screen", 0) + ROM_LOAD("ctk601.svg", 0, 366949, CRC(7596bb55) SHA1(73f999675158e41b96ab9d2ee31edd19b8ab3e0e)) +ROM_END + ROM_START(ctk551) ROM_REGION(0x100000, "maincpu", 0) ROM_LOAD16_WORD_SWAP("ctk551.lsi2", 0x000000, 0x100000, CRC(66fc34cd) SHA1(47e9559edc106132f8a83462ed17a6c5c3872157)) // MSM538002E-T6 ROM_REGION(285279, "screen", 0) ROM_LOAD("ctk551lcd.svg", 0, 285279, CRC(1bb5da03) SHA1(a0cf22c6577c4ff0119ee7bb4ba8b487e23872d4)) - ROM_END + +void ctk551_state::init_ap10() +{ + uint16_t* rom = (uint16_t*)memregion("maincpu")->base(); + for (uint32_t addr = 0; addr < 0x80000; addr++) + 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_gz70sp() +{ + /* + the version of this ROM bundled with the SW-10 softsynth has little endian samples, so byteswap them + (and stop at the end of sample data, not the end of the whole ROM, otherwise the ROM test fails) + */ + uint16_t* rom = (uint16_t*)memregion("maincpu")->base(); + for (uint32_t addr = 0x2f000 >> 1; addr < 0x1fe8c2 >> 1; addr++) + rom[addr] = swapendian_int16(rom[addr]); +} + } // anonymous namespace -// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -SYST( 2000, ctk551, 0, 0, ctk551, ctk551, ctk551_state, empty_init, "Casio", "CTK-551", MACHINE_SUPPORTS_SAVE ) +// 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( 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( 2000, ctk551, 0, 0, ctk551, ctk551, ctk551_state, empty_init, "Casio", "CTK-551", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/layout/ap10.lay b/src/mame/layout/ap10.lay new file mode 100644 index 00000000000..ca7c56a1d97 --- /dev/null +++ b/src/mame/layout/ap10.lay @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 622d3c433ec..18001976e30 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -11661,7 +11661,10 @@ ct486 // 1993? 486 with CS4031 megatrix @source:casio/ctk551.cpp +ap10 // ctk551 // +ctk601 // +gz70sp // @source:casio/ctk2000.cpp ctk2100 // -- cgit v1.2.3