summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/bus/intv
diff options
context:
space:
mode:
author Fabio Priuli <etabeta78@users.noreply.github.com>2014-10-08 16:42:01 +0000
committer Fabio Priuli <etabeta78@users.noreply.github.com>2014-10-08 16:42:01 +0000
commit278a884012d0fffe57297c346f782eda3bd8c616 (patch)
tree740296e41a141f68c32cc7d4167841ead84736ee /src/emu/bus/intv
parent03f8deff8afcf7470a319b3cd9042d3f3b6d6f17 (diff)
(MESS) intv: converted the driver to use slot devices for
cartridges and implemented the IntelliVoice expansion and the Entertainment Computer System expansion as passthru devices. The official syntax to launch games requiring the speech expansion is now mess intv -cart voice -cart2 gamename which corresponds to mounting the IntelliVoice and plugging the game cart in its subslot. The official syntax to launch games requiring the ECS expansion is now instead mess intv -cart ecs -cart2 gamename and mess intv -cart ecs -cart2 voice -cart3 gamename if the game requires both expansions at once. For additional user friendliness, we also offer intvecs (which emulates an Intellivision unit with both expansions added) and intvoice (which emulates an Intellivision with Intellivoice expansion added) drivers, where games can simply be mounted with the -cart media switch. [Fabio Priuli]
Diffstat (limited to 'src/emu/bus/intv')
-rw-r--r--src/emu/bus/intv/ecs.c588
-rw-r--r--src/emu/bus/intv/ecs.h145
-rw-r--r--src/emu/bus/intv/rom.c50
-rw-r--r--src/emu/bus/intv/rom.h82
-rw-r--r--src/emu/bus/intv/slot.c572
-rw-r--r--src/emu/bus/intv/slot.h184
-rw-r--r--src/emu/bus/intv/voice.c122
-rw-r--r--src/emu/bus/intv/voice.h76
8 files changed, 1819 insertions, 0 deletions
diff --git a/src/emu/bus/intv/ecs.c b/src/emu/bus/intv/ecs.c
new file mode 100644
index 00000000000..6b42f004bab
--- /dev/null
+++ b/src/emu/bus/intv/ecs.c
@@ -0,0 +1,588 @@
+/***********************************************************************************************************
+
+
+ Mattel Intellivision Entertainment Computer System expansion emulation
+
+ TODO:
+ - Make paged rom emulation more accurate (according to
+ http://spatula-city.org/~im14u2c/intv/tech/ecs.html
+ writes to $xa5y should be available for every x and every y, i.e. we shall
+ have writes to every 4K chunk of the memory map, and there shall be 16 pages
+ for each)
+ Current emulation is instead tailored around the minimal usage necessary to
+ make the main expansion and World Series Major League Baseball happy
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "ecs.h"
+
+
+//-------------------------------------------------
+// intv_ecs_device - constructor
+//-------------------------------------------------
+
+const device_type INTV_ROM_ECS = &device_creator<intv_ecs_device>;
+
+intv_ecs_device::intv_ecs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : intv_rom_device(mconfig, INTV_ROM_ECS, "Intellivision ECS Expansion", tag, owner, clock, "intv_ecs", __FILE__),
+ m_snd(*this, "ay8914"),
+ m_subslot(*this, "subslot"),
+ m_keybd(*this, "ROW"),
+ m_synth(*this, "SYNTH"),
+ m_cntrlsel(*this, "CNTRLSEL"),
+ m_options(*this, "OPTIONS"),
+ m_keypad(*this, "KEYPAD"),
+ m_disc(*this, "DISC"),
+ m_discx(*this, "DISCX"),
+ m_discy(*this, "DISCY"),
+ m_psg_porta(0),
+ m_voice_enabled(false),
+ m_ramd0_enabled(false),
+ m_ram88_enabled(false)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void intv_ecs_device::device_start()
+{
+ // if the ECS is mounted directly in the system, use device rom and alloc RAM
+ if (m_rom == NULL)
+ {
+ astring region_tag;
+ m_rom = memregion(region_tag.cpy(tag()).cat(":ecs"))->base();
+ }
+ if (!m_ram.count())
+ {
+ m_ram.resize(0x800);
+ }
+
+ save_item(NAME(m_bank_base));
+ save_item(NAME(m_psg_porta));
+}
+
+void intv_ecs_device::device_reset()
+{
+ memset(m_bank_base, 0, sizeof(m_bank_base));
+}
+
+void intv_ecs_device::late_subslot_setup()
+{
+ switch (m_subslot->get_type())
+ {
+ case INTV_RAM:
+ m_ramd0_enabled = true;
+ break;
+ case INTV_GFACT:
+ m_ram88_enabled = true;
+ break;
+ case INTV_VOICE:
+ m_voice_enabled = true;
+ m_subslot->late_subslot_setup();
+ break;
+ case INTV_ECS:
+ printf("WARNING: You cannot connect serially multiple ECS units.\n");
+ printf("WARNING: Emulation will likely misbehave.\n");
+ break;
+ case INTV_KEYCOMP:
+ printf("WARNING: You cannot connect the Keyboard component to the ECS unit.\n");
+ printf("WARNING: Emulation will likely misbehave.\n");
+ break;
+ }
+}
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( sub_slot )
+//-------------------------------------------------
+
+UINT8 intv_ecs_device::intv_control_r(int hand)
+{
+ static const UINT8 keypad_table[] =
+ {
+ 0xFF, 0x3F, 0x9F, 0x5F, 0xD7, 0xB7, 0x77, 0xDB,
+ 0xBB, 0x7B, 0xDD, 0xBD, 0x7D, 0xDE, 0xBE, 0x7E
+ };
+
+ static const UINT8 disc_table[] =
+ {
+ 0xF3, 0xE3, 0xE7, 0xF7, 0xF6, 0xE6, 0xEE, 0xFE,
+ 0xFC, 0xEC, 0xED, 0xFD, 0xF9, 0xE9, 0xEB, 0xFB
+ };
+
+ static const UINT8 discyx_table[5][5] =
+ {
+ { 0xE3, 0xF3, 0xFB, 0xEB, 0xE9 },
+ { 0xE7, 0xE3, 0xFB, 0xE9, 0xF9 },
+ { 0xF7, 0xF7, 0xFF, 0xFD, 0xFD },
+ { 0xF6, 0xE6, 0xFE, 0xEC, 0xED },
+ { 0xE6, 0xEE, 0xFE, 0xFC, 0xEC }
+ };
+
+ int x, y;
+ UINT8 val = 0xff;
+
+ /* keypad */
+ x = m_keypad[hand]->read();
+ for (y = 0; y < 16; y++)
+ {
+ if (x & (1 << y))
+ {
+ val &= keypad_table[y];
+ }
+ }
+
+ switch ((m_options->read() >> hand) & 4)
+ {
+ case 0: /* disc == digital */
+ default:
+
+ x = m_disc[hand]->read();
+ for (y = 0; y < 16; y++)
+ {
+ if (x & (1 << y))
+ {
+ val &= disc_table[y];
+ }
+ }
+ break;
+
+ case 1: /* disc == _fake_ analog */
+
+ x = m_discx[hand]->read();
+ y = m_discy[hand]->read();
+ val &= discyx_table[y / 32][x / 32];
+ }
+
+ return val;
+}
+
+READ8_MEMBER( intv_ecs_device::ay_porta_r )
+{
+ if (m_cntrlsel->read() == 0)
+ return intv_control_r(0);
+ else
+ return 0xff; // not sure what to return here, maybe it should be last output?
+}
+
+READ8_MEMBER( intv_ecs_device::ay_portb_r )
+{
+ switch (m_cntrlsel->read())
+ {
+ case 0x00: // hand controller
+ return intv_control_r(1);
+
+ case 0x01: // synthesizer keyboard
+ {
+ UINT8 val = 0xff;
+ // return correct result if more than one bit of 0xFE is set
+ for (int i = 0; i < 7; i++)
+ {
+ if (BIT(m_psg_porta, i))
+ val &= m_synth[i]->read();
+ }
+ return val;
+ }
+ case 0x02: // ecs keyboard
+ {
+ UINT8 val = 0xff;
+ // return correct result if more than one bit of 0xFE is set
+ for (int i = 0; i < 7; i++)
+ {
+ if (BIT(m_psg_porta, i))
+ val &= m_keybd[i]->read();
+ }
+ return val;
+ }
+ default:
+ return 0xff;
+ }
+}
+
+WRITE8_MEMBER( intv_ecs_device::ay_porta_w )
+{
+ m_psg_porta = (~data) & 0xff;
+}
+
+static MACHINE_CONFIG_FRAGMENT( sub_slot )
+ MCFG_SPEAKER_STANDARD_MONO("mono_ecs")
+
+ MCFG_SOUND_ADD("ay8914", AY8914, XTAL_3_579545MHz/2)
+ MCFG_AY8910_PORT_A_READ_CB(READ8(intv_ecs_device, ay_porta_r))
+ MCFG_AY8910_PORT_B_READ_CB(READ8(intv_ecs_device, ay_portb_r))
+ MCFG_AY8910_PORT_A_WRITE_CB(WRITE8(intv_ecs_device, ay_porta_w))
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono_ecs", 0.33)
+
+ MCFG_INTV_CARTRIDGE_ADD("subslot", intv_cart, NULL)
+MACHINE_CONFIG_END
+
+
+machine_config_constructor intv_ecs_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( sub_slot );
+}
+
+
+ROM_START( ecs )
+ ROM_REGION( 0x20000, "ecs", ROMREGION_ERASEFF )
+ ROM_LOAD16_WORD_SWAP( "ecs_rom.20", 0x04000, 0x2000, CRC(5f9d05e5) SHA1(083a3e7405b8f8b4b8a5003ca9c31b8d824b535c))
+ ROM_LOAD16_WORD_SWAP( "ecs_rom.70", 0x0e000, 0x2000, CRC(46bb1f48) SHA1(eda44a8476fdada1ae90fba0d0287611e2efa074))
+ ROM_LOAD16_WORD_SWAP( "ecs_rom.e0", 0x1c000, 0x2000, CRC(c2ebcd90) SHA1(b3c14955f56c57e6f0d8fbb695771946cfcf6582))
+ROM_END
+
+const rom_entry *intv_ecs_device::device_rom_region() const
+{
+ return ROM_NAME( ecs );
+}
+
+
+static INPUT_PORTS_START( intv_ecs_kbd )
+/*
+ ECS matrix scanned by setting 0xFE bits to output and reading 0xFF
+ ECS Keyboard Layout:
+ FF\FE Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
+ Bit 0 NC RTN 0 ESC P ; . (left)
+ Bit 1 L O 8 9 I K M ,
+ Bit 2 J U 6 7 Y H B N
+ Bit 3 G T 4 5 R F C V
+ Bit 4 D E 2 3 W S Z X
+ Bit 5 A CTL (right) 1 Q (up) (down) (space)
+ Bit 6 SHIFT NC NC NC NC NC NC NC
+
+ Shifted keys that differ from pc:
+ Key : 1 2 5 6 7 (left) (right) (up) (down)
+ Shift + key: = " + - / % ' ^ ?
+ */
+
+ PORT_START("ROW.0")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("RTN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_CHAR('%') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+
+ PORT_START("ROW.1")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('L') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('O') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('I') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('K') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('M') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+
+ PORT_START("ROW.2")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('J') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('U') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('-') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('/') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('H') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('B') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('N') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+
+ PORT_START("ROW.3")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('G') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('T') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('R') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('F') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('C') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('V') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+
+ PORT_START("ROW.4")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('D') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('E') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('W') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('S') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+
+ PORT_START("ROW.5")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('A') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CTL") PORT_CODE(KEYCODE_RCONTROL) PORT_CODE(KEYCODE_LCONTROL) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_CHAR('\'') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('=') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_CHAR('^') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_CHAR('?') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+
+ PORT_START("ROW.6")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_RSHIFT) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( intv_ecs_synth )
+/*
+ ECS Synthesizer Layout:
+ FF\FE Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
+ Bit 0 G2 Gb2 F2 E2 Eb2 D2 Db2 C2
+ Bit 1 Eb3 D3 Db3 C3 B2 Bb2 A2 Ab2
+ Bit 2 B3 Bb3 A3 Ab3 G3 Gb3 F3 E3
+ Bit 3 G4 Gb4 F4 E4 Eb4 D4 Db4 C4
+ Bit 4 Eb5 D5 Db5 C5 B4 Bb4 A4 Ab4
+ Bit 5 B5 Bb5 A5 Ab5 G5 Gb5 F5 E5
+ Bit 6 C6 NC NC NC NC NC NC NC
+ */
+ PORT_START("SYNTH.0")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Gb2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Eb2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Db2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+
+ PORT_START("SYNTH.1")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Eb3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Db3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Bb2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ab2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+
+ PORT_START("SYNTH.2")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Bb3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ab3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Gb3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+
+ PORT_START("SYNTH.3")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Gb4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Eb4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Db4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+
+ PORT_START("SYNTH.4")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Eb5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Db5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Bb4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ab4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+
+ PORT_START("SYNTH.5")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Bb5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ab5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Gb5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+
+ PORT_START("SYNTH.6")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C6") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( intv_ecs_pads )
+ // First ECS Hand Controller
+ PORT_START("KEYPAD.0")
+ PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/1") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/6") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/7") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/8") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/9") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/Clear") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/0") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/Enter") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P3/Upper") PORT_PLAYER(3) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P3/Lower-Left") PORT_PLAYER(3) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P3/Lower-Right") PORT_PLAYER(3) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("DISC.0")
+ PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_NAME("P3/Up") PORT_PLAYER(3) PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Up-Up-Right") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Right") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Right-Up-Right") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_NAME("P3/Right") PORT_PLAYER(3) PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Right-Down-Right") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Down-Right") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Down-Down-Right") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_NAME("P3/Down") PORT_PLAYER(3) PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Down-Down-Left") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Down-Left") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Left-Down-Left") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_NAME("P3/Left") PORT_PLAYER(3) PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Left-Up-Left") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Up-Left") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Up-Up-Left") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+
+ PORT_START("DISCX.0")
+ PORT_BIT( 0xff, 0x50, IPT_AD_STICK_X ) PORT_NAME("P3/X") PORT_MINMAX(0x00,0x9f) PORT_SENSITIVITY(100) PORT_KEYDELTA(0x50) PORT_PLAYER(3) PORT_CONDITION("OPTIONS",0x04,EQUALS,0x04) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+
+ PORT_START("DISCY.0")
+ PORT_BIT( 0xff, 0x50, IPT_AD_STICK_Y ) PORT_NAME("P3/Y") PORT_MINMAX(0x00,0x9f) PORT_SENSITIVITY(100) PORT_KEYDELTA(0x50) PORT_PLAYER(3) PORT_CONDITION("OPTIONS",0x04,EQUALS,0x04) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+
+ // Second ECS Hand Controller
+ PORT_START("KEYPAD.1")
+ PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/1") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/6") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/7") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/8") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/9") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/Clear") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/0") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/Enter") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P4/Upper") PORT_PLAYER(4) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P4/Lower-Left") PORT_PLAYER(4) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P4/Lower-Right") PORT_PLAYER(4) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("DISC.1")
+ PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_NAME("P4/Up") PORT_PLAYER(4) PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Up-Up-Right") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Up-Right") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Right-Up-Right") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_NAME("P4/Right") PORT_PLAYER(4) PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Right-Down-Right") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Down-Right") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Down-Down-Right") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_NAME("P4/Down") PORT_PLAYER(4) PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Down-Down-Left") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Down-Left") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Left-Down-Left") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_NAME("P4/Left") PORT_PLAYER(4) PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Left-Up-Left") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Up-Left") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Up-Up-Left") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+
+ PORT_START("DISCX.1")
+ PORT_BIT( 0xff, 0x50, IPT_AD_STICK_X ) PORT_NAME("P4/X") PORT_MINMAX(0x00,0x9f) PORT_SENSITIVITY(100) PORT_KEYDELTA(0x50) PORT_CODE_DEC(KEYCODE_D) PORT_CODE_INC(KEYCODE_G) PORT_PLAYER(4) PORT_CONDITION("OPTIONS",0x08,EQUALS,0x08) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+
+ PORT_START("DISCY.1")
+ PORT_BIT( 0xff, 0x50, IPT_AD_STICK_Y ) PORT_NAME("P4/Y") PORT_MINMAX(0x00,0x9f) PORT_SENSITIVITY(100) PORT_KEYDELTA(0x50) PORT_CODE_DEC(KEYCODE_R) PORT_CODE_INC(KEYCODE_F) PORT_PLAYER(4) PORT_CONDITION("OPTIONS",0x08,EQUALS,0x08) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( intv_ecs )
+ PORT_INCLUDE( intv_ecs_pads )
+ PORT_INCLUDE( intv_ecs_synth )
+ PORT_INCLUDE( intv_ecs_kbd )
+
+ PORT_START("OPTIONS")
+ PORT_CONFNAME( 0x04, 0x00, "ECS_P3 Disc" ) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_CONFSETTING( 0x00, "Digital" )
+ PORT_CONFSETTING( 0x04, "Analog" )
+ PORT_CONFNAME( 0x08, 0x00, "ECS_P4 Disc" ) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00)
+ PORT_CONFSETTING( 0x00, "Digital" )
+ PORT_CONFSETTING( 0x08, "Analog" )
+
+ PORT_START("CNTRLSEL")
+ PORT_CONFNAME( 0x0F, 0x02, "ECS Controller")
+ PORT_CONFSETTING( 0x00, "Gamepads" )
+ PORT_CONFSETTING( 0x01, "Piano" )
+ PORT_CONFSETTING( 0x02, "Keyboard" )
+INPUT_PORTS_END
+
+ioport_constructor intv_ecs_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( intv_ecs );
+}
+
+
+/*-------------------------------------------------
+ Paged ROM handling
+ -------------------------------------------------*/
+
+READ16_MEMBER(intv_ecs_device::read_rom20)
+{
+ if (m_bank_base[2])
+ return INTV_ROM16_READ(offset + 0x2000);
+ else
+ return 0xffff;
+}
+
+READ16_MEMBER(intv_ecs_device::read_rom70)
+{
+ if (m_bank_base[7])
+ return 0xffff;
+ else
+ return INTV_ROM16_READ(offset + 0x7000);
+}
+
+READ16_MEMBER(intv_ecs_device::read_rome0)
+{
+ if (m_bank_base[14])
+ return INTV_ROM16_READ(offset + 0xe000);
+ else // if WSMLB is loaded, it shall go here, otherwise 0xffff
+ return m_subslot->read_rome0(space, offset, mem_mask);
+}
+
+READ16_MEMBER(intv_ecs_device::read_romf0)
+{
+ // only WSMLB should come here with bank_base = 1
+ if (m_bank_base[15])
+ return m_subslot->read_romf0(space, offset + 0x1000, mem_mask);
+ else
+ return m_subslot->read_romf0(space, offset, mem_mask);
+}
+
+
+/*-------------------------------------------------
+ read_audio
+ -------------------------------------------------*/
+
+READ16_MEMBER(intv_ecs_device::read_ay)
+{
+ if (ACCESSING_BITS_0_7)
+ return m_snd->read(space, offset, mem_mask);
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ write_audio
+ -------------------------------------------------*/
+
+WRITE16_MEMBER(intv_ecs_device::write_ay)
+{
+ if (ACCESSING_BITS_0_7)
+ return m_snd->write(space, offset, data, mem_mask);
+}
+
diff --git a/src/emu/bus/intv/ecs.h b/src/emu/bus/intv/ecs.h
new file mode 100644
index 00000000000..6db3609c7ce
--- /dev/null
+++ b/src/emu/bus/intv/ecs.h
@@ -0,0 +1,145 @@
+#ifndef __INTV_ECS_H
+#define __INTV_ECS_H
+
+#include "slot.h"
+#include "rom.h"
+#include "sound/ay8910.h"
+
+
+
+// ======================> intv_ecs_device
+
+class intv_ecs_device : public intv_rom_device
+{
+public:
+ // construction/destruction
+ intv_ecs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ // reading and writing
+
+ // actual ECS accesses
+ // paged ROMs
+ virtual DECLARE_READ16_MEMBER(read_rom20);
+ virtual DECLARE_READ16_MEMBER(read_rom70);
+ virtual DECLARE_READ16_MEMBER(read_rome0);
+ virtual DECLARE_READ16_MEMBER(read_romf0);
+ // RAM
+ virtual DECLARE_READ16_MEMBER(read_ram) { return (int)m_ram[offset & (m_ram.count() - 1)]; }
+ virtual DECLARE_WRITE16_MEMBER(write_ram) { m_ram[offset & (m_ram.count() - 1)] = data & 0xff; }
+ // AY8914
+ virtual DECLARE_READ16_MEMBER(read_ay);
+ virtual DECLARE_WRITE16_MEMBER(write_ay);
+ DECLARE_READ8_MEMBER(ay_porta_r);
+ DECLARE_READ8_MEMBER(ay_portb_r);
+ DECLARE_WRITE8_MEMBER(ay_porta_w);
+
+ // passthru accesses
+ virtual DECLARE_READ16_MEMBER(read_rom04) { return m_subslot->read_rom04(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_rom40) { return m_subslot->read_rom40(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_rom48) { return m_subslot->read_rom48(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_rom50) { return m_subslot->read_rom50(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_rom60) { return m_subslot->read_rom60(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_rom80)
+ {
+ if (m_ram88_enabled && offset >= 0x800)
+ return m_subslot->read_ram(space, offset & 0x7ff, mem_mask);
+ else
+ return m_subslot->read_rom80(space, offset, mem_mask);
+ }
+ virtual DECLARE_READ16_MEMBER(read_rom90) { return m_subslot->read_rom90(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_roma0) { return m_subslot->read_roma0(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_romb0) { return m_subslot->read_romb0(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_romc0) { return m_subslot->read_romc0(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_romd0)
+ {
+ if (m_ramd0_enabled && offset < 0x800)
+ return m_subslot->read_ram(space, offset, mem_mask);
+ else
+ return m_subslot->read_romd0(space, offset, mem_mask);
+ }
+
+ // paged ROM banking
+ virtual DECLARE_WRITE16_MEMBER(write_rom20)
+ {
+ if (offset == 0xfff)
+ {
+ if (data == 0x2a50)
+ m_bank_base[2] = 0;
+ else if (data == 0x2a51)
+ m_bank_base[2] = 1;
+ }
+ }
+ virtual DECLARE_WRITE16_MEMBER(write_rom70)
+ {
+ if (offset == 0xfff)
+ {
+ if (data == 0x7a50)
+ m_bank_base[7] = 0;
+ else if (data == 0x7a51)
+ m_bank_base[7] = 1;
+ }
+ }
+ virtual DECLARE_WRITE16_MEMBER(write_rome0)
+ {
+ if (offset == 0xfff)
+ {
+ if (data == 0xea50)
+ m_bank_base[14] = 0;
+ else if (data == 0xea51)
+ m_bank_base[14] = 1;
+ }
+ }
+ virtual DECLARE_WRITE16_MEMBER(write_romf0)
+ {
+ if (offset == 0xfff)
+ {
+ if (data == 0xfa50)
+ m_bank_base[15] = 0;
+ else if (data == 0xfa51)
+ m_bank_base[15] = 1;
+ }
+ }
+ // RAM passthru write
+ virtual DECLARE_WRITE16_MEMBER(write_88) { if (m_ram88_enabled) m_subslot->write_ram(space, offset, data, mem_mask); }
+ virtual DECLARE_WRITE16_MEMBER(write_d0) { if (m_ramd0_enabled) m_subslot->write_ram(space, offset, data, mem_mask); }
+ // IntelliVoice passthru
+ virtual DECLARE_READ16_MEMBER(read_speech) { if (m_voice_enabled) return m_subslot->read_speech(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_WRITE16_MEMBER(write_speech) { if (m_voice_enabled) m_subslot->write_speech(space, offset, data, mem_mask); }
+
+ virtual void late_subslot_setup();
+
+ UINT8 intv_control_r(int hand);
+
+private:
+
+ required_device<ay8914_device> m_snd;
+ required_device<intv_cart_slot_device> m_subslot;
+ required_ioport_array<7> m_keybd;
+ required_ioport_array<7> m_synth;
+ required_ioport m_cntrlsel;
+ required_ioport m_options;
+ required_ioport_array<2> m_keypad;
+ required_ioport_array<2> m_disc;
+ required_ioport_array<2> m_discx;
+ required_ioport_array<2> m_discy;
+
+ int m_bank_base[0x10];
+ UINT8 m_psg_porta;
+ bool m_voice_enabled, m_ramd0_enabled, m_ram88_enabled;
+};
+
+
+
+
+
+// device type definition
+extern const device_type INTV_ROM_ECS;
+
+#endif
diff --git a/src/emu/bus/intv/rom.c b/src/emu/bus/intv/rom.c
new file mode 100644
index 00000000000..6bc190f4a83
--- /dev/null
+++ b/src/emu/bus/intv/rom.c
@@ -0,0 +1,50 @@
+/***********************************************************************************************************
+
+
+ Mattel Intellivision cart emulation
+
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "rom.h"
+
+
+//-------------------------------------------------
+// intv_rom_device - constructor
+//-------------------------------------------------
+
+const device_type INTV_ROM_STD = &device_creator<intv_rom_device>;
+const device_type INTV_ROM_RAM = &device_creator<intv_ram_device>;
+const device_type INTV_ROM_GFACT = &device_creator<intv_gfact_device>;
+const device_type INTV_ROM_WSMLB = &device_creator<intv_wsmlb_device>;
+
+
+intv_rom_device::intv_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
+ : device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_intv_cart_interface( mconfig, *this )
+{
+}
+
+intv_rom_device::intv_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, INTV_ROM_STD, "Intellivision Standard Carts", tag, owner, clock, "intv_rom", __FILE__),
+ device_intv_cart_interface( mconfig, *this )
+{
+}
+
+intv_ram_device::intv_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : intv_rom_device(mconfig, INTV_ROM_RAM, "Intellivision Carts w/RAM", tag, owner, clock, "intv_ram", __FILE__)
+{
+}
+
+intv_gfact_device::intv_gfact_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : intv_rom_device(mconfig, INTV_ROM_GFACT, "Intellivision Game Factory Cart", tag, owner, clock, "intv_gfact", __FILE__)
+{
+}
+
+intv_wsmlb_device::intv_wsmlb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : intv_rom_device(mconfig, INTV_ROM_WSMLB, "Intellivision World Series Baseball Cart", tag, owner, clock, "intv_wsmlb", __FILE__)
+{
+}
+
diff --git a/src/emu/bus/intv/rom.h b/src/emu/bus/intv/rom.h
new file mode 100644
index 00000000000..2eb13cc5c76
--- /dev/null
+++ b/src/emu/bus/intv/rom.h
@@ -0,0 +1,82 @@
+#ifndef __INTV_ROM_H
+#define __INTV_ROM_H
+
+#include "slot.h"
+
+
+// ======================> intv_rom_device
+
+class intv_rom_device : public device_t,
+ public device_intv_cart_interface
+{
+public:
+ // construction/destruction
+ intv_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+ intv_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // reading and writing
+ virtual DECLARE_READ16_MEMBER(read_rom04) { return INTV_ROM16_READ(offset + 0x0400); }
+ virtual DECLARE_READ16_MEMBER(read_rom20) { return INTV_ROM16_READ(offset + 0x2000); }
+ virtual DECLARE_READ16_MEMBER(read_rom40) { return INTV_ROM16_READ(offset + 0x4000); }
+ virtual DECLARE_READ16_MEMBER(read_rom48) { return INTV_ROM16_READ(offset + 0x4800); }
+ virtual DECLARE_READ16_MEMBER(read_rom50) { return INTV_ROM16_READ(offset + 0x5000); }
+ virtual DECLARE_READ16_MEMBER(read_rom60) { return INTV_ROM16_READ(offset + 0x6000); }
+ virtual DECLARE_READ16_MEMBER(read_rom70) { return INTV_ROM16_READ(offset + 0x7000); }
+ virtual DECLARE_READ16_MEMBER(read_rom80) { return INTV_ROM16_READ(offset + 0x8000); }
+ virtual DECLARE_READ16_MEMBER(read_rom90) { return INTV_ROM16_READ(offset + 0x9000); }
+ virtual DECLARE_READ16_MEMBER(read_roma0) { return INTV_ROM16_READ(offset + 0xa000); }
+ virtual DECLARE_READ16_MEMBER(read_romb0) { return INTV_ROM16_READ(offset + 0xb000); }
+ virtual DECLARE_READ16_MEMBER(read_romc0) { return INTV_ROM16_READ(offset + 0xc000); }
+ virtual DECLARE_READ16_MEMBER(read_romd0) { return INTV_ROM16_READ(offset + 0xd000); }
+ virtual DECLARE_READ16_MEMBER(read_rome0) { return INTV_ROM16_READ(offset + 0xe000); }
+ virtual DECLARE_READ16_MEMBER(read_romf0) { return INTV_ROM16_READ(offset + 0xf000); }
+
+ // device-level overrides
+ virtual void device_start() {}
+ virtual void device_reset() {}
+};
+
+// ======================> intv_ram_device
+
+class intv_ram_device : public intv_rom_device
+{
+public:
+ // construction/destruction
+ intv_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // reading and writing
+ virtual DECLARE_READ16_MEMBER(read_ram) { return (int)m_ram[offset & (m_ram.count() - 1)]; }
+ virtual DECLARE_WRITE16_MEMBER(write_ram) { m_ram[offset & (m_ram.count() - 1)] = data & 0xff; }
+};
+
+// ======================> intv_gfact_device
+
+class intv_gfact_device : public intv_rom_device
+{
+public:
+ // construction/destruction
+ intv_gfact_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // reading and writing
+ virtual DECLARE_READ16_MEMBER(read_ram) { return (int)m_ram[offset & (m_ram.count() - 1)]; }
+ virtual DECLARE_WRITE16_MEMBER(write_ram) { m_ram[offset & (m_ram.count() - 1)] = data & 0xff; }
+};
+
+// ======================> intv_wsmlb_device
+
+class intv_wsmlb_device : public intv_rom_device
+{
+public:
+ // construction/destruction
+ intv_wsmlb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+
+// device type definition
+extern const device_type INTV_ROM_STD;
+extern const device_type INTV_ROM_RAM;
+extern const device_type INTV_ROM_GFACT;
+extern const device_type INTV_ROM_WSMLB;
+
+#endif
diff --git a/src/emu/bus/intv/slot.c b/src/emu/bus/intv/slot.c
new file mode 100644
index 00000000000..df50465b1c0
--- /dev/null
+++ b/src/emu/bus/intv/slot.c
@@ -0,0 +1,572 @@
+/***********************************************************************************************************
+
+ Mattel Intellivision cart emulation
+ (through slot devices)
+
+
+ This is a strange beast, because INTV carts had potentially access to
+ a *LOT* of memory ranges!
+ Quoting Joe Zbiciak's documentation for his emu (jzIntv):
+
+
+ The Intellivision leaves many addresses available to cartridges. However,
+ several address ranges come with caveats, such as interactions with other
+ devices in the system, or incompatibilities with various peripherals.
+
+ Below is a summary.
+
+ ADDRESSES NOTES
+ -------------- --------------------------------------------------------------
+ $0400 - $04FF RAM/ROM ok on all but Intellivision 2.
+ $0500 - $06FF RAM/ROM ok.
+ $0700 - $0CFF RAM/ROM ok if no Intellivoice.
+ $0D00 - $0FFF RAM/ROM ok.
+ $2000 - $2FFF RAM/ROM ok if no ECS.
+ $4000 - $47FF RAM/ROM ok if no ECS.
+ $4800 ROM ok. RAM ok only if boot ROM at $7000.
+ $4801 - $4FFF RAM/ROM ok.
+ $5000 - $5014 ROM ok. RAM ok only if boot ROM at $7000 or $4800.
+ $5015 - $6FFF RAM/ROM ok.
+ $7000 ROM ok if no ECS. RAM at $7000 confuses EXEC boot sequence.
+ $7001 - $77FF RAM/ROM ok if no ECS.
+ $7800 - $7FFF ROM ok if no ECS. Do not map RAM here due to GRAM alias.
+ $8000 - $8FFF RAM/ROM ok. Avoid STIC alias at $8000 - $803F.
+ $9000 - $B7FF RAM/ROM ok.
+ $B800 - $BFFF ROM ok. Do not map RAM here due to GRAM alias.
+ $C000 - $CFFF RAM/ROM ok. Avoid STIC alias at $C000 - $C03F.
+ $D000 - $DFFF RAM/ROM ok.
+ $E000 - $EFFF RAM/ROM ok if no ECS.
+ $F000 - $F7FF RAM/ROM ok.
+ $F800 - $FFFF ROM ok. Do not map RAM here due to GRAM alias.
+
+
+ We handle this, by always creating a 0x10000 wide ROM region to load the
+ cart image and exposing the following (long list of) read handlers:
+ read_rom04
+ read_rom20
+ read_rom40
+ read_rom48
+ read_rom50
+ read_rom60
+ read_rom70
+ read_rom80
+ read_rom90
+ read_roma0
+ read_romb0
+ read_romc0
+ read_romd0
+ read_rome0
+ read_romf0
+ Each pcb types will then use the correct ones for its wiring setup.
+
+ The BIN+CFG format introduced by INTVPC emulator includes metadata about where to
+ load ROM into memory in the CFG file, but we don't support it (because we don't parse
+ the CFG at all) and we rely instead on the intv.hsi metadata for fullpath loading of
+ these.
+ Alternatively, we support the .ROM format used by jzIntv.
+
+
+ TODO:
+ - Convert also the keyboard component to be a passthru slot device
+ - Merge some of the ROM accessor above, once it is clear which ones can be merged
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "slot.h"
+#include "hashfile.h"
+
+#define INTELLIVOICE_MASK 0x02
+#define ECS_MASK 0x01
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type INTV_CART_SLOT = &device_creator<intv_cart_slot_device>;
+
+//**************************************************************************
+// Intellivision Cartridges Interface
+//**************************************************************************
+
+//-------------------------------------------------
+// device_intv_cart_interface - constructor
+//-------------------------------------------------
+
+device_intv_cart_interface::device_intv_cart_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig, device),
+ m_rom(NULL),
+ m_rom_size(0)
+{
+}
+
+
+//-------------------------------------------------
+// ~device_intv_cart_interface - destructor
+//-------------------------------------------------
+
+device_intv_cart_interface::~device_intv_cart_interface()
+{
+}
+
+//-------------------------------------------------
+// rom_alloc - alloc the space for the cart
+//-------------------------------------------------
+
+void device_intv_cart_interface::rom_alloc(UINT32 size, const char *tag)
+{
+ if (m_rom == NULL)
+ {
+ astring tempstring(tag);
+ tempstring.cat(INTVSLOT_ROM_REGION_TAG);
+ m_rom = device().machine().memory().region_alloc(tempstring, size, 1, ENDIANNESS_LITTLE)->base();
+ memset(m_rom, 0xff, size);
+ m_rom_size = size;
+ }
+}
+
+
+//-------------------------------------------------
+// ram_alloc - alloc the space for the ram
+//-------------------------------------------------
+
+void device_intv_cart_interface::ram_alloc(UINT32 size)
+{
+ m_ram.resize(size);
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// intv_cart_slot_device - constructor
+//-------------------------------------------------
+intv_cart_slot_device::intv_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, INTV_CART_SLOT, "Intellivision Cartridge Slot", tag, owner, clock, "intv_cart_slot", __FILE__),
+ device_image_interface(mconfig, *this),
+ device_slot_interface(mconfig, *this),
+ m_type(INTV_STD)
+{
+}
+
+
+//-------------------------------------------------
+// intv_cart_slot_device - destructor
+//-------------------------------------------------
+
+intv_cart_slot_device::~intv_cart_slot_device()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void intv_cart_slot_device::device_start()
+{
+ m_cart = dynamic_cast<device_intv_cart_interface *>(get_card_device());
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void intv_cart_slot_device::device_config_complete()
+{
+ // set brief and instance name
+ update_names();
+}
+
+
+//-------------------------------------------------
+// INTV PCB
+//-------------------------------------------------
+
+struct intv_slot
+{
+ int pcb_id;
+ const char *slot_option;
+};
+
+// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it
+static const intv_slot slot_list[] =
+{
+ { INTV_STD, "intv_rom" },
+ { INTV_RAM, "intv_ram" },
+ { INTV_GFACT, "intv_gfact" },
+ { INTV_WSMLB, "intv_wsmlb" },
+ { INTV_VOICE, "intv_voice" },
+ { INTV_ECS, "intv_ecs" },
+ { INTV_KEYCOMP, "intv_keycomp" }
+};
+
+static int intv_get_pcb_id(const char *slot)
+{
+ for (int i = 0; i < ARRAY_LENGTH(slot_list); i++)
+ {
+ if (!core_stricmp(slot_list[i].slot_option, slot))
+ return slot_list[i].pcb_id;
+ }
+
+ return 0;
+}
+
+#if 1
+static const char *intv_get_slot(int type)
+{
+ for (int i = 0; i < ARRAY_LENGTH(slot_list); i++)
+ {
+ if (slot_list[i].pcb_id == type)
+ return slot_list[i].slot_option;
+ }
+
+ return "intv_rom";
+}
+#endif
+
+/*-------------------------------------------------
+ call load
+ -------------------------------------------------*/
+
+int intv_cart_slot_device::load_fullpath()
+{
+ UINT8 temp;
+ UINT8 num_segments;
+ UINT8 start_seg;
+ UINT8 end_seg;
+
+ UINT32 current_address;
+ UINT32 end_address;
+
+ UINT8 high_byte;
+ UINT8 low_byte;
+
+ UINT8 *ROM;
+ const char *file_type = filetype();
+
+ /* if it is in .rom format, we enter here */
+ if (!core_stricmp (file_type, "rom"))
+ {
+ // header
+ fread(&temp, 1);
+ if (temp != 0xa8)
+ return IMAGE_INIT_FAIL;
+
+ fread(&num_segments, 1);
+
+ fread(&temp, 1);
+ if (temp != (num_segments ^ 0xff))
+ return IMAGE_INIT_FAIL;
+
+ m_cart->rom_alloc(0x10000, tag());
+ ROM = (UINT8 *)m_cart->get_rom_base();
+
+ for (int i = 0; i < num_segments; i++)
+ {
+ fread(&start_seg, 1);
+ current_address = start_seg * 0x100;
+
+ fread(&end_seg, 1);
+ end_address = end_seg * 0x100 + 0xff;
+
+ while (current_address <= end_address)
+ {
+ fread(&low_byte, 1);
+ ROM[(current_address << 1) + 1] = low_byte;
+ fread(&high_byte, 1);
+ ROM[current_address << 1] = high_byte;
+ current_address++;
+ }
+
+ // Here we should calculate and compare the CRC16...
+ fread(&temp, 1);
+ fread(&temp, 1);
+ }
+
+ // Access tables and fine address restriction tables are not supported ATM
+ for (int i = 0; i < (16 + 32 + 2); i++)
+ {
+ fread(&temp, 1);
+ }
+ return IMAGE_INIT_PASS;
+ }
+ /* otherwise, we load it as a .bin file, using extrainfo from intv.hsi in place of .cfg */
+ else
+ {
+ // This code is a blatant hack, due to impossibility to load a separate .cfg file in MESS.
+ // It shall be eventually replaced by the .xml loading
+
+ // extrainfo format
+ // 1. mapper number (to deal with bankswitch). no bankswitch is mapper 0 (most games).
+ // 2.->5. current images have at most 4 chunks of data. we store here block size and location to load
+ // (value & 0xf0) >> 4 is the location / 0x1000
+ // (value & 0x0f) is the size / 0x800
+ // 6. some images have a ram chunk. as above we store location and size in 8 bits
+ // 7. extra = 1 ECS, 2 Intellivoice
+ int start, size;
+ int mapper, rom[5], ram, extra;
+ astring extrainfo;
+
+ m_cart->rom_alloc(0x10000, tag());
+ ROM = (UINT8 *)m_cart->get_rom_base();
+
+ if (!hashfile_extrainfo(*this, extrainfo))
+ {
+ // If no extrainfo, we assume a single 0x2000 chunk at 0x5000
+ for (int i = 0; i < 0x2000; i++ )
+ {
+ fread(&low_byte, 1);
+ ROM[((0x5000 + i) << 1) + 1] = low_byte;
+ fread(&high_byte, 1);
+ ROM[(0x5000 + i) << 1] = high_byte;
+ }
+ }
+ else
+ {
+ sscanf(extrainfo.cstr() ,"%d %d %d %d %d %d %d", &mapper, &rom[0], &rom[1], &rom[2],
+ &rom[3], &ram, &extra);
+ //printf("extrainfo: %d %d %d %d %d %d %d \n", mapper, rom[0], rom[1], rom[2], rom[3], ram, extra);
+
+ if (mapper)
+ logerror("Bankswitch not yet implemented!\n");
+
+ if (ram)
+ {
+ start = ((ram & 0xf0) >> 4) * 0x1000;
+ size = (ram & 0x0f) * 0x800;
+
+ if (start == 0xd000 && size == 0x800)
+ {
+ m_type = INTV_RAM;
+ m_cart->ram_alloc(0x800);
+ }
+ else if (start == 0x8800 && size == 0x800)
+ {
+ m_type = INTV_GFACT;
+ m_cart->ram_alloc(0x800);
+ }
+ else
+ printf("Unrecognized RAM setup [Start 0x%X - End 0x%X]. Please contact MESSdevs.\n", start, start + size);
+ }
+ if (extra & INTELLIVOICE_MASK)
+ {
+ printf("WARNING: This game requires emulation of the IntelliVoice module.\n");
+ }
+
+ if (extra & ECS_MASK)
+ {
+ printf("WARNING: This game requires emulation of the ECS module.\n");
+ }
+
+ for (int j = 0; j < 4; j++)
+ {
+ start = ((rom[j] & 0xf0) >> 4) * 0x1000;
+ size = (rom[j] & 0x0f) * 0x800;
+
+ // some cart has to be loaded to 0x4800, but none of the available ones goes to 0x4000.
+ // Hence, we use 0x04 << 4 in extrainfo (to reduce the stored values) and fix the value here.
+ if (start == 0x4000) start += 0x800;
+
+// logerror("step %d: %d %d \n", j, start / 0x1000, size / 0x1000);
+
+ for (int i = 0; i < size; i++)
+ {
+ fread(&low_byte, 1);
+ ROM[((start + i) << 1) + 1] = low_byte;
+ fread(&high_byte, 1);
+ ROM[(start + i) << 1] = high_byte;
+ }
+ }
+ }
+
+ return IMAGE_INIT_PASS;
+ }
+}
+
+bool intv_cart_slot_device::call_load()
+{
+ if (m_cart)
+ {
+ if (software_entry() == NULL)
+ return load_fullpath();
+ else
+ {
+ UINT16 offset[] = { 0x400, 0x2000, 0x4000, 0x4800, 0x5000, 0x6000, 0x7000, 0x8000, 0x9000, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000};
+ const char* region_name[] = {"0400", "2000", "4000", "4800", "5000", "6000", "7000", "8000", "9000", "A000", "B000", "C000", "D000", "E000", "F000"};
+ const char *pcb_name = get_feature("slot");
+ bool extra_bank = false;
+
+ if (pcb_name)
+ m_type = intv_get_pcb_id(pcb_name);
+
+ // these two carts have paged roms, which does not work well with our 0x10000 rom region
+ // so if we are loading one of these, we allocate additional 0x2000 bytes for the paged bank
+ if (m_type == INTV_WSMLB)
+ extra_bank = true;
+
+ UINT32 size = 0;
+ UINT16 address = 0;
+ UINT8 *ROM, *region;
+
+ m_cart->rom_alloc(extra_bank ? 0x22000 : 0x20000, tag());
+ ROM = m_cart->get_rom_base();
+
+ for (int i = 0; i < 15; i++)
+ {
+ address = offset[i];
+ size = get_software_region_length(region_name[i]);
+ if (size)
+ {
+ region = get_software_region(region_name[i]);
+
+ for (int j = 0; j < size / 2; j++)
+ {
+ ROM[((address + j) << 1) + 1] = region[2 * j];
+ ROM[(address + j) << 1] = region[2 * j + 1];
+ }
+ }
+ }
+
+ if (m_type == INTV_RAM || m_type == INTV_GFACT || m_type == INTV_ECS)
+ m_cart->ram_alloc(get_software_region_length("ram"));
+
+ //printf("Type: %s\n", intv_get_slot(m_type));
+ return IMAGE_INIT_PASS;
+ }
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+
+/*-------------------------------------------------
+ call softlist load
+ -------------------------------------------------*/
+
+bool intv_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry)
+{
+ load_software_part_region(*this, swlist, swname, start_entry);
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ get default card software
+ -------------------------------------------------*/
+
+void intv_cart_slot_device::get_default_card_software(astring &result)
+{
+ if (open_image_file(mconfig().options()))
+ {
+ const char *slot_string = "intv_rom";
+ UINT32 len = core_fsize(m_file);
+ dynamic_buffer rom(len);
+ int type = INTV_STD;
+
+ core_fread(m_file, rom, len);
+
+ if (rom[0] == 0xa8 && (rom[1] == rom[2] ^ 0xff ))
+ {
+ // it's .ROM file, so that we don't have currently any way to distinguish RAM-equipped carts
+ }
+ else
+ {
+ // assume it's .BIN and try to use .hsi file to determine type (just RAM)
+ int start;
+ int mapper, rom[5], ram, extra;
+ astring extrainfo;
+
+ if (hashfile_extrainfo(*this, extrainfo))
+ {
+ sscanf(extrainfo.cstr() ,"%d %d %d %d %d %d %d", &mapper, &rom[0], &rom[1], &rom[2],
+ &rom[3], &ram, &extra);
+
+ if (ram)
+ {
+ start = ((ram & 0xf0) >> 4) * 0x1000;
+ if (start == 0xd000)
+ type = INTV_RAM;
+ if (start == 0x8800)
+ type = INTV_GFACT;
+ }
+ }
+
+ }
+
+ slot_string = intv_get_slot(type);
+
+ //printf("type: %s\n", slot_string);
+ clear();
+
+ result.cpy(slot_string);
+ return;
+ }
+ software_get_default_slot(result, "intv_rom");
+}
+
+/*-------------------------------------------------
+ read_ay
+ -------------------------------------------------*/
+
+READ16_MEMBER(intv_cart_slot_device::read_ay)
+{
+ if (m_cart)
+ return m_cart->read_ay(space, offset, mem_mask);
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ write_ay
+ -------------------------------------------------*/
+
+WRITE16_MEMBER(intv_cart_slot_device::write_ay)
+{
+ if (m_cart)
+ m_cart->write_ay(space, offset, data, mem_mask);
+}
+
+/*-------------------------------------------------
+ read_speech
+ -------------------------------------------------*/
+
+READ16_MEMBER(intv_cart_slot_device::read_speech)
+{
+ if (m_cart)
+ return m_cart->read_speech(space, offset, mem_mask);
+ else
+ return 0xffff;
+}
+
+/*-------------------------------------------------
+ write_speech
+ -------------------------------------------------*/
+
+WRITE16_MEMBER(intv_cart_slot_device::write_speech)
+{
+ if (m_cart)
+ m_cart->write_speech(space, offset, data, mem_mask);
+}
+
+
+
+#include "bus/intv/rom.h"
+#include "bus/intv/ecs.h"
+//#include "bus/intv/keycomp.h"
+#include "bus/intv/voice.h"
+
+SLOT_INTERFACE_START(intv_cart)
+ SLOT_INTERFACE_INTERNAL("intv_rom", INTV_ROM_STD)
+ SLOT_INTERFACE_INTERNAL("intv_ram", INTV_ROM_RAM)
+ SLOT_INTERFACE_INTERNAL("intv_gfact", INTV_ROM_GFACT)
+ SLOT_INTERFACE_INTERNAL("intv_wsmlb", INTV_ROM_WSMLB)
+ SLOT_INTERFACE_INTERNAL("intv_voice", INTV_ROM_VOICE)
+ SLOT_INTERFACE_INTERNAL("intv_ecs", INTV_ROM_ECS)
+// SLOT_INTERFACE_INTERNAL("intv_keycomp", INTV_ROM_KEYCOMP)
+SLOT_INTERFACE_END
+
diff --git a/src/emu/bus/intv/slot.h b/src/emu/bus/intv/slot.h
new file mode 100644
index 00000000000..e14243f190f
--- /dev/null
+++ b/src/emu/bus/intv/slot.h
@@ -0,0 +1,184 @@
+#ifndef __INTV_SLOT_H
+#define __INTV_SLOT_H
+
+/***************************************************************************
+ TYPE DEFINITIONS
+ ***************************************************************************/
+
+
+/* PCB */
+enum
+{
+ INTV_STD = 0,
+ INTV_RAM,
+ INTV_GFACT, // has RAM too but at diff offset
+ INTV_WSMLB,
+ INTV_VOICE,
+ INTV_ECS,
+ INTV_KEYCOMP
+};
+
+
+#define INTV_ROM16_READ(addr) \
+ (UINT16) (m_rom[(addr) << 1] | (m_rom[((addr) << 1) + 1] << 8))
+
+
+// ======================> device_intv_cart_interface
+
+class device_intv_cart_interface : public device_slot_card_interface
+{
+public:
+ // construction/destruction
+ device_intv_cart_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_intv_cart_interface();
+
+ // reading and writing
+ virtual DECLARE_READ16_MEMBER(read_rom04) { return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom20) { return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom40) { return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom48) { return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom50) { return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom60) { return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom70) { return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom80) { return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom90) { return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_roma0) { return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_romb0) { return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_romc0) { return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_romd0) { return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rome0) { return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_romf0) { return 0xffff; }
+
+ virtual DECLARE_READ16_MEMBER(read_ram) { return 0xffff; }
+ virtual DECLARE_WRITE16_MEMBER(write_ram) {}
+
+ // Used by IntelliVoice & ECS
+ virtual DECLARE_READ16_MEMBER(read_ay) { return 0xffff; }
+ virtual DECLARE_WRITE16_MEMBER(write_ay) {}
+ virtual DECLARE_READ16_MEMBER(read_speech) { return 0xffff; }
+ virtual DECLARE_WRITE16_MEMBER(write_speech) {}
+ virtual DECLARE_WRITE16_MEMBER(write_d0) {}
+ virtual DECLARE_WRITE16_MEMBER(write_88) {}
+ virtual DECLARE_WRITE16_MEMBER(write_rom20) {}
+ virtual DECLARE_WRITE16_MEMBER(write_rom70) {}
+ virtual DECLARE_WRITE16_MEMBER(write_rome0) {}
+ virtual DECLARE_WRITE16_MEMBER(write_romf0) {}
+
+ void rom_alloc(UINT32 size, const char *tag);
+ void ram_alloc(UINT32 size);
+ UINT8* get_rom_base() { return m_rom; }
+ UINT8* get_ram_base() { return m_ram; }
+ UINT32 get_rom_size() { return m_rom_size; }
+ UINT32 get_ram_size() { return m_ram.count(); }
+
+ void save_ram() { device().save_item(NAME(m_ram)); }
+ virtual void late_subslot_setup() {}
+
+protected:
+ // internal state
+ UINT8 *m_rom;
+ UINT32 m_rom_size;
+ dynamic_buffer m_ram;
+};
+
+
+// ======================> intv_cart_slot_device
+
+class intv_cart_slot_device : public device_t,
+ public device_image_interface,
+ public device_slot_interface
+{
+public:
+ // construction/destruction
+ intv_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~intv_cart_slot_device();
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete();
+
+ // image-level overrides
+ virtual bool call_load();
+ virtual void call_unload() {}
+ virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry);
+
+ int get_type() { return m_type; }
+ int load_fullpath();
+
+ void save_ram() { if (m_cart && m_cart->get_ram_size()) m_cart->save_ram(); }
+
+ virtual iodevice_t image_type() const { return IO_CARTSLOT; }
+ virtual bool is_readable() const { return 1; }
+ virtual bool is_writeable() const { return 0; }
+ virtual bool is_creatable() const { return 0; }
+ virtual bool must_be_loaded() const { return 0; }
+ virtual bool is_reset_on_load() const { return 1; }
+ virtual const option_guide *create_option_guide() const { return NULL; }
+ virtual const char *image_interface() const { return "intv_cart"; }
+ virtual const char *file_extensions() const { return "bin,int,rom,itv"; }
+
+ // slot interface overrides
+ virtual void get_default_card_software(astring &result);
+
+ // reading and writing
+ virtual DECLARE_READ16_MEMBER(read_rom04) { if (m_cart) return m_cart->read_rom04(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom20) { if (m_cart) return m_cart->read_rom20(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom40) { if (m_cart) return m_cart->read_rom40(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom48) { if (m_cart) return m_cart->read_rom48(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom50) { if (m_cart) return m_cart->read_rom50(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom60) { if (m_cart) return m_cart->read_rom60(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom70) { if (m_cart) return m_cart->read_rom70(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom80) { if (m_cart) return m_cart->read_rom80(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rom90) { if (m_cart) return m_cart->read_rom90(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_roma0) { if (m_cart) return m_cart->read_roma0(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_romb0) { if (m_cart) return m_cart->read_romb0(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_romc0) { if (m_cart) return m_cart->read_romc0(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_romd0) { if (m_cart) return m_cart->read_romd0(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_rome0) { if (m_cart) return m_cart->read_rome0(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_READ16_MEMBER(read_romf0) { if (m_cart) return m_cart->read_romf0(space, offset, mem_mask); else return 0xffff; }
+
+ virtual DECLARE_READ16_MEMBER(read_ay);
+ virtual DECLARE_WRITE16_MEMBER(write_ay);
+ virtual DECLARE_READ16_MEMBER(read_speech);
+ virtual DECLARE_WRITE16_MEMBER(write_speech);
+ virtual DECLARE_READ16_MEMBER(read_ram) { if (m_cart) return m_cart->read_ram(space, offset, mem_mask); else return 0xffff; }
+ virtual DECLARE_WRITE16_MEMBER(write_ram) { if (m_cart) m_cart->write_ram(space, offset, data, mem_mask); }
+
+ virtual void late_subslot_setup() { if (m_cart) return m_cart->late_subslot_setup(); }
+
+ // these RAM accessors are needed to deal with IntelliVoice and ECS mounting RAM-equipped carts
+ virtual DECLARE_WRITE16_MEMBER(write_d0) { if (m_cart) m_cart->write_d0(space, offset, data, mem_mask); }
+ virtual DECLARE_WRITE16_MEMBER(write_88) { if (m_cart) m_cart->write_88(space, offset, data, mem_mask); }
+
+ // ECS paged roms need these
+ virtual DECLARE_WRITE16_MEMBER(write_rom20) { if (m_cart) m_cart->write_rom20(space, offset, data, mem_mask); }
+ virtual DECLARE_WRITE16_MEMBER(write_rom70) { if (m_cart) m_cart->write_rom70(space, offset, data, mem_mask); }
+ virtual DECLARE_WRITE16_MEMBER(write_rome0) { if (m_cart) m_cart->write_rome0(space, offset, data, mem_mask); }
+ virtual DECLARE_WRITE16_MEMBER(write_romf0) { if (m_cart) m_cart->write_romf0(space, offset, data, mem_mask); }
+
+//protected:
+
+ int m_type;
+ device_intv_cart_interface* m_cart;
+};
+
+
+
+// device type definition
+extern const device_type INTV_CART_SLOT;
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+ ***************************************************************************/
+
+#define INTVSLOT_ROM_REGION_TAG ":cart:rom"
+
+#define MCFG_INTV_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \
+ MCFG_DEVICE_ADD(_tag, INTV_CART_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \
+
+
+SLOT_INTERFACE_EXTERN(intv_cart);
+
+#endif
diff --git a/src/emu/bus/intv/voice.c b/src/emu/bus/intv/voice.c
new file mode 100644
index 00000000000..ac5bc8cdc5b
--- /dev/null
+++ b/src/emu/bus/intv/voice.c
@@ -0,0 +1,122 @@
+/***********************************************************************************************************
+
+
+ Mattel Intellivoice cart emulation
+
+ TODO:
+ - speech ROM shall be loaded from softlist
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "voice.h"
+
+
+//-------------------------------------------------
+// intv_voice_device - constructor
+//-------------------------------------------------
+
+const device_type INTV_ROM_VOICE = &device_creator<intv_voice_device>;
+
+intv_voice_device::intv_voice_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : intv_rom_device(mconfig, INTV_ROM_VOICE, "Intellivision Intellivoice Expansion", tag, owner, clock, "intv_voice", __FILE__),
+ m_speech(*this, "sp0256_speech"),
+ m_subslot(*this, "subslot"),
+ m_ramd0_enabled(false),
+ m_ram88_enabled(false)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void intv_voice_device::device_start()
+{
+}
+
+void intv_voice_device::late_subslot_setup()
+{
+ switch (m_subslot->get_type())
+ {
+ case INTV_RAM:
+ m_ramd0_enabled = true;
+ break;
+ case INTV_GFACT:
+ m_ram88_enabled = true;
+ break;
+ case INTV_VOICE:
+ printf("WARNING: You cannot connect serially multiple IntelliVoice units.\n");
+ printf("WARNING: Emulation will likely misbehave.\n");
+ break;
+ case INTV_ECS:
+ printf("WARNING: You cannot connect ECS to IntelliVoice in this manner.\n");
+ printf("WARNING: Emulation will likely misbehave.\n");
+ break;
+ case INTV_KEYCOMP:
+ printf("WARNING: You cannot connect the Keyboard component to the IntelliVoice unit.\n");
+ printf("WARNING: Emulation will likely misbehave.\n");
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( intellivoice )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( intellivoice )
+ MCFG_SPEAKER_STANDARD_MONO("mono_voice")
+
+ MCFG_SOUND_ADD("sp0256_speech", SP0256, 3120000)
+ /* The Intellivoice uses a speaker with its own volume control so the relative volumes to use are subjective */
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono_voice", 1.00)
+
+ MCFG_INTV_CARTRIDGE_ADD("subslot", intv_cart, NULL)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor intv_voice_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( intellivoice );
+}
+
+
+ROM_START( intellivoice )
+ ROM_REGION( 0x10000, "sp0256_speech", 0 )
+ /* SP0256-012 Speech chip w/2KiB mask rom */
+ ROM_LOAD( "sp0256-012.bin", 0x1000, 0x0800, CRC(0de7579d) SHA1(618563e512ff5665183664f52270fa9606c9d289) )
+ROM_END
+
+const rom_entry *intv_voice_device::device_rom_region() const
+{
+ return ROM_NAME( intellivoice );
+}
+
+/*-------------------------------------------------
+ read_audio
+ -------------------------------------------------*/
+
+READ16_MEMBER(intv_voice_device::read_speech)
+{
+ if (ACCESSING_BITS_0_7)
+ return m_speech->spb640_r(space, offset, mem_mask);
+ else
+ return 0xff;
+}
+
+/*-------------------------------------------------
+ write_audio
+ -------------------------------------------------*/
+
+WRITE16_MEMBER(intv_voice_device::write_speech)
+{
+ if (ACCESSING_BITS_0_7)
+ return m_speech->spb640_w(space, offset, data, mem_mask);
+}
diff --git a/src/emu/bus/intv/voice.h b/src/emu/bus/intv/voice.h
new file mode 100644
index 00000000000..9ba16aef358
--- /dev/null
+++ b/src/emu/bus/intv/voice.h
@@ -0,0 +1,76 @@
+#ifndef __INTV_VOICE_H
+#define __INTV_VOICE_H
+
+#include "slot.h"
+#include "rom.h"
+#include "sound/sp0256.h"
+
+
+// ======================> intv_voice_device
+
+class intv_voice_device : public intv_rom_device
+{
+public:
+ // construction/destruction
+ intv_voice_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ // reading and writing
+ // actual IntelliVoice access
+ virtual DECLARE_READ16_MEMBER(read_speech);
+ virtual DECLARE_WRITE16_MEMBER(write_speech);
+
+ // passthru access
+ virtual DECLARE_READ16_MEMBER(read_rom04) { return m_subslot->read_rom04(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_rom20) { return m_subslot->read_rom20(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_rom40) { return m_subslot->read_rom40(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_rom48) { return m_subslot->read_rom48(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_rom50) { return m_subslot->read_rom50(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_rom60) { return m_subslot->read_rom60(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_rom70) { return m_subslot->read_rom70(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_rom80)
+ {
+ if (m_ram88_enabled && offset >= 0x800)
+ return m_subslot->read_ram(space, offset & 0x7ff, mem_mask);
+ else
+ return m_subslot->read_rom80(space, offset, mem_mask);
+ }
+ virtual DECLARE_READ16_MEMBER(read_rom90) { return m_subslot->read_rom90(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_roma0) { return m_subslot->read_roma0(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_romb0) { return m_subslot->read_romb0(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_romc0) { return m_subslot->read_romc0(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_romd0)
+ {
+ if (m_ramd0_enabled && offset < 0x800)
+ return m_subslot->read_ram(space, offset, mem_mask);
+ else
+ return m_subslot->read_romd0(space, offset, mem_mask);
+ }
+ virtual DECLARE_READ16_MEMBER(read_rome0) { return m_subslot->read_rome0(space, offset, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_romf0) { return m_subslot->read_romf0(space, offset, mem_mask); }
+
+ // RAM passthru write
+ virtual DECLARE_WRITE16_MEMBER(write_88) { if (m_ram88_enabled) m_subslot->write_ram(space, offset, data, mem_mask); }
+ virtual DECLARE_WRITE16_MEMBER(write_d0) { if (m_ramd0_enabled) m_subslot->write_ram(space, offset, data, mem_mask); }
+ virtual DECLARE_READ16_MEMBER(read_ram) { return m_subslot->read_ram(space, offset, mem_mask); }
+ virtual DECLARE_WRITE16_MEMBER(write_ram) { m_subslot->write_ram(space, offset, data, mem_mask); }
+
+ virtual void late_subslot_setup();
+
+private:
+ required_device<sp0256_device> m_speech;
+ required_device<intv_cart_slot_device> m_subslot;
+ bool m_ramd0_enabled, m_ram88_enabled;
+};
+
+
+
+
+// device type definition
+extern const device_type INTV_ROM_VOICE;
+
+#endif