Genesis-Plus-GX/core/cart_hw/eeprom_i2c.c
2022-10-11 23:10:06 +02:00

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(void)
{
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(void)
{
/* 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(void)
{
/* 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;
}