From cf3a3b74da7cfe027bcaa5ef22302785da8a034e Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Thu, 25 Feb 2010 22:12:36 +0000 Subject: [PATCH] TWI: Work in progress Changed to look more like qemu Signed-off-by: Michel Pollet --- simavr/sim/avr_twi.c | 42 ++++++++++++++++++++++++++---------------- simavr/sim/avr_twi.h | 2 +- simavr/sim/sim_twi.c | 27 ++++++++++++++++++--------- simavr/sim/sim_twi.h | 27 +++++++++++++++++---------- 4 files changed, 62 insertions(+), 36 deletions(-) diff --git a/simavr/sim/avr_twi.c b/simavr/sim/avr_twi.c index 0f7e648..6ebe7bb 100644 --- a/simavr/sim/avr_twi.c +++ b/simavr/sim/avr_twi.c @@ -70,14 +70,16 @@ static void avr_twi_irq_input(struct avr_irq_t * irq, uint32_t value, void * par #endif } -static int twi_slave_has_address(struct twi_slave_t* p, uint8_t address) -{ - return 0; -} - - // handle start conditionto address+w, restart means "stop" wasn't called -static int twi_slave_start(struct twi_slave_t* p, uint8_t address, int restart) +static int twi_slave_event(struct twi_slave_t* p, uint8_t address, enum twi_event event) { + switch (event) { + case TWI_START: + break; + case TWI_STOP: + break; + case TWI_PROBE: + break; + } return 0; } @@ -93,19 +95,26 @@ static uint8_t twi_slave_read(struct twi_slave_t* p) return 0; } - // stop condition detected -static void twi_slave_stop(struct twi_slave_t* p) -{ -} - static twi_slave_t slave_driver = { - .has_address = twi_slave_has_address, - .start = twi_slave_start, - .stop = twi_slave_stop, + .event = twi_slave_event, .write = twi_slave_write, .read = twi_slave_read }; +static int avr_twi_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param) +{ + avr_twi_t * p = (avr_twi_t *)port; + int res = -1; + + if (ctl == AVR_IOCTL_TWI_GETSLAVE(p->name)) { + *(twi_slave_t**)io_param = &p->slave; + } else if (ctl == AVR_IOCTL_TWI_GETBUS(p->name)) { + *(twi_bus_t**)io_param = &p->bus; + } + + return res; +} + void avr_twi_reset(struct avr_io_t *io) { avr_twi_t * p = (avr_twi_t *)io; @@ -115,6 +124,7 @@ void avr_twi_reset(struct avr_io_t *io) static avr_io_t _io = { .kind = "twi", .reset = avr_twi_reset, + .ioctl = avr_twi_ioctl, }; void avr_twi_init(avr_t * avr, avr_twi_t * p) @@ -123,7 +133,7 @@ void avr_twi_init(avr_t * avr, avr_twi_t * p) avr_register_io(avr, &p->io); avr_register_vector(avr, &p->twi); p->slave = slave_driver; // get default callbacks - twi_slave_init(&p->slave, p); + twi_slave_init(&p->slave, 0, p); twi_bus_init(&p->bus); //printf("%s TWI%c init\n", __FUNCTION__, p->name); diff --git a/simavr/sim/avr_twi.h b/simavr/sim/avr_twi.h index 31c3ca5..1de1ef4 100644 --- a/simavr/sim/avr_twi.h +++ b/simavr/sim/avr_twi.h @@ -57,7 +57,7 @@ typedef struct avr_twi_t { avr_io_addr_t r_twdr; // data register avr_regbit_t twen; // twi enable bit - avr_regbit_t twea; // enabke acknowledge bit + avr_regbit_t twea; // enable acknowledge bit avr_regbit_t twsta; // start condition avr_regbit_t twsto; // stop condition avr_regbit_t twwc; // write collision diff --git a/simavr/sim/sim_twi.c b/simavr/sim/sim_twi.c index 9d6501e..b5c19fb 100644 --- a/simavr/sim/sim_twi.c +++ b/simavr/sim/sim_twi.c @@ -22,10 +22,12 @@ */ #include +#include #include "sim_twi.h" void twi_bus_init(twi_bus_t * bus) { + memset(bus, 0, sizeof(twi_bus_t)); } void twi_bus_attach(twi_bus_t * bus, twi_slave_t * slave) @@ -40,14 +42,17 @@ 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 && twi_slave_match(bus->peer, address)) - return bus->peer->start(bus->peer, address, 1); + 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->start(s, address, 0)) { + if (s->event(s, address, TWI_START)) { bus->peer = s; s->byte_index = 0; return 1; @@ -60,8 +65,10 @@ int twi_bus_start(twi_bus_t * bus, uint8_t address) void twi_bus_stop(twi_bus_t * bus) { - if (bus->peer && bus->peer->stop) - bus->peer->stop(bus->peer); + if (bus->peer) { + bus->peer->event(bus->peer, 0, TWI_STOP); + bus->peer->byte_index = 0; + } bus->peer = NULL; } @@ -87,8 +94,10 @@ uint8_t twi_bus_read(twi_bus_t * bus) return res; } -void twi_slave_init(twi_slave_t * slave, void * param) +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; } @@ -114,8 +123,8 @@ void twi_slave_detach(twi_slave_t * slave) int twi_slave_match(twi_slave_t * slave, uint8_t address) { - if (slave->has_address) - return slave->has_address(slave, address); - return (address & ~1) == (slave->address & ~1); + if (slave->address) + return (address & ~1) == (slave->address & ~1); + return slave->event(slave, address, TWI_PROBE); } diff --git a/simavr/sim/sim_twi.h b/simavr/sim/sim_twi.h index 7f383cb..0c841f2 100644 --- a/simavr/sim/sim_twi.h +++ b/simavr/sim/sim_twi.h @@ -28,27 +28,34 @@ #include +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. */ +}; + +#define TWI_ADDRESS_READ_MASK 0x01 + typedef struct twi_slave_t { struct twi_bus_t * bus; // bus we are attached to struct twi_slave_t * next; // daisy chain on the bus - void * param; // module parameter + 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) - // 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. - int (*has_address)(struct twi_slave_t* p, uint8_t address); // optional - // handle start conditionto address+w, restart means "stop" wasn't called - int (*start)(struct twi_slave_t* p, uint8_t address, int restart); + 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); - // stop condition detected - void (*stop)(struct twi_slave_t* p); } twi_slave_t; @@ -64,7 +71,7 @@ int twi_bus_write(twi_bus_t * bus, uint8_t data); uint8_t twi_bus_read(twi_bus_t * bus); void twi_bus_stop(twi_bus_t * bus); -void twi_slave_init(twi_slave_t * slave, void * param); +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); -- 2.39.5