From 160884eda003b467dfe92cb007c4f25a6cb5e6e1 Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Sun, 20 Jun 2010 11:24:54 +0100 Subject: [PATCH] ioports: Cleanup and implement PINx toggle Turns out writing 1 to PINx register toggles the bit in PORTx. Did'nt know it worked like that... Signed-off-by: Michel Pollet --- simavr/sim/avr_ioport.c | 48 +++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/simavr/sim/avr_ioport.c b/simavr/sim/avr_ioport.c index a2710f6..555de85 100644 --- a/simavr/sim/avr_ioport.c +++ b/simavr/sim/avr_ioport.c @@ -25,16 +25,13 @@ static uint8_t avr_ioport_read(struct avr_t * avr, avr_io_addr_t addr, void * param) { avr_ioport_t * p = (avr_ioport_t *)param; - uint8_t v = avr->data[addr]; - - if (addr == p->r_pin) { - uint8_t ddr = avr->data[p->r_ddr]; - uint8_t v = (avr->data[p->r_pin] & ~ddr) | (avr->data[p->r_port] & ddr); - avr->data[addr] = v; - // made to trigger potential watchpoints - v = avr_core_watch_read(avr, addr); + uint8_t ddr = avr->data[p->r_ddr]; + uint8_t v = (avr->data[p->r_pin] & ~ddr) | (avr->data[p->r_port] & ddr); + avr->data[addr] = v; + // made to trigger potential watchpoints + v = avr_core_watch_read(avr, addr); // printf("** PIN%c(%02x) = %02x\n", p->name, addr, v); - } + return v; } @@ -43,22 +40,30 @@ static void avr_ioport_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, avr_ioport_t * p = (avr_ioport_t *)param; uint8_t oldv = avr->data[addr]; - if (addr == p->r_port) { - - avr_core_watch_write(avr, addr, v); - if (v != oldv) { - // printf("PORT%c(%02x) = %02x (was %02x)\n", p->name, addr, v, oldv); - int mask = v ^ oldv; + avr_core_watch_write(avr, addr, v); + if (v != oldv) { + // printf("PORT%c(%02x) = %02x (was %02x)\n", p->name, addr, v, oldv); + int mask = v ^ oldv; - // raise the internal IRQ callbacks - for (int i = 0; i < 8; i++) - if (mask & (1 << i)) - avr_raise_irq(p->io.irq + i, (v >> i) & 1); - avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, v); - } + // raise the internal IRQ callbacks + for (int i = 0; i < 8; i++) + if (mask & (1 << i)) + avr_raise_irq(p->io.irq + i, (v >> i) & 1); + avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, v); } } +/* + * This is a reasonably new behaviour for the io-ports. Writing 1's to the PIN register + * toggles the PORT equivalent bit (regardless of direction + */ +static void avr_ioport_pin_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) +{ + avr_ioport_t * p = (avr_ioport_t *)param; + + avr_ioport_write(avr, p->r_port, avr->data[p->r_port] ^ v, param); +} + /* * this is our "main" pin change callback, it can be triggered by either the * AVR code, or any external piece of code that see fit to do it. @@ -149,5 +154,6 @@ void avr_ioport_init(avr_t * avr, avr_ioport_t * p) avr_register_io_write(avr, p->r_port, avr_ioport_write, p); avr_register_io_read(avr, p->r_pin, avr_ioport_read, p); + avr_register_io_write(avr, p->r_pin, avr_ioport_pin_write, p); } -- 2.20.1