summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame
diff options
context:
space:
mode:
author Dirk Best <mail@dirk-best.de>2018-05-16 02:19:06 +0200
committer Dirk Best <mail@dirk-best.de>2018-05-16 03:23:54 +0200
commit5b533f87d725125bbc61599a5152586ccd28942d (patch)
tree9071001c8cf16b6a860b5057177e0308e6238467 /src/mame
parent4308e2a0c75c1813671327d19e9f983a62f71133 (diff)
model1: Emulate the I/O board used by Wing War and Netmerc
It's also used by Virtua Cop, will be hooked up later to it.
Diffstat (limited to 'src/mame')
-rw-r--r--src/mame/drivers/model1.cpp283
-rw-r--r--src/mame/includes/model1.h9
-rw-r--r--src/mame/layout/model1io2.lay46
-rw-r--r--src/mame/machine/315_5338a.cpp17
-rw-r--r--src/mame/machine/model1io2.cpp349
-rw-r--r--src/mame/machine/model1io2.h153
6 files changed, 758 insertions, 99 deletions
diff --git a/src/mame/drivers/model1.cpp b/src/mame/drivers/model1.cpp
index dd0a02a5c04..293a1c2a714 100644
--- a/src/mame/drivers/model1.cpp
+++ b/src/mame/drivers/model1.cpp
@@ -585,16 +585,24 @@ Notes:
#include "cpu/i386/i386.h"
#include "machine/clock.h"
-#include "machine/mb8421.h"
#include "machine/model1io.h"
+#include "machine/model1io2.h"
#include "speaker.h"
#include "vr.lh"
+#include "model1io2.lh"
// On the real system, another 315-5338A is acting as slave
// and writes the data to the dual port RAM. This isn't
// emulated yet, data just gets written to RAM.
+READ8_MEMBER( model1_state::dpram_r )
+{
+ // insert waitstate
+ m_maincpu->adjust_icount(-1);
+ return m_dpram->right_r(space, offset);
+}
+
WRITE8_MEMBER( model1_state::vf_outputs_w )
{
// 7654---- unknown (not used?)
@@ -677,6 +685,63 @@ WRITE8_MEMBER( model1_state::netmerc_outputs_w )
machine().bookkeeping().coin_counter_w(0, BIT(data, 0));
}
+READ8_MEMBER( model1_state::r360_r )
+{
+ return m_r360_state;
+}
+
+WRITE8_MEMBER( model1_state::r360_w )
+{
+ /*
+ this uses the feedback board protocol
+ command group B - these seem to be gamestates
+
+ bf = init
+ be = attract
+ bd = setup #1 (lower safety bar etc.)
+ bc = setup #2 (push emergency button)
+ bb = ready to go
+ ba = ingame
+ b9 = game over
+
+ results:
+ 40 = default status
+ 41 = * (setup #1 ack)
+ 42 = lowered safety bar
+ 43 = closed belt
+ 44 = lever up
+ 45 = pushed button
+ 46 = game start
+ 47 = game over
+ 48 = lever down
+ 49 = released belt
+ */
+ switch (data & 0xff)
+ {
+ case 0xbf:
+ case 0xbe:
+ m_r360_state = ~0x40;
+ break;
+
+ case 0xbd:
+ m_r360_state = ~0x44;
+ break;
+
+ case 0xbc:
+ m_r360_state = ~0x45;
+ break;
+
+ case 0xbb:
+ m_r360_state = ~0x46;
+ break;
+
+ case 0xba:
+ case 0xb9:
+ m_r360_state = ~0x40;
+ break;
+ }
+}
+
READ16_MEMBER(model1_state::fifoin_status_r)
{
return 0xffff;
@@ -871,7 +936,7 @@ void model1_state::model1_mem(address_map &map)
map(0x900000, 0x903fff).ram().w(this, FUNC(model1_state::p_w)).share("palette");
map(0x910000, 0x91bfff).ram().share("color_xlat");
- map(0xc00000, 0xc00fff).rw("dpram", FUNC(mb8421_device::right_r), FUNC(mb8421_device::right_w)).umask16(0x00ff); // 2k*8-bit dual port ram
+ map(0xc00000, 0xc00fff).r(this, FUNC(model1_state::dpram_r)).w(m_dpram, FUNC(mb8421_device::right_w)).umask16(0x00ff); // 2k*8-bit dual port ram
map(0xc40000, 0xc40000).rw(m_m1uart, FUNC(i8251_device::data_r), FUNC(i8251_device::data_w));
map(0xc40002, 0xc40002).rw(m_m1uart, FUNC(i8251_device::status_r), FUNC(i8251_device::control_w));
@@ -1028,17 +1093,44 @@ static INPUT_PORTS_START( wingwar )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("Smoke")
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
- PORT_START("IN.2") /* 8Bit RX-line from r360 board */
- PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )
-
PORT_START("STICKX")
PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_SENSITIVITY(100) PORT_KEYDELTA(4) PORT_REVERSE
PORT_START("STICKY")
- PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_SENSITIVITY(100) PORT_KEYDELTA(4) PORT_REVERSE
+ PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_SENSITIVITY(100) PORT_KEYDELTA(4)
PORT_START("THROTTLE")
PORT_BIT( 0xff, 0x01, IPT_PEDAL ) PORT_MINMAX(1,0xff) PORT_SENSITIVITY(100) PORT_KEYDELTA(16)
+
+ PORT_START("ioboard:dsw1")
+ PORT_DIPUNKNOWN_DIPLOC(0x01, 0x01, "DSW1:1")
+ PORT_DIPUNKNOWN_DIPLOC(0x02, 0x02, "DSW1:2")
+ PORT_DIPUNKNOWN_DIPLOC(0x04, 0x04, "DSW1:3")
+ PORT_DIPUNKNOWN_DIPLOC(0x08, 0x08, "DSW1:4")
+ PORT_DIPUNKNOWN_DIPLOC(0x10, 0x10, "DSW1:5")
+ PORT_DIPUNKNOWN_DIPLOC(0x20, 0x20, "DSW1:6")
+ PORT_DIPUNKNOWN_DIPLOC(0x40, 0x40, "DSW1:7")
+ PORT_DIPUNKNOWN_DIPLOC(0x80, 0x80, "DSW1:8")
+
+ PORT_START("ioboard:dsw2")
+ PORT_DIPUNKNOWN_DIPLOC(0x01, 0x01, "DSW2:1")
+ PORT_DIPUNKNOWN_DIPLOC(0x02, 0x02, "DSW2:2")
+ PORT_DIPUNKNOWN_DIPLOC(0x04, 0x04, "DSW2:3")
+ PORT_DIPUNKNOWN_DIPLOC(0x08, 0x08, "DSW2:4")
+ PORT_DIPUNKNOWN_DIPLOC(0x10, 0x10, "DSW2:5")
+ PORT_DIPUNKNOWN_DIPLOC(0x20, 0x20, "DSW2:6")
+ PORT_DIPUNKNOWN_DIPLOC(0x40, 0x40, "DSW2:7")
+ PORT_DIPUNKNOWN_DIPLOC(0x80, 0x80, "DSW2:8")
+
+ PORT_START("ioboard:dsw3")
+ PORT_DIPUNKNOWN_DIPLOC(0x01, 0x01, "DSW3:1")
+ PORT_DIPUNKNOWN_DIPLOC(0x02, 0x02, "DSW3:2")
+ PORT_DIPUNKNOWN_DIPLOC(0x04, 0x04, "DSW3:3")
+ PORT_DIPUNKNOWN_DIPLOC(0x08, 0x08, "DSW3:4")
+ PORT_DIPUNKNOWN_DIPLOC(0x10, 0x10, "DSW3:5")
+ PORT_DIPUNKNOWN_DIPLOC(0x20, 0x20, "DSW3:6")
+ PORT_DIPUNKNOWN_DIPLOC(0x40, 0x40, "DSW3:7")
+ PORT_DIPUNKNOWN_DIPLOC(0x80, 0x80, "DSW3:8")
INPUT_PORTS_END
static INPUT_PORTS_START( wingwar360 )
@@ -1050,6 +1142,12 @@ static INPUT_PORTS_START( wingwar360 )
PORT_MODIFY("IN.1")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_MODIFY("STICKX")
+ PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_SENSITIVITY(100) PORT_KEYDELTA(4)
+
+ PORT_MODIFY("STICKY")
+ PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_SENSITIVITY(100) PORT_KEYDELTA(4) PORT_REVERSE
INPUT_PORTS_END
static INPUT_PORTS_START( netmerc )
@@ -1066,14 +1164,41 @@ static INPUT_PORTS_START( netmerc )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("MVD Holder")
PORT_BIT( 0xf8, IP_ACTIVE_LOW, IPT_UNUSED )
- PORT_START("IN.2")
- PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )
-
PORT_START("STICKX")
PORT_BIT( 0xff, 0x7f, IPT_AD_STICK_X ) PORT_SENSITIVITY(100) PORT_KEYDELTA(4) PORT_REVERSE
PORT_START("STICKY")
PORT_BIT( 0xff, 0x7f, IPT_AD_STICK_Y ) PORT_SENSITIVITY(100) PORT_KEYDELTA(4) PORT_REVERSE
+
+ PORT_START("ioboard:dsw1")
+ PORT_DIPUNKNOWN_DIPLOC(0x01, 0x01, "DSW1:1")
+ PORT_DIPUNKNOWN_DIPLOC(0x02, 0x02, "DSW1:2")
+ PORT_DIPUNKNOWN_DIPLOC(0x04, 0x04, "DSW1:3")
+ PORT_DIPUNKNOWN_DIPLOC(0x08, 0x08, "DSW1:4")
+ PORT_DIPUNKNOWN_DIPLOC(0x10, 0x10, "DSW1:5")
+ PORT_DIPUNKNOWN_DIPLOC(0x20, 0x20, "DSW1:6")
+ PORT_DIPUNKNOWN_DIPLOC(0x40, 0x40, "DSW1:7")
+ PORT_DIPUNKNOWN_DIPLOC(0x80, 0x80, "DSW1:8")
+
+ PORT_START("ioboard:dsw2")
+ PORT_DIPUNKNOWN_DIPLOC(0x01, 0x01, "DSW2:1")
+ PORT_DIPUNKNOWN_DIPLOC(0x02, 0x02, "DSW2:2")
+ PORT_DIPUNKNOWN_DIPLOC(0x04, 0x04, "DSW2:3")
+ PORT_DIPUNKNOWN_DIPLOC(0x08, 0x08, "DSW2:4")
+ PORT_DIPUNKNOWN_DIPLOC(0x10, 0x10, "DSW2:5")
+ PORT_DIPUNKNOWN_DIPLOC(0x20, 0x20, "DSW2:6")
+ PORT_DIPUNKNOWN_DIPLOC(0x40, 0x40, "DSW2:7")
+ PORT_DIPUNKNOWN_DIPLOC(0x80, 0x80, "DSW2:8")
+
+ PORT_START("ioboard:dsw3")
+ PORT_DIPUNKNOWN_DIPLOC(0x01, 0x01, "DSW3:1")
+ PORT_DIPUNKNOWN_DIPLOC(0x02, 0x02, "DSW3:2")
+ PORT_DIPUNKNOWN_DIPLOC(0x04, 0x04, "DSW3:3")
+ PORT_DIPUNKNOWN_DIPLOC(0x08, 0x08, "DSW3:4")
+ PORT_DIPUNKNOWN_DIPLOC(0x10, 0x10, "DSW3:5")
+ PORT_DIPUNKNOWN_DIPLOC(0x20, 0x20, "DSW3:6")
+ PORT_DIPUNKNOWN_DIPLOC(0x40, 0x40, "DSW3:7")
+ PORT_DIPUNKNOWN_DIPLOC(0x80, 0x80, "DSW3:8")
INPUT_PORTS_END
@@ -1352,6 +1477,9 @@ ROM_START( wingwar )
ROM_LOAD32_BYTE( "mpr-16742.40", 0x000001, 0x80000, CRC(e9cc12bb) SHA1(40c83c968be3b11fad193a00e7b760f074450683) )
ROM_LOAD32_BYTE( "mpr-16739.41", 0x000002, 0x80000, CRC(6c73e98f) SHA1(7b31e62922ab6d0df97c3ecc52b78e6d086c8635) )
ROM_LOAD32_BYTE( "mpr-16740.42", 0x000003, 0x80000, CRC(44b31007) SHA1(4bb265fea25a7bbcbb8ab080fdcf09849b18f1de) )
+
+ ROM_REGION( 0x10000, "ioboard:iocpu", 0 ) // taken from r360 version, is it the same?
+ ROM_LOAD("epr-16891.6", 0x00000, 0x10000, CRC(a33f84d1) SHA1(3079397c7241c1a6f494fa310faff0989dfa04a0) )
ROM_END
ROM_START( wingwaru )
@@ -1404,6 +1532,9 @@ ROM_START( wingwaru )
ROM_LOAD32_BYTE( "mpr-16742.40", 0x000001, 0x80000, CRC(e9cc12bb) SHA1(40c83c968be3b11fad193a00e7b760f074450683) )
ROM_LOAD32_BYTE( "mpr-16739.41", 0x000002, 0x80000, CRC(6c73e98f) SHA1(7b31e62922ab6d0df97c3ecc52b78e6d086c8635) )
ROM_LOAD32_BYTE( "mpr-16740.42", 0x000003, 0x80000, CRC(44b31007) SHA1(4bb265fea25a7bbcbb8ab080fdcf09849b18f1de) )
+
+ ROM_REGION( 0x10000, "ioboard:iocpu", 0 ) // taken from r360 version, is it the same?
+ ROM_LOAD("epr-16891.6", 0x00000, 0x10000, CRC(a33f84d1) SHA1(3079397c7241c1a6f494fa310faff0989dfa04a0) )
ROM_END
ROM_START( wingwarj )
@@ -1456,6 +1587,9 @@ ROM_START( wingwarj )
ROM_LOAD32_BYTE( "mpr-16742.40", 0x000001, 0x80000, CRC(e9cc12bb) SHA1(40c83c968be3b11fad193a00e7b760f074450683) )
ROM_LOAD32_BYTE( "mpr-16739.41", 0x000002, 0x80000, CRC(6c73e98f) SHA1(7b31e62922ab6d0df97c3ecc52b78e6d086c8635) )
ROM_LOAD32_BYTE( "mpr-16740.42", 0x000003, 0x80000, CRC(44b31007) SHA1(4bb265fea25a7bbcbb8ab080fdcf09849b18f1de) )
+
+ ROM_REGION( 0x10000, "ioboard:iocpu", 0 ) // taken from r360 version, is it the same?
+ ROM_LOAD("epr-16891.6", 0x00000, 0x10000, CRC(a33f84d1) SHA1(3079397c7241c1a6f494fa310faff0989dfa04a0) )
ROM_END
// Dumper's note: As per other R360 games wingwar is just a slightly modified version with 4 roms different on the rom board.
@@ -1511,7 +1645,7 @@ ROM_START( wingwar360 )
ROM_LOAD32_BYTE( "mpr-16739.41", 0x000002, 0x80000, CRC(6c73e98f) SHA1(7b31e62922ab6d0df97c3ecc52b78e6d086c8635) )
ROM_LOAD32_BYTE( "mpr-16740.42", 0x000003, 0x80000, CRC(44b31007) SHA1(4bb265fea25a7bbcbb8ab080fdcf09849b18f1de) )
- ROM_REGION( 0x10000, "ioboard", 0 )
+ ROM_REGION( 0x10000, "ioboard:iocpu", 0 )
ROM_LOAD("epr-16891.6", 0x00000, 0x10000, CRC(a33f84d1) SHA1(3079397c7241c1a6f494fa310faff0989dfa04a0) )
// Dumper's note: Video & Drive is the control board in the attendants' tower, same hardware as G-Loc R360 with the two program roms being the only difference.
@@ -1558,7 +1692,7 @@ ROM_START( netmerc )
ROM_REGION32_LE( 0x200000, "tgp_data", ROMREGION_ERASE00 ) // IC39-IC42 unpopulated
- ROM_REGION( 0x10000, "ioboard", 0 ) /* IO board */
+ ROM_REGION( 0x10000, "ioboard:iocpu", 0 )
ROM_LOAD( "epr-18021.ic6", 0x00000, 0x10000, CRC(5551837e) SHA1(bf5b9aad99c0f8f5e262e0855796f39119d11a97) )
ROM_REGION( 0x8000, "polhemus", 0 ) /* POLHEMUS board */
@@ -1690,11 +1824,19 @@ MACHINE_CONFIG_START(model1_state::wingwar)
MCFG_DEVICE_MODIFY("maincpu")
MCFG_DEVICE_PROGRAM_MAP(model1_comm_mem)
- MCFG_DEVICE_MODIFY("ioboard")
- MCFG_MODEL1IO_AN0_CB(IOPORT("STICKX"))
- MCFG_MODEL1IO_AN1_CB(IOPORT("STICKY"))
- MCFG_MODEL1IO_AN2_CB(IOPORT("THROTTLE"))
- MCFG_MODEL1IO_OUTPUT_CB(WRITE8(*this, model1_state, wingwar_outputs_w))
+ MCFG_DEVICE_REMOVE("ioboard")
+
+ MCFG_DEVICE_ADD("ioboard", SEGA_MODEL1IO2, 0)
+ MCFG_MODEL1IO2_READ_CB(READ8("dpram", mb8421_device, left_r))
+ MCFG_MODEL1IO2_WRITE_CB(WRITE8("dpram", mb8421_device, left_w))
+ MCFG_MODEL1IO2_IN0_CB(IOPORT("IN.0"))
+ MCFG_MODEL1IO2_IN1_CB(IOPORT("IN.1"))
+ MCFG_MODEL1IO2_AN0_CB(IOPORT("STICKX"))
+ MCFG_MODEL1IO2_AN1_CB(IOPORT("STICKY"))
+ MCFG_MODEL1IO2_AN2_CB(IOPORT("THROTTLE"))
+ MCFG_MODEL1IO2_OUTPUT_CB(WRITE8(*this, model1_state, wingwar_outputs_w))
+
+ MCFG_DEFAULT_LAYOUT(layout_model1io2)
MCFG_M1COMM_ADD(M1COMM_TAG)
MCFG_DEVICE_BIOS("epr15112");
@@ -1704,7 +1846,12 @@ MACHINE_CONFIG_START(model1_state::wingwar360)
wingwar(config);
MCFG_DEVICE_MODIFY("ioboard")
- MCFG_MODEL1IO_OUTPUT_CB(WRITE8(*this, model1_state, wingwar360_outputs_w))
+ MCFG_MODEL1IO2_IN2_CB(READ8(*this, model1_state, r360_r))
+ MCFG_MODEL1IO2_DRIVE_WRITE_CB(WRITE8(*this, model1_state, r360_w))
+ MCFG_MODEL1IO2_AN2_CB(NOOP)
+ MCFG_MODEL1IO2_OUTPUT_CB(WRITE8(*this, model1_state, wingwar360_outputs_w))
+
+ MCFG_DEFAULT_LAYOUT(layout_model1io2)
MACHINE_CONFIG_END
void model1_state::polhemus_map(address_map &map)
@@ -1719,83 +1866,31 @@ MACHINE_CONFIG_START(model1_state::netmerc)
MCFG_DEVICE_ADD("polhemus", I386SX, 16000000)
MCFG_DEVICE_PROGRAM_MAP(polhemus_map)
- MCFG_DEVICE_MODIFY("ioboard")
- MCFG_MODEL1IO_AN0_CB(IOPORT("STICKX"))
- MCFG_MODEL1IO_AN2_CB(IOPORT("STICKY"))
- MCFG_MODEL1IO_OUTPUT_CB(WRITE8(*this, model1_state, netmerc_outputs_w))
+ MCFG_DEVICE_REMOVE("ioboard")
+
+ MCFG_DEVICE_ADD("ioboard", SEGA_MODEL1IO2, 0)
+ MCFG_MODEL1IO2_READ_CB(READ8("dpram", mb8421_device, left_r))
+ MCFG_MODEL1IO2_WRITE_CB(WRITE8("dpram", mb8421_device, left_w))
+ MCFG_MODEL1IO2_IN0_CB(IOPORT("IN.0"))
+ MCFG_MODEL1IO2_IN1_CB(IOPORT("IN.1"))
+ MCFG_MODEL1IO2_AN0_CB(IOPORT("STICKX"))
+ MCFG_MODEL1IO2_AN2_CB(IOPORT("STICKY"))
+ MCFG_MODEL1IO2_OUTPUT_CB(WRITE8(*this, model1_state, netmerc_outputs_w))
+ MCFG_DEFAULT_LAYOUT(layout_model1io2)
MACHINE_CONFIG_END
-void model1_state::init_wingwar360()
-{
- // install r360 hack
- m_maincpu->space(AS_PROGRAM).install_read_handler(0xc00014, 0xc00015, read16_delegate(FUNC(model1_state::r360_r),this));
- m_maincpu->space(AS_PROGRAM).install_write_handler(0xc00022, 0xc00023, write16_delegate(FUNC(model1_state::r360_w),this));
-}
-
-READ16_MEMBER(model1_state::r360_r)
-{
- return m_r360_state;
-}
-
-WRITE16_MEMBER(model1_state::r360_w)
-{
- /*
- this uses the feedback board protocol
- command group B - these seem to be gamestates
-
- bf = init
- be = attract
- bd = setup #1 (lower safety bar etc.)
- bc = setup #2 (push emergency button)
- bb = ready to go
- ba = ingame
- b9 = game over
-
- results:
- 40 = default status
- 41 = * (setup #1 ack)
- 42 = lowered safety bar
- 43 = closed belt
- 44 = lever up
- 45 = pushed button
- 46 = game start
- 47 = game over
- 48 = lever down
- 49 = released belt
- */
- switch (data & 0xff)
- {
- case 0xbf:
- case 0xbe:
- m_r360_state = ~0x40;
- break;
-
- case 0xbd:
- m_r360_state = ~0x44;
- break;
-
- case 0xbc:
- m_r360_state = ~0x45;
- break;
-
- case 0xbb:
- m_r360_state = ~0x46;
- break;
-
- case 0xba:
- case 0xb9:
- m_r360_state = ~0x40;
- break;
- }
-}
-
-GAME( 1993, vf, 0, vf, vf, model1_state, empty_init, ROT0, "Sega", "Virtua Fighter", MACHINE_IMPERFECT_GRAPHICS )
-GAMEL(1992, vr, 0, vr, vr, model1_state, empty_init, ROT0, "Sega", "Virtua Racing", 0, layout_vr )
-GAME( 1993, vformula, vr, vformula, vr, model1_state, empty_init, ROT0, "Sega", "Virtua Formula", MACHINE_IMPERFECT_GRAPHICS )
-GAME( 1993, swa, 0, swa, swa, model1_state, empty_init, ROT0, "Sega", "Star Wars Arcade", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND )
-GAME( 1994, wingwar, 0, wingwar, wingwar, model1_state, empty_init, ROT0, "Sega", "Wing War (World)", MACHINE_NOT_WORKING )
-GAME( 1994, wingwaru, wingwar, wingwar, wingwar, model1_state, empty_init, ROT0, "Sega", "Wing War (US)", MACHINE_NOT_WORKING )
-GAME( 1994, wingwarj, wingwar, wingwar, wingwar, model1_state, empty_init, ROT0, "Sega", "Wing War (Japan)", MACHINE_NOT_WORKING )
-GAME( 1994, wingwar360, wingwar, wingwar360, wingwar360, model1_state, init_wingwar360, ROT0, "Sega", "Wing War R360 (US)", MACHINE_NOT_WORKING )
-GAME( 1993, netmerc, 0, netmerc, netmerc, model1_state, empty_init, ROT0, "Sega", "Sega NetMerc", MACHINE_NOT_WORKING )
+//**************************************************************************
+// SYSTEM DRIVERS
+//**************************************************************************
+
+// YEAR NAME PARENT MACHINE INPUT CLASS INIT ROTATION COMPANY FULLNAME FLAGS
+GAME( 1993, vf, 0, vf, vf, model1_state, empty_init, ROT0, "Sega", "Virtua Fighter", MACHINE_IMPERFECT_GRAPHICS )
+GAMEL(1992, vr, 0, vr, vr, model1_state, empty_init, ROT0, "Sega", "Virtua Racing", 0, layout_vr )
+GAME( 1993, vformula, vr, vformula, vr, model1_state, empty_init, ROT0, "Sega", "Virtua Formula", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1993, swa, 0, swa, swa, model1_state, empty_init, ROT0, "Sega", "Star Wars Arcade", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND )
+GAME( 1994, wingwar, 0, wingwar, wingwar, model1_state, empty_init, ROT0, "Sega", "Wing War (World)", MACHINE_NOT_WORKING )
+GAME( 1994, wingwaru, wingwar, wingwar, wingwar, model1_state, empty_init, ROT0, "Sega", "Wing War (US)", MACHINE_NOT_WORKING )
+GAME( 1994, wingwarj, wingwar, wingwar, wingwar, model1_state, empty_init, ROT0, "Sega", "Wing War (Japan)", MACHINE_NOT_WORKING )
+GAME( 1994, wingwar360, wingwar, wingwar360, wingwar360, model1_state, empty_init, ROT0, "Sega", "Wing War R360 (US)", MACHINE_NOT_WORKING )
+GAME( 1993, netmerc, 0, netmerc, netmerc, model1_state, empty_init, ROT0, "Sega", "Sega NetMerc", MACHINE_NOT_WORKING )
diff --git a/src/mame/includes/model1.h b/src/mame/includes/model1.h
index a3f6a2b2903..c89e12463e0 100644
--- a/src/mame/includes/model1.h
+++ b/src/mame/includes/model1.h
@@ -12,6 +12,7 @@
#include "cpu/v60/v60.h"
#include "machine/i8251.h"
#include "machine/gen_fifo.h"
+#include "machine/mb8421.h"
#include "machine/m1comm.h"
#include "machine/timer.h"
#include "video/segaic24.h"
@@ -34,6 +35,7 @@ public:
model1_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
+ , m_dpram(*this, "dpram")
, m_m1audio(*this, M1AUDIO_TAG)
, m_m1uart(*this, "m1uart")
, m_m1comm(*this, "m1comm")
@@ -116,9 +118,8 @@ public:
u32 m_copro_ram_adr;
uint16_t m_r360_state;
- void init_wingwar360();
- DECLARE_READ16_MEMBER(r360_r);
- DECLARE_WRITE16_MEMBER(r360_w);
+ DECLARE_READ8_MEMBER(r360_r);
+ DECLARE_WRITE8_MEMBER(r360_w);
// Rendering
DECLARE_VIDEO_START(model1);
@@ -235,6 +236,7 @@ private:
// Devices
required_device<v60_device> m_maincpu; // V60
+ required_device<mb8421_device> m_dpram;
required_device<segam1audio_device> m_m1audio; // Model 1 standard sound board
required_device<i8251_device> m_m1uart;
optional_device<m1comm_device> m_m1comm; // Model 1 communication board
@@ -502,6 +504,7 @@ private:
// I/O related
output_finder<2> m_digits;
+ DECLARE_READ8_MEMBER(dpram_r);
DECLARE_WRITE8_MEMBER(vf_outputs_w);
DECLARE_WRITE8_MEMBER(vr_outputs_w);
DECLARE_WRITE8_MEMBER(swa_outputs_w);
diff --git a/src/mame/layout/model1io2.lay b/src/mame/layout/model1io2.lay
new file mode 100644
index 00000000000..3c62bd3a522
--- /dev/null
+++ b/src/mame/layout/model1io2.lay
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+
+<mamelayout version="2">
+ <element name="background">
+ </element>
+
+ <element name="led_red" defstate="0">
+ <disk state="0">
+ <color red="0.2" green="0.05" blue="0.05" />
+ </disk>
+ <disk state="1">
+ <color red="0.8" green="0.05" blue="0.05" />
+ </disk>
+ </element>
+
+ <element name="text_comm_err">
+ <text string="COMM_ERR"><color red="1.00" green="1.00" blue="1.00" /></text>
+ </element>
+
+ <view name="Default">
+ <screen index="1">
+ <bounds left="0" top="0" right="1" bottom="1" />
+ </screen>
+ <screen index="0">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ </view>
+
+ <view name="Diagnostic">
+ <backdrop element="background">
+ <bounds x="0" y="0" width="496" height="419" />
+ </backdrop>
+ <screen index="0">
+ <bounds left="0" top="0" right="496" bottom="384" />
+ </screen>
+ <screen index="1">
+ <bounds left="8" top="392" right="129" bottom="411" />
+ </screen>
+ <cpanel name="led_comm_err" element="led_red">
+ <bounds x="141" y="399" width="5" height="5" />
+ </cpanel>
+ <cpanel element="text_comm_err">
+ <bounds x="145" y="398" width="40" height="7" />
+ </cpanel>
+ </view>
+</mamelayout>
diff --git a/src/mame/machine/315_5338a.cpp b/src/mame/machine/315_5338a.cpp
index 1d6cc4abcdc..3dff2458933 100644
--- a/src/mame/machine/315_5338a.cpp
+++ b/src/mame/machine/315_5338a.cpp
@@ -88,6 +88,8 @@ READ8_MEMBER( sega_315_5338a_device::read )
data = m_port_value[offset];
break;
+ case 0x08: data = m_port_config; break;
+
// serial data read back?
case 0x0a: data = m_serial_output; break;
@@ -124,11 +126,22 @@ WRITE8_MEMBER( sega_315_5338a_device::write )
case 0x05:
case 0x06:
m_port_value[offset] = data;
- m_out_port_cb[offset](data);
+ if (BIT(m_port_config, offset) == 0)
+ m_out_port_cb[offset](data);
break;
// port direction register (0 = output, 1 = input)
- case 0x08: m_port_config = data; break;
+ case 0x08:
+ // handle ports that were previously set to input and are now output
+ {
+ uint8_t changed = data ^ m_port_config;
+ for (unsigned i = 0; i < 7; i++)
+ if (BIT(changed, i) && BIT(data, i) == 0)
+ m_out_port_cb[i](m_port_value[i]);
+ }
+
+ m_port_config = data;
+ break;
// command register
case 0x09:
diff --git a/src/mame/machine/model1io2.cpp b/src/mame/machine/model1io2.cpp
new file mode 100644
index 00000000000..dd606859f95
--- /dev/null
+++ b/src/mame/machine/model1io2.cpp
@@ -0,0 +1,349 @@
+// license: BSD-3-Clause
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ Sega Model 1 I/O Board (Advanced)
+
+ Used by:
+ - Wing War (R360) (837-10859)
+ - NetMerc (837-11659)
+ - Virtua Cop (837-11130 with 837-11131)
+
+ Diagnostic LCD:
+
+ It's possible to attach a small LCD to the board and enable a
+ diagnostic mode. To try this in MAME, enable the 'Diagnostic'
+ view, then map keys to I/O board buttons. Hold button 0 and
+ press F3 to reset. The main screen will display 'I/O board error'
+ but the LCD at the bottom is now active. Control it with board
+ buttons 0 (up), 1 (down) and 2 (select).
+
+ It's also possible to show some debug values while the game is
+ running. To do this, hold board button '1' and push reset. Use
+ buttons 0 and 1 to scroll the screen.
+
+ Debug mode:
+
+ You can attach a terminal to SIO channel B. Attach it to the
+ MAME slot option 'ioboard:debug'. You need to set the dip
+ switch to 'Debug Console' and hold board button 0 at startup.
+
+ Default settings are 9600-8-N-1. It will output "RS".
+ You can then enter the following commands:
+
+ - DT[word1][word2]: Returns word2 bytes from location word1
+ - GO: ?
+ - IN[byte1]: Return value from I/O port byte1
+ - LH: ?
+ - OP[byte1][byte2]: Write value byte2 to I/O port byte1
+ - T: Nothing
+ - XR: Return 26 bytes starting at location ff07
+ - XM[26 bytes]: Write 26 bytes to location starting at ff07
+ - ZP[word1][word2]: ff03=word1, ff05=word2
+ - VR: Return id string
+
+ NMI is related to the debug mode, not hooked up.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "model1io2.h"
+#include "cpu/z80/tmpz84c015.h"
+#include "machine/msm6253.h"
+#include "machine/315_5338a.h"
+#include "bus/rs232/rs232.h"
+#include "screen.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(SEGA_MODEL1IO2, model1io2_device, "model1io2", "Sega Model 1 I/O Board (Advanced)")
+
+//-------------------------------------------------
+// mem_map - z80 memory map
+//-------------------------------------------------
+
+void model1io2_device::mem_map(address_map &map)
+{
+ map(0x0000, 0x7fff).rom();
+ map(0x8000, 0x800f).rw("io", FUNC(sega_315_5338a_device::read), FUNC(sega_315_5338a_device::write));
+ map(0x8040, 0x8040).portr("board");
+ map(0x8080, 0x8080).portr("dsw1");
+ map(0x8100, 0x8100).rw(this, FUNC(model1io2_device::fpga_r), FUNC(model1io2_device::fpga_w));
+// map(0x8180, 0x8183).nopr(); // displayed as 4 byte values in the diagnostic screen
+// map(0x81a0, 0x81af).nopw(); // the (reserved) test in the diagnostic screen sets these
+ map(0x8200, 0x8203).mirror(0x04).rw("adc", FUNC(msm6253_device::d0_r), FUNC(msm6253_device::address_w));
+// map(0x8400, 0x8400) // jumps here when debug mode is set and board button 0 is not active on reset
+ map(0xe000, 0xefff).ram(); // backup ram
+ map(0xf000, 0xffff).ram();
+}
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+static INPUT_PORTS_START( model1io2 )
+ PORT_START("board")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Board 0") // on reset: port 4 does diagnostic menu (in debug mode: prevents jump to 8400)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Board 1") // on reset: port 4 does parameter display
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Board 2") // button 2 and 3 adjust the baud rate in debug
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Board 3") // mode when active at reset (9600, 4800, 2400, 1200)
+ PORT_DIPNAME(0x30, 0x30, "Mode") // jumpers on board?
+ PORT_DIPSETTING( 0x00, "Debug Console")
+ PORT_DIPSETTING( 0x10, "Normal 2")
+ PORT_DIPSETTING( 0x20, "Normal 1")
+ PORT_DIPSETTING( 0x30, "Normal 0") // default: no sio rx int (wingwar)
+// might be mapped like this:
+// PORT_DIPUNKNOWN(0x10, 0x10) // MODE (or ROM_EMU?)
+// PORT_DIPUNKNOWN(0x20, 0x20) // GA_INT
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_CUSTOM) PORT_READ_LINE_DEVICE_MEMBER("eeprom", eeprom_serial_93cxx_device, do_read)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED)
+INPUT_PORTS_END
+
+ioport_constructor model1io2_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(model1io2);
+}
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+MACHINE_CONFIG_START( model1io2_device::device_add_mconfig )
+ MCFG_DEVICE_ADD("iocpu", TMPZ84C015, 19.6608_MHz_XTAL / 2) // TMPZ84C015AF-12
+ MCFG_DEVICE_PROGRAM_MAP(mem_map)
+
+ // SIO channel a baud rate adjusted by dsw1 1+2: 38400, 19200, 9600, 4800
+ MCFG_TMPZ84C015_ZC2_CB(WRITELINE("iocpu", tmpz84c015_device, rxca_w))
+ MCFG_DEVCB_CHAIN_OUTPUT(WRITELINE("iocpu", tmpz84c015_device, txca_w))
+ MCFG_TMPZ84C015_ZC3_CB(WRITELINE("iocpu", tmpz84c015_device, rxtxcb_w))
+
+ MCFG_TMPZ84C015_OUT_TXDB_CB(WRITELINE("debug", rs232_port_device, write_txd))
+
+ MCFG_TMPZ84C015_IN_PA_CB(IOPORT("dsw2"))
+ MCFG_TMPZ84C015_IN_PB_CB(IOPORT("dsw3"))
+
+ MCFG_DEVICE_ADD("debug", RS232_PORT, default_rs232_devices, nullptr)
+ MCFG_RS232_RXD_HANDLER(WRITELINE("iocpu", tmpz84c015_device, rxb_w))
+
+ MCFG_DEVICE_ADD("io", SEGA_315_5338A, 0)
+ MCFG_315_5338A_READ_CB(READ8(*this, model1io2_device, io_r))
+ MCFG_315_5338A_WRITE_CB(WRITE8(*this, model1io2_device, io_w))
+ MCFG_315_5338A_IN0_CB(READ8(*this, model1io2_device, in0_r))
+ MCFG_315_5338A_IN1_CB(READ8(*this, model1io2_device, in1_r))
+ MCFG_315_5338A_IN2_CB(READ8(*this, model1io2_device, in2_r))
+ MCFG_315_5338A_IN4_CB(READ8(*this, model1io2_device, in4_r))
+ MCFG_315_5338A_OUT3_CB(WRITE8(*this, model1io2_device, out3_w))
+ MCFG_315_5338A_OUT4_CB(WRITE8(*this, model1io2_device, out4_w))
+ MCFG_315_5338A_OUT5_CB(WRITE8(*this, model1io2_device, out5_w))
+ MCFG_315_5338A_OUT6_CB(WRITE8(*this, model1io2_device, out6_w))
+
+ MCFG_EEPROM_SERIAL_93C46_ADD("eeprom") // 93C45
+
+ MCFG_DEVICE_ADD("adc", MSM6253, 0)
+ MCFG_MSM6253_IN0_ANALOG_READ(model1io2_device, analog0_r)
+ MCFG_MSM6253_IN1_ANALOG_READ(model1io2_device, analog1_r)
+ MCFG_MSM6253_IN2_ANALOG_READ(model1io2_device, analog2_r)
+ MCFG_MSM6253_IN3_ANALOG_READ(model1io2_device, analog3_r)
+
+ // diagnostic lcd display
+ MCFG_SCREEN_ADD("screen", LCD)
+ MCFG_SCREEN_REFRESH_RATE(50)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) // not accurate
+ MCFG_SCREEN_SIZE(6*20+1, 19)
+ MCFG_SCREEN_VISIBLE_AREA(0, 6*20, 0, 19-1)
+ MCFG_SCREEN_UPDATE_DEVICE("lcd", hd44780_device, screen_update)
+ MCFG_SCREEN_PALETTE("palette")
+
+ MCFG_PALETTE_ADD("palette", 3)
+ MCFG_PALETTE_INIT_OWNER(model1io2_device, lcd)
+
+ MCFG_HD44780_ADD("lcd")
+ MCFG_HD44780_LCD_SIZE(2, 20)
+ MCFG_HD44780_PIXEL_UPDATE_CB(model1io2_device, lcd_pixel_update)
+MACHINE_CONFIG_END
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// model1io2_device - constructor
+//-------------------------------------------------
+
+model1io2_device::model1io2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, SEGA_MODEL1IO2, tag, owner, clock),
+ m_eeprom(*this, "eeprom"),
+ m_lcd(*this, "lcd"),
+ m_led_comm_err(*this, "led_comm_err"),
+ m_read_cb(*this), m_write_cb(*this),
+ m_in_cb{ {*this}, {*this}, {*this} },
+ m_drive_read_cb(*this), m_drive_write_cb(*this),
+ m_an_cb{ {*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this} },
+ m_output_cb(*this),
+ m_secondary_controls(false),
+ m_lcd_data(0)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void model1io2_device::device_start()
+{
+ // resolve callbacks
+ m_led_comm_err.resolve();
+
+ m_read_cb.resolve_safe(0xff);
+ m_write_cb.resolve_safe();
+
+ for (unsigned i = 0; i < 3; i++)
+ m_in_cb[i].resolve_safe(0xff);
+
+ m_drive_read_cb.resolve_safe(0xff);
+ m_drive_write_cb.resolve_safe();
+
+ for (unsigned i = 0; i < 8; i++)
+ m_an_cb[i].resolve_safe(0xff);
+
+ m_output_cb.resolve_safe();
+
+ // register for save states
+ save_item(NAME(m_secondary_controls));
+ save_item(NAME(m_lcd_data));
+}
+
+
+//**************************************************************************
+// DIAGNOSTIC LCD
+//**************************************************************************
+
+PALETTE_INIT_MEMBER( model1io2_device, lcd )
+{
+ palette.set_pen_color(0, rgb_t(138, 146, 148)); // background
+ palette.set_pen_color(1, rgb_t( 92, 83, 88)); // lcd pixel on
+ palette.set_pen_color(2, rgb_t(131, 136, 139)); // lcd pixel off
+}
+
+HD44780_PIXEL_UPDATE( model1io2_device::lcd_pixel_update )
+{
+ // char size is 5x8
+ if (x > 4 || y > 7)
+ return;
+
+ if (line < 2 && pos < 20)
+ bitmap.pix16(1 + y + line*8 + line, 1 + pos*6 + x) = state ? 1 : 2;
+}
+
+
+//**************************************************************************
+// INTERFACE
+//**************************************************************************
+
+READ8_MEMBER( model1io2_device::io_r )
+{
+ return m_read_cb(offset);
+}
+
+WRITE8_MEMBER( model1io2_device::io_w )
+{
+ m_write_cb(offset, data, 0xff);
+}
+
+READ8_MEMBER( model1io2_device::in0_r )
+{
+ return m_in_cb[0](0);
+}
+
+READ8_MEMBER( model1io2_device::in1_r )
+{
+ return m_in_cb[1](0);
+}
+
+READ8_MEMBER( model1io2_device::in2_r )
+{
+ return m_in_cb[2](0);
+}
+
+WRITE8_MEMBER( model1io2_device::out3_w )
+{
+ m_output_cb(data);
+}
+
+READ8_MEMBER( model1io2_device::in4_r )
+{
+ return m_drive_read_cb(0);
+}
+
+WRITE8_MEMBER( model1io2_device::out4_w )
+{
+ m_lcd_data = data;
+ m_drive_write_cb(data);
+}
+
+WRITE8_MEMBER( model1io2_device::out5_w )
+{
+ // 7------- not used?
+ // -6------ eeprom di
+ // --5----- eeprom clk
+ // ---4---- eeprom cs
+ // ----3--- unknown
+ // -----2-- lcd e
+ // ------1- lcd rw
+ // -------0 lcd rs
+
+ m_eeprom->clk_write(BIT(data, 5) ? ASSERT_LINE : CLEAR_LINE);
+ m_eeprom->di_write(BIT(data, 6));
+ m_eeprom->cs_write(BIT(data, 4) ? ASSERT_LINE : CLEAR_LINE);
+
+ if (BIT(data, 2) == 1 && BIT(data, 1) == 0)
+ m_lcd->write(space, BIT(data, 0), m_lcd_data);
+}
+
+WRITE8_MEMBER( model1io2_device::out6_w )
+{
+ // 7------- unknown (input related?)
+ // -6------ control panel switch
+ // --5----- comm_err led
+ // ---4---- unknown
+ // ----32-- not used?
+ // ------1- unknown (sio channel a related)
+ // -------0 interrupt processing (1 while in the int routine)
+
+ m_secondary_controls = BIT(data, 6);
+ m_led_comm_err = BIT(~data, 5);
+}
+
+READ8_MEMBER( model1io2_device::fpga_r )
+{
+ return 0x80;
+}
+
+WRITE8_MEMBER( model1io2_device::fpga_w )
+{
+ // fpga data uploaded here (vcop)
+}
+
+ioport_value model1io2_device::analog0_r()
+{
+ return m_secondary_controls ? m_an_cb[4](0) : m_an_cb[0](0);
+}
+
+ioport_value model1io2_device::analog1_r()
+{
+ return m_secondary_controls ? m_an_cb[5](0) : m_an_cb[1](0);
+}
+
+ioport_value model1io2_device::analog2_r()
+{
+ return m_secondary_controls ? m_an_cb[6](0) : m_an_cb[2](0);
+}
+
+ioport_value model1io2_device::analog3_r()
+{
+ return m_secondary_controls ? m_an_cb[7](0) : m_an_cb[3](0);
+}
diff --git a/src/mame/machine/model1io2.h b/src/mame/machine/model1io2.h
new file mode 100644
index 00000000000..d91c114f6ec
--- /dev/null
+++ b/src/mame/machine/model1io2.h
@@ -0,0 +1,153 @@
+// license: BSD-3-Clause
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ Sega Model 1 I/O Board (Advanced)
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_MODEL1IO2_H
+#define MAME_MACHINE_MODEL1IO2_H
+
+#pragma once
+
+#include "machine/eepromser.h"
+#include "video/hd44780.h"
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_MODEL1IO2_READ_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_read_callback(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_WRITE_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_write_callback(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_IN0_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_in_callback<0>(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_IN1_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_in_callback<1>(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_IN2_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_in_callback<2>(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_DRIVE_READ_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_drive_read_callback(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_DRIVE_WRITE_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_drive_write_callback(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_AN0_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_an_callback<0>(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_AN1_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_an_callback<1>(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_AN2_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_an_callback<2>(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_AN3_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_an_callback<3>(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_AN4_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_an_callback<4>(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_AN5_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_an_callback<5>(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_AN6_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_an_callback<6>(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_AN7_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_an_callback<7>(DEVCB_##_devcb);
+
+#define MCFG_MODEL1IO2_OUTPUT_CB(_devcb) \
+ devcb = &downcast<model1io2_device &>(*device).set_output_callback(DEVCB_##_devcb);
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class model1io2_device : public device_t
+{
+public:
+ // construction/destruction
+ model1io2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // configuration
+ template <class Object> devcb_base &set_read_callback(Object &&cb)
+ { return m_read_cb.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base &set_write_callback(Object &&cb)
+ { return m_write_cb.set_callback(std::forward<Object>(cb)); }
+
+ template <int Index, class Object> devcb_base &set_in_callback(Object &&cb)
+ { return m_in_cb[Index].set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base &set_drive_read_callback(Object &&cb)
+ { return m_drive_read_cb.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base &set_drive_write_callback(Object &&cb)
+ { return m_drive_write_cb.set_callback(std::forward<Object>(cb)); }
+
+ template <int Index, class Object> devcb_base &set_an_callback(Object &&cb)
+ { return m_an_cb[Index].set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base &set_output_callback(Object &&cb)
+ { return m_output_cb.set_callback(std::forward<Object>(cb)); }
+
+ void mem_map(address_map &map);
+ void io_map(address_map &map);
+
+ DECLARE_PALETTE_INIT(lcd);
+ HD44780_PIXEL_UPDATE(lcd_pixel_update);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual ioport_constructor device_input_ports() const override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+private:
+ required_device<eeprom_serial_93cxx_device> m_eeprom;
+ required_device<hd44780_device> m_lcd;
+ output_finder<> m_led_comm_err;
+
+ DECLARE_READ8_MEMBER(io_r);
+ DECLARE_WRITE8_MEMBER(io_w);
+ DECLARE_READ8_MEMBER(in0_r);
+ DECLARE_READ8_MEMBER(in1_r);
+ DECLARE_READ8_MEMBER(in2_r);
+ DECLARE_READ8_MEMBER(in4_r);
+ DECLARE_WRITE8_MEMBER(out3_w);
+ DECLARE_WRITE8_MEMBER(out4_w);
+ DECLARE_WRITE8_MEMBER(out5_w);
+ DECLARE_WRITE8_MEMBER(out6_w);
+ DECLARE_READ8_MEMBER(fpga_r);
+ DECLARE_WRITE8_MEMBER(fpga_w);
+
+ ioport_value analog0_r();
+ ioport_value analog1_r();
+ ioport_value analog2_r();
+ ioport_value analog3_r();
+
+ devcb_read8 m_read_cb;
+ devcb_write8 m_write_cb;
+ devcb_read8 m_in_cb[3];
+ devcb_read8 m_drive_read_cb;
+ devcb_write8 m_drive_write_cb;
+ devcb_read8 m_an_cb[8];
+ devcb_write8 m_output_cb;
+
+ bool m_secondary_controls;
+ uint8_t m_lcd_data;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(SEGA_MODEL1IO2, model1io2_device)
+
+#endif // MAME_MACHINE_MODEL1IO2_H