#include "shared.h"
#include "eeprom_i2c.h"
#define GAME_CNT 28
typedef struct
{
char game_id[16];
uint16 chk;
T_CONFIG_I2C config;
} T_GAME_ENTRY;
static const T_GAME_ENTRY database[GAME_CNT] =
{
{{"T-081326" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200001, 0, 1, 1}},
{{"T-81033" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200001, 0, 1, 1}},
{{"T-081276" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}},
{{"T-81406" }, 0, {8, 0x1FF, 0x1FF, 0x200001, 0x200001, 0x200000, 0, 0, 0}},
{{"T-081586" }, 0, {8, 0x7FF, 0x7FF, 0x200001, 0x200001, 0x200000, 0, 0, 0}},
{{"T-81576" }, 0, {16, 0x1FFF, 0x1FFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}},
{{"T-81476" }, 0, {16, 0x1FFF, 0x1FFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}},
{{"T-50176" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 7, 7, 6}},
{{"T-50396" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 7, 7, 6}},
{{"T-50446" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 7, 7, 6}},
{{"T-50516" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 7, 7, 6}},
{{"T-50606" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 7, 7, 6}},
{{"T-12046" }, 0xAD23, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}},
{{"T-12053" }, 0xEA80, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}},
{{"MK-1215" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}},
{{"MK-1228" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}},
{{"G-5538" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}},
{{"PR-1993" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}},
{{"G-4060" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}},
{{"00001211-00"}, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}},
{{"00004076-00"}, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}},
{{"G-4524" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}},
{{"00054503-00"}, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}},
{{"T-120106" }, 0, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}},
{{"00000000-00"}, 0xCEE0, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}},
{{"T-120096" }, 0, {8, 0x7FF, 0x7FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}},
{{"00000000-00"}, 0x2C41, {8, 0x7FF, 0x7FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}},
{{"T-120146-50"}, 0, {16, 0x1FFF, 0x1FFF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}
};
T_EEPROM_I2C eeprom_i2c;
static unsigned int eeprom_i2c_read_byte(unsigned int address);
static unsigned int eeprom_i2c_read_word(unsigned int address);
static void eeprom_i2c_write_byte(unsigned int address, unsigned int data);
static void eeprom_i2c_write_word(unsigned int address, unsigned int data);
void eeprom_i2c_init()
{
int i = 0;
memset(&eeprom_i2c, 0, sizeof(T_EEPROM_I2C));
eeprom_i2c.sda = eeprom_i2c.old_sda = 1;
eeprom_i2c.scl = eeprom_i2c.old_scl = 1;
eeprom_i2c.state = STAND_BY;
sram.custom = 0;
while (i<GAME_CNT)
{
if (strstr(rominfo.product,database[i].game_id) != NULL)
{
if ((database[i].chk == 0x0000) || (database[i].chk == rominfo.realchecksum))
{
sram.custom = 1;
sram.on = 1;
memcpy(&eeprom_i2c.config, &database[i].config, sizeof(T_CONFIG_I2C));
i = GAME_CNT;
}
}
i++;
}
if (!sram.custom && sram.detected)
{
if ((READ_BYTE(cart.rom,0x1b2) == 0xe8) || ((sram.end - sram.start) < 2))
{
sram.custom = 1;
memcpy(&eeprom_i2c.config, &database[9].config, sizeof(T_CONFIG_I2C));
}
}
if (sram.custom)
{
m68k.memory_map[eeprom_i2c.config.sda_out_adr >> 16].read8 = eeprom_i2c_read_byte;
m68k.memory_map[eeprom_i2c.config.sda_out_adr >> 16].read16 = eeprom_i2c_read_word;
m68k.memory_map[eeprom_i2c.config.sda_in_adr >> 16].read8 = eeprom_i2c_read_byte;
m68k.memory_map[eeprom_i2c.config.sda_in_adr >> 16].read16 = eeprom_i2c_read_word;
m68k.memory_map[eeprom_i2c.config.scl_adr >> 16].write8 = eeprom_i2c_write_byte;
m68k.memory_map[eeprom_i2c.config.scl_adr >> 16].write16 = eeprom_i2c_write_word;
zbank_memory_map[eeprom_i2c.config.sda_out_adr >> 16].read = eeprom_i2c_read_byte;
zbank_memory_map[eeprom_i2c.config.sda_in_adr >> 16].read = eeprom_i2c_read_byte;
zbank_memory_map[eeprom_i2c.config.scl_adr >> 16].write = eeprom_i2c_write_byte;
}
}
INLINE void Detect_START()
{
if (eeprom_i2c.old_scl && eeprom_i2c.scl)
{
if (eeprom_i2c.old_sda && !eeprom_i2c.sda)
{
eeprom_i2c.cycles = 0;
eeprom_i2c.slave_mask = 0;
if (eeprom_i2c.config.address_bits == 7)
{
eeprom_i2c.word_address = 0;
eeprom_i2c.state = GET_WORD_ADR_7BITS;
}
else eeprom_i2c.state = GET_SLAVE_ADR;
}
}
}
INLINE void Detect_STOP()
{
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)
{
switch (eeprom_i2c.state)
{
case STAND_BY:
{
Detect_START();
Detect_STOP();
break;
}
case WAIT_STOP:
{
Detect_STOP();
break;
}
case GET_WORD_ADR_7BITS:
{
Detect_START();
Detect_STOP();
if (!eeprom_i2c.old_scl && eeprom_i2c.scl)
{
if (eeprom_i2c.cycles == 0) eeprom_i2c.cycles ++;
}
if (eeprom_i2c.old_scl && !eeprom_i2c.scl && (eeprom_i2c.cycles > 0))
{
if (eeprom_i2c.cycles < 8)
{
eeprom_i2c.word_address |= (eeprom_i2c.old_sda << (7 - eeprom_i2c.cycles));
}
else if (eeprom_i2c.cycles == 8)
{
eeprom_i2c.rw = eeprom_i2c.old_sda;
}
else
{
eeprom_i2c.cycles = 0;
eeprom_i2c.word_address &= eeprom_i2c.config.size_mask;
eeprom_i2c.state = eeprom_i2c.rw ? READ_DATA : WRITE_DATA;
}
eeprom_i2c.cycles ++;
}
break;
}
case GET_SLAVE_ADR:
{
Detect_START();
Detect_STOP();
if (!eeprom_i2c.old_scl && eeprom_i2c.scl)
{
if (eeprom_i2c.cycles == 0) eeprom_i2c.cycles ++;
}
if (eeprom_i2c.old_scl && !eeprom_i2c.scl && (eeprom_i2c.cycles > 0))
{
if ((eeprom_i2c.cycles > 4) && (eeprom_i2c.cycles <8))
{
if ((eeprom_i2c.config.address_bits == 16) ||
(eeprom_i2c.config.size_mask < (1 << (15 - eeprom_i2c.cycles))))
{
eeprom_i2c.slave_mask |= (eeprom_i2c.old_sda << (7 - eeprom_i2c.cycles));
}
else
{
if (eeprom_i2c.old_sda) eeprom_i2c.word_address |= (1 << (15 - eeprom_i2c.cycles));
else eeprom_i2c.word_address &= ~(1 << (15 - eeprom_i2c.cycles));
}
}
else if (eeprom_i2c.cycles == 8) eeprom_i2c.rw = eeprom_i2c.old_sda;
else if (eeprom_i2c.cycles > 8)
{
eeprom_i2c.cycles = 0;
if (eeprom_i2c.config.address_bits == 16)
{
eeprom_i2c.state = eeprom_i2c.rw ? READ_DATA : GET_WORD_ADR_HIGH;
eeprom_i2c.slave_mask <<= 16;
}
else
{
eeprom_i2c.state = eeprom_i2c.rw ? READ_DATA : GET_WORD_ADR_LOW;
eeprom_i2c.slave_mask <<= 8;
}
}
eeprom_i2c.cycles ++;
}
break;
}
case GET_WORD_ADR_HIGH:
{
Detect_START();
Detect_STOP();
if (eeprom_i2c.old_scl && !eeprom_i2c.scl)
{
if (eeprom_i2c.cycles < 9)
{
if ((eeprom_i2c.config.size_mask + 1) < (1 << (17 - eeprom_i2c.cycles)))
{
eeprom_i2c.slave_mask >>= 1;
}
else
{
if (eeprom_i2c.old_sda) eeprom_i2c.word_address |= (1 << (16 - eeprom_i2c.cycles));
else eeprom_i2c.word_address &= ~(1 << (16 - eeprom_i2c.cycles));
}
eeprom_i2c.cycles ++;
}
else
{
eeprom_i2c.cycles = 1;
eeprom_i2c.state = GET_WORD_ADR_LOW;
}
}
break;
}
case GET_WORD_ADR_LOW:
{
Detect_START();
Detect_STOP();
if (eeprom_i2c.old_scl && !eeprom_i2c.scl)
{
if (eeprom_i2c.cycles < 9)
{
if ((eeprom_i2c.config.size_mask + 1) < (1 << (9 - eeprom_i2c.cycles)))
{
eeprom_i2c.slave_mask >>= 1;
}
else
{
if (eeprom_i2c.old_sda) eeprom_i2c.word_address |= (1 << (8 - eeprom_i2c.cycles));
else eeprom_i2c.word_address &= ~(1 << (8 - eeprom_i2c.cycles));
}
eeprom_i2c.cycles ++;
}
else
{
eeprom_i2c.cycles = 1;
eeprom_i2c.word_address &= eeprom_i2c.config.size_mask;
eeprom_i2c.state = WRITE_DATA;
}
}
break;
}
case READ_DATA:
{
Detect_START();
Detect_STOP();
if (eeprom_i2c.old_scl && !eeprom_i2c.scl)
{
if (eeprom_i2c.cycles < 9) eeprom_i2c.cycles ++;
else
{
eeprom_i2c.cycles = 1;
if (eeprom_i2c.old_sda) eeprom_i2c.state = WAIT_STOP;
}
}
break;
}
case WRITE_DATA:
{
Detect_START();
Detect_STOP();
if (eeprom_i2c.old_scl && !eeprom_i2c.scl)
{
if (eeprom_i2c.cycles < 9)
{
uint16 sram_address = (eeprom_i2c.slave_mask | eeprom_i2c.word_address) & 0xFFFF;
if (eeprom_i2c.old_sda) sram.sram[sram_address] |= (1 << (8 - eeprom_i2c.cycles));
else sram.sram[sram_address] &= ~(1 << (8 - eeprom_i2c.cycles));
if (eeprom_i2c.cycles == 8)
{
eeprom_i2c.word_address = (eeprom_i2c.word_address & (0xFFFF - eeprom_i2c.config.pagewrite_mask)) |
((eeprom_i2c.word_address + 1) & eeprom_i2c.config.pagewrite_mask);
}
eeprom_i2c.cycles ++;
}
else eeprom_i2c.cycles = 1;
}
break;
}
}
eeprom_i2c.old_scl = eeprom_i2c.scl;
eeprom_i2c.old_sda = eeprom_i2c.sda;
}
static unsigned char eeprom_i2c_out(void)
{
uint8 sda_out = eeprom_i2c.sda;
switch (eeprom_i2c.state)
{
case READ_DATA:
{
if (eeprom_i2c.cycles < 9)
{
uint16 sram_address = (eeprom_i2c.slave_mask | eeprom_i2c.word_address) & 0xffff;
sda_out = (sram.sram[sram_address] >> (8 - eeprom_i2c.cycles)) & 1;
if (eeprom_i2c.cycles == 8)
{
eeprom_i2c.word_address ++;
eeprom_i2c.word_address &= eeprom_i2c.config.size_mask;
}
}
break;
}
case GET_WORD_ADR_7BITS:
case GET_SLAVE_ADR:
case GET_WORD_ADR_HIGH:
case GET_WORD_ADR_LOW:
case WRITE_DATA:
{
if (eeprom_i2c.cycles == 9) sda_out = 0;
break;
}
default:
{
break;
}
}
return (sda_out << eeprom_i2c.config.sda_out_bit);
}
static unsigned int eeprom_i2c_read_byte(unsigned int address)
{
if (address == eeprom_i2c.config.sda_out_adr)
{
return eeprom_i2c_out();
}
return READ_BYTE(cart.rom, address);
}
static unsigned int eeprom_i2c_read_word(unsigned int address)
{
if (address == eeprom_i2c.config.sda_out_adr)
{
return (eeprom_i2c_out() << 8);
}
if (address == (eeprom_i2c.config.sda_out_adr ^ 1))
{
return eeprom_i2c_out();
}
return *(uint16 *)(cart.rom + address);
}
static void eeprom_i2c_write_byte(unsigned int address, unsigned int data)
{
int do_update = 0;
if (address == eeprom_i2c.config.sda_in_adr)
{
eeprom_i2c.sda = (data >> eeprom_i2c.config.sda_in_bit) & 1;
do_update = 1;
}
if (address == eeprom_i2c.config.scl_adr)
{
eeprom_i2c.scl = (data >> eeprom_i2c.config.scl_bit) & 1;
do_update = 1;
}
if (do_update)
{
eeprom_i2c_update();
return;
}
m68k_unused_8_w(address, data);
}
static void eeprom_i2c_write_word(unsigned int address, unsigned int data)
{
int do_update = 0;
if (address == eeprom_i2c.config.sda_in_adr)
{
eeprom_i2c.sda = (data >> (8 + eeprom_i2c.config.sda_in_bit)) & 1;
do_update = 1;
}
else if (address == (eeprom_i2c.config.sda_in_adr ^1))
{
eeprom_i2c.sda = (data >> eeprom_i2c.config.sda_in_bit) & 1;
do_update = 1;
}
if (address == eeprom_i2c.config.scl_adr)
{
eeprom_i2c.scl = (data >> (8 + eeprom_i2c.config.scl_bit)) & 1;
do_update = 1;
}
else if (address == (eeprom_i2c.config.scl_adr ^1))
{
eeprom_i2c.scl = (data >> eeprom_i2c.config.scl_bit) & 1;
do_update = 1;
}
if (do_update)
{
eeprom_i2c_update();
return;
}
m68k_unused_16_w(address, data);
}