mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-12-27 03:31:49 +01:00
891 lines
28 KiB
C
891 lines
28 KiB
C
/****************************************************************************
|
|
* Genesis Plus
|
|
* I2C serial EEPROM (24Cxx) boards
|
|
*
|
|
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
|
|
*
|
|
* Redistribution and use of this code or any derivative works are permitted
|
|
* provided that the following conditions are met:
|
|
*
|
|
* - Redistributions may not be sold, nor may they be used in a commercial
|
|
* product or activity.
|
|
*
|
|
* - Redistributions that are modified from the original source must include the
|
|
* complete source code, including the source code for all components used by a
|
|
* binary built from the modified sources. However, as a special exception, the
|
|
* source code distributed need not include anything that is normally distributed
|
|
* (in either source or binary form) with the major components (compiler, kernel,
|
|
* and so on) of the operating system on which the executable runs, unless that
|
|
* component itself accompanies the executable.
|
|
*
|
|
* - Redistributions must reproduce the above copyright notice, this list of
|
|
* conditions and the following disclaimer in the documentation and/or other
|
|
* materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
****************************************************************************************/
|
|
|
|
#include "shared.h"
|
|
#include "gamepad.h"
|
|
|
|
/* Some notes from 8BitWizard (http://gendev.spritesmind.net/forum/viewtopic.php?t=206):
|
|
*
|
|
* Mode 1 (7-bit) - the chip takes a single byte with a 7-bit memory address and a R/W bit (X24C01)
|
|
* Mode 2 (8-bit) - the chip takes a 7-bit device address and R/W bit followed by an 8-bit memory address;
|
|
* the device address may contain up to three more memory address bits (24C01 - 24C16).
|
|
* You can also string eight 24C01, four 24C02, two 24C08, or various combinations, set their address config lines correctly,
|
|
* and the result appears exactly the same as a 24C16
|
|
* Mode 3 (16-bit) - the chip takes a 7-bit device address and R/W bit followed by a 16-bit memory address (24C32 and larger)
|
|
*
|
|
*/
|
|
|
|
typedef enum
|
|
{
|
|
STAND_BY = 0,
|
|
WAIT_STOP,
|
|
GET_DEVICE_ADR,
|
|
GET_WORD_ADR_7BITS,
|
|
GET_WORD_ADR_HIGH,
|
|
GET_WORD_ADR_LOW,
|
|
WRITE_DATA,
|
|
READ_DATA
|
|
} T_I2C_STATE;
|
|
|
|
typedef enum
|
|
{
|
|
NO_EEPROM = -1,
|
|
EEPROM_X24C01,
|
|
EEPROM_X24C02,
|
|
EEPROM_24C01,
|
|
EEPROM_24C02,
|
|
EEPROM_24C04,
|
|
EEPROM_24C08,
|
|
EEPROM_24C16,
|
|
EEPROM_24C32,
|
|
EEPROM_24C64,
|
|
EEPROM_24C65,
|
|
EEPROM_24C128,
|
|
EEPROM_24C256,
|
|
EEPROM_24C512
|
|
} T_I2C_TYPE;
|
|
|
|
typedef struct
|
|
{
|
|
uint8 address_bits;
|
|
uint16 size_mask;
|
|
uint16 pagewrite_mask;
|
|
} T_I2C_SPEC;
|
|
|
|
static const T_I2C_SPEC i2c_specs[] =
|
|
{
|
|
{ 7 , 0x7F , 0x03},
|
|
{ 8 , 0xFF , 0x03},
|
|
{ 8 , 0x7F , 0x07},
|
|
{ 8 , 0xFF , 0x07},
|
|
{ 8 , 0x1FF , 0x0F},
|
|
{ 8 , 0x3FF , 0x0F},
|
|
{ 8 , 0x7FF , 0x0F},
|
|
{16 , 0xFFF , 0x1F},
|
|
{16 , 0x1FFF , 0x1F},
|
|
{16 , 0x1FFF , 0x3F},
|
|
{16 , 0x3FFF , 0x3F},
|
|
{16 , 0x7FFF , 0x3F},
|
|
{16 , 0xFFFF , 0x7F}
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
char id[16];
|
|
uint32 sp;
|
|
uint16 chk;
|
|
void (*mapper_init)(void);
|
|
T_I2C_TYPE eeprom_type;
|
|
} T_I2C_GAME;
|
|
|
|
static void mapper_i2c_ea_init(void);
|
|
static void mapper_i2c_sega_init(void);
|
|
static void mapper_i2c_acclaim_16M_init(void);
|
|
static void mapper_i2c_acclaim_32M_init(void);
|
|
static void mapper_i2c_jcart_init(void);
|
|
|
|
static const T_I2C_GAME i2c_database[] =
|
|
{
|
|
{"T-50176" , 0 , 0 , mapper_i2c_ea_init , EEPROM_X24C01 }, /* Rings of Power */
|
|
{"T-50396" , 0 , 0 , mapper_i2c_ea_init , EEPROM_X24C01 }, /* NHLPA Hockey 93 */
|
|
{"T-50446" , 0 , 0 , mapper_i2c_ea_init , EEPROM_X24C01 }, /* John Madden Football 93 */
|
|
{"T-50516" , 0 , 0 , mapper_i2c_ea_init , EEPROM_X24C01 }, /* John Madden Football 93 (Championship Ed.) */
|
|
{"T-50606" , 0 , 0 , mapper_i2c_ea_init , EEPROM_X24C01 }, /* Bill Walsh College Football (warning: invalid SRAM header !) */
|
|
{" T-12046" , 0 , 0 , mapper_i2c_sega_init , EEPROM_X24C01 }, /* Megaman - The Wily Wars (warning: SRAM hack exists !) */
|
|
{" T-12053" , 0 , 0 , mapper_i2c_sega_init , EEPROM_X24C01 }, /* Rockman Mega World (warning: SRAM hack exists !) */
|
|
{"MK-1215" , 0 , 0 , mapper_i2c_sega_init , EEPROM_X24C01 }, /* Evander 'Real Deal' Holyfield's Boxing */
|
|
{"MK-1228" , 0 , 0 , mapper_i2c_sega_init , EEPROM_X24C01 }, /* Greatest Heavyweights of the Ring (U)(E) */
|
|
{"G-5538" , 0 , 0 , mapper_i2c_sega_init , EEPROM_X24C01 }, /* Greatest Heavyweights of the Ring (J) */
|
|
{"PR-1993" , 0 , 0 , mapper_i2c_sega_init , EEPROM_X24C01 }, /* Greatest Heavyweights of the Ring (Prototype) */
|
|
{" G-4060" , 0 , 0 , mapper_i2c_sega_init , EEPROM_X24C01 }, /* Wonderboy in Monster World (warning: SRAM hack exists !) */
|
|
{"00001211" , 0 , 0 , mapper_i2c_sega_init , EEPROM_X24C01 }, /* Sports Talk Baseball */
|
|
{"00004076" , 0 , 0 , mapper_i2c_sega_init , EEPROM_X24C01 }, /* Honoo no Toukyuuji Dodge Danpei */
|
|
{"G-4524" , 0 , 0 , mapper_i2c_sega_init , EEPROM_X24C01 }, /* Ninja Burai Densetsu */
|
|
{"00054503" , 0 , 0 , mapper_i2c_sega_init , EEPROM_X24C01 }, /* Game Toshokan */
|
|
{"T-81033" , 0 , 0 , mapper_i2c_acclaim_16M_init , EEPROM_X24C02 }, /* NBA Jam (J) */
|
|
{"T-081326" , 0 , 0 , mapper_i2c_acclaim_16M_init , EEPROM_X24C02 }, /* NBA Jam (UE) */
|
|
{"T-081276" , 0 , 0 , mapper_i2c_acclaim_32M_init , EEPROM_24C02 }, /* NFL Quarterback Club */
|
|
{"T-81406" , 0 , 0 , mapper_i2c_acclaim_32M_init , EEPROM_24C04 }, /* NBA Jam TE */
|
|
{"T-081586" , 0 , 0 , mapper_i2c_acclaim_32M_init , EEPROM_24C16 }, /* NFL Quarterback Club '96 */
|
|
{"T-81476" , 0 , 0 , mapper_i2c_acclaim_32M_init , EEPROM_24C65 }, /* Frank Thomas Big Hurt Baseball */
|
|
{"T-81576" , 0 , 0 , mapper_i2c_acclaim_32M_init , EEPROM_24C65 }, /* College Slam */
|
|
{"T-120106" , 0 , 0 , mapper_i2c_jcart_init , EEPROM_24C08 }, /* Brian Lara Cricket */
|
|
{"00000000" , 0x444e4c44 , 0x168B , mapper_i2c_jcart_init , EEPROM_24C08 }, /* Micro Machines Military */
|
|
{"00000000" , 0x444e4c44 , 0x165E , mapper_i2c_jcart_init , EEPROM_24C16 }, /* Micro Machines Turbo Tournament 96 */
|
|
{"T-120096" , 0 , 0 , mapper_i2c_jcart_init , EEPROM_24C16 }, /* Micro Machines 2 - Turbo Tournament */
|
|
{"T-120146" , 0 , 0 , mapper_i2c_jcart_init , EEPROM_24C65 }, /* Brian Lara Cricket 96 / Shane Warne Cricket */
|
|
{"00000000" , 0xfffffffc , 0x168B , mapper_i2c_jcart_init , NO_EEPROM }, /* Super Skidmarks */
|
|
{"00000000" , 0xfffffffc , 0x165E , mapper_i2c_jcart_init , NO_EEPROM }, /* Pete Sampras Tennis (Prototype) */
|
|
{"T-120066" , 0 , 0 , mapper_i2c_jcart_init , NO_EEPROM }, /* Pete Sampras Tennis */
|
|
{"T-123456" , 0 , 0 , mapper_i2c_jcart_init , NO_EEPROM }, /* Pete Sampras Tennis 96 */
|
|
{"XXXXXXXX" , 0 , 0xDF39 , mapper_i2c_jcart_init , NO_EEPROM }, /* Pete Sampras Tennis 96 (Prototype ?) */
|
|
};
|
|
|
|
static struct
|
|
{
|
|
uint8 sda; /* current SDA line state */
|
|
uint8 scl; /* current SCL line state */
|
|
uint8 old_sda; /* previous SDA line state */
|
|
uint8 old_scl; /* previous SCL line state */
|
|
uint8 cycles; /* operation internal cycle (0-9) */
|
|
uint8 rw; /* operation type (1:READ, 0:WRITE) */
|
|
uint16 device_address; /* device address */
|
|
uint16 word_address; /* memory address */
|
|
uint8 buffer; /* write buffer */
|
|
T_I2C_STATE state; /* current operation state */
|
|
T_I2C_SPEC spec; /* EEPROM characteristics */
|
|
uint8 scl_in_bit; /* SCL (write) bit position */
|
|
uint8 sda_in_bit; /* SDA (write) bit position */
|
|
uint8 sda_out_bit; /* SDA (read) bit position */
|
|
} eeprom_i2c;
|
|
|
|
|
|
/********************************************************************/
|
|
/* I2C EEPROM mapper initialization */
|
|
/********************************************************************/
|
|
|
|
void eeprom_i2c_init()
|
|
{
|
|
int i = sizeof(i2c_database) / sizeof(T_I2C_GAME) - 1;
|
|
|
|
/* no serial EEPROM found by default */
|
|
sram.custom = 0;
|
|
|
|
/* initialize I2C EEPROM state */
|
|
memset(&eeprom_i2c, 0, sizeof(eeprom_i2c));
|
|
eeprom_i2c.sda = eeprom_i2c.old_sda = 1;
|
|
eeprom_i2c.scl = eeprom_i2c.old_scl = 1;
|
|
eeprom_i2c.state = STAND_BY;
|
|
|
|
/* auto-detect games listed in database */
|
|
do
|
|
{
|
|
/* check game internal id code */
|
|
if (strstr(rominfo.product, i2c_database[i].id))
|
|
{
|
|
/* additional check for known SRAM-patched hacks */
|
|
if ((i2c_database[i].id[0] == ' ') && ((sram.end - sram.start) > 2))
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* additional check for Codemasters games */
|
|
if (((i2c_database[i].chk == 0) || (i2c_database[i].chk == rominfo.checksum)) &&
|
|
((i2c_database[i].sp == 0) || (i2c_database[i].sp == READ_WORD_LONG(cart.rom, 0))))
|
|
{
|
|
/* additional check for J-CART games without serial EEPROM */
|
|
if (i2c_database[i].eeprom_type > NO_EEPROM)
|
|
{
|
|
/* get EEPROM characteristics */
|
|
memcpy(&eeprom_i2c.spec, &i2c_specs[i2c_database[i].eeprom_type], sizeof(T_I2C_SPEC));
|
|
|
|
/* serial EEPROM game found */
|
|
sram.on = sram.custom = 1;
|
|
}
|
|
|
|
/* initialize memory mapping */
|
|
i2c_database[i].mapper_init();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
while (i--);
|
|
|
|
/* for games not present in database, check if ROM header indicates serial EEPROM is used */
|
|
if (!sram.custom && sram.detected)
|
|
{
|
|
if ((READ_BYTE(cart.rom,0x1b2) == 0xe8) || ((sram.end - sram.start) < 2))
|
|
{
|
|
/* serial EEPROM game found */
|
|
sram.custom = 1;
|
|
|
|
/* assume SEGA mapper as default */
|
|
memcpy(&eeprom_i2c.spec, &i2c_specs[EEPROM_X24C01], sizeof(T_I2C_SPEC));
|
|
mapper_i2c_sega_init();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/********************************************************************/
|
|
/* I2C EEPROM internal */
|
|
/********************************************************************/
|
|
|
|
INLINE void Detect_START()
|
|
{
|
|
/* detect SDA HIGH to LOW transition while SCL is held HIGH */
|
|
if (eeprom_i2c.old_scl && eeprom_i2c.scl)
|
|
{
|
|
if (eeprom_i2c.old_sda && !eeprom_i2c.sda)
|
|
{
|
|
/* initialize cycle counter */
|
|
eeprom_i2c.cycles = 0;
|
|
|
|
/* initialize sequence */
|
|
if (eeprom_i2c.spec.address_bits == 7)
|
|
{
|
|
/* get Word Address */
|
|
eeprom_i2c.word_address = 0;
|
|
eeprom_i2c.state = GET_WORD_ADR_7BITS;
|
|
}
|
|
else
|
|
{
|
|
/* get Device Address */
|
|
eeprom_i2c.device_address = 0;
|
|
eeprom_i2c.state = GET_DEVICE_ADR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
INLINE void Detect_STOP()
|
|
{
|
|
/* detect SDA LOW to HIGH transition while SCL is held HIGH */
|
|
if (eeprom_i2c.old_scl && eeprom_i2c.scl)
|
|
{
|
|
if (!eeprom_i2c.old_sda && eeprom_i2c.sda)
|
|
{
|
|
eeprom_i2c.state = STAND_BY;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void eeprom_i2c_update(void)
|
|
{
|
|
/* EEPROM current state */
|
|
switch (eeprom_i2c.state)
|
|
{
|
|
/* Standby Mode */
|
|
case STAND_BY:
|
|
{
|
|
Detect_START();
|
|
break;
|
|
}
|
|
|
|
/* Suspended Mode */
|
|
case WAIT_STOP:
|
|
{
|
|
Detect_STOP();
|
|
break;
|
|
}
|
|
|
|
/* Get Word Address (7-bit): Mode 1 (X24C01) only
|
|
* and R/W bit
|
|
*/
|
|
case GET_WORD_ADR_7BITS:
|
|
{
|
|
Detect_START();
|
|
Detect_STOP();
|
|
|
|
/* look for SCL HIGH to LOW transition */
|
|
if (eeprom_i2c.old_scl && !eeprom_i2c.scl)
|
|
{
|
|
if (eeprom_i2c.cycles < 9)
|
|
{
|
|
/* increment cycle counter */
|
|
eeprom_i2c.cycles++;
|
|
}
|
|
else
|
|
{
|
|
/* next sequence */
|
|
eeprom_i2c.cycles = 1;
|
|
eeprom_i2c.state = eeprom_i2c.rw ? READ_DATA : WRITE_DATA;
|
|
|
|
/* clear write buffer */
|
|
eeprom_i2c.buffer = 0x00;
|
|
}
|
|
}
|
|
|
|
/* look for SCL LOW to HIGH transition */
|
|
else if (!eeprom_i2c.old_scl && eeprom_i2c.scl)
|
|
{
|
|
if (eeprom_i2c.cycles < 8)
|
|
{
|
|
/* latch Word Address bits 6-0 */
|
|
eeprom_i2c.word_address |= (eeprom_i2c.sda << (7 - eeprom_i2c.cycles));
|
|
}
|
|
else if (eeprom_i2c.cycles == 8)
|
|
{
|
|
/* latch R/W bit */
|
|
eeprom_i2c.rw = eeprom_i2c.sda;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/* Get Device Address (0-3 bits, depending on the array size) : Mode 2 & Mode 3 (24C01 - 24C512) only
|
|
* or/and Word Address MSB: Mode 2 only (24C04 - 24C16) (0-3 bits, depending on the array size)
|
|
* and R/W bit
|
|
*/
|
|
case GET_DEVICE_ADR:
|
|
{
|
|
Detect_START();
|
|
Detect_STOP();
|
|
|
|
/* look for SCL HIGH to LOW transition */
|
|
if (eeprom_i2c.old_scl && !eeprom_i2c.scl)
|
|
{
|
|
if (eeprom_i2c.cycles < 9)
|
|
{
|
|
/* increment cycle counter */
|
|
eeprom_i2c.cycles++;
|
|
}
|
|
else
|
|
{
|
|
/* shift Device Address bits */
|
|
eeprom_i2c.device_address <<= eeprom_i2c.spec.address_bits;
|
|
|
|
/* next sequence */
|
|
eeprom_i2c.cycles = 1;
|
|
if (eeprom_i2c.rw)
|
|
{
|
|
eeprom_i2c.state = READ_DATA;
|
|
}
|
|
else
|
|
{
|
|
eeprom_i2c.word_address = 0;
|
|
eeprom_i2c.state = (eeprom_i2c.spec.address_bits == 16) ? GET_WORD_ADR_HIGH : GET_WORD_ADR_LOW;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* look for SCL LOW to HIGH transition */
|
|
else if (!eeprom_i2c.old_scl && eeprom_i2c.scl)
|
|
{
|
|
if ((eeprom_i2c.cycles > 4) && (eeprom_i2c.cycles < 8))
|
|
{
|
|
/* latch Device Address bits */
|
|
eeprom_i2c.device_address |= (eeprom_i2c.sda << (7 - eeprom_i2c.cycles));
|
|
}
|
|
else if (eeprom_i2c.cycles == 8)
|
|
{
|
|
/* latch R/W bit */
|
|
eeprom_i2c.rw = eeprom_i2c.sda;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/* Get Word Address MSB (4-8 bits depending on the array size)
|
|
* Mode 3 only (24C32 - 24C512)
|
|
*/
|
|
case GET_WORD_ADR_HIGH:
|
|
{
|
|
Detect_START();
|
|
Detect_STOP();
|
|
|
|
/* look for SCL HIGH to LOW transition */
|
|
if (eeprom_i2c.old_scl && !eeprom_i2c.scl)
|
|
{
|
|
if (eeprom_i2c.cycles < 9)
|
|
{
|
|
/* increment cycle counter */
|
|
eeprom_i2c.cycles++;
|
|
}
|
|
else
|
|
{
|
|
/* next sequence */
|
|
eeprom_i2c.cycles = 1;
|
|
eeprom_i2c.state = GET_WORD_ADR_LOW;
|
|
}
|
|
}
|
|
|
|
/* look for SCL LOW to HIGH transition */
|
|
else if (!eeprom_i2c.old_scl && eeprom_i2c.scl)
|
|
{
|
|
if (eeprom_i2c.cycles < 9)
|
|
{
|
|
if (eeprom_i2c.spec.size_mask < (1 << (16 - eeprom_i2c.cycles)))
|
|
{
|
|
/* ignored bit: Device Address bits should be right-shifted */
|
|
eeprom_i2c.device_address >>= 1;
|
|
}
|
|
else
|
|
{
|
|
/* latch Word Address high bits */
|
|
eeprom_i2c.word_address |= (eeprom_i2c.sda << (16 - eeprom_i2c.cycles));
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/* Get Word Address LSB: 7bits (24C01) or 8bits (24C02-24C512)
|
|
* MODE-2 and MODE-3 only (24C01 - 24C512)
|
|
*/
|
|
case GET_WORD_ADR_LOW:
|
|
{
|
|
Detect_START();
|
|
Detect_STOP();
|
|
|
|
/* look for SCL HIGH to LOW transition */
|
|
if (eeprom_i2c.old_scl && !eeprom_i2c.scl)
|
|
{
|
|
if (eeprom_i2c.cycles < 9)
|
|
{
|
|
/* increment cycle counter */
|
|
eeprom_i2c.cycles++;
|
|
}
|
|
else
|
|
{
|
|
/* next sequence */
|
|
eeprom_i2c.cycles = 1;
|
|
eeprom_i2c.state = WRITE_DATA;
|
|
|
|
/* clear write buffer */
|
|
eeprom_i2c.buffer = 0x00;
|
|
}
|
|
}
|
|
|
|
/* look for SCL LOW to HIGH transition */
|
|
else if (!eeprom_i2c.old_scl && eeprom_i2c.scl)
|
|
{
|
|
if (eeprom_i2c.cycles < 9)
|
|
{
|
|
if (eeprom_i2c.spec.size_mask < (1 << (8 - eeprom_i2c.cycles)))
|
|
{
|
|
/* ignored bit (24C01): Device Address bits should be right-shifted */
|
|
eeprom_i2c.device_address >>= 1;
|
|
}
|
|
else
|
|
{
|
|
/* latch Word Address low bits */
|
|
eeprom_i2c.word_address |= (eeprom_i2c.sda << (8 - eeprom_i2c.cycles));
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Read Sequence
|
|
*/
|
|
case READ_DATA:
|
|
{
|
|
Detect_START();
|
|
Detect_STOP();
|
|
|
|
/* look for SCL HIGH to LOW transition */
|
|
if (eeprom_i2c.old_scl && !eeprom_i2c.scl)
|
|
{
|
|
if (eeprom_i2c.cycles < 9)
|
|
{
|
|
/* increment cycle counter */
|
|
eeprom_i2c.cycles++;
|
|
}
|
|
else
|
|
{
|
|
/* next read sequence */
|
|
eeprom_i2c.cycles = 1;
|
|
}
|
|
}
|
|
|
|
/* look for SCL LOW to HIGH transition */
|
|
else if (!eeprom_i2c.old_scl && eeprom_i2c.scl)
|
|
{
|
|
if (eeprom_i2c.cycles == 9)
|
|
{
|
|
/* check if ACK is received */
|
|
if (eeprom_i2c.sda)
|
|
{
|
|
/* end of read sequence */
|
|
eeprom_i2c.state = WAIT_STOP;
|
|
}
|
|
else
|
|
{
|
|
/* increment Word Address (roll up at maximum array size) */
|
|
eeprom_i2c.word_address = (eeprom_i2c.word_address + 1) & eeprom_i2c.spec.size_mask;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Write Sequence
|
|
*/
|
|
case WRITE_DATA:
|
|
{
|
|
Detect_START();
|
|
Detect_STOP();
|
|
|
|
/* look for SCL HIGH to LOW transition */
|
|
if (eeprom_i2c.old_scl && !eeprom_i2c.scl)
|
|
{
|
|
if (eeprom_i2c.cycles < 9)
|
|
{
|
|
/* increment cycle counter */
|
|
eeprom_i2c.cycles++;
|
|
}
|
|
else
|
|
{
|
|
/* next write sequence */
|
|
eeprom_i2c.cycles = 1;
|
|
}
|
|
}
|
|
|
|
/* look for SCL LOW to HIGH transition */
|
|
else if (!eeprom_i2c.old_scl && eeprom_i2c.scl)
|
|
{
|
|
if (eeprom_i2c.cycles < 9)
|
|
{
|
|
/* latch DATA bits 7-0 to write buffer */
|
|
eeprom_i2c.buffer |= (eeprom_i2c.sda << (8 - eeprom_i2c.cycles));
|
|
}
|
|
else
|
|
{
|
|
/* write back to memory array (max 64kB) */
|
|
sram.sram[(eeprom_i2c.device_address | eeprom_i2c.word_address) & 0xffff] = eeprom_i2c.buffer;
|
|
|
|
/* clear write buffer */
|
|
eeprom_i2c.buffer = 0;
|
|
|
|
/* increment Word Address (roll over at maximum page size) */
|
|
eeprom_i2c.word_address = (eeprom_i2c.word_address & ~eeprom_i2c.spec.pagewrite_mask) |
|
|
((eeprom_i2c.word_address + 1) & eeprom_i2c.spec.pagewrite_mask);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* save SCL & SDA previous state */
|
|
eeprom_i2c.old_scl = eeprom_i2c.scl;
|
|
eeprom_i2c.old_sda = eeprom_i2c.sda;
|
|
}
|
|
|
|
static uint8 eeprom_i2c_out(void)
|
|
{
|
|
/* check EEPROM state */
|
|
if (eeprom_i2c.state == READ_DATA)
|
|
{
|
|
/* READ cycle */
|
|
if (eeprom_i2c.cycles < 9)
|
|
{
|
|
/* return memory array (max 64kB) DATA bits */
|
|
return ((sram.sram[(eeprom_i2c.device_address | eeprom_i2c.word_address) & 0xffff] >> (8 - eeprom_i2c.cycles)) & 1);
|
|
}
|
|
}
|
|
else if (eeprom_i2c.cycles == 9)
|
|
{
|
|
/* ACK cycle */
|
|
return 0;
|
|
}
|
|
|
|
/* return latched /SDA input by default */
|
|
return eeprom_i2c.sda;
|
|
}
|
|
|
|
|
|
/********************************************************************/
|
|
/* Common I2C board memory mapping */
|
|
/********************************************************************/
|
|
|
|
static uint32 mapper_i2c_generic_read8(uint32 address)
|
|
{
|
|
/* only use D0-D7 */
|
|
if (address & 0x01)
|
|
{
|
|
return eeprom_i2c_out() << eeprom_i2c.sda_out_bit;
|
|
}
|
|
|
|
return m68k_read_bus_8(address);
|
|
}
|
|
|
|
static uint32 mapper_i2c_generic_read16(uint32 address)
|
|
{
|
|
return eeprom_i2c_out() << eeprom_i2c.sda_out_bit;
|
|
}
|
|
|
|
static void mapper_i2c_generic_write8(uint32 address, uint32 data)
|
|
{
|
|
/* only use /LWR */
|
|
if (address & 0x01)
|
|
{
|
|
eeprom_i2c.sda = (data >> eeprom_i2c.sda_in_bit) & 1;
|
|
eeprom_i2c.scl = (data >> eeprom_i2c.scl_in_bit) & 1;
|
|
eeprom_i2c_update();
|
|
}
|
|
else
|
|
{
|
|
m68k_unused_8_w(address, data);
|
|
}
|
|
}
|
|
|
|
static void mapper_i2c_generic_write16(uint32 address, uint32 data)
|
|
{
|
|
eeprom_i2c.sda = (data >> eeprom_i2c.sda_in_bit) & 1;
|
|
eeprom_i2c.scl = (data >> eeprom_i2c.scl_in_bit) & 1;
|
|
eeprom_i2c_update();
|
|
}
|
|
|
|
|
|
/********************************************************************/
|
|
/* EA mapper (PWA P10003 & P10004 boards) */
|
|
/********************************************************************/
|
|
|
|
static void mapper_i2c_ea_init(void)
|
|
{
|
|
int i;
|
|
|
|
/* serial EEPROM (read/write) mapped to $200000-$3fffff */
|
|
for (i=0x20; i<0x40; i++)
|
|
{
|
|
m68k.memory_map[i].read8 = mapper_i2c_generic_read8;
|
|
m68k.memory_map[i].read16 = mapper_i2c_generic_read16;
|
|
m68k.memory_map[i].write8 = mapper_i2c_generic_write8;
|
|
m68k.memory_map[i].write16 = mapper_i2c_generic_write16;
|
|
zbank_memory_map[i].read = mapper_i2c_generic_read8;
|
|
zbank_memory_map[i].write = mapper_i2c_generic_write8;
|
|
}
|
|
|
|
/* SCL (in) -> D6 */
|
|
/* SDA (in/out) -> D7 */
|
|
eeprom_i2c.scl_in_bit = 6;
|
|
eeprom_i2c.sda_in_bit = 7;
|
|
eeprom_i2c.sda_out_bit = 7;
|
|
}
|
|
|
|
|
|
/********************************************************************/
|
|
/* SEGA mapper (171-5878, 171-6111, 171-6304 & 171-6584 boards) */
|
|
/********************************************************************/
|
|
|
|
static void mapper_i2c_sega_init(void)
|
|
{
|
|
int i;
|
|
|
|
/* serial EEPROM (read/write) mapped to $200000-$3fffff */
|
|
for (i=0x20; i<0x40; i++)
|
|
{
|
|
m68k.memory_map[i].read8 = mapper_i2c_generic_read8;
|
|
m68k.memory_map[i].read16 = mapper_i2c_generic_read16;
|
|
m68k.memory_map[i].write8 = mapper_i2c_generic_write8;
|
|
m68k.memory_map[i].write16 = mapper_i2c_generic_write16;
|
|
zbank_memory_map[i].read = mapper_i2c_generic_read8;
|
|
zbank_memory_map[i].write = mapper_i2c_generic_write8;
|
|
}
|
|
|
|
/* SCL (in) -> D1 */
|
|
/* SDA (in/out) -> D0 */
|
|
eeprom_i2c.scl_in_bit = 1;
|
|
eeprom_i2c.sda_in_bit = 0;
|
|
eeprom_i2c.sda_out_bit = 0;
|
|
}
|
|
|
|
|
|
/********************************************************************/
|
|
/* ACCLAIM 16M mapper (P/N 670120 board) */
|
|
/********************************************************************/
|
|
|
|
static void mapper_i2c_acclaim_16M_init(void)
|
|
{
|
|
int i;
|
|
|
|
/* serial EEPROM (read/write) mapped to $200000-$3fffff */
|
|
for (i=0x20; i<0x40; i++)
|
|
{
|
|
/* /LWR & /UWR are unused */
|
|
m68k.memory_map[i].read8 = mapper_i2c_generic_read8;
|
|
m68k.memory_map[i].read16 = mapper_i2c_generic_read16;
|
|
m68k.memory_map[i].write8 = mapper_i2c_generic_write16;
|
|
m68k.memory_map[i].write16 = mapper_i2c_generic_write16;
|
|
zbank_memory_map[i].read = mapper_i2c_generic_read8;
|
|
zbank_memory_map[i].write = mapper_i2c_generic_write16;
|
|
}
|
|
|
|
/* SCL (in) & SDA (out) -> D1 */
|
|
/* SDA (in) -> D0 */
|
|
eeprom_i2c.scl_in_bit = 1;
|
|
eeprom_i2c.sda_in_bit = 0;
|
|
eeprom_i2c.sda_out_bit = 1;
|
|
}
|
|
|
|
|
|
/********************************************************************/
|
|
/* ACCLAIM 32M mapper (P/N 670125 & 670127 boards with LZ95A53 PAL) */
|
|
/********************************************************************/
|
|
|
|
static void mapper_acclaim_32M_write8(uint32 address, uint32 data)
|
|
{
|
|
if (address & 0x01)
|
|
{
|
|
/* D0 goes to /SDA when only /LWR is asserted */
|
|
eeprom_i2c.sda = data & 1;
|
|
}
|
|
else
|
|
{
|
|
/* D0 goes to /SCL when only /UWR is asserted */
|
|
eeprom_i2c.scl = data & 1;
|
|
}
|
|
|
|
eeprom_i2c_update();
|
|
}
|
|
|
|
static void mapper_acclaim_32M_write16(uint32 address, uint32 data)
|
|
{
|
|
int i;
|
|
|
|
/* custom bankshifting when both /LWR and /UWR are asserted */
|
|
if (data & 0x01)
|
|
{
|
|
/* cartridge ROM (read) mapped to $200000-$2fffff */
|
|
for (i=0x20; i<0x30; i++)
|
|
{
|
|
m68k.memory_map[i].read8 = NULL;
|
|
m68k.memory_map[i].read16 = NULL;
|
|
zbank_memory_map[i].read = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* serial EEPROM (read) mapped to $200000-$2fffff */
|
|
for (i=0x20; i<0x30; i++)
|
|
{
|
|
m68k.memory_map[i].read8 = mapper_i2c_generic_read8;
|
|
m68k.memory_map[i].read16 = mapper_i2c_generic_read16;
|
|
zbank_memory_map[i].read = mapper_i2c_generic_read8;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void mapper_i2c_acclaim_32M_init(void)
|
|
{
|
|
int i;
|
|
|
|
/* custom LZ95A53 PAL (write) mapped to $200000-$2fffff */
|
|
for (i=0x20; i<0x30; i++)
|
|
{
|
|
m68k.memory_map[i].write8 = mapper_acclaim_32M_write8;
|
|
m68k.memory_map[i].write16 = mapper_acclaim_32M_write16;
|
|
zbank_memory_map[i].write = mapper_acclaim_32M_write8;
|
|
}
|
|
|
|
/* SCL (in) & SDA (in/out) -> D0 */
|
|
eeprom_i2c.scl_in_bit = 0;
|
|
eeprom_i2c.sda_in_bit = 0;
|
|
eeprom_i2c.sda_out_bit = 0;
|
|
|
|
/* cartridge ROM mapping is reinitialized on reset */
|
|
cart.hw.bankshift = 1;
|
|
}
|
|
|
|
|
|
/********************************************************************/
|
|
/* CODEMASTERS mapper (SRJCV2-1 & SRJCV2-2 boards with 16R4 PAL) */
|
|
/********************************************************************/
|
|
|
|
static uint32 mapper_i2c_jcart_read8(uint32 address)
|
|
{
|
|
/* only D7 used for /SDA */
|
|
if (address & 0x01)
|
|
{
|
|
return ((eeprom_i2c_out() << 7) | (jcart_read(address) & 0x7f));
|
|
}
|
|
|
|
return (jcart_read(address) >> 8);
|
|
}
|
|
|
|
static uint32 mapper_i2c_jcart_read16(uint32 address)
|
|
{
|
|
return ((eeprom_i2c_out() << 7) | jcart_read(address));
|
|
}
|
|
|
|
static void mapper_i2c_jcart_init(void)
|
|
{
|
|
int i;
|
|
|
|
/* check if serial EEPROM is used (support for SRJCV1-1 & SRJCV1-2 boards with only J-CART) */
|
|
if (sram.custom)
|
|
{
|
|
/* serial EEPROM (write) mapped to $300000-$37ffff */
|
|
for (i=0x30; i<0x38; i++)
|
|
{
|
|
/* /LWR & /UWR are unused */
|
|
m68k.memory_map[i].write8 = mapper_i2c_generic_write16;
|
|
m68k.memory_map[i].write16 = mapper_i2c_generic_write16;
|
|
zbank_memory_map[i].write = mapper_i2c_generic_write16;
|
|
}
|
|
}
|
|
|
|
/* check if J-CART is used (support for Brian Lara Cricket games without J-CART) */
|
|
if (strstr(rominfo.product,"T-120106") || strstr(rominfo.product,"T-120146"))
|
|
{
|
|
/* only serial EEPROM (read) mapped to $380000-$3fffff */
|
|
for (i=0x38; i<0x40; i++)
|
|
{
|
|
m68k.memory_map[i].read8 = mapper_i2c_generic_read8;
|
|
m68k.memory_map[i].read16 = mapper_i2c_generic_read16;
|
|
m68k.memory_map[i].write8 = m68k_unused_8_w;
|
|
m68k.memory_map[i].write16 = m68k_unused_16_w;
|
|
zbank_memory_map[i].read = mapper_i2c_generic_read8;
|
|
zbank_memory_map[i].write = m68k_unused_8_w;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* enable J-CART controllers */
|
|
cart.special |= HW_J_CART;
|
|
|
|
/* serial EEPROM (read) & J-CART (read/write) mapped to $380000-$3fffff */
|
|
for (i=0x38; i<0x40; i++)
|
|
{
|
|
/* /LWR & /UWR are unused */
|
|
m68k.memory_map[i].read8 = mapper_i2c_jcart_read8;
|
|
m68k.memory_map[i].read16 = mapper_i2c_jcart_read16;
|
|
m68k.memory_map[i].write8 = jcart_write;
|
|
m68k.memory_map[i].write16 = jcart_write;
|
|
zbank_memory_map[i].read = mapper_i2c_jcart_read8;
|
|
zbank_memory_map[i].write = jcart_write;
|
|
}
|
|
}
|
|
|
|
/* SCL (in) -> D1 */
|
|
/* SDA (in) -> D0 */
|
|
/* SDA (out) -> D7 */
|
|
eeprom_i2c.scl_in_bit = 1;
|
|
eeprom_i2c.sda_in_bit = 0;
|
|
eeprom_i2c.sda_out_bit = 7;
|
|
}
|