summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/drivers/tb303.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/drivers/tb303.c')
-rw-r--r--src/mess/drivers/tb303.c202
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