megadrive: added custom X24C02 emulation to NBA Jam cart,

making finally possible to save records at exit. Hopefully, this
will help finding the problem in our core emulation. [Fabio Priuli]
This commit is contained in:
etabeta78 2016-05-01 19:37:48 +02:00
parent 0ed5f5687e
commit 1441709592
6 changed files with 332 additions and 4 deletions

View File

@ -5282,7 +5282,7 @@ Info on Sega chip labels (from Sunbeam / Digital Corruption)
<year>1993</year>
<publisher>Arena</publisher>
<part name="cart" interface="megadriv_cart">
<feature name="slot" value="rom_nbajam"/>
<feature name="slot" value="rom_nbajam_alt"/>
<feature name="pcb" value="670120 REV 2"/>
<feature name="u1" value="NBA JAM GEN VER 1.00"/> <!-- also found pic (from US cart?) with rom marked "GEN NBA JAM 9402 VER 1.00 S285" -->
<feature name="u2" value="DV74ALS138N"/>
@ -5302,7 +5302,7 @@ Info on Sega chip labels (from Sunbeam / Digital Corruption)
<publisher>Acclaim Japan</publisher>
<info name="alt_title" value="NBA ジャム"/>
<part name="cart" interface="megadriv_cart">
<feature name="slot" value="rom_nbajam"/>
<feature name="slot" value="rom_nbajam_alt"/>
<feature name="pcb" value="171-6568C"/>
<feature name="pcb2" value="837-9952"/>
<feature name="ic1" value="27c4000"/>
@ -19553,7 +19553,7 @@ Notice that these are not working on real hardware due to bugged code with VDP i
<year>1993</year>
<publisher>Arena</publisher>
<part name="cart" interface="megadriv_cart">
<feature name="slot" value="rom_nbajam"/>
<feature name="slot" value="rom_nbajam_alt"/>
<dataarea name="rom" width="16" endianness="big" size="2097152">
<rom name="nba jam (euro, usa) (v1.1).bin" size="2097152" crc="eb8360e6" sha1="55f2b26a932c69b2c7cb4f24f56b43f24f113a7c" offset="0x000000"/>
</dataarea>
@ -19568,7 +19568,7 @@ Notice that these are not working on real hardware due to bugged code with VDP i
<info name="release" value="19940429"/>
<info name="alt_title" value="NBA ジャム"/>
<part name="cart" interface="megadriv_cart">
<feature name="slot" value="rom_nbajam"/>
<feature name="slot" value="rom_nbajam_alt"/>
<dataarea name="rom" width="16" endianness="big" size="2097152">
<rom name="nba jam (jpn).bin" size="2097152" crc="a6c6305a" sha1="2a88b2e1ecf115fa6246397d829448b755a5385e" offset="0x000000"/>
</dataarea>

View File

@ -374,3 +374,263 @@ WRITE16_MEMBER(md_eeprom_blara_device::write)
m_i2cmem->write_sda(m_i2c_mem);
}
}
// TEMPORARY ADDITION UNTIL WE FIND OUT WHAT IS MISSING IN THE CORE X24C02 CODE
// THIS IS A CUSTOM I2C EEPROM EMULATION THAT ALLOWS NBA JAM TO WORK
const device_type MD_EEPROM_NBAJAM_ALT = &device_creator<md_eeprom_nbajam_device_alt>;
md_eeprom_nbajam_device_alt::md_eeprom_nbajam_device_alt(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: md_std_eeprom_device(mconfig, MD_EEPROM_NBAJAM_ALT, "MD NBA Jam (Alt)", tag, owner, clock, "md_eeprom_nbajama", __FILE__)
{
}
void md_eeprom_nbajam_device_alt::device_start()
{
eeprom_i2c_init();
}
void md_eeprom_nbajam_device_alt::eeprom_i2c_init()
{
m_eeprom_cnt = 0;
m_eeprom_readwrite = 0;
m_eeprom_slave_mask = 0;
m_eeprom_word_address = 0;
m_eeprom_devsel = 0;
m_eeprom_sda = m_eeprom_prev_sda = 1;
m_eeprom_scl = m_eeprom_prev_scl = 1;
m_eeprom_cur_state = STATE_I2C_IDLE;
m_eeprom_mask = 0xff;
m_eeprom_pagewrite_mask = 0xff;
}
// this is analogous to i2cmem.cpp implementation of write_sda
void md_eeprom_nbajam_device_alt::idle_devsel_check()
{
if (m_eeprom_scl)
{
// All commands are preceded by the start condition, which is a HIGH to LOW
// transition of SDA when SCL is HIGH
if (m_eeprom_prev_sda && !m_eeprom_sda)
{
m_eeprom_cnt = 0;
m_eeprom_slave_mask = 0;
m_eeprom_cur_state = STATE_I2C_DEVSEL;
}
// All communications must be terminated by a stop condition, which is a LOW to HIGH
// transition of SDA when SCL is HIGH
else if (!m_eeprom_prev_sda && m_eeprom_sda)
{
m_eeprom_cur_state = STATE_I2C_IDLE;
}
}
}
void md_eeprom_nbajam_device_alt::eeprom_i2c_update(void)
{
switch (m_eeprom_cur_state)
{
case STATE_I2C_IDLE:
idle_devsel_check();
break;
case STATE_I2C_WAIT_STOP:
if (!m_eeprom_prev_sda && m_eeprom_sda && m_eeprom_scl)
m_eeprom_cur_state = STATE_I2C_IDLE;
break;
// device select: there can be up to 8 EEPROM in series, so that we start with writing 3 bits
// to identify which device has to be accessed, followed by a Read/Write bit to specify the action
case STATE_I2C_DEVSEL:
idle_devsel_check();
// LOW to HIGH transition of SCL = prepare to transmit, by moving to cnt = 1
if (!m_eeprom_prev_scl && m_eeprom_scl)
if (m_eeprom_cnt == 0)
m_eeprom_cnt++;
// HIGH to LOW transition of SCL = a new bit has been put on SDA line and we can read it
// provided we already got the LOW to HIGH transition above
if (m_eeprom_prev_scl && !m_eeprom_scl && (m_eeprom_cnt > 0))
{
if (m_eeprom_cnt <= 4)
{
// here we would transmit the Device Type Identifier which is 0101 for X24C02
// but apparently the game does not check it, so let's skip it
m_eeprom_cnt++;
}
else if ((m_eeprom_cnt > 4) && (m_eeprom_cnt < 8))
{
// here store the 3 bits of DEVICE ADDRESS
if (m_eeprom_prev_sda)
m_eeprom_devsel |= (1 << (7 - m_eeprom_cnt));
else
m_eeprom_devsel &= ~(1 << (7 - m_eeprom_cnt));
m_eeprom_cnt++;
}
else if (m_eeprom_cnt == 8)
{
m_eeprom_readwrite = m_eeprom_prev_sda;
m_eeprom_cnt++;
}
else if (m_eeprom_cnt > 8)
{
// ACK
m_eeprom_cnt = 1;
m_eeprom_cur_state = m_eeprom_readwrite ? STATE_I2C_READ_DATA : STATE_I2C_GET_WORD_ADDR;
m_eeprom_slave_mask <<= 8;
}
}
break;
// read operation = count 8 operations and at 9th check whether ACK has been issued
case STATE_I2C_READ_DATA:
idle_devsel_check();
// HIGH to LOW transition of SCL
if (m_eeprom_prev_scl && !m_eeprom_scl)
{
if (m_eeprom_cnt < 9)
m_eeprom_cnt++;
else
{
m_eeprom_cnt = 1;
// no ACK
if (m_eeprom_prev_sda)
m_eeprom_cur_state = STATE_I2C_WAIT_STOP;
}
}
break;
// For a write operation, the x24c02 requires a second address field. This address field is the
// word address, comprised of eight bits, providing access to any one of the 256 words of memory.
case STATE_I2C_GET_WORD_ADDR:
idle_devsel_check();
// HIGH to LOW transition of SCL
if (m_eeprom_prev_scl && !m_eeprom_scl)
{
if (m_eeprom_cnt < 9)
{
if (m_eeprom_prev_sda)
m_eeprom_word_address |= (1 << (8 - m_eeprom_cnt));
else
m_eeprom_word_address &= ~(1 << (8 - m_eeprom_cnt));
m_eeprom_cnt++;
}
else
{
// ACK
m_eeprom_cnt = 1;
m_eeprom_word_address &= m_eeprom_mask;
m_eeprom_cur_state = STATE_I2C_WRITE_DATA;
}
}
break;
// write operation
case STATE_I2C_WRITE_DATA:
idle_devsel_check();
// HIGH to LOW transition of SCL
if (m_eeprom_prev_scl && !m_eeprom_scl)
{
if (m_eeprom_cnt < 9)
{
UINT8 *nvram = (UINT8 *)&m_nvram[0];
UINT16 sram_address = m_eeprom_slave_mask | (m_eeprom_devsel * 0x100) | m_eeprom_word_address;
sram_address &= 0xffff;
if (m_eeprom_prev_sda)
nvram[sram_address] |= (1 << (8 - m_eeprom_cnt));
else
nvram[sram_address] &= ~(1 << (8 - m_eeprom_cnt));
if (m_eeprom_cnt == 8)
{
//printf("Write EEPROM : status %d addr %x data %x (count 8)\n", m_eeprom_cur_state, sram_address, nvram[sram_address]);
// WORD ADDRESS++
m_eeprom_word_address = (m_eeprom_word_address & ~m_eeprom_pagewrite_mask) |
((m_eeprom_word_address + 1) & m_eeprom_pagewrite_mask);
}
m_eeprom_cnt++;
}
else // ACK
m_eeprom_cnt = 1;
}
break;
}
m_eeprom_prev_scl = m_eeprom_scl;
m_eeprom_prev_sda = m_eeprom_sda;
//printf("Write line : status %d SDA %x SCL %x (count %d)\n", m_eeprom_cur_state, m_eeprom_sda, m_eeprom_scl, m_eeprom_cnt);
}
UINT8 md_eeprom_nbajam_device_alt::eeprom_i2c_out()
{
UINT8 res = m_eeprom_sda;
switch (m_eeprom_cur_state)
{
case STATE_I2C_READ_DATA:
if (m_eeprom_cnt < 9)
{
UINT8 *nvram = (UINT8 *)&m_nvram[0];
UINT16 sram_address = m_eeprom_slave_mask | (m_eeprom_devsel * 0x100) | m_eeprom_word_address;
sram_address &= 0xffff;
res = (nvram[sram_address] >> (8 - m_eeprom_cnt)) & 1;
if (m_eeprom_cnt == 8)
{
//printf("Read EEPROM : status %d addr %x data %x (count 8)\n", m_eeprom_cur_state, sram_address, nvram[sram_address]);
// WORD ADDRESS++
m_eeprom_word_address++;
m_eeprom_word_address &= m_eeprom_mask;
}
}
break;
case STATE_I2C_DEVSEL:
case STATE_I2C_GET_WORD_ADDR:
case STATE_I2C_WRITE_DATA:
if (m_eeprom_cnt == 9)
res = 0;
break;
default:
break;
}
//printf("Read line : status %d data %x (count %d)\n", m_eeprom_cur_state, res, m_eeprom_cnt);
return res;
}
READ16_MEMBER(md_eeprom_nbajam_device_alt::read)
{
if (offset == 0x200000/2)
{
return eeprom_i2c_out() << 1;
}
if (offset < 0x400000/2)
return m_rom[MD_ADDR(offset)];
else
return 0xffff;
}
WRITE16_MEMBER(md_eeprom_nbajam_device_alt::write)
{
if (offset == 0x200000/2)
{
m_eeprom_sda = BIT(data, 0);
m_eeprom_scl = BIT(data, 1);
eeprom_i2c_update();
}
}

View File

@ -140,4 +140,64 @@ extern const device_type MD_EEPROM_NFLQB;
extern const device_type MD_EEPROM_NHLPA;
extern const device_type MD_EEPROM_BLARA;
// TEMPORARY ADDITION UNTIL WE FIND OUT WHAT IS MISSING IN THE CORE X24C02 CODE
// THIS IS A CUSTOM I2C EEPROM EMULATION THAT ALLOWS NBA JAM TO WORK
enum
{
STATE_I2C_IDLE = 0,
STATE_I2C_WAIT_STOP,
STATE_I2C_DEVSEL,
STATE_I2C_GET_WORD_ADDR,
STATE_I2C_WRITE_DATA,
STATE_I2C_READ_DATA
};
// ======================> md_eeprom_nbajam_device_alt
class md_eeprom_nbajam_device_alt : public md_std_eeprom_device
{
public:
// construction/destruction
md_eeprom_nbajam_device_alt(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
// device-level overrides
// virtual machine_config_constructor device_mconfig_additions() const override;
virtual void device_start() override;
// reading and writing
virtual DECLARE_READ16_MEMBER(read) override;
virtual DECLARE_WRITE16_MEMBER(write) override;
std::vector<UINT8> m_sram;
void eeprom_i2c_init();
void idle_devsel_check();
void eeprom_i2c_update();
UINT8 eeprom_i2c_out();
private:
// EEPROM runtime vars
UINT8 m_eeprom_sda; // current SDA
UINT8 m_eeprom_prev_sda; // previous SDA
UINT8 m_eeprom_scl; // current SCL
UINT8 m_eeprom_prev_scl; // previous SCL
UINT8 m_eeprom_cnt; // operation count in 0-9
UINT8 m_eeprom_readwrite; // read/write bit
UINT16 m_eeprom_slave_mask; // dev addr
UINT16 m_eeprom_word_address; // memory addr
UINT16 m_eeprom_devsel; // selected device
int m_eeprom_cur_state; // current state
// EEPROM physical characteristics (configured at init)
UINT16 m_eeprom_mask; // size of the memory - 1
UINT16 m_eeprom_pagewrite_mask; // max number of bytes that can be written in a single write cycle
};
extern const device_type MD_EEPROM_NBAJAM_ALT;
#endif

View File

@ -68,4 +68,7 @@ SLOT_INTERFACE_START(md_cart)
SLOT_INTERFACE_INTERNAL("rom_squir", MD_ROM_SQUIR)
SLOT_INTERFACE_INTERNAL("rom_tekkensp", MD_ROM_TEKKENSP)
SLOT_INTERFACE_INTERNAL("rom_topf", MD_ROM_TOPF)
SLOT_INTERFACE_INTERNAL("rom_nbajam_alt", MD_EEPROM_NBAJAM_ALT)
SLOT_INTERFACE_END

View File

@ -240,6 +240,7 @@ static const md_slot slot_list[] =
{ SEGA_EEPROM, "rom_eeprom" },
{ NBA_JAM, "rom_nbajam" },
{ NBA_JAM_ALT, "rom_nbajam_alt" },
{ NBA_JAM_TE, "rom_nbajamte" },
{ NFL_QB_96, "rom_nflqb" },
{ C_SLAM, "rom_cslam" },
@ -666,6 +667,9 @@ void base_md_cart_slot_device::setup_nvram()
m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1);
m_cart->m_nvram_active = 1;
break;
case NBA_JAM_ALT:
m_cart->nvram_alloc(0x100);
break;
}
}

View File

@ -30,6 +30,7 @@ enum
// EEPROM
SEGA_EEPROM, /* Wonder Boy V / Evander Holyfield's Boxing / Greatest Heavyweights of the Ring / Sports Talk Baseball / Megaman */
NBA_JAM, /* NBA Jam */
NBA_JAM_ALT, /* NBA Jam */
NBA_JAM_TE, /* NBA Jam TE / NFL Quarterback Club */
NFL_QB_96, /* NFL Quarterback Club '96 */
C_SLAM, /* College Slam / Frank Thomas Big Hurt Baseball */