From f1fb1de3fce7aab23e7e52bc8b93067dda2ee5dc Mon Sep 17 00:00:00 2001
From: Michel <michel@acer.vidiactive.com>
Date: Sun, 4 Apr 2010 15:36:17 +0100
Subject: [PATCH] TWI: Temp TWI changes with new IRQ system

Signed-off-by:  <>
---
 simavr/sim/sim_twi.c | 107 ++++++++++++++++++++++++++++++++-----------
 simavr/sim/sim_twi.h |  62 ++++++++++++++++---------
 2 files changed, 121 insertions(+), 48 deletions(-)

diff --git a/simavr/sim/sim_twi.c b/simavr/sim/sim_twi.c
index b5c19fb..b0eea39 100644
--- a/simavr/sim/sim_twi.c
+++ b/simavr/sim/sim_twi.c
@@ -25,9 +25,81 @@
 #include <string.h>
 #include "sim_twi.h"
 
+static void twi_bus_master_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param)
+{
+	switch (irq->irq) {
+		case TWI_MASTER_STOP:
+			bus->peer = NULL;
+			break;
+		case TWI_MASTER_START:
+			bus->peer = NULL;
+			bus->ack = 0;
+			break;
+		case TWI_MASTER_MISO:
+			bus->ack = 0;
+			break;
+		case TWI_MASTER_MOSI:
+			bus->ack = 0;
+			break;
+		case TWI_MASTER_ACK:
+			if (!peer) {
+			}
+			break;
+	}
+}
+
+static void twi_bus_slave_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param)
+{
+	twi_slave_t * slave = (twi_slave_t*)param;
+	twi_bus_t * bus = slave->bus;
+	switch (irq->irq) {
+		case TWI_SLAVE_MISO:
+			bus->latch = value;
+			break;
+		case TWI_SLAVE_ACK:
+			if (!bus->peer) {
+				bus->peer = slave;
+				printf("twi bus: slave %x selected\n", slave->address);
+			}
+			bus->ack = 0x80 | (value & 1);
+			break;
+	}
+}
+
+static void twi_slave_master_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param)
+{
+	twi_slave_t * slave = (twi_slave_t*)param;
+	switch (irq->irq) {
+		case TWI_MASTER_STOP:
+			if (slave->match) {
+				// we were target
+			}
+			slave->match = 0;
+			break;
+		case TWI_MASTER_START:
+			if ((value & 0xfe) == slave->address & 0xfe) {
+				if (slave->match) {
+					// restart
+				}
+				slave->match = 1;
+				avr_raise_irq(slave->irq + TWI_SLAVE_ACK, 1);
+			}
+			break;
+		case TWI_MASTER_MISO:
+			break;
+		case TWI_MASTER_MOSI:
+			break;
+		case TWI_MASTER_ACK:
+			break;
+	}
+}
+
 void twi_bus_init(twi_bus_t * bus)
 {
 	memset(bus, 0, sizeof(twi_bus_t));
+	avr_init_irq(bus->irq, 0, TWI_STATE_COUNT);
+	for (int i = 0; i < TWI_MASTER_STATE_COUNT; i++)
+		avr_irq_register_notify(bus->irq + i, twi_bus_master_irq_notify, bus);
 }
 
 void twi_bus_attach(twi_bus_t * bus, twi_slave_t * slave)
@@ -36,40 +108,22 @@ void twi_bus_attach(twi_bus_t * bus, twi_slave_t * slave)
 	slave->bus = bus;
 	slave->next = bus->slave;
 	bus->slave = slave;
+	
+	for (int i = 0; i < TWI_SLAVE_STATE_COUNT; i++)
+		avr_irq_register_notify(slave->irq + i, twi_bus_slave_irq_notify, slave);
+	for (int i = 0; i < TWI_MASTER_STATE_COUNT; i++)
+		avr_irq_register_notify(bus->irq + i, twi_slave_irq_notify, slave);
 }
 
 int twi_bus_start(twi_bus_t * bus, uint8_t address)
 {
-	// if we already have a peer, check to see if it's 
-	// still matching, if so, skip the lookup
-	if (bus->peer) {
-		if (twi_slave_match(bus->peer, address))
-			return bus->peer->event(bus->peer, address, TWI_START);
-		twi_bus_stop(bus);
-	}
-		
-	bus->peer = NULL;
-	twi_slave_t *s = bus->slave;
-	while (s) {
-		if (twi_slave_match(s, address)) {
-			if (s->event(s, address, TWI_START)) {
-				bus->peer = s;
-				s->byte_index = 0;
-				return 1;
-			}
-		}
-		s = s->next;
-	}
-	return 0;
+	avr_raise_irq(bus->irq + TWI_MASTER_START, address);
+	return bus->peer != NULL ? 1 : 0;
 }
 
 void twi_bus_stop(twi_bus_t * bus)
 {
-	if (bus->peer) {
-		bus->peer->event(bus->peer, 0, TWI_STOP);
-		bus->peer->byte_index = 0;
-	}
-	bus->peer = NULL;
+	avr_raise_irq(bus->irq + TWI_MASTER_STOP, 0);
 }
 
 int twi_bus_write(twi_bus_t * bus, uint8_t data)
@@ -99,6 +153,7 @@ void twi_slave_init(twi_slave_t * slave, uint8_t address, void * param)
 	memset(slave, 0, sizeof(twi_slave_t));
 	slave->address = address;
 	slave->param = param;
+
 }
 
 void twi_slave_detach(twi_slave_t * slave)
diff --git a/simavr/sim/sim_twi.h b/simavr/sim/sim_twi.h
index 0c841f2..41db043 100644
--- a/simavr/sim/sim_twi.h
+++ b/simavr/sim/sim_twi.h
@@ -27,42 +27,61 @@
 #define SIM_TWI_H_
 
 #include <stdint.h>
+#include "sim_irq.h"
 
-enum twi_event {
-    TWI_START,
-    TWI_STOP,
-	// return non-zero if this slave address is handled by this slave
-	// if NULL, the "address" field is used instead. If this function
-	// is present, 'address' field is not used.
-    TWI_PROBE,
-    TWI_NACK /* Masker NACKed a receive byte.  */
+/*
+ * The TWI system is designed to be representing the same state as 
+ * a TWI/i2c bus itself. So each "state" of the bus is an IRQ sent
+ * by the master to the slave, with a couple sent from the
+ * slave to the master.
+ * This is designed to decorelate the operations on the "bus" so
+ * the firmware has time to "run" before acknowledging a byte, for
+ * example.
+ * 
+ * IRQ Timeline goes as follow  with an example transaction that
+ * does write addres, write registrer, read a byte after a i2c restart
+ * then stops the transaction.
+ * 
+ * Master:	START	MOSI	START	MISO	ACK	STOP
+ * Slave:		ACK		ACK		ACK		MISO	
+ */
+enum twi_state_e {
+	TWI_MASTER_STOP = 0,
+	TWI_MASTER_START,			// master does a start with address
+	TWI_MASTER_MOSI,			// master i2c write
+	TWI_MASTER_MISO,			// master i2c read
+	TWI_MASTER_ACK,				// master i2c ACK after a i2c read
+	TWI_MASTER_STATE_COUNT,
+
+	TWI_SLAVE_MISO = 0,			// slave i2c read.
+	TWI_SLAVE_ACK,				// slave acknowledges TWI_MASTER_MOSI
+	TWI_SLAVE_STATE_COUNT,	
 };
 
 #define TWI_ADDRESS_READ_MASK	0x01
 
 typedef struct twi_slave_t {
+	avr_irq_t		irq[TWI_SLAVE_STATE_COUNT];
+
 	struct twi_bus_t * bus;	// bus we are attached to
 	struct twi_slave_t * next;	// daisy chain on the bus
 	
-	void * param;		// module private parameter
-	uint8_t	address;	// slave address (lowest bit is not used, it's for the W bit)
-	int byte_index;		// byte index in the transaction (since last start, restart)
-
-	// handle start conditionto address+w, restart means "stop" wasn't called
-	int (*event)(struct twi_slave_t* p, uint8_t address, enum twi_event event);
-
-	// handle a data write, after a (re)start
-	int (*write)(struct twi_slave_t* p, uint8_t v);
-
-	// handle a data read, after a (re)start
-	uint8_t (*read)(struct twi_slave_t* p);
+	uint32_t		address;	// can specify up to 4 matching addresses here
+	int				match;		// we are selected on the bus
+	int				index;		// byte index in the transaction
+	
+	uint8_t			latch;		// last received byte
 } twi_slave_t;
 
 
 typedef struct twi_bus_t {
+	avr_irq_t		irq[TWI_MASTER_STATE_COUNT];
+	
 	struct twi_slave_t * slave;	// daisy chain on the bus
-
 	struct twi_slave_t * peer;	// during a transaction, this is the selected slave
+
+	uint8_t			latch;		// last received byte
+	uint8_t			ack;		// last received ack
 } twi_bus_t;
 
 void twi_bus_init(twi_bus_t * bus);
@@ -73,6 +92,5 @@ void twi_bus_stop(twi_bus_t * bus);
 
 void twi_slave_init(twi_slave_t * slave, uint8_t address, void * param);
 void twi_slave_detach(twi_slave_t * slave);
-int twi_slave_match(twi_slave_t * slave, uint8_t address);
 
 #endif /*  SIM_TWI_H_ */
-- 
2.39.5