# HG changeset patch # User Michael Pavone # Date 1436923685 25200 # Node ID a3b90f746dcf52e2dc31c5ad6fb43702fa090c0c # Parent 4638b88bc72d7d3d0f0bcb2e0a804d9aa672715b Broken EEPROM support diff -r 4638b88bc72d -r a3b90f746dcf blastem.c --- a/blastem.c Fri Jul 10 18:46:18 2015 -0700 +++ b/blastem.c Tue Jul 14 18:28:05 2015 -0700 @@ -827,7 +827,7 @@ } 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 -r 4638b88bc72d -r a3b90f746dcf romdb.c --- a/romdb.c Fri Jul 10 18:46:18 2015 -0700 +++ b/romdb.c Tue Jul 14 18:28:05 2015 -0700 @@ -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_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 @@ 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 @@ 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 -r 4638b88bc72d -r a3b90f746dcf romdb.h --- a/romdb.h Fri Jul 10 18:46:18 2015 -0700 +++ b/romdb.h Tue Jul 14 18:28:05 2015 -0700 @@ -24,9 +24,15 @@ } 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 @@ 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_