mirror of
https://github.com/holub/mame
synced 2025-10-04 08:28:39 +03:00
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:
parent
0ed5f5687e
commit
1441709592
@ -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>
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user