diff options
Diffstat (limited to 'src/mame/drivers/roland_tb303.cpp')
-rw-r--r-- | src/mame/drivers/roland_tb303.cpp | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/src/mame/drivers/roland_tb303.cpp b/src/mame/drivers/roland_tb303.cpp new file mode 100644 index 00000000000..7596b78a4ce --- /dev/null +++ b/src/mame/drivers/roland_tb303.cpp @@ -0,0 +1,332 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/*************************************************************************** + + Roland TB-303 Bass Line, 1982, designed by Tadao Kikumoto + * NEC uCOM-43 MCU, labeled D650C 133 + * 3*uPD444C 1024x4 Static CMOS SRAM + * board is packed with discrete components + + TODO: + - still too much to list here + +***************************************************************************/ + +#include "emu.h" +#include "cpu/ucom4/ucom4.h" +#include "video/pwm.h" +#include "machine/timer.h" + +#include "tb303.lh" + + +class tb303_state : public driver_device +{ +public: + tb303_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_display(*this, "display"), + m_inputs(*this, "IN.%u", 0) + { } + + void tb303(machine_config &config); + +protected: + virtual void machine_start() override; + +private: + required_device<ucom4_cpu_device> m_maincpu; + required_device<pwm_display_device> m_display; + required_ioport_array<5> m_inputs; + + u8 m_ram[0xc00]; + u8 m_ram_addrset[3]; + u16 m_ram_address; + u8 m_ram_data; + bool m_ram_ce; + bool m_ram_we; + u8 m_led_data; + u8 m_inp_mux; + + void refresh_ram(); + template<int N> DECLARE_WRITE8_MEMBER(ram_address_w); + DECLARE_WRITE8_MEMBER(ram_data_w); + DECLARE_READ8_MEMBER(ram_data_r); + DECLARE_WRITE8_MEMBER(strobe_w); + + void update_leds(); + DECLARE_WRITE8_MEMBER(led_w); + DECLARE_WRITE8_MEMBER(input_w); + DECLARE_READ8_MEMBER(input_r); + + TIMER_DEVICE_CALLBACK_MEMBER(tp3_clock) { m_maincpu->set_input_line(0, ASSERT_LINE); } + TIMER_DEVICE_CALLBACK_MEMBER(tp3_clear) { m_maincpu->set_input_line(0, CLEAR_LINE); } +}; + +void tb303_state::machine_start() +{ + // zerofill + memset(m_ram, 0, sizeof(m_ram)); + memset(m_ram_addrset, 0, sizeof(m_ram_addrset)); + m_ram_address = 0; + m_ram_data = 0; + m_ram_ce = false; + m_ram_we = false; + m_led_data = 0; + m_inp_mux = 0; + + // register for savestates + save_item(NAME(m_ram)); + save_item(NAME(m_ram_addrset)); + save_item(NAME(m_ram_address)); + save_item(NAME(m_ram_data)); + save_item(NAME(m_ram_ce)); + save_item(NAME(m_ram_we)); + save_item(NAME(m_led_data)); + save_item(NAME(m_inp_mux)); +} + +// TP2 to MCU CLK: LC circuit(TI S74230), stable sine wave, 2.2us interval +#define TP2_HZ 454545 + +// TP3 to MCU _INT: square wave, 1.8ms interval, short duty cycle +#define TP3_PERIOD attotime::from_usec(1800) +#define TP3_LOW (TP3_PERIOD / 8) + + +/*************************************************************************** + + I/O + +***************************************************************************/ + +// external ram + +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; + u8 hi = 0; + switch (m_ram_addrset[2] >> 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_ram_addrset[2] << 8 & 0x300) | m_ram_addrset[1] << 4 | m_ram_addrset[0]; + else + m_ram[m_ram_address] = m_ram_data; + } +} + +template<int N> +WRITE8_MEMBER(tb303_state::ram_address_w) +{ + // MCU D,F,E: RAM address + m_ram_addrset[N] = data; + refresh_ram(); + + // MCU D,F01: pitch data + //.. +} + +WRITE8_MEMBER(tb303_state::ram_data_w) +{ + // MCU C: RAM data + m_ram_data = data; + refresh_ram(); +} + +READ8_MEMBER(tb303_state::ram_data_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::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 +} + + +// switch board + +void tb303_state::update_leds() +{ + // 4*4 LED matrix from port G/H: + /* + 0.0 D204 1.0 D211 2.0 D217 3.0 D205 + 0.1 D206 1.1 D213 2.1 D218 3.1 D207 + 0.2 D208 1.2 D215 2.2 D220 3.2 D210 + 0.3 D209 1.3 D216 2.3 D221 3.3 D212 + */ + m_display->matrix(m_inp_mux, m_led_data); + + // todo: battery led + // todo: 4 more leds(see top-left part) +} + +WRITE8_MEMBER(tb303_state::led_w) +{ + // MCU G: leds state + m_led_data = data; + update_leds(); +} + +WRITE8_MEMBER(tb303_state::input_w) +{ + // MCU H: input/led mux + m_inp_mux = data ^ 0xf; + update_leds(); +} + +READ8_MEMBER(tb303_state::input_r) +{ + u8 data = 0; + + // MCU A,B: multiplexed inputs + // if input mux(port H) is 0, port A status buffer & gate is selected (via Q5 NAND) + if (offset == 0 && m_inp_mux == 0) + { + // todo.. + data = m_inputs[4]->read(); + } + else + { + for (int i = 0; i < 4; i++) + if (BIT(m_inp_mux, i)) + data |= m_inputs[i]->read(); + + data >>= (offset*4) & 0xf; + } + + return data; +} + + + +/*************************************************************************** + + 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 + + + +/*************************************************************************** + + Machine Config + +***************************************************************************/ + +void tb303_state::tb303(machine_config &config) +{ + /* basic machine hardware */ + NEC_D650(config, m_maincpu, TP2_HZ); + m_maincpu->read_a().set(FUNC(tb303_state::input_r)); + m_maincpu->read_b().set(FUNC(tb303_state::input_r)); + m_maincpu->read_c().set(FUNC(tb303_state::ram_data_r)); + m_maincpu->write_c().set(FUNC(tb303_state::ram_data_w)); + m_maincpu->write_d().set(FUNC(tb303_state::ram_address_w<0>)); + m_maincpu->write_e().set(FUNC(tb303_state::ram_address_w<2>)); + m_maincpu->write_f().set(FUNC(tb303_state::ram_address_w<1>)); + m_maincpu->write_g().set(FUNC(tb303_state::led_w)); + m_maincpu->write_h().set(FUNC(tb303_state::input_w)); + m_maincpu->write_i().set(FUNC(tb303_state::strobe_w)); + + timer_device &tp3_clock(TIMER(config, "tp3_clock")); + tp3_clock.configure_periodic(FUNC(tb303_state::tp3_clock), TP3_PERIOD); + tp3_clock.set_start_delay(TP3_PERIOD - TP3_LOW); + TIMER(config, "tp3_clear").configure_periodic(FUNC(tb303_state::tp3_clear), TP3_PERIOD); + + /* video hardware */ + PWM_DISPLAY(config, m_display).set_size(4, 4); + config.set_default_layout(layout_tb303); + + /* sound hardware */ + // discrete... +} + + + +/*************************************************************************** + + Game driver(s) + +***************************************************************************/ + +ROM_START( tb303 ) + ROM_REGION( 0x0800, "maincpu", 0 ) + ROM_LOAD( "d650c-133.ic8", 0x0000, 0x0800, CRC(268a8d8b) SHA1(7a4236b2bc9a5cd4c80c63ca1a193e03becfcb4c) ) +ROM_END + + +CONS( 1982, tb303, 0, 0, tb303, tb303, tb303_state, empty_init, "Roland", "TB-303 Bass Line", MACHINE_NOT_WORKING | MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE ) |