diff options
Diffstat (limited to 'src/mess/drivers/tb303.c')
-rw-r--r-- | src/mess/drivers/tb303.c | 202 |
1 files changed, 194 insertions, 8 deletions
diff --git a/src/mess/drivers/tb303.c b/src/mess/drivers/tb303.c index 1631ce2b0a6..6f8536a636b 100644 --- a/src/mess/drivers/tb303.c +++ b/src/mess/drivers/tb303.c @@ -2,6 +2,8 @@ // copyright-holders:hap /*************************************************************************** + ** subclass of hh_ucom4_state (includes/hh_ucom4.h, drivers/hh_ucom4.c) ** + Roland TB-303 Bass Line, 1982, designed by Tadao Kikumoto * NEC uCOM-43 MCU, labeled D650C 133 * 3*uPD444C 1024x4 Static CMOS SRAM @@ -11,23 +13,34 @@ ***************************************************************************/ -#include "emu.h" -#include "cpu/ucom4/ucom4.h" +#include "includes/hh_ucom4.h" #include "tb303.lh" -class tb303_state : public driver_device +class tb303_state : public hh_ucom4_state { public: tb303_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag), - m_maincpu(*this, "maincpu"), + : hh_ucom4_state(mconfig, type, tag), m_t3_off_timer(*this, "t3_off") { } - required_device<cpu_device> m_maincpu; required_device<timer_device> m_t3_off_timer; + + UINT8 m_ram[0xc00]; + UINT16 m_ram_address; + bool m_ram_ce; + bool m_ram_we; + + DECLARE_WRITE8_MEMBER(ram_w); + DECLARE_READ8_MEMBER(ram_r); + void refresh_ram(); + + DECLARE_WRITE8_MEMBER(led_w); + DECLARE_WRITE8_MEMBER(switch_w); + DECLARE_WRITE8_MEMBER(strobe_w); + DECLARE_READ8_MEMBER(input_r); TIMER_DEVICE_CALLBACK_MEMBER(t3_clock); TIMER_DEVICE_CALLBACK_MEMBER(t3_off); @@ -36,6 +49,12 @@ public: }; +/*************************************************************************** + + Timer/Interrupt + +***************************************************************************/ + // T2 to MCU CLK: LC circuit, stable sine wave, 2.2us interval #define TB303_T2_CLOCK_HZ 454545 /* in hz */ @@ -56,8 +75,152 @@ TIMER_DEVICE_CALLBACK_MEMBER(tb303_state::t3_clock) +/*************************************************************************** + + I/O + +***************************************************************************/ + +void tb303_state::refresh_ram() +{ + // MCU E2,E3 goes through a 4556 IC(pin 14,13) to one of uPD444 _CE: + // _Q0: N/C, _Q1: IC-5, _Q2: IC-3, _Q3: IC-4 + m_ram_ce = true; + UINT8 hi = 0; + switch (m_port[NEC_UCOM4_PORTE] >> 2 & 3) + { + case 0: m_ram_ce = false; break; + case 1: hi = 0; break; + case 2: hi = 1; break; + case 3: hi = 2; break; + } + + if (m_ram_ce) + { + // _WE must be high(read mode) for address transitions + if (!m_ram_we) + m_ram_address = hi << 10 | (m_port[NEC_UCOM4_PORTE] << 8 & 0x300) | m_port[NEC_UCOM4_PORTF] << 4 | m_port[NEC_UCOM4_PORTD]; + else + m_ram[m_ram_address] = m_port[NEC_UCOM4_PORTC]; + } + + // to switchboard pin 19-22 + //.. +} + +WRITE8_MEMBER(tb303_state::ram_w) +{ + // MCU C: RAM data + // MCU D,F,E: RAM address + m_port[offset] = data; + refresh_ram(); + + // MCU D,F01: pitch data + //.. +} + +READ8_MEMBER(tb303_state::ram_r) +{ + // MCU C: RAM data + if (m_ram_ce && !m_ram_we) + return m_ram[m_ram_address]; + else + return 0; +} + +WRITE8_MEMBER(tb303_state::led_w) +{ + // MCU G: leds state + display_matrix(4, 4, data, m_inp_mux); +} + +WRITE8_MEMBER(tb303_state::switch_w) +{ + // MCU H: input/led mux + m_inp_mux = data; +} + +WRITE8_MEMBER(tb303_state::strobe_w) +{ + // MCU I0: RAM _WE + m_ram_we = (data & 1) ? false : true; + refresh_ram(); + + // MCU I1: pitch data latch strobe + // MCU I2: gate signal +} + +READ8_MEMBER(tb303_state::input_r) +{ + // MCU A,B: multiplexed inputs + // if input mux(port H) is 0, port A status buffer & gate is selected (via Q5 NAND) + if (offset == NEC_UCOM4_PORTA && m_inp_mux == 0) + { + // todo.. + return m_inp_matrix[4]->read(); + } + else + return read_inputs(4) >> (offset*4) & 0xf; +} + + + +/*************************************************************************** + + Inputs + +***************************************************************************/ static INPUT_PORTS_START( tb303 ) + PORT_START("IN.0") // H0 port A/B + PORT_CONFNAME( 0x03, 0x03, "Mode" ) + PORT_CONFSETTING( 0x03, "Track Write" ) + PORT_CONFSETTING( 0x02, "Track Play" ) + PORT_CONFSETTING( 0x00, "Pattern Play" ) + PORT_CONFSETTING( 0x01, "Pattern Write" ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_Q) PORT_NAME("DEL C#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_W) PORT_NAME("INS D#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1) PORT_NAME("1 C") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2) PORT_NAME("2 D") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3) PORT_NAME("3 E") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4) PORT_NAME("4 F") + + PORT_START("IN.1") // H1 port A/B + PORT_CONFNAME( 0x07, 0x00, "Track / Patt.Group" ) + PORT_CONFSETTING( 0x00, "1 / I" ) + PORT_CONFSETTING( 0x01, "2 / I" ) + PORT_CONFSETTING( 0x02, "3 / II" ) + PORT_CONFSETTING( 0x03, "4 / II" ) + PORT_CONFSETTING( 0x04, "5 / III" ) + PORT_CONFSETTING( 0x05, "6 / III" ) + PORT_CONFSETTING( 0x06, "7 / IV" ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5) PORT_NAME("5 G") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6) PORT_NAME("6 A") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7) PORT_NAME("7 B") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8) PORT_NAME("8 C") + + PORT_START("IN.2") // H2 port A/B + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_D) PORT_NAME("Pattern Clear") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_F) PORT_NAME("Function") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_A) PORT_NAME("Pitch Mode") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_S) PORT_NAME("Time Mode") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9) PORT_NAME("9 Step") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0) PORT_NAME("0 3n") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS) PORT_NAME("100 A") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_EQUALS) PORT_NAME("200 B") + + PORT_START("IN.3") // H3 port B + PORT_BIT( 0x0f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_R) PORT_NAME("F#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_T) PORT_NAME("G#") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_Y) PORT_NAME("A#") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("Back") + + PORT_START("IN.4") // H=0 port A + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_ENTER) PORT_NAME("Run/Stop") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_SPACE) PORT_NAME("Tap") + PORT_BIT( 0xfc, IP_ACTIVE_HIGH, IPT_UNUSED ) INPUT_PORTS_END @@ -70,18 +233,41 @@ INPUT_PORTS_END void tb303_state::machine_start() { + hh_ucom4_state::machine_start(); + + // zerofill + memset(m_ram, 0, sizeof(m_ram)); + m_ram_address = 0; + m_ram_ce = false; + m_ram_we = false; + + // register for savestates + save_item(NAME(m_ram)); + save_item(NAME(m_ram_address)); + save_item(NAME(m_ram_ce)); + save_item(NAME(m_ram_we)); } - static MACHINE_CONFIG_START( tb303, tb303_state ) /* basic machine hardware */ MCFG_CPU_ADD("maincpu", NEC_D650, TB303_T2_CLOCK_HZ) + MCFG_UCOM4_READ_A_CB(READ8(tb303_state, input_r)) + MCFG_UCOM4_READ_B_CB(READ8(tb303_state, input_r)) + MCFG_UCOM4_READ_C_CB(READ8(tb303_state, ram_r)) + MCFG_UCOM4_WRITE_C_CB(WRITE8(tb303_state, ram_w)) + MCFG_UCOM4_WRITE_D_CB(WRITE8(tb303_state, ram_w)) + MCFG_UCOM4_WRITE_E_CB(WRITE8(tb303_state, ram_w)) + MCFG_UCOM4_WRITE_F_CB(WRITE8(tb303_state, ram_w)) + MCFG_UCOM4_WRITE_G_CB(WRITE8(tb303_state, led_w)) + MCFG_UCOM4_WRITE_H_CB(WRITE8(tb303_state, switch_w)) + MCFG_UCOM4_WRITE_I_CB(WRITE8(tb303_state, strobe_w)) MCFG_TIMER_DRIVER_ADD_PERIODIC("t3_clock", tb303_state, t3_clock, TB303_T3_CLOCK) MCFG_TIMER_START_DELAY(TB303_T3_CLOCK) MCFG_TIMER_DRIVER_ADD("t3_off", tb303_state, t3_off) + MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", hh_ucom4_state, display_decay_tick, attotime::from_msec(1)) MCFG_DEFAULT_LAYOUT(layout_tb303) /* no video! */ @@ -100,7 +286,7 @@ MACHINE_CONFIG_END ROM_START( tb303 ) ROM_REGION( 0x0800, "maincpu", 0 ) - ROM_LOAD( "d650c-133.ic8", 0x0000, 0x0800, CRC(dd2f26ae) SHA1(7f5e37f38d970219dc9e5d49a20dc5335a5c0b30) ) + ROM_LOAD( "d650c-133.ic8", 0x0000, 0x0800, CRC(0805b37a) SHA1(9a0c1891b56446535cef66a11b8366e1b22cc23f) ) ROM_END |