diff --git a/hash/megadriv.xml b/hash/megadriv.xml
index bb01af7931f..21c0849b2f7 100644
--- a/hash/megadriv.xml
+++ b/hash/megadriv.xml
@@ -5282,7 +5282,7 @@ Info on Sega chip labels (from Sunbeam / Digital Corruption)
1993
Arena
-
+
@@ -5302,7 +5302,7 @@ Info on Sega chip labels (from Sunbeam / Digital Corruption)
Acclaim Japan
-
+
@@ -19553,7 +19553,7 @@ Notice that these are not working on real hardware due to bugged code with VDP i
1993
Arena
-
+
@@ -19568,7 +19568,7 @@ Notice that these are not working on real hardware due to bugged code with VDP i
-
+
diff --git a/src/devices/bus/megadrive/eeprom.cpp b/src/devices/bus/megadrive/eeprom.cpp
index 1a432d6f6d6..b56273255e8 100644
--- a/src/devices/bus/megadrive/eeprom.cpp
+++ b/src/devices/bus/megadrive/eeprom.cpp
@@ -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(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();
+ }
+}
+
diff --git a/src/devices/bus/megadrive/eeprom.h b/src/devices/bus/megadrive/eeprom.h
index 78ed7689547..619e821f051 100644
--- a/src/devices/bus/megadrive/eeprom.h
+++ b/src/devices/bus/megadrive/eeprom.h
@@ -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 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
diff --git a/src/devices/bus/megadrive/md_carts.cpp b/src/devices/bus/megadrive/md_carts.cpp
index 698060c6014..fd5a9032ac3 100644
--- a/src/devices/bus/megadrive/md_carts.cpp
+++ b/src/devices/bus/megadrive/md_carts.cpp
@@ -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
diff --git a/src/devices/bus/megadrive/md_slot.cpp b/src/devices/bus/megadrive/md_slot.cpp
index 5a496ac124a..2d7bc239968 100644
--- a/src/devices/bus/megadrive/md_slot.cpp
+++ b/src/devices/bus/megadrive/md_slot.cpp
@@ -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;
}
}
diff --git a/src/devices/bus/megadrive/md_slot.h b/src/devices/bus/megadrive/md_slot.h
index 086d02bc79f..099b17e9d51 100644
--- a/src/devices/bus/megadrive/md_slot.h
+++ b/src/devices/bus/megadrive/md_slot.h
@@ -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 */