mirror of
https://github.com/holub/mame
synced 2025-05-30 01:23:07 +03:00
267 lines
6.4 KiB
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));
|
|
}
|
|
}
|