diff options
Diffstat (limited to 'src/mame/drivers/spg2xx_playvision.cpp')
-rw-r--r-- | src/mame/drivers/spg2xx_playvision.cpp | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/src/mame/drivers/spg2xx_playvision.cpp b/src/mame/drivers/spg2xx_playvision.cpp new file mode 100644 index 00000000000..037bf736ec5 --- /dev/null +++ b/src/mame/drivers/spg2xx_playvision.cpp @@ -0,0 +1,230 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz, David Haywood + +#include "includes/spg2xx.h" +#include "pvmil.lh" + + +class pvmil_state : public spg2xx_game_state +{ +public: + pvmil_state(const machine_config &mconfig, device_type type, const char *tag) : + spg2xx_game_state(mconfig, type, tag), + m_portcdata(0x0000), + m_latchcount(0), + m_latchbit(0), + m_outdat(0), + m_p4inputs(*this, "EXTRA"), + m_leds(*this, "led%u", 0U) + { } + + void pvmil(machine_config &config); + + DECLARE_READ_LINE_MEMBER(pvmil_p4buttons_r); + +protected: + virtual void machine_start() override; + + virtual DECLARE_WRITE16_MEMBER(porta_w) override; + virtual DECLARE_WRITE16_MEMBER(portb_w) override; + virtual DECLARE_WRITE16_MEMBER(portc_w) override; + +private: + uint16_t m_portcdata; + int m_latchcount; + int m_latchbit; + uint16_t m_outdat; + optional_ioport m_p4inputs; + output_finder<4> m_leds; +}; + + +void pvmil_state::machine_start() +{ + spg2xx_game_state::machine_start(); + + m_leds.resolve(); + save_item(NAME(m_portcdata)); + save_item(NAME(m_latchcount)); + save_item(NAME(m_latchbit)); + save_item(NAME(m_outdat)); +} + + +WRITE16_MEMBER(pvmil_state::porta_w) +{ + logerror("%s: pvmil_porta_w %04x\n", machine().describe_context(), data); +} + +WRITE16_MEMBER(pvmil_state::portb_w) +{ + logerror("%s: pvmil_portb_w %04x\n", machine().describe_context(), data); +} + + +READ_LINE_MEMBER(pvmil_state::pvmil_p4buttons_r) +{ + return m_latchbit; +} + + +WRITE16_MEMBER(pvmil_state::portc_w) +{ + // ---- -432 1--- r-?c + // 4,3,2,1 = player controller LEDs + // r = reset input multiplexer + // ? = unknown + // m = input multiplexer clock + + // p4 input reading + // the code to read them is interesting tho, it even includes loops that poll port a 16 times before/after, why? + logerror("%s: pvmil_portc_w %04x\n", machine().describe_context(), data); + + uint16_t bit; + + // for logging bits changed on the port + if (0) + { + for (int i = 0; i < 16; i++) + { + bit = 1 << i; + if ((m_portcdata & bit) != (data & bit)) + { + if (data & bit) + { + logerror("port c %04x low to high\n", bit); + } + else + { + logerror("port c %04x high to low\n", bit); + } + } + + if ((m_portcdata & 0x0400) != (data & 0x0400)) + { + logerror("-------------------------------------------------\n"); + } + } + } + + // happens on startup, before it starts reading inputs for the first time, assume 'reset counter' + bit = 0x0008; + if ((m_portcdata & bit) != (data & bit)) + { + if (data & bit) + { + logerror("reset read counter\n"); + m_latchcount = 0; + } + } + + bit = 0x0001; + if ((m_portcdata & bit) != (data & bit)) + { + if (!(data & bit)) + { + //logerror("latch with count of %d (outbit is %d)\n", m_latchcount, (m_portcdata & 0x0002)>>1 ); + // what is bit 0x0002? it gets flipped in the same code as the inputs are read. + // it doesn't follow any obvious pattern + m_outdat &= ~(1 << m_latchcount); + m_outdat |= ((data & 0x0002) >> 1) << m_latchcount; + if (0) + popmessage("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", + (m_outdat & 0x8000) ? 1 : 0, (m_outdat & 0x4000) ? 1 : 0, (m_outdat & 0x2000) ? 1 : 0, (m_outdat & 0x1000) ? 1 : 0, + (m_outdat & 0x0800) ? 1 : 0, (m_outdat & 0x0400) ? 1 : 0, (m_outdat & 0x0200) ? 1 : 0, (m_outdat & 0x0100) ? 1 : 0, + (m_outdat & 0x0080) ? 1 : 0, (m_outdat & 0x0040) ? 1 : 0, (m_outdat & 0x0020) ? 1 : 0, (m_outdat & 0x0010) ? 1 : 0, + (m_outdat & 0x0008) ? 1 : 0, (m_outdat & 0x0004) ? 1 : 0, (m_outdat & 0x0002) ? 1 : 0, (m_outdat & 0x0001) ? 1 : 0); + + + m_latchbit = (((m_p4inputs->read()) << m_latchcount) & 0x8000) ? 1 : 0; + + m_latchcount++; + if (m_latchcount == 16) + m_latchcount = 0; + } + } + + m_portcdata = data; + + if (0) + popmessage("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", + (m_portcdata & 0x8000) ? 1 : 0, (m_portcdata & 0x4000) ? 1 : 0, (m_portcdata & 0x2000) ? 1 : 0, (m_portcdata & 0x1000) ? 1 : 0, + (m_portcdata & 0x0800) ? 1 : 0, (m_portcdata & 0x0400) ? 1 : 0, (m_portcdata & 0x0200) ? 1 : 0, (m_portcdata & 0x0100) ? 1 : 0, + (m_portcdata & 0x0080) ? 1 : 0, (m_portcdata & 0x0040) ? 1 : 0, (m_portcdata & 0x0020) ? 1 : 0, (m_portcdata & 0x0010) ? 1 : 0, + (m_portcdata & 0x0008) ? 1 : 0, (m_portcdata & 0x0004) ? 1 : 0, (m_portcdata & 0x0002) ? 1 : 0, (m_portcdata & 0x0001) ? 1 : 0); + + m_leds[0] = (m_portcdata & 0x0080) ? 0 : 1; + m_leds[1] = (m_portcdata & 0x0100) ? 0 : 1; + m_leds[2] = (m_portcdata & 0x0200) ? 0 : 1; + m_leds[3] = (m_portcdata & 0x0400) ? 0 : 1; +} + + +static INPUT_PORTS_START( pvmil ) // hold "console start" + "console select" on boot for test mode + PORT_START("P1") + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("Player 1 A") + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("Player 1 B") + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("Player 1 C") + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_NAME("Player 1 D") + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_NAME("Player 2 A") + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_NAME("Player 2 B") + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_NAME("Player 2 C") + PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(2) PORT_NAME("Player 2 D") + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(3) PORT_NAME("Player 3 A") + PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(3) PORT_NAME("Player 3 B") + PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(3) PORT_NAME("Player 3 C") + PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(3) PORT_NAME("Player 3 D") + PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_PLAYER(1) PORT_NAME("Player 1 Lifeline") + PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_START ) PORT_CODE(KEYCODE_1) PORT_NAME("Console Start") + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_CODE(KEYCODE_5) PORT_NAME("Console Select") + + PORT_START("P2") + PORT_BIT( 0xffff, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("P3") + PORT_BIT( 0x0003, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(pvmil_state, pvmil_p4buttons_r) // Player 4 buttons read through here + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_PLAYER(2) PORT_NAME("Player 2 Lifeline") + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_PLAYER(3) PORT_NAME("Player 3 Lifeline") + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_PLAYER(4) PORT_NAME("Player 4 Lifeline") + PORT_BIT( 0xff80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("EXTRA") + PORT_BIT( 0x0fff, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(4) PORT_NAME("Player 4 A") + PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(4) PORT_NAME("Player 4 B") + PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(4) PORT_NAME("Player 4 C") + PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(4) PORT_NAME("Player 4 D") +INPUT_PORTS_END + + +void pvmil_state::pvmil(machine_config &config) +{ + SPG24X(config, m_maincpu, XTAL(27'000'000), m_screen); + m_maincpu->set_addrmap(AS_PROGRAM, &pvmil_state::mem_map_4m); + m_maincpu->set_pal(true); + + spg2xx_base(config); + + m_screen->set_refresh_hz(50); + //m_screen->set_size(320, 312); + + m_maincpu->porta_in().set_ioport("P1"); + m_maincpu->portb_in().set_ioport("P2"); + m_maincpu->portc_in().set_ioport("P3"); + m_maincpu->porta_out().set(FUNC(pvmil_state::porta_w)); + m_maincpu->portb_out().set(FUNC(pvmil_state::portb_w)); + m_maincpu->portc_out().set(FUNC(pvmil_state::portc_w)); + + config.set_default_layout(layout_pvmil); +} + +ROM_START( pvmil ) + ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASE00 ) // Fujistu 29Z0002TN, read as ST M29W320FB + ROM_LOAD16_WORD_SWAP( "millionare4.bin", 0x000000, 0x400000, CRC(9c43d0f2) SHA1(fb4ba0115000b10b7c0e0d44b9fa3234c900e694) ) +ROM_END + +// there are other regions of this, including a Finnish version "Haluatko miljonääriksi?" (see https://millionaire.fandom.com/wiki/Haluatko_miljon%C3%A4%C3%A4riksi%3F_(Play_Vision_game) ) +CONS( 2006, pvmil, 0, 0, pvmil, pvmil, pvmil_state, empty_init, "Play Vision", "Who Wants to Be a Millionaire? (Play Vision, Plug and Play, UK)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) |