// license:BSD-3-Clause // copyright-holders:cam900 /********************************************************************** NEC PC Engine/TurboGrafx-16 6 button joypad emulation Based on SMS controller port emulation (devices\bus\sms_ctrl\*.*) by Fabio Priuli, PC engine emulation (mame\*\pce.*) by Charles MacDonald, Wilbert Pol, Angelo Salese There's 2 officially licensed 6 button joypad models: NEC Avenue Pad 6 (NAPD-1002) - Supports autofire for Button I, II, Run (slow motion) NEC Arcade Pad 6 (PCE-TP1) - Supports autofire for Button I-VI, Bundled in PC Engine Duo-RX TODO: - Needs verifications for Part numbers - Verify DTC114Y function for Slow motion in Avenue Pad 6 **********************************************************************/ #include "emu.h" #include "joypad6.h" //************************************************************************** // DEVICE DEFINITIONS //************************************************************************** DEFINE_DEVICE_TYPE(PCE_AVENUE_PAD_6, pce_avenue_pad_6_device, "pce_avenue_pad_6", "NEC Avenue Pad 6") DEFINE_DEVICE_TYPE(PCE_ARCADE_PAD_6, pce_arcade_pad_6_device, "pce_arcade_pad_6", "NEC Arcade Pad 6") static INPUT_PORTS_START( pce_joypad6 ) // Action button order on original pad is bottom row: III, II, I, and top row: IV, V, VI PORT_START("BUTTONS_0") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("%p Button I") PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("%p Button II") PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("%p Select") PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("%p Run") PORT_START("DIRECTION") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_START("BUTTONS_1") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("%p Button III") PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("%p Button IV") PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("%p Button V") PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("%p Button VI") PORT_START("JOY_MODE") PORT_CONFNAME( 0x01, 0x00, "Joypad Mode" ) PORT_CHANGED_MEMBER(DEVICE_SELF, pce_joypad6_base_device, joypad_mode_changed, 0) PORT_CONFSETTING( 0x00, "2-buttons mode" ) // A at avenue pad 6 PORT_CONFSETTING( 0x01, "6-buttons mode" ) // B at avenue pad 6 INPUT_PORTS_END static INPUT_PORTS_START( pce_avenue_pad_6 ) PORT_INCLUDE( pce_joypad6 ) PORT_START("TURBO") PORT_CONFNAME( 0x01, 0x00, "Button I Turbo" ) PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x01, DEF_STR( On ) ) PORT_CONFNAME( 0x02, 0x00, "Button II Turbo" ) PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x02, DEF_STR( On ) ) PORT_CONFNAME( 0x08, 0x00, "Slow motion" ) // TODO: 74xx163 QB pin is connected with DTC114Y for Slow motion (Run button) PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x08, DEF_STR( On ) ) PORT_BIT( 0xf4, IP_ACTIVE_HIGH, IPT_UNUSED ) INPUT_PORTS_END static INPUT_PORTS_START( pce_arcade_pad_6 ) PORT_INCLUDE( pce_joypad6 ) PORT_START("TURBO") PORT_CONFNAME( 0x01, 0x00, "Button I Turbo" ) PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x01, DEF_STR( On ) ) PORT_CONFNAME( 0x02, 0x00, "Button II Turbo" ) PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x02, DEF_STR( On ) ) PORT_BIT( 0x0c, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONFNAME( 0x10, 0x00, "Button III Turbo" ) PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x10, DEF_STR( On ) ) PORT_CONFNAME( 0x20, 0x00, "Button IV Turbo" ) PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x20, DEF_STR( On ) ) PORT_CONFNAME( 0x40, 0x00, "Button V Turbo" ) PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x40, DEF_STR( On ) ) PORT_CONFNAME( 0x80, 0x00, "Button VI Turbo" ) PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x80, DEF_STR( On ) ) INPUT_PORTS_END //------------------------------------------------- // input_ports - device-specific input ports //------------------------------------------------- ioport_constructor pce_avenue_pad_6_device::device_input_ports() const { return INPUT_PORTS_NAME( pce_avenue_pad_6 ); } ioport_constructor pce_arcade_pad_6_device::device_input_ports() const { return INPUT_PORTS_NAME( pce_arcade_pad_6 ); } //************************************************************************** // LIVE DEVICE //************************************************************************** //------------------------------------------------- // pce_joypad6_base_device - constructor //------------------------------------------------- pce_joypad6_base_device::pce_joypad6_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, const XTAL &clock) : device_t(mconfig, type, tag, owner, clock), device_pce_control_port_interface(mconfig, *this), m_muxer(*this, "mux_%u", 0U), m_joypad_mode(*this, "JOY_MODE"), m_counter(0), m_prev_clr(false) { } //------------------------------------------------- // pce_avenue_pad_6_device - constructor //------------------------------------------------- pce_avenue_pad_6_device::pce_avenue_pad_6_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, const XTAL &clock) : pce_joypad6_base_device(mconfig, type, tag, owner, clock), m_buttons_io(*this, "BUTTONS_%u", 0U), m_turbo_io(*this, "TURBO") { } pce_avenue_pad_6_device::pce_avenue_pad_6_device(const machine_config &mconfig, const char *tag, device_t *owner, const XTAL &clock) : pce_avenue_pad_6_device(mconfig, PCE_AVENUE_PAD_6, tag, owner, clock) { } //------------------------------------------------- // pce_arcade_pad_6_device - constructor //------------------------------------------------- pce_arcade_pad_6_device::pce_arcade_pad_6_device(const machine_config &mconfig, const char *tag, device_t *owner, const XTAL &clock) : pce_avenue_pad_6_device(mconfig, PCE_ARCADE_PAD_6, tag, owner, clock) { } //------------------------------------------------- // device_add_mconfig - device-specific machine // configuration addiitons //------------------------------------------------- void pce_joypad6_base_device::device_add_mconfig(machine_config &config) { LS157(config, m_muxer[0]); m_muxer[0]->a_in_callback().set_ioport("BUTTONS_0"); m_muxer[0]->b_in_callback().set_ioport("DIRECTION"); LS157(config, m_muxer[1]); m_muxer[1]->a_in_callback().set_ioport("BUTTONS_1"); m_muxer[1]->b_in_callback().set_constant(0x0); // 6-button pad header LS157(config, m_muxer[2]); m_muxer[2]->a_in_callback().set(m_muxer[0], FUNC(ls157_device::output_r)); m_muxer[2]->b_in_callback().set(m_muxer[1], FUNC(ls157_device::output_r)); } void pce_avenue_pad_6_device::device_add_mconfig(machine_config &config) { pce_joypad6_base_device::device_add_mconfig(config); m_muxer[0]->a_in_callback().set(FUNC(pce_avenue_pad_6_device::buttons_r<0>)); m_muxer[1]->a_in_callback().set(FUNC(pce_avenue_pad_6_device::buttons_r<1>)); } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void pce_joypad6_base_device::device_start() { save_item(NAME(m_counter)); save_item(NAME(m_prev_clr)); } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- void pce_joypad6_base_device::device_reset() { m_counter = 0; m_prev_clr = false; } //------------------------------------------------- // peripheral_r - joypad read //------------------------------------------------- u8 pce_joypad6_base_device::peripheral_r() { return m_muxer[2]->output_r(); } //------------------------------------------------- // sel_w - MUXer select pin write //------------------------------------------------- void pce_joypad6_base_device::sel_w(int state) { m_muxer[0]->select_w(state); m_muxer[1]->select_w(state); } //------------------------------------------------- // clr_w - MUXer strobe pin write, toggle button // set and autofire control //------------------------------------------------- void pce_joypad6_base_device::clr_w(int state) { m_muxer[0]->strobe_w(state); m_muxer[1]->strobe_w(state); if ((!m_prev_clr) && state) // rising edge, connected to 74xx163 clock pin m_counter = (m_counter + 1) & 0x3; // Toggle buttons/autofire, connected to 74xx163; QC, QD pin not used m_prev_clr = state; buttonset_update(); } //------------------------------------------------- // buttonset_update - toggle buttonsets //------------------------------------------------- void pce_joypad6_base_device::buttonset_update() { m_muxer[2]->select_w((m_joypad_mode->read() & 1) ? BIT(m_counter, 0) : 0); } //------------------------------------------------- // joypad_mode_changed //------------------------------------------------- INPUT_CHANGED_MEMBER(pce_joypad6_base_device::joypad_mode_changed) { buttonset_update(); } //------------------------------------------------- // buttons_r - read button with autofire counter //------------------------------------------------- template u8 pce_avenue_pad_6_device::buttons_r() { u8 ret = m_buttons_io[Buttonset]->read() & 0xf; const u8 turbo = BIT(m_turbo_io->read(), Buttonset << 2, 4); for (int i = 0; i < 4; i++) { if (BIT(turbo, i)) // enable autofire { if (BIT(m_counter, 1)) // QB pin from 74xx163 ret |= (1 << i); } } return ret; }