summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/vsmjtria.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/drivers/vsmjtria.cpp')
-rw-r--r--src/mame/drivers/vsmjtria.cpp572
1 files changed, 572 insertions, 0 deletions
diff --git a/src/mame/drivers/vsmjtria.cpp b/src/mame/drivers/vsmjtria.cpp
new file mode 100644
index 00000000000..6835680731b
--- /dev/null
+++ b/src/mame/drivers/vsmjtria.cpp
@@ -0,0 +1,572 @@
+// license:BSD-3-Clause
+// copyright-holders:
+
+/*
+VS Mahjong Triangle (c) 1986? Dyna
+
+Unmarked board with everything doubled up, to provide a versus experience with a single board
+2 players can play separately or one against the other
+
+CPU: 2x Z80
+RAM: 6x M5M5117P
+Sound: 2x AY-3-8910
+I/O: 2x 8255, 4x 8-dip banks, 1x single dip
+OSC: 20MHz
+
+TODO:
+- coins don't work (set to free play to test for now)
+- VS. feature communications aren't implemented
+- the hardware is based on the one in rmhaihai.cpp. Derive, merge or neither?
+*/
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "machine/gen_latch.h"
+#include "machine/i8255.h"
+#include "machine/nvram.h"
+#include "sound/ay8910.h"
+#include "emupal.h"
+#include "screen.h"
+#include "speaker.h"
+#include "tilemap.h"
+
+#include "layout/generic.h"
+
+
+namespace {
+
+class vsmjtria_state : public driver_device
+{
+public:
+ vsmjtria_state(const machine_config &mconfig, device_type type, const char *tag) :
+ driver_device(mconfig, type, tag),
+ m_maincpu(*this, "maincpu"),
+ m_gfxdecode(*this, "gfxdecode%u", 0U),
+ m_colorram(*this, "colorram%u", 0U),
+ m_videoram(*this, "videoram%u", 0U),
+ m_p1_key(*this, "P1_KEY%u", 0U),
+ m_p2_key(*this, "P2_KEY%u", 0U)
+ { }
+
+ void vsmjtria(machine_config &config);
+
+ void init_vsmjtria();
+
+protected:
+ virtual void machine_start() override;
+ virtual void video_start() override;
+
+private:
+ required_device<cpu_device> m_maincpu;
+ required_device_array<gfxdecode_device, 2> m_gfxdecode;
+ required_shared_ptr_array<uint8_t, 2> m_colorram;
+ required_shared_ptr_array<uint8_t, 2> m_videoram;
+ required_ioport_array<5> m_p1_key;
+ required_ioport_array<5> m_p2_key;
+
+ tilemap_t *m_bg_tilemap[2];
+ uint8_t m_keyboard_cmd[2];
+
+ template <uint8_t Which> void ctrl_w(uint8_t data);
+ uint8_t p1_keyboard_r();
+ uint8_t p2_keyboard_r();
+ template <uint8_t Which> void keyboard_w(uint8_t data);
+
+ template <uint8_t Which> TILE_GET_INFO_MEMBER(get_bg_tile_info);
+ template <uint8_t Which> void videoram_w(offs_t offset, uint8_t data);
+ template <uint8_t Which> void colorram_w(offs_t offset, uint8_t data);
+ template <uint8_t Which> uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+ void main_prg_map(address_map &map);
+ void main_io_map(address_map &map);
+ void sub_prg_map(address_map &map);
+ void sub_io_map(address_map &map);
+};
+
+
+void vsmjtria_state::machine_start()
+{
+ m_keyboard_cmd[0] = m_keyboard_cmd[1] = 0;
+
+ save_item(NAME(m_keyboard_cmd));
+}
+
+template <uint8_t Which>
+void vsmjtria_state::ctrl_w(uint8_t data)
+{
+ flip_screen_set(data & 0x01);
+
+ // (data & 0x02) is switched on and off in service mode
+
+ machine().bookkeeping().coin_lockout_w(0, ~data & 0x04);
+ machine().bookkeeping().coin_counter_w(0, data & 0x08);
+}
+
+uint8_t vsmjtria_state::p1_keyboard_r()
+{
+ uint8_t data = 0x00;
+
+ if (BIT(m_keyboard_cmd[0], 0)) data |= m_p1_key[0]->read();
+ if (BIT(m_keyboard_cmd[0], 1)) data |= m_p1_key[1]->read();
+ if (BIT(m_keyboard_cmd[0], 2)) data |= m_p1_key[2]->read();
+ if (BIT(m_keyboard_cmd[0], 3)) data |= m_p1_key[3]->read();
+ if (BIT(m_keyboard_cmd[0], 4)) data |= m_p1_key[4]->read();
+
+ return data;
+}
+
+uint8_t vsmjtria_state::p2_keyboard_r()
+{
+ uint8_t data = 0x00;
+
+ if (BIT(m_keyboard_cmd[1], 0)) data |= m_p2_key[0]->read();
+ if (BIT(m_keyboard_cmd[1], 1)) data |= m_p2_key[1]->read();
+ if (BIT(m_keyboard_cmd[1], 2)) data |= m_p2_key[2]->read();
+ if (BIT(m_keyboard_cmd[1], 3)) data |= m_p2_key[3]->read();
+ if (BIT(m_keyboard_cmd[1], 4)) data |= m_p2_key[4]->read();
+
+ return data;
+}
+
+template <uint8_t Which>
+void vsmjtria_state::keyboard_w(uint8_t data)
+{
+ m_keyboard_cmd[Which] = data;
+}
+
+
+void vsmjtria_state::video_start()
+{
+ m_bg_tilemap[0] = &machine().tilemap().create(*m_gfxdecode[0], tilemap_get_info_delegate(*this, FUNC(vsmjtria_state::get_bg_tile_info<0>)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
+ m_bg_tilemap[1] = &machine().tilemap().create(*m_gfxdecode[1], tilemap_get_info_delegate(*this, FUNC(vsmjtria_state::get_bg_tile_info<1>)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
+}
+
+template <uint8_t Which>
+void vsmjtria_state::videoram_w(offs_t offset, uint8_t data)
+{
+ m_videoram[Which][offset] = data;
+ m_bg_tilemap[Which]->mark_tile_dirty(offset);
+}
+
+template <uint8_t Which>
+void vsmjtria_state::colorram_w(offs_t offset, uint8_t data)
+{
+ m_colorram[Which][offset] = data;
+ m_bg_tilemap[Which]->mark_tile_dirty(offset);
+}
+
+template <uint8_t Which>
+TILE_GET_INFO_MEMBER(vsmjtria_state::get_bg_tile_info)
+{
+ int attr = m_colorram[Which][tile_index];
+ int code = m_videoram[Which][tile_index] + ((attr & 0x07) << 8) + ((attr & 0x80) << 4);
+ int color = (attr >> 3);
+
+ tileinfo.set(0, code, color, 0);
+}
+
+template <uint8_t Which>
+uint32_t vsmjtria_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ m_bg_tilemap[Which]->draw(screen, bitmap, cliprect, 0, 0);
+ return 0;
+}
+
+
+void vsmjtria_state::main_prg_map(address_map &map)
+{
+ map(0x0000, 0x9fff).rom();
+ map(0xa000, 0xa7ff).ram().share("nvram0");
+ map(0xa800, 0xafff).ram().w(FUNC(vsmjtria_state::colorram_w<0>)).share(m_colorram[0]);
+ map(0xb000, 0xb7ff).ram().w(FUNC(vsmjtria_state::videoram_w<0>)).share(m_videoram[0]);
+ map(0xc000, 0xdfff).rom();
+ map(0xe000, 0xffff).rom();
+}
+
+void vsmjtria_state::main_io_map(address_map &map)
+{
+ map(0x8000, 0x8003).rw("ppi0", FUNC(i8255_device::read), FUNC(i8255_device::write));
+ map(0x8020, 0x8020).r("ay0", FUNC(ay8910_device::data_r));
+ map(0x8020, 0x8021).w("ay0", FUNC(ay8910_device::address_data_w));
+ map(0x8060, 0x8060).w(FUNC(vsmjtria_state::ctrl_w<0>));
+ // 0x80e0 latch to and from subcpu?
+}
+
+void vsmjtria_state::sub_prg_map(address_map &map)
+{
+ map(0x0000, 0x9fff).rom();
+ map(0xa000, 0xa7ff).ram().share("nvram1");
+ map(0xa800, 0xafff).ram().w(FUNC(vsmjtria_state::colorram_w<1>)).share(m_colorram[1]);
+ map(0xb000, 0xb7ff).ram().w(FUNC(vsmjtria_state::videoram_w<1>)).share(m_videoram[1]);
+ map(0xc000, 0xdfff).rom();
+ map(0xe000, 0xffff).rom();
+}
+
+void vsmjtria_state::sub_io_map(address_map &map)
+{
+ map(0x8000, 0x8003).rw("ppi1", FUNC(i8255_device::read), FUNC(i8255_device::write));
+ map(0x8020, 0x8020).r("ay1", FUNC(ay8910_device::data_r));
+ map(0x8020, 0x8021).w("ay1", FUNC(ay8910_device::address_data_w));
+ map(0x8060, 0x8060).w(FUNC(vsmjtria_state::ctrl_w<1>));
+ // 0x80e0 latch to and from maincpu?
+}
+
+
+static INPUT_PORTS_START( vsmjtria )
+ // TODO: coins?
+
+ PORT_START("P1_KEY0")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_START1 ) // for single player mode
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_MAHJONG_KAN )
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_MAHJONG_M )
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_MAHJONG_I )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_MAHJONG_E )
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_MAHJONG_A )
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("P1_KEY1")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_MAHJONG_REACH )
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_MAHJONG_N )
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_MAHJONG_J )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_MAHJONG_F )
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_MAHJONG_B )
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("P1_KEY2")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_MAHJONG_RON )
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_MAHJONG_CHI )
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_MAHJONG_K )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_MAHJONG_G )
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_MAHJONG_C )
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("P1_KEY3")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_MAHJONG_PON )
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_MAHJONG_L )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_MAHJONG_H )
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_MAHJONG_D )
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("P1_KEY4")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(3) // selects VS mode for player 1
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("P2_KEY0")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_START2 )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_MAHJONG_KAN ) PORT_PLAYER(2)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_MAHJONG_M ) PORT_PLAYER(2)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_MAHJONG_I ) PORT_PLAYER(2)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_MAHJONG_E ) PORT_PLAYER(2)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_MAHJONG_A ) PORT_PLAYER(2)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("P2_KEY1")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_MAHJONG_REACH ) PORT_PLAYER(2)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_MAHJONG_N ) PORT_PLAYER(2)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_MAHJONG_J ) PORT_PLAYER(2)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_MAHJONG_F ) PORT_PLAYER(2)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_MAHJONG_B ) PORT_PLAYER(2)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("P2_KEY2")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_MAHJONG_RON ) PORT_PLAYER(2)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_MAHJONG_CHI ) PORT_PLAYER(2)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_MAHJONG_K ) PORT_PLAYER(2)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_MAHJONG_G ) PORT_PLAYER(2)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_MAHJONG_C ) PORT_PLAYER(2)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("P2_KEY3")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_MAHJONG_PON ) PORT_PLAYER(2)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_MAHJONG_L ) PORT_PLAYER(2)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_MAHJONG_H ) PORT_PLAYER(2)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_MAHJONG_D ) PORT_PLAYER(2)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("P2_KEY4")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(3) // selects VS mode for player 2
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("DSW1") // DSW1 and 2 are for main CPU
+ PORT_DIPNAME( 0x01, 0x01, "Test Mode (P1)" )
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, DEF_STR( Free_Play ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0c, 0x0c, DEF_STR( Coinage ) )
+ PORT_DIPSETTING( 0x0c, DEF_STR( 2C_1C ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( 1C_2C ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( 1C_3C ) )
+ PORT_DIPNAME( 0x10, 0x10, "Unknown 1-4" )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, "Hide Girls" )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, "Unknown 1-6" )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, "Unknown 1-7" )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_START("DSW2")
+ PORT_DIPNAME( 0x01, 0x01, "Unknown 2-0" )
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, "Unknown 2-1" )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x04, "Unknown 2-2" )
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, "Unknown 2-3" )
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, "Unknown 2-4" )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, "Unknown 2-5" )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, "Unknown 2-6" )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, "Unknown 2-7" )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_START("DSW3") // DSW3 and 4 are for sub CPU
+ PORT_DIPNAME( 0x01, 0x01, "Test Mode (P2)" )
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, DEF_STR( Free_Play ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0c, 0x0c, DEF_STR( Coinage ) )
+ PORT_DIPSETTING( 0x0c, DEF_STR( 2C_1C ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( 1C_2C ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( 1C_3C ) )
+ PORT_DIPNAME( 0x10, 0x10, "Unknown 3-4" )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, "Hide Girls" )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, "Unknown 3-6" )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, "Unknown 3-7" )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_START("DSW4")
+ PORT_DIPNAME( 0x01, 0x01, "Unknown 4-0" )
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, "Unknown 4-1" )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x04, "Unknown 4-2" )
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, "Unknown 4-3" )
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, "Unknown 4-4" )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, "Unknown 4-5" )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, "Unknown 4-6" )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, "Unknown 4-7" )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+INPUT_PORTS_END
+
+
+static const gfx_layout charlayout =
+{
+ 8,8,
+ RGN_FRAC(1,2),
+ 3,
+ { RGN_FRAC(1,2)+4, 0, 4 },
+ { 0, 1, 2, 3, 8*8+0, 8*8+1, 8*8+2, 8*8+3 },
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
+ 16*8
+};
+
+static GFXDECODE_START( gfx_vsmjtria_main )
+ GFXDECODE_ENTRY( "maingfx", 0, charlayout, 0, 32 )
+GFXDECODE_END
+
+static GFXDECODE_START( gfx_vsmjtria_sub )
+ GFXDECODE_ENTRY( "subgfx", 0, charlayout, 0, 32 )
+GFXDECODE_END
+
+void vsmjtria_state::vsmjtria(machine_config &config)
+{
+ Z80(config, m_maincpu, 20_MHz_XTAL / 5); // divider guessed
+ m_maincpu->set_addrmap(AS_PROGRAM, &vsmjtria_state::main_prg_map);
+ m_maincpu->set_addrmap(AS_IO, &vsmjtria_state::main_io_map);
+ m_maincpu->set_vblank_int("lscreen", FUNC(vsmjtria_state::irq0_line_hold));
+
+ z80_device &sub(Z80(config, "subcpu", 20_MHz_XTAL / 5)); // divider guessed
+ sub.set_addrmap(AS_PROGRAM, &vsmjtria_state::sub_prg_map);
+ sub.set_addrmap(AS_IO, &vsmjtria_state::sub_io_map);
+ sub.set_vblank_int("rscreen", FUNC(vsmjtria_state::irq0_line_hold));
+
+ NVRAM(config, "nvram0", nvram_device::DEFAULT_ALL_0);
+ NVRAM(config, "nvram1", nvram_device::DEFAULT_ALL_0);
+
+ i8255_device &ppi0(I8255(config, "ppi0"));
+ ppi0.in_pa_callback().set_log("ppi0 pa read");
+ ppi0.in_pb_callback().set(FUNC(vsmjtria_state::p1_keyboard_r));
+ ppi0.in_pc_callback().set_log("ppi0 pc read"); // pending read for latch?
+ ppi0.out_pa_callback().set(FUNC(vsmjtria_state::keyboard_w<0>));
+ ppi0.out_pb_callback().set_log("ppi0 pb write");
+ ppi0.out_pc_callback().set_log("ppi0 pc write");
+
+ i8255_device &ppi1(I8255(config, "ppi1"));
+ ppi1.in_pa_callback().set_log("ppi1 pa read");
+ ppi1.in_pb_callback().set(FUNC(vsmjtria_state::p2_keyboard_r));
+ ppi1.in_pc_callback().set_log("ppi1 pc read"); // pending read for latch?
+ ppi1.out_pa_callback().set(FUNC(vsmjtria_state::keyboard_w<1>));
+ ppi1.out_pb_callback().set_log("ppi1 pb write");
+ ppi1.out_pc_callback().set_log("ppi1 pc write");
+
+ PALETTE(config, "palette0", palette_device::RGB_444_PROMS, "mainproms", 256);
+ PALETTE(config, "palette1", palette_device::RGB_444_PROMS, "subproms", 256);
+
+ GFXDECODE(config, m_gfxdecode[0], "palette0", gfx_vsmjtria_main);
+ GFXDECODE(config, m_gfxdecode[1], "palette1", gfx_vsmjtria_sub);
+
+ config.set_default_layout(layout_dualhsxs);
+
+ screen_device &lscreen(SCREEN(config, "lscreen", SCREEN_TYPE_RASTER));
+ lscreen.set_refresh_hz(60);
+ lscreen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
+ lscreen.set_size(64*8, 32*8);
+ lscreen.set_visarea(4*8, 60*8-1, 2*8, 30*8-1);
+ lscreen.set_screen_update(FUNC(vsmjtria_state::screen_update<0>));
+ lscreen.set_palette("palette0");
+
+ screen_device &rscreen(SCREEN(config, "rscreen", SCREEN_TYPE_RASTER));
+ rscreen.set_refresh_hz(60);
+ rscreen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
+ rscreen.set_size(64*8, 32*8);
+ rscreen.set_visarea(4*8, 60*8-1, 2*8, 30*8-1);
+ rscreen.set_screen_update(FUNC(vsmjtria_state::screen_update<1>));
+ rscreen.set_palette("palette1");
+
+ SPEAKER(config, "speaker").front_center();
+
+ ay8910_device &ay0(AY8910(config, "ay0", 20_MHz_XTAL / 16)); // divider guessed
+ ay0.port_a_read_callback().set_ioport("DSW2");
+ ay0.port_b_read_callback().set_ioport("DSW1");
+ ay0.add_route(ALL_OUTPUTS, "speaker", 0.33);
+
+ ay8910_device &ay1(AY8910(config, "ay1", 20_MHz_XTAL / 16)); // divider guessed
+ ay1.port_a_read_callback().set_ioport("DSW4");
+ ay1.port_b_read_callback().set_ioport("DSW3");
+ ay1.add_route(ALL_OUTPUTS, "speaker", 0.33);
+}
+
+ROM_START( vsmjtria )
+ ROM_REGION( 0x10000, "maincpu", 0 ) // only 5.n8 and 6.n12 differ, and only for 2 bytes
+ ROM_LOAD( "dyna 5.n8", 0x0000, 0x8000, CRC(526e3e6e) SHA1(db7b116f285761b040bb3b5cb3e00f5bf78606a9) )
+ ROM_LOAD( "dyna 41.n7", 0x8000, 0x8000, CRC(0c150add) SHA1(856de25fe43b656ea7c3066f838de6581df896c9) )
+
+ ROM_REGION( 0x10000, "subcpu", 0 )
+ ROM_LOAD( "dyna 6.n12", 0x0000, 0x8000, CRC(f1b09d7a) SHA1(89b653ce332f3b1c1c9f7b82e3636dfb329ebd93) )
+ ROM_LOAD( "dyna 41.n13", 0x8000, 0x8000, CRC(0c150add) SHA1(856de25fe43b656ea7c3066f838de6581df896c9) )
+
+ ROM_REGION( 0x20000, "maingfx", 0 ) // main and sub GFX are identical
+ ROM_LOAD( "dyna 1.h4", 0x00000, 0x08000, CRC(3a16a4f8) SHA1(3a3cb6559be96a3070f53d192cc240e3619a749a) )
+ ROM_LOAD( "dyna 2.h5", 0x08000, 0x08000, CRC(a6c80d40) SHA1(f28efec537f7d5825d9336569fcbec38928eaba2) )
+ ROM_LOAD( "dyna 3.h7", 0x10000, 0x08000, CRC(30a22f1b) SHA1(52aea2dde753556df0a8d96b5a297ddd34d917cf) )
+ // 0x18000-0x1ffff empty space filled by the init function
+
+ ROM_REGION( 0x20000, "subgfx", 0 )
+ ROM_LOAD( "dyna 1.h16", 0x00000, 0x08000, CRC(3a16a4f8) SHA1(3a3cb6559be96a3070f53d192cc240e3619a749a) )
+ ROM_LOAD( "dyna 2.h15", 0x08000, 0x08000, CRC(a6c80d40) SHA1(f28efec537f7d5825d9336569fcbec38928eaba2) )
+ ROM_LOAD( "dyna 3.h13", 0x10000, 0x08000, CRC(30a22f1b) SHA1(52aea2dde753556df0a8d96b5a297ddd34d917cf) )
+ // 0x18000-0x1ffff empty space filled by the init function
+
+ ROM_REGION( 0x300, "mainproms", 0 ) // main and sub PROMs are identical
+ ROM_LOAD( "82s129a_bkr.e5", 0x000, 0x100, CRC(7a6f5c49) SHA1(d0699e6c2c5760b62aba563e039f84f811d1c6a7) )
+ ROM_LOAD( "82s129a_bkg.e4", 0x100, 0x100, CRC(bafdf4e2) SHA1(ddaf98c6d04c9b199f0006ef3f8758ca6b0385ae) )
+ ROM_LOAD( "82s129a_bkb.e6", 0x200, 0x100, CRC(6dc54155) SHA1(c95d2b1ada45bc8b439b3562ebef451e3e27cb42) )
+
+ ROM_REGION( 0x300, "subproms", 0 )
+ ROM_LOAD( "82s129a_bkr.e15", 0x000, 0x100, CRC(7a6f5c49) SHA1(d0699e6c2c5760b62aba563e039f84f811d1c6a7) )
+ ROM_LOAD( "82s129a_bkg.e16", 0x100, 0x100, CRC(bafdf4e2) SHA1(ddaf98c6d04c9b199f0006ef3f8758ca6b0385ae) )
+ ROM_LOAD( "82s129a_bkb.e14", 0x200, 0x100, CRC(6dc54155) SHA1(c95d2b1ada45bc8b439b3562ebef451e3e27cb42) )
+
+ ROM_REGION( 0x200, "mainplds", 0 ) // main and sub PLDs are identical, read as PLS153
+ ROM_LOAD( "ck2605_tp1.d1", 0x000, 0x0eb, CRC(98da4486) SHA1(a5a300978e3e5ccb68e1768a50f3e9d9459ee81d) )
+ ROM_LOAD( "ck2605_tp2.l3", 0x100, 0x0eb, CRC(89b69b50) SHA1(c5d95488540e10092f9935427a6f680959c413d9) )
+
+ ROM_REGION( 0x200, "subplds", 0 ) // main and sub PLDs are identical, read as PLS153
+ ROM_LOAD( "ck2605_tp1.d19", 0x000, 0x0eb, CRC(98da4486) SHA1(a5a300978e3e5ccb68e1768a50f3e9d9459ee81d) )
+ ROM_LOAD( "ck2605_tp2.l17", 0x100, 0x0eb, CRC(89b69b50) SHA1(c5d95488540e10092f9935427a6f680959c413d9) )
+ROM_END
+
+
+static void unpack_high_bit(int size, uint8_t *rom)
+{
+ // unpack the high bit of gfx
+ for (int b = size - 0x4000; b >= 0; b -= 0x4000)
+ {
+ if (b) memcpy(rom + b, rom + b/2, 0x2000);
+
+ for (int a = 0; a < 0x2000;a++)
+ {
+ rom[a + b + 0x2000] = rom[a + b] >> 4;
+ }
+ }
+}
+void vsmjtria_state::init_vsmjtria()
+{
+ unpack_high_bit(memregion("maingfx")->bytes() / 2, memregion("maingfx")->base() + 0x10000);
+ unpack_high_bit(memregion("subgfx")->bytes() / 2, memregion("subgfx")->base() + 0x10000);
+}
+
+} // Anonymous namespace
+
+
+GAME( 1986?, vsmjtria, 0, vsmjtria, vsmjtria, vsmjtria_state, init_vsmjtria, ROT0, "Dyna", "VS Mahjong Triangle", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // puts Home Data in RAM? coins and CPU comms not working