Rewrote TMS6100 command handling, mrchalgr sound is now correct.

snread/snspell/etc still works fine, lantutor is still gibberish:(
This commit is contained in:
hap 2016-01-02 23:58:57 +01:00
parent 91e94bdad0
commit ddf09f292c
4 changed files with 257 additions and 179 deletions

View File

@ -1,93 +1,29 @@
// license:BSD-3-Clause
// copyright-holders:Couriersud
// copyright-holders:hap, Couriersud
/**********************************************************************************************
Texas Instruments TMS6100 Voice Synthesis Memory (VSM)
Written for MAME by Couriersud
References:
- TMS 6100 Voice Synthesis Memory Data Manual
- TMS 6125 Voice Synthesis Memory Data Manual
- Speak & Spell patent US4189779 for low-level documentation
- 1982 Mitsubishi Data Book (M58819S section)
Todo:
- implement CS
- implement clock pin(CLK) and gating(RCK) properly
- implement chip addressing (0-15 mask programmed)
TMS6100:
+-----------------+
VDD | 1 28 | NC
NC | 2 27 | NC
DATA/ADD1 | 3 26 | NC
DATA/ADD2 | 4 25 | NC
DATA/ADD4 | 5 24 | NC
DATA/ADD8 | 6 23 | NC
CLK | 7 22 | NC
NC | 8 21 | NC
NC | 9 20 | NC
M0 | 10 19 | NC
M1 | 11 18 | NC
NC | 12 17 | NC
/CS | 13 16 | NC
VSS | 14 15 | NC
+-----------------+
TMS6125:
+---------+
DATA/ADD1 | 1 16 | NC
DATA/ADD2 | 2 15 | NC
DATA/ADD4 | 3 14 | NC
RCK | 4 13 | NC
CLK | 5 12 | VDD
DATA/ADD8 | 6 11 | CS
NC | 7 10 | M1
M0 | 8 9 | VSS
+---------+
Mitsubishi M58819S EPROM Interface:
+-----------------+
AD0 | 1 40 | AD1
VDDl | 2 39 | AD2
VDD | 3 38 | AD3
A0 | 4 37 | NC
NC | 5 36 | AD4
NC | 6 35 | AD5
A1 | 7 34 | AD6
A2 | 8 33 | AD7
A3/Q | 9 32 | AD8
CLK | 10 31 | AD9
POW | 11 30 | AD10
SL | 12 29 | AD11
C0 | 13 28 | AD12
C1 | 14 27 | AD13
NC | 15 26 | D7
NC | 16 25 | NC
VSS | 17 24 | D6
D0 | 18 23 | D5
D1 | 19 22 | D4
D2 | 20 21 | D3
+-----------------+
The M58819S is used as an interface to external speech eproms.
Other than not having its ROM internal, it is a clone of TMS6100.
C0/C1 = command pins, equal to M0/M1
SL = PROM expansion input
POC = power-on clear (think reset)
TODO:
- implement clock pin(CLK) properly, xtal/timer
- command processing timing is not accurate, on the real chip it will take a few microseconds
- current implementation does not regard multi-chip configuration and pretends it is 1 chip,
this will work fine under normal circumstances since CS would be disabled on invalid address
- implement chip addressing (0-15 mask programmed, see above)
- M58819S pins SL(PROM expansion input), POC(reset)
***********************************************************************************************/
#include "tms6100.h"
#define VERBOSE (0)
#if VERBOSE
#define LOG(x) logerror x
#else
#define LOG(x)
#endif
#define TMS6100_READ_PENDING 0x01
#define TMS6100_NEXT_READ_IS_DUMMY 0x02
// device definitions
const device_type TMS6100 = &device_creator<tms6100_device>;
@ -95,7 +31,7 @@ tms6100_device::tms6100_device(const machine_config &mconfig, device_type type,
: device_t(mconfig, type, name, tag, owner, clock, shortname, source),
m_rom(*this, DEVICE_SELF),
m_reverse_bits(false),
m_4bit_read(false)
m_4bit_mode(false)
{
}
@ -103,7 +39,7 @@ tms6100_device::tms6100_device(const machine_config &mconfig, const char *tag, d
: device_t(mconfig, TMS6100, "TMS6100", tag, owner, clock, "tms6100", __FILE__),
m_rom(*this, DEVICE_SELF),
m_reverse_bits(false),
m_4bit_read(false)
m_4bit_mode(false)
{
}
@ -114,33 +50,43 @@ m58819_device::m58819_device(const machine_config &mconfig, const char *tag, dev
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void tms6100_device::device_start()
{
m_rommask = m_rom.bytes() - 1;
// zerofill
m_addr_bits = 0;
m_address = 0;
m_address_latch = 0;
m_loadptr = 0;
m_sa = 0;
m_count = 0;
m_prev_cmd = 0;
m_prev_m = 0;
m_add = 0;
m_data = 0;
m_m0 = 0;
m_m1 = 0;
m_state = 0;
m_data = 0;
m_tms_clock = 0;
m_cs = 1;
m_clk = 0;
m_rck = 0;
// save device variables
save_item(NAME(m_addr_bits));
// register for savestates
save_item(NAME(m_address));
save_item(NAME(m_address_latch));
save_item(NAME(m_loadptr));
save_item(NAME(m_sa));
save_item(NAME(m_count));
save_item(NAME(m_prev_cmd));
save_item(NAME(m_prev_m));
save_item(NAME(m_add));
save_item(NAME(m_data));
save_item(NAME(m_m0));
save_item(NAME(m_m1));
save_item(NAME(m_state));
save_item(NAME(m_data));
save_item(NAME(m_tms_clock));
save_item(NAME(m_cs));
save_item(NAME(m_clk));
save_item(NAME(m_rck));
}
void m58819_device::device_start()
@ -162,94 +108,153 @@ WRITE_LINE_MEMBER(tms6100_device::m1_w)
m_m1 = (state) ? 1 : 0;
}
WRITE_LINE_MEMBER(tms6100_device::cs_w)
{
// chip select pin
m_cs = (state) ? 1 : 0;
}
WRITE_LINE_MEMBER(tms6100_device::rck_w)
{
// gate/mask for clk
m_rck = (state) ? 1 : 0;
}
WRITE8_MEMBER(tms6100_device::addr_w)
{
m_addr_bits = data & 0xf;
m_add = data & 0xf;
}
READ8_MEMBER(tms6100_device::data_r)
{
return m_data;
return m_data & 0xf;
}
READ_LINE_MEMBER(tms6100_device::data_line_r)
{
// DATA/ADD8
return m_data;
return (m_data & 8) ? 1 : 0;
}
// CLK/RCK pin
WRITE_LINE_MEMBER(tms6100_device::romclock_w)
{
// process on falling edge
if (m_tms_clock && !state)
if (m_clk && !m_rck && !state)
{
switch (m_m1 << 1 | m_m0)
if (m_cs)
{
case 0x00:
// NOP in datasheet, not really ...
if (m_state & TMS6100_READ_PENDING)
{
if (m_state & TMS6100_NEXT_READ_IS_DUMMY)
{
LOG(("loaded address %08x\n", m_address_latch));
m_address = (m_address_latch << 3);
m_address_latch = 0;
m_loadptr = 0;
m_state &= ~TMS6100_NEXT_READ_IS_DUMMY;
}
else
{
// read bit(s) at address
UINT8 word = m_rom[m_address >> 3];
if (m_reverse_bits)
word = BITSWAP8(word,0,1,2,3,4,5,6,7);
// new command enabled on rising edge of m0/m1
UINT8 m = m_m1 << 1 | m_m0;
if ((m & ~m_prev_m & 1) || (m & ~m_prev_m & 2))
handle_command(m);
if (m_4bit_read)
{
m_data = word >> (m_address & 4) & 0xf;
m_address += 4;
}
else
{
m_data = word >> (m_address & 7) & 1;
m_address++;
m_prev_m = m;
}
}
m_state &= ~TMS6100_READ_PENDING;
}
break;
case 0x01:
// READ
m_state |= TMS6100_READ_PENDING;
break;
case 0x02:
// LOAD ADDRESS
m_state |= TMS6100_NEXT_READ_IS_DUMMY;
m_address_latch |= (m_addr_bits << m_loadptr);
LOG(("loaded address latch %08x\n", m_address_latch));
m_loadptr += 4;
break;
case 0x03:
// READ AND BRANCH
if (m_state & TMS6100_NEXT_READ_IS_DUMMY)
{
m_state |= TMS6100_READ_PENDING;
m_state &= ~TMS6100_NEXT_READ_IS_DUMMY; // clear - no dummy read according to datasheet
m_address = m_rom[m_address_latch] | (m_rom[m_address_latch+1] << 8);
m_address &= 0x3fff; // 14 bits
LOG(("loaded indirect address %04x\n", m_address));
m_address = (m_address << 3);
m_address_latch = 0;
m_loadptr = 0;
}
break;
}
}
m_tms_clock = state;
m_clk = (state) ? 1 : 0;
}
// m0/m1 commands
void tms6100_device::handle_command(UINT8 cmd)
{
enum
{
M_NOP = 0, M_TB, M_LA, M_RB
};
switch (cmd)
{
// TB: transfer bit (read)
case M_TB:
if (m_prev_cmd == M_LA)
{
// dummy read after LA
m_count = 0;
}
else
{
// load new data from rom
if (m_count == 0)
{
m_sa = m_rom[m_address & m_rommask];
// M58819S reads serial data reversed
if (m_reverse_bits)
m_sa = BITSWAP8(m_sa,0,1,2,3,4,5,6,7);
}
else
{
// or shift(rotate) right
m_sa = (m_sa >> 1) | (m_sa << 7 & 0x80);
}
// output to DATA pin(s)
if (!m_4bit_mode)
{
// 1-bit mode: SA0 to ADD8/DATA
m_data = m_sa << 3 & 8;
}
else
{
// 4-bit mode: SA0-3 or SA3-6(!) to DATA
if (m_count & 1)
m_data = m_sa >> 3 & 0xf;
else
m_data = m_sa & 0xf;
}
// 8 bits in 1-bit mode, otherwise 2 nybbles
m_count = (m_count + 1) & (m_4bit_mode ? 1 : 7);
// TB8
if (m_count == 0)
m_address++; // CS bits too
}
break;
// LA: load address
case M_LA:
if (m_prev_cmd == M_TB)
{
// start LA after TB
m_address = (m_address & ~0xf) | m_add;
m_count = 0;
}
else if (m_prev_cmd == M_LA)
{
// load consecutive address bits (including CS bits)
// the 8-step counter PLA is shared between LA and TB
if (m_count < 4)
{
const UINT8 shift = 4 * (m_count+1);
m_address = (m_address & ~(0xf << shift)) | (m_add << shift);
}
m_count = (m_count + 1) & 7;
}
break;
// RB: read and branch
case M_RB:
// process RB after LA or TB8
if (m_prev_cmd == M_LA || (m_prev_cmd == M_TB && m_count == 0))
{
m_count = 0;
// load new address bits (14 bits on TMS6100)
UINT16 rb = m_rom[m_address & m_rommask];
m_address++;
rb |= (m_rom[m_address & m_rommask] << 8);
m_address = (m_address & ~0x3fff) | (rb & 0x3fff);
}
break;
default:
break;
}
m_prev_cmd = cmd;
}

View File

@ -1,9 +1,10 @@
// license:BSD-3-Clause
// copyright-holders:Couriersud
// copyright-holders:hap, Couriersud
/**********************************************************************************************
/* TMS 6100 memory controller */
Texas Instruments TMS6100 Voice Synthesis Memory (VSM)
#pragma once
***********************************************************************************************/
#ifndef __TMS6100_H__
#define __TMS6100_H__
@ -11,7 +12,6 @@
#include "emu.h"
//**************************************************************************
// INTERFACE CONFIGURATION MACROS
//**************************************************************************
@ -23,6 +23,69 @@
tms6100_device::enable_4bit_mode(*device);
// pinout reference
/*
TMS6100:
+-----------------+
VDD | 1 28 | NC
NC | 2 27 | NC
DATA/ADD1 | 3 26 | NC
DATA/ADD2 | 4 25 | NC
DATA/ADD4 | 5 24 | NC
DATA/ADD8 | 6 23 | NC
CLK | 7 22 | NC
NC | 8 21 | NC
NC | 9 20 | NC
M0 | 10 19 | NC
M1 | 11 18 | NC
NC | 12 17 | NC
/CS | 13 16 | NC
VSS | 14 15 | NC
+-----------------+
TMS6125: two types known
+---------+ +---------+
DATA/ADD1 | 1 16 | NC DATA/ADD1 | 1 16 | NC
DATA/ADD2 | 2 15 | NC DATA/ADD2 | 2 15 | NC
DATA/ADD4 | 3 14 | NC DATA/ADD4 | 3 14 | NC
RCK | 4 13 | NC DATA/ADD8 | 4 13 | NC
CLK | 5 12 | VDD CLK | 5 12 | VDD
DATA/ADD8 | 6 11 | CS NC | 6 11 | /CS
NC | 7 10 | M1 NC | 7 10 | M1
M0 | 8 9 | VSS M0 | 8 9 | VSS
+---------+ +---------+
Mitsubishi M58819S EPROM Interface:
It is a clone of TMS6100, but external EPROM instead
+-----------------+
AD0 | 1 40 | AD1
VDDl | 2 39 | AD2
VDD | 3 38 | AD3
A0 | 4 37 | NC
NC | 5 36 | AD4
NC | 6 35 | AD5
A1 | 7 34 | AD6
A2 | 8 33 | AD7
A3/Q | 9 32 | AD8
CLK | 10 31 | AD9
POW | 11 30 | AD10
SL | 12 29 | AD11
C0 | 13 28 | AD12
C1 | 14 27 | AD13
NC | 15 26 | D7
NC | 16 25 | NC
VSS | 17 24 | D6
D0 | 18 23 | D5
D1 | 19 22 | D4
D2 | 20 21 | D3
+-----------------+
*/
//**************************************************************************
// TYPE DEFINITIONS
@ -34,10 +97,12 @@ public:
tms6100_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
tms6100_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);
static void enable_4bit_mode(device_t &device) { downcast<tms6100_device &>(device).m_4bit_read = true; }
static void enable_4bit_mode(device_t &device) { downcast<tms6100_device &>(device).m_4bit_mode = true; }
DECLARE_WRITE_LINE_MEMBER(m0_w);
DECLARE_WRITE_LINE_MEMBER(m1_w);
DECLARE_WRITE_LINE_MEMBER(rck_w);
DECLARE_WRITE_LINE_MEMBER(cs_w);
DECLARE_WRITE_LINE_MEMBER(romclock_w);
DECLARE_WRITE8_MEMBER(addr_w);
@ -48,22 +113,29 @@ protected:
// device-level overrides
virtual void device_start() override;
void handle_command(UINT8 cmd);
// internal state
required_region_ptr<UINT8> m_rom;
bool m_reverse_bits;
bool m_4bit_read;
UINT32 m_address;
UINT32 m_address_latch;
UINT8 m_loadptr;
bool m_4bit_mode;
UINT32 m_rommask;
UINT32 m_address; // internal address + chipselect
UINT8 m_sa; // romdata shift register
UINT8 m_count; // TB/LA counter (-> PLA)
UINT8 m_prev_cmd; // previous handled command
UINT8 m_prev_m; // previous valid m0/m1 state
UINT8 m_add; // ADD/DATA pins input
UINT8 m_data; // ADD/DATA pins output
int m_m0;
int m_m1;
UINT8 m_addr_bits;
int m_tms_clock;
UINT8 m_data;
UINT8 m_state;
int m_cs; // chipselect pin
int m_clk; // CLK pin
int m_rck; // RCK pin (mask/gate to CLK?)
};
extern const device_type TMS6100;
class m58819_device : public tms6100_device
{
@ -75,6 +147,8 @@ protected:
virtual void device_start() override;
};
extern const device_type TMS6100;
extern const device_type M58819;

View File

@ -1071,7 +1071,7 @@ ROM_START( snspell )
ROM_REGION( 1246, "maincpu:opla", 0 )
ROM_LOAD( "tms0270_tmc0271_output.pla", 0, 1246, CRC(9ebe12ab) SHA1(acb4e07ba26f2daca5f1c234885ac0371c7ce87f) )
ROM_REGION( 0xc000, "tms6100", ROMREGION_ERASEFF ) // 8000-bfff = space reserved for cartridge
ROM_REGION( 0x10000, "tms6100", ROMREGION_ERASEFF ) // 8000-bfff = space reserved for cartridge
ROM_LOAD( "tmc0351nl.vsm", 0x0000, 0x4000, CRC(beea3373) SHA1(8b0f7586d2f12c3d4a885fdb528cf23feffa1a3b) )
ROM_LOAD( "tmc0352nl.vsm", 0x4000, 0x4000, CRC(d51f0587) SHA1(ddaa484be1bba5fef46b481cafae517e4acaa8ed) )
ROM_END
@ -1087,7 +1087,7 @@ ROM_START( snspella )
ROM_REGION( 1246, "maincpu:opla", 0 )
ROM_LOAD( "tms0270_tmc0271_output.pla", 0, 1246, CRC(9ebe12ab) SHA1(acb4e07ba26f2daca5f1c234885ac0371c7ce87f) )
ROM_REGION( 0xc000, "tms6100", ROMREGION_ERASEFF ) // 8000-bfff = space reserved for cartridge
ROM_REGION( 0x10000, "tms6100", ROMREGION_ERASEFF ) // 8000-bfff = space reserved for cartridge
ROM_LOAD( "tmc0351n2l.vsm", 0x0000, 0x4000, CRC(2d03b292) SHA1(a3e9a365307ae936c7472f720a7a8240741531d6) )
ROM_LOAD( "tmc0352n2l.vsm", 0x4000, 0x4000, CRC(a6d56883) SHA1(eebf9c07f2f9001679dec06c2367d4a50596d04b) )
ROM_END
@ -1103,7 +1103,7 @@ ROM_START( snspellb )
ROM_REGION( 1246, "maincpu:opla", 0 )
ROM_LOAD( "tms0270_tmc0271_output.pla", 0, 1246, CRC(9ebe12ab) SHA1(acb4e07ba26f2daca5f1c234885ac0371c7ce87f) )
ROM_REGION( 0xc000, "tms6100", ROMREGION_ERASEFF ) // uses only 1 rom, 8000-bfff = space reserved for cartridge
ROM_REGION( 0x10000, "tms6100", ROMREGION_ERASEFF ) // uses only 1 rom, 8000-bfff = space reserved for cartridge
ROM_LOAD( "cd2350a.vsm", 0x0000, 0x4000, CRC(2adda742) SHA1(3f868ed8284b723c815a30343057e03467c043b5) )
ROM_END
@ -1118,7 +1118,7 @@ ROM_START( snspelluk )
ROM_REGION( 1246, "maincpu:opla", 0 )
ROM_LOAD( "tms0270_tmc0271_output.pla", 0, 1246, CRC(9ebe12ab) SHA1(acb4e07ba26f2daca5f1c234885ac0371c7ce87f) )
ROM_REGION( 0xc000, "tms6100", ROMREGION_ERASEFF ) // 8000-bfff = space reserved for cartridge
ROM_REGION( 0x10000, "tms6100", ROMREGION_ERASEFF ) // 8000-bfff = space reserved for cartridge
ROM_LOAD( "cd2303.vsm", 0x0000, 0x4000, CRC(0fae755c) SHA1(b68c3120a63a61db474feb5d71a6e5dd67910d80) )
ROM_LOAD( "cd2304.vsm", 0x4000, 0x4000, CRC(e2a270eb) SHA1(c13c95ad15f1923a4841f66504e0f22646e71d99) )
ROM_END
@ -1134,7 +1134,7 @@ ROM_START( snspelluka )
ROM_REGION( 1246, "maincpu:opla", 0 )
ROM_LOAD( "tms0270_tmc0271_output.pla", 0, 1246, CRC(9ebe12ab) SHA1(acb4e07ba26f2daca5f1c234885ac0371c7ce87f) )
ROM_REGION( 0xc000, "tms6100", ROMREGION_ERASEFF ) // uses only 1 rom, 8000-bfff = space reserved for cartridge
ROM_REGION( 0x10000, "tms6100", ROMREGION_ERASEFF ) // uses only 1 rom, 8000-bfff = space reserved for cartridge
ROM_LOAD( "cd62175.vsm", 0x0000, 0x4000, CRC(6e1063d4) SHA1(b5c66c51148c5921ecb8ffccd7a460ae639cdb68) )
ROM_END
@ -1149,7 +1149,7 @@ ROM_START( snspelljp )
ROM_REGION( 1246, "maincpu:opla", 0 )
ROM_LOAD( "tms0270_tmc0271_output.pla", 0, 1246, CRC(9ebe12ab) SHA1(acb4e07ba26f2daca5f1c234885ac0371c7ce87f) )
ROM_REGION( 0xc000, "tms6100", ROMREGION_ERASEFF ) // 8000-bfff = space reserved for cartridge
ROM_REGION( 0x10000, "tms6100", ROMREGION_ERASEFF ) // 8000-bfff = space reserved for cartridge
ROM_LOAD( "cd2321.vsm", 0x0000, 0x4000, CRC(ac010cce) SHA1(c0200d857b62be696248ac2d684a390c66ab0c31) )
ROM_LOAD( "cd2322.vsm", 0x4000, 0x4000, CRC(b6f4bba4) SHA1(65d686a9385b5ef3f080a5f47c6b2418bb9455b0) )
ROM_END
@ -1165,7 +1165,7 @@ ROM_START( snspellfr )
ROM_REGION( 1246, "maincpu:opla", 0 )
ROM_LOAD( "tms0270_tmc0271_output.pla", 0, 1246, BAD_DUMP CRC(9ebe12ab) SHA1(acb4e07ba26f2daca5f1c234885ac0371c7ce87f) ) // placeholder, use the one we have
ROM_REGION( 0xc000, "tms6100", ROMREGION_ERASEFF ) // uses only 1 rom, 8000-bfff = space reserved for cartridge
ROM_REGION( 0x10000, "tms6100", ROMREGION_ERASEFF ) // uses only 1 rom, 8000-bfff = space reserved for cartridge
ROM_LOAD( "cd2352.vsm", 0x0000, 0x4000, CRC(181a239e) SHA1(e16043766c385e152b7005c1c010be4c5fccdd9b) )
ROM_END
@ -1180,7 +1180,7 @@ ROM_START( snspellit )
ROM_REGION( 1246, "maincpu:opla", 0 )
ROM_LOAD( "tms0270_tmc0271_output.pla", 0, 1246, BAD_DUMP CRC(9ebe12ab) SHA1(acb4e07ba26f2daca5f1c234885ac0371c7ce87f) ) // placeholder, use the one we have
ROM_REGION( 0xc000, "tms6100", ROMREGION_ERASEFF ) // uses only 1 rom, 8000-bfff = space reserved for cartridge
ROM_REGION( 0x10000, "tms6100", ROMREGION_ERASEFF ) // uses only 1 rom, 8000-bfff = space reserved for cartridge
ROM_LOAD( "cd62190.vsm", 0x0000, 0x4000, CRC(63832002) SHA1(ea8124b2bf0f5908c5f1a56d60063f2468a10143) )
ROM_END
@ -1234,7 +1234,7 @@ ROM_START( snread )
ROM_REGION( 1246, "maincpu:opla", 0 )
ROM_LOAD( "tms0270_cd2705_output.pla", 0, 1246, CRC(bf859848) SHA1(66b297fbf534968fa6db7413b99ef0e81cc35ddc) )
ROM_REGION( 0xc000, "tms6100", ROMREGION_ERASEFF ) // 8000-bfff = space reserved for cartridge
ROM_REGION( 0x10000, "tms6100", ROMREGION_ERASEFF ) // 8000-bfff = space reserved for cartridge
ROM_LOAD( "cd2394a.vsm", 0x0000, 0x4000, CRC(cbb0e2b1) SHA1(5e322c683baf806523de171310258ae371671327) )
ROM_LOAD( "cd2395a.vsm", 0x4000, 0x4000, CRC(3d519504) SHA1(76b19ba5a9a3486005e09c98e8a6abc8b88288dd) )
ROM_END

View File

@ -51,7 +51,6 @@
TODO:
- spellb fetches wrong word sometimes (on lv1 SPOON and ANT) - roms were doublechecked
- mrchalgr wrong sound, need more accurate tms6100 emulation
***************************************************************************/
@ -428,7 +427,7 @@ ROM_START( mrchalgr )
ROM_REGION( 1246, "maincpu:opla", 0 )
ROM_LOAD( "tms0270_mrchalgr_output.pla", 0, 1246, CRC(4785289c) SHA1(60567af0ea120872a4ccf3128e1365fe84722aa8) )
ROM_REGION( 0x4000, "tms6100", ROMREGION_ERASEFF )
ROM_REGION( 0x1000, "tms6100", 0 )
ROM_LOAD( "cd2601.vsm", 0x0000, 0x1000, CRC(a9fbe7e9) SHA1(9d480cb30313b8cbce2d048140c1e5e6c5b92452) )
ROM_END