mame/src/mess/machine/md_stm95.c

267 lines
6.4 KiB
C

/***************************************************************************
MegaDrive / Genesis Cart + STM95 EEPROM device
Emulation by MetalliC, converted to slot by Fabio Priuli
TO DO: split STM95 to a separate device...
***************************************************************************/
#include "emu.h"
#include "machine/md_stm95.h"
stm95_eeprom_device::stm95_eeprom_device(running_machine &machine, UINT8 *eeprom) :
stm_state(IDLE),
stream_pos(0),
m_machine(machine)
{
eeprom_data = eeprom;
state_save_register_item(machine, "STM95", NULL, 0, latch);
state_save_register_item(machine, "STM95", NULL, 0, reset_line);
state_save_register_item(machine, "STM95", NULL, 0, sck_line);
state_save_register_item(machine, "STM95", NULL, 0, WEL);
state_save_register_item(machine, "STM95", NULL, 0, stream_pos);
state_save_register_item(machine, "STM95", NULL, 0, stream_data);
state_save_register_item(machine, "STM95", NULL, 0, eeprom_addr);
}
void stm95_eeprom_device::set_cs_line(int state)
{
reset_line = state;
if (reset_line != CLEAR_LINE)
{
stream_pos = 0;
stm_state = IDLE;
}
}
void stm95_eeprom_device::set_si_line(int state)
{
latch = state;
}
int stm95_eeprom_device::get_so_line(void)
{
if (stm_state == READING || stm_state == CMD_RDSR)
return (stream_data >> 8) & 1;
else
return 0;
}
void stm95_eeprom_device::set_sck_line(int state)
{
if (reset_line == CLEAR_LINE)
{
if (state == ASSERT_LINE && sck_line == CLEAR_LINE)
{
switch (stm_state)
{
case IDLE:
stream_data = (stream_data << 1) | (latch ? 1 : 0);
stream_pos++;
if (stream_pos == 8)
{
stream_pos = 0;
//printf("STM95 EEPROM: got cmd %02X\n", stream_data&0xff);
switch(stream_data & 0xff)
{
case 0x01: // write status register
if (WEL != 0)
stm_state = CMD_WRSR;
WEL = 0;
break;
case 0x02: // write
if (WEL != 0)
stm_state = CMD_WRITE;
stream_data = 0;
WEL = 0;
break;
case 0x03: // read
stm_state = M95320_CMD_READ;
stream_data = 0;
break;
case 0x04: // write disable
WEL = 0;
break;
case 0x05: // read status register
stm_state = CMD_RDSR;
stream_data = WEL<<1;
break;
case 0x06: // write enable
WEL = 1;
break;
default:
logerror("STM95 EEPROM: unknown cmd %02X\n", stream_data&0xff);
}
}
break;
case CMD_WRSR:
stream_pos++; // just skip, don't care block protection
if (stream_pos == 8)
{
stm_state = IDLE;
stream_pos = 0;
}
break;
case CMD_RDSR:
stream_data = stream_data<<1;
stream_pos++;
if (stream_pos == 8)
{
stm_state = IDLE;
stream_pos = 0;
}
break;
case M95320_CMD_READ:
stream_data = (stream_data << 1) | (latch ? 1 : 0);
stream_pos++;
if (stream_pos == 16)
{
eeprom_addr = stream_data & (M95320_SIZE - 1);
stream_data = eeprom_data[eeprom_addr];
stm_state = READING;
stream_pos = 0;
}
break;
case READING:
stream_data = stream_data<<1;
stream_pos++;
if (stream_pos == 8)
{
if (++eeprom_addr == M95320_SIZE)
eeprom_addr = 0;
stream_data |= eeprom_data[eeprom_addr];
stream_pos = 0;
}
break;
case CMD_WRITE:
stream_data = (stream_data << 1) | (latch ? 1 : 0);
stream_pos++;
if (stream_pos == 16)
{
eeprom_addr = stream_data & (M95320_SIZE - 1);
stm_state = WRITING;
stream_pos = 0;
}
break;
case WRITING:
stream_data = (stream_data << 1) | (latch ? 1 : 0);
stream_pos++;
if (stream_pos == 8)
{
eeprom_data[eeprom_addr] = stream_data;
if (++eeprom_addr == M95320_SIZE)
eeprom_addr = 0;
stream_pos = 0;
}
break;
}
}
}
sck_line = state;
}
//-------------------------------------------------
// md_rom_device - constructor
//-------------------------------------------------
const device_type MD_EEPROM_STM95 = &device_creator<md_eeprom_stm95_device>;
md_eeprom_stm95_device::md_eeprom_stm95_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_md_cart_interface( mconfig, *this )
{
}
md_eeprom_stm95_device::md_eeprom_stm95_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, MD_EEPROM_STM95, "MD Cart + EEPROM STM95", tag, owner, clock, "md_eeprom_stm95", __FILE__),
device_md_cart_interface( mconfig, *this )
{
}
void md_eeprom_stm95_device::device_start()
{
nvram_alloc(machine(), M95320_SIZE);
m_stm95 = auto_alloc(machine(), stm95_eeprom_device(machine(), (UINT8*)get_nvram_base()));
save_item(NAME(m_rdcnt));
save_item(NAME(m_bank));
}
void md_eeprom_stm95_device::device_reset()
{
m_rdcnt = 0;
m_bank[0] = 0;
m_bank[1] = 0;
m_bank[2] = 0;
}
/*-------------------------------------------------
mapper specific handlers
-------------------------------------------------*/
READ16_MEMBER(md_eeprom_stm95_device::read)
{
if (offset == 0x0015e6/2 || offset == 0x0015e8/2)
{
// ugly hack until we don't know much about game protection
// first 3 reads from 15e6 return 0x00000010, then normal 0x00018010 value for crc check
UINT16 res;
offset -= 0x0015e6/2;
logerror("read 0x15e6 %d\n", m_rdcnt);
if (m_rdcnt < 6)
{
m_rdcnt++;
res = offset ? 0x10 : 0;
}
else
res = offset ? 0x8010 : 0x0001;
return res;
}
if (offset < 0x280000/2)
return m_rom[offset];
else // last 0x180000 are bankswitched
{
UINT8 bank = (offset - 0x280000/2) >> 18;
return m_rom[(offset & 0x7ffff/2) + (m_bank[bank] * 0x80000)/2];
}
}
READ16_MEMBER(md_eeprom_stm95_device::read_a13)
{
if (offset == 0x0a/2)
{
return m_stm95->get_so_line() & 1;
}
return 0xffff;
}
WRITE16_MEMBER(md_eeprom_stm95_device::write_a13)
{
if (offset == 0x00/2)
{
logerror("A13001 write %02x\n", data);
}
else if (offset < 0x08/2)
{
m_bank[offset - 1] = data & 0x0f;
}
else if (offset < 0x0a/2)
{
m_stm95->set_si_line(BIT(data, 0));
m_stm95->set_sck_line(BIT(data, 1));
m_stm95->set_halt_line(BIT(data, 2));
m_stm95->set_cs_line(BIT(data, 3));
}
}