summaryrefslogtreecommitdiff
path: root/romdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'romdb.c')
-rw-r--r--romdb.c141
1 files changed, 134 insertions, 7 deletions
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;