diff options
Diffstat (limited to 'src/devices/bus/megadrive/stm95.cpp')
-rw-r--r-- | src/devices/bus/megadrive/stm95.cpp | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/src/devices/bus/megadrive/stm95.cpp b/src/devices/bus/megadrive/stm95.cpp new file mode 100644 index 00000000000..cc8765f3b4a --- /dev/null +++ b/src/devices/bus/megadrive/stm95.cpp @@ -0,0 +1,265 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli, MetalliC +/*************************************************************************** + + + MegaDrive / Genesis Cart + STM95 EEPROM device + + + TO DO: split STM95 to a separate device... + +***************************************************************************/ + + +#include "emu.h" +#include "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; + m_machine.save().save_item(latch, "STM95/latch"); + m_machine.save().save_item(reset_line, "STM95/reset_line"); + m_machine.save().save_item(sck_line, "STM95/sck_line"); + m_machine.save().save_item(WEL, "STM95/WEL"); + m_machine.save().save_item(stream_pos, "STM95/stream_pos"); + m_machine.save().save_item(stream_data, "STM95/stream_data"); + m_machine.save().save_item(eeprom_addr, "STM95/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: + machine().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(M95320_SIZE); + m_stm95.reset(global_alloc(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)); + } +} |