summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/target/mame/mess.lua1
-rw-r--r--src/mame/drivers/ld50.cpp322
-rw-r--r--src/mame/mame.lst3
-rw-r--r--src/mame/mess.flt1
4 files changed, 327 insertions, 0 deletions
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index a60601cc8b3..62c91167e85 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -2044,6 +2044,7 @@ files {
MAME_DIR .. "src/mame/drivers/ctk2000.cpp",
MAME_DIR .. "src/mame/drivers/ctk551.cpp",
MAME_DIR .. "src/mame/drivers/ht6000.cpp",
+ MAME_DIR .. "src/mame/drivers/ld50.cpp",
MAME_DIR .. "src/mame/drivers/pb1000.cpp",
MAME_DIR .. "src/mame/drivers/pv1000.cpp",
MAME_DIR .. "src/mame/drivers/pv2000.cpp",
diff --git a/src/mame/drivers/ld50.cpp b/src/mame/drivers/ld50.cpp
new file mode 100644
index 00000000000..0e27739c69a
--- /dev/null
+++ b/src/mame/drivers/ld50.cpp
@@ -0,0 +1,322 @@
+// license:BSD-3-Clause
+// copyright-holders:Devin Acker
+/*
+ Casio LD-50 electronic drums
+
+ Unlike most Casio instruments, this is either rebranded or outsourced.
+ It's unclear who developed it, or if it was ever sold under other brands,
+ but the data ROM mentions "SharpWin".
+
+ Main board:
+ bottom left: "DIGITAL DRUM [LD-50] DATE: 2001/07/20"
+ bottom right: "LD50 Main PCB Rev.1"
+
+ IC1: Burr-Brown PCM1717E DAC
+ IC2: unknown SOIC8 ("2429 170")
+ IC4: Philips P87C52UBAA MCU
+ IC5: AMD AM29F040 ROM
+ IC7/8/9/10: 4x 74HC374
+ IC11: unknown COB (letter "B" handwritten on epoxy)
+ IC12: Dream SAM9793
+ XTAL1: 9.6MHz (for SAM9793)
+ XTAL2: 12MHz (for MCU)
+
+ A 10-pin header at the upper left connects to the input matrix and
+ a small plastic LCD assembly on the other side of the board.
+
+ Most of the sound is provided by the SAM9793, which is just a MIDI
+ synth on a chip that takes in serial MIDI input and outputs I2S.
+ The four sound effect pads also trigger PCM samples separately,
+ possibly via the black blob at IC11.
+
+ The external ROM contains the demo and rhythms, which are all stored
+ as standard type 0 MIDI files.
+
+ To activate the test mode, hold "Rhythm" and "Assign" when powering on.
+ From here, hitting the drum pads will display time/velocity measurements.
+
+ TODO:
+ - drum LEDs
+ - LCD artwork
+ - clickable layout?
+ - possibly connect a MIDI out port in lieu of the SAM9793
+ (MCS51 core needs proper serial output first)
+ - dump/emulate the other PCM device somehow
+ */
+
+#include "emu.h"
+
+#include "bus/midi/midioutport.h"
+#include "cpu/mcs51/mcs51.h"
+#include "video/hd44780.h"
+#include "emupal.h"
+#include "screen.h"
+
+namespace {
+
+class ld50_state : public driver_device
+{
+public:
+ ld50_state(machine_config const &mconfig, device_type type, char const *tag)
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_lcdc(*this, "lcdc")
+ , m_datarom(*this, "datarom")
+ , m_inputs(*this, "IN%u", 0)
+ , m_pads(*this, "PADS")
+ , m_dial(*this, "DIAL")
+ {
+ }
+
+ void ld50(machine_config &config);
+
+ DECLARE_CUSTOM_INPUT_MEMBER(dial_r);
+
+private:
+ u8 port0_r();
+ void port0_w(u8 data);
+ u8 port1_r();
+ void port2_w(u8 data);
+ void port3_w(u8 data);
+
+ virtual void driver_start() override;
+ virtual void driver_reset() override;
+
+ HD44780_PIXEL_UPDATE(lcd_update);
+ void palette_init(palette_device &palette);
+
+ required_device<mcs51_cpu_device> m_maincpu;
+ required_device<hd44780_device> m_lcdc;
+
+ required_memory_region m_datarom;
+ required_ioport_array<5> m_inputs;
+ required_ioport m_pads;
+ required_ioport m_dial;
+
+ u8 m_port[4];
+ u32 m_rom_addr;
+ u16 m_shift_data;
+};
+
+HD44780_PIXEL_UPDATE(ld50_state::lcd_update)
+{
+ if (x < 6 && y < 8 && line < 2 && pos < 8)
+ bitmap.pix(y, line * 48 + pos * 6 + x) = state;
+}
+
+void ld50_state::palette_init(palette_device &palette)
+{
+ palette.set_pen_color(0, rgb_t(255, 255, 255));
+ palette.set_pen_color(1, rgb_t(0, 0, 0));
+}
+
+
+u8 ld50_state::port0_r()
+{
+ u8 data = 0xf0 | (m_lcdc->db_r() >> 4);
+ if (!BIT(m_port[2], 3))
+ data &= m_datarom->base()[m_rom_addr & 0x7ffff];
+
+ return data;
+}
+
+void ld50_state::port0_w(u8 data)
+{
+ m_lcdc->db_w(data << 4);
+ m_port[0] = data;
+}
+
+u8 ld50_state::port1_r()
+{
+ /*
+ bits 0-3: drum pads (active high)
+ bits 4-7: multiplexed inputs (active low)
+
+ The drum pads are read during the timer 0 interrupt.
+ Note velocity is based on the number of timer intervals that the pad remains pressed.
+ */
+ return (m_port[1] & 0xf0) | m_pads->read();
+}
+
+void ld50_state::port2_w(u8 data)
+{
+ /*
+ bit 0: ?
+ bit 1: ?
+ bit 2: ?
+ bit 3: ROM output enable
+ bit 4: ROM address low byte latch
+ bit 5: ROM address mid byte latch
+ bit 6: ROM address hi byte & input latch
+ bit 7: LCD control latch
+ */
+
+ const u8 set = data & ~m_port[2];
+ m_port[2] = data;
+
+ if (BIT(set, 4))
+ {
+ m_rom_addr = (m_rom_addr & 0x7ff00) | m_port[0];
+ }
+ if (BIT(set, 5))
+ {
+ m_rom_addr = (m_rom_addr & 0x700ff) | (m_port[0] << 8);
+ }
+ if (BIT(set, 6))
+ {
+ m_rom_addr = (m_rom_addr & 0x0ffff) | ((m_port[0] & 0xe0) << 11);
+
+ m_port[1] |= 0xf0;
+ for (int i = 0; i < 5; i++)
+ {
+ if (!BIT(m_port[0], i))
+ m_port[1] &= (m_inputs[i]->read() << 4);
+ }
+ }
+ if (BIT(set, 7))
+ {
+ m_lcdc->rw_w(BIT(m_port[0], 6));
+ m_lcdc->rs_w(BIT(m_port[0], 7));
+ }
+}
+
+void ld50_state::port3_w(u8 data)
+{
+ /*
+ bit 0: LCD enable
+ bit 1: MIDI Tx (TODO)
+ bit 2: ?
+ bit 3: trigger sound effect
+ bit 4: ?
+ bit 5: shift register data
+ bit 6: shift register clock
+ bit 7: ?
+
+ The LD-50 transmits MIDI both through the UART registers and manually via port 3.
+ Demo/rhythm playback uses the UART, while drum pads, effect values, etc. are
+ bit-banged through the port instead (why?)
+ */
+
+ const u8 set = data & ~m_port[3];
+ m_port[3] = data;
+
+ m_lcdc->e_w(BIT(data, 0));
+
+ if (BIT(set, 3))
+ {
+ logerror("play sound effect %u\n", m_shift_data & 0x1f);
+ }
+ if (BIT(set, 6))
+ {
+ m_shift_data <<= 1;
+ m_shift_data |= BIT(data, 5);
+ }
+ if (BIT(set, 7))
+ {
+ logerror("unknown serial cmd (data = 0x%4x)\n", m_shift_data);
+ }
+}
+
+CUSTOM_INPUT_MEMBER(ld50_state::dial_r)
+{
+ // return the dial position as a 2-bit gray code
+ const u8 val = m_dial->read();
+ return (val >> 6) ^ (val >> 7);
+}
+
+
+void ld50_state::driver_start()
+{
+ save_item(NAME(m_port));
+ save_item(NAME(m_rom_addr));
+ save_item(NAME(m_shift_data));
+}
+
+void ld50_state::driver_reset()
+{
+ memset(m_port, 0xff, sizeof m_port);
+
+ m_rom_addr = 0;
+ m_shift_data = 0;
+}
+
+void ld50_state::ld50(machine_config &config)
+{
+ // CPU
+ I87C52(config, m_maincpu, 12_MHz_XTAL);
+ m_maincpu->port_in_cb<0>().set(FUNC(ld50_state::port0_r));
+ m_maincpu->port_out_cb<0>().set(FUNC(ld50_state::port0_w));
+ m_maincpu->port_in_cb<1>().set(FUNC(ld50_state::port1_r));
+ m_maincpu->port_out_cb<2>().set(FUNC(ld50_state::port2_w));
+ m_maincpu->port_out_cb<3>().set(FUNC(ld50_state::port3_w));
+
+ // LCD
+ HD44780(config, m_lcdc, 0);
+ m_lcdc->set_lcd_size(2, 8);
+ m_lcdc->set_pixel_update_cb(FUNC(ld50_state::lcd_update));
+
+ // screen (for testing only)
+ // TODO: the actual LCD with custom segments
+ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD));
+ screen.set_refresh_hz(60);
+ screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
+ screen.set_screen_update("lcdc", FUNC(hd44780_device::screen_update));
+ screen.set_size(6 * 16, 8);
+ screen.set_visarea_full();
+ screen.set_palette("palette");
+
+ PALETTE(config, "palette", FUNC(ld50_state::palette_init), 2);
+}
+
+INPUT_PORTS_START(ld50)
+ PORT_START("PADS")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Drum Pad 4")
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Drum Pad 3")
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Drum Pad 2")
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Drum Pad 1")
+
+ PORT_START("DIAL")
+ PORT_BIT( 0xff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(50) PORT_KEYDELTA(50) PORT_REVERSE
+
+ PORT_START("IN0")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("SE Pad 4")
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("SE Pad 3")
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("SE Pad 2")
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("SE Pad 1")
+
+ PORT_START("IN1")
+ PORT_BIT( 0x03, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(ld50_state, dial_r)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("Effect")
+
+ PORT_START("IN2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_EQUALS) PORT_NAME("Assign")
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS) PORT_NAME("Drum Set")
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_0) PORT_NAME("SE Set")
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_9) PORT_NAME("Rhythm")
+
+ PORT_START("IN3")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_8) PORT_NAME("Play Level")
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_7) PORT_NAME("Light")
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_6) PORT_NAME("Tempo")
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_5) PORT_NAME("Start/Stop")
+
+ PORT_START("IN4")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_4) PORT_NAME("Synchro Start")
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_3) PORT_NAME("Demo")
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_2) PORT_NAME("Rhythm Vol.")
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_1) PORT_NAME("Main Vol.")
+INPUT_PORTS_END
+
+ROM_START(ld50)
+ ROM_REGION(0x2000, "maincpu", 0)
+ ROM_LOAD("87c52.ic4", 0x0000, 0x2000, CRC(126108cc) SHA1(cb8d7359628f8e519862cec73e38078275c3bd48))
+
+ ROM_REGION(0x80000, "datarom", 0)
+ ROM_LOAD("ld50.ic5", 0x00000, 0x80000, CRC(acaee847) SHA1(7235aefd72260b6d9d1f652c643022515a880781))
+ROM_END
+
+} // anonymous namespace
+
+// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
+SYST( 2002, ld50, 0, 0, ld50, ld50, ld50_state, empty_init, "Casio", "LD-50", MACHINE_NO_SOUND | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 850cfb03b60..16fdb9474a8 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -19968,6 +19968,9 @@ lckydrawa // (c) 1979 Mirco
@source:lcmate2.cpp
lcmate2 //
+@source:ld50.cpp
+ld50 //
+
@source:leapfrog_iquest.cpp
iquest
ttwistfb
diff --git a/src/mame/mess.flt b/src/mame/mess.flt
index f46d9c60f10..307b65f9877 100644
--- a/src/mame/mess.flt
+++ b/src/mame/mess.flt
@@ -537,6 +537,7 @@ lb186.cpp
lbpc.cpp
lc80.cpp
lcmate2.cpp
+ld50.cpp
leapfrog_iquest.cpp
leapfrog_leappad.cpp
leapfrog_leapster_explorer.cpp