summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blastem.c2
-rw-r--r--romdb.c141
-rw-r--r--romdb.h8
3 files changed, 142 insertions, 9 deletions
diff --git a/blastem.c b/blastem.c
index a48ba30..51f188e 100644
--- a/blastem.c
+++ b/blastem.c
@@ -827,7 +827,7 @@ void init_run_cpu(genesis_context * gen, rom_info *rom, FILE * address_log, char
}
atexit(persist_save);
if (gen->save_type == SAVE_I2C) {
- eeprom_init(&gen->eeprom);
+ eeprom_init(&gen->eeprom, gen->save_storage, gen->save_size);
}
} else {
gen->save_storage = NULL;
diff --git a/romdb.c b/romdb.c
index ed845ab..072c1b1 100644
--- a/romdb.c
+++ b/romdb.c
@@ -16,19 +16,55 @@
#define RAM_END 0x1B8
#define REGION_START 0x1F0
-void eeprom_init(eeprom_state *state)
+enum {
+ I2C_IDLE,
+ I2C_START,
+ I2C_DEVICE_ACK,
+ I2C_ADDRESS_HI,
+ I2C_ADDRESS_HI_ACK,
+ I2C_ADDRESS,
+ I2C_ADDRESS_ACK,
+ I2C_READ,
+ I2C_READ_ACK,
+ I2C_WRITE,
+ I2C_WRITE_ACK
+};
+
+char * i2c_states[] = {
+ "idle",
+ "start",
+ "device ack",
+ "address hi",
+ "address hi ack",
+ "address",
+ "address ack",
+ "read",
+ "read_ack",
+ "write",
+ "write_ack"
+};
+
+void eeprom_init(eeprom_state *state, uint8_t *buffer, uint32_t size)
{
state->slave_sda = 1;
state->host_sda = state->scl = 0;
+ state->buffer = buffer;
+ state->size = size;
+ state->state = I2C_IDLE;
}
void set_host_sda(eeprom_state *state, uint8_t val)
{
if (state->scl) {
if (val & ~state->host_sda) {
- //stop condition
+ //low to high, stop condition
+ state->state = I2C_IDLE;
+ state->slave_sda = 1;
} else if (~val & state->host_sda) {
- //start condition
+ //high to low, start condition
+ state->state = I2C_START;
+ state->slave_sda = 1;
+ state->counter = 8;
}
}
state->host_sda = val;
@@ -37,7 +73,98 @@ void set_host_sda(eeprom_state *state, uint8_t val)
void set_scl(eeprom_state *state, uint8_t val)
{
if (val & ~state->scl) {
- //latch sda
+ //low to high transition
+ switch (state->state)
+ {
+ case I2C_START:
+ case I2C_ADDRESS_HI:
+ case I2C_ADDRESS:
+ case I2C_WRITE:
+ state->latch = state->host_sda << 7 | state->latch >> 1;
+ state->counter--;
+ if (!state->counter) {
+ switch (state->state & 0x7F)
+ {
+ case I2C_START:
+ state->state = I2C_DEVICE_ACK;
+ break;
+ case I2C_ADDRESS_HI:
+ state->address = state->latch << 8;
+ state->state = I2C_ADDRESS_HI_ACK;
+ break;
+ case I2C_ADDRESS:
+ state->address |= state->latch;
+ state->state = I2C_ADDRESS_ACK;
+ break;
+ case I2C_WRITE:
+ state->buffer[state->address] = state->latch;
+ state->state = I2C_WRITE_ACK;
+ state->address++;
+ //TODO: page mask
+ state->address &= state->size-1;
+ break;
+ }
+ }
+ break;
+ case I2C_DEVICE_ACK:
+ if (state->latch & 1) {
+ state->state = I2C_READ;
+ state->counter = 8;
+ state->latch = state->buffer[state->address];
+ state->address++;
+ //TODO: page mask
+ state->address &= state->size-1;
+ } else {
+ if (state->size < 256) {
+ state->address = state->latch >> 1;
+ state->state = I2C_WRITE;
+ } else if (state->size < 8192) {
+ state->address = state->latch << 8;
+ state->state = I2C_ADDRESS;
+ } else {
+ state->state = I2C_ADDRESS_HI;
+ }
+ state->counter = 8;
+ }
+ break;
+ case I2C_ADDRESS_HI_ACK:
+ state->state = I2C_ADDRESS;
+ break;
+ case I2C_ADDRESS_ACK:
+ state->state = I2C_WRITE;
+ break;
+ case I2C_READ:
+ state->counter--;
+ if (!state->counter) {
+ state->state = I2C_READ_ACK;
+ }
+ break;
+ case I2C_READ_ACK:
+ state->state = I2C_READ;
+ break;
+ case I2C_WRITE_ACK:
+ state->state = I2C_WRITE;
+ break;
+ }
+ } else if (~val & state->scl) {
+ //high to low transition
+ switch (state->state & 0x7F)
+ {
+ case I2C_DEVICE_ACK:
+ case I2C_ADDRESS_HI_ACK:
+ case I2C_ADDRESS_ACK:
+ case I2C_READ_ACK:
+ case I2C_WRITE_ACK:
+ state->slave_sda = 0;
+ break;
+ case I2C_READ:
+ state->slave_sda = state->latch >> 7;
+ state->latch = state->latch << 1;
+ break;
+ default:
+ state->slave_sda = 1;
+ break;
+ }
}
state->scl = val;
}
@@ -192,8 +319,8 @@ void * write_eeprom_i2c_w(uint32_t address, void * context, uint16_t value)
set_host_sda(&gen->eeprom, (value & map->sda_write_mask) != 0);
}
if (map->scl_mask) {
- printf("scl: %d\n", (value & map->scl_mask) != 0);
- set_scl(&gen->eeprom, (value & map->sda_write_mask) != 0);
+ set_scl(&gen->eeprom, (value & map->scl_mask) != 0);
+ printf("scl: %d, state: %s, counter: %d\n", (value & map->scl_mask) != 0, i2c_states[gen->eeprom.state], gen->eeprom.counter);
}
return context;
}
@@ -221,7 +348,7 @@ void * write_eeprom_i2c_b(uint32_t address, void * context, uint8_t value)
set_host_sda(&gen->eeprom, (expanded & map->sda_write_mask) != 0);
}
if (map->scl_mask & mask) {
- printf("scl: %d\n", (expanded & map->scl_mask) != 0);
+ printf("scl: %d, state: %s\n", (expanded & map->scl_mask) != 0, i2c_states[gen->eeprom.state]);
set_scl(&gen->eeprom, (expanded & map->scl_mask) != 0);
}
return context;
diff --git a/romdb.h b/romdb.h
index e126640..3bf9fa6 100644
--- a/romdb.h
+++ b/romdb.h
@@ -24,9 +24,15 @@ typedef struct {
} eeprom_map;
typedef struct {
+ char *buffer;
+ uint32_t size;
+ uint16_t address;
uint8_t host_sda;
uint8_t slave_sda;
uint8_t scl;
+ uint8_t state;
+ uint8_t counter;
+ uint8_t latch;
} eeprom_state;
typedef struct {
@@ -46,6 +52,6 @@ tern_node *load_rom_db();
rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks);
rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks);
uint8_t translate_region_char(uint8_t c);
-void eeprom_init(eeprom_state *state);
+void eeprom_init(eeprom_state *state, uint8_t *buffer, uint32_t size);
#endif //ROMDB_H_