changeset 770:a3b90f746dcf

Broken EEPROM support
author Michael Pavone <pavone@retrodev.com>
date Tue, 14 Jul 2015 18:28:05 -0700
parents 4638b88bc72d
children 0565b2c1a034
files blastem.c romdb.c romdb.h
diffstat 3 files changed, 142 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- 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;
--- 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;
--- 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_