From 1d6bfe721dca859750edccd3ecd8d243b56df72a Mon Sep 17 00:00:00 2001 From: ga Date: Sat, 17 Apr 2021 09:15:49 +0100 Subject: [PATCH] Add "clear interrupt on write 1 to flag" function to avr_ioport.c and some code to test it in atmega168_ioport.c and friend. --- simavr/sim/avr_ioport.c | 22 ++++++++++++++++++++-- tests/atmega168_ioport.c | 21 +++++++++++++++++++++ tests/test_atmega168_ioport.c | 3 ++- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/simavr/sim/avr_ioport.c b/simavr/sim/avr_ioport.c index 13dfea6..ca43896 100644 --- a/simavr/sim/avr_ioport.c +++ b/simavr/sim/avr_ioport.c @@ -24,6 +24,21 @@ #define D(_w) +static void +avr_ioport_flag_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_ioport_t * p = (avr_ioport_t *)param; + + // Clear interrupt if 1 is written to flag. + + if (avr_regbit_from_value(avr, p->pcint.raised, v)) + avr_clear_interrupt(avr, &p->pcint); +} + static uint8_t avr_ioport_read( struct avr_t * avr, @@ -122,7 +137,6 @@ avr_ioport_ddr_write( D(if (avr->data[addr] != v) printf("** DDR%c(%02x) = %02x\r\n", p->name, addr, v);) avr_raise_irq(p->io.irq + IOPORT_IRQ_DIRECTION_ALL, v); avr_core_watch_write(avr, addr, v); - avr_ioport_update_irqs(p); } @@ -165,7 +179,7 @@ avr_ioport_irq_notify( /* BUG: If DDR bit is set here, there should be no * interrupt. But a spurious IRQ call by the user - * is indestinguishable from an internal one + * is indistinguishable from an internal one * caused by writing the output port register and * that should cause an interrupt. Doh! */ @@ -319,4 +333,8 @@ void avr_ioport_init(avr_t * avr, avr_ioport_t * 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); avr_register_io_write(avr, p->r_ddr, avr_ioport_ddr_write, p); + if (p->pcint.raised.reg) { + avr_register_io_write(avr, p->pcint.raised.reg, + avr_ioport_flag_write, p); + } } diff --git a/tests/atmega168_ioport.c b/tests/atmega168_ioport.c index 401b170..96d1284 100644 --- a/tests/atmega168_ioport.c +++ b/tests/atmega168_ioport.c @@ -30,6 +30,11 @@ ISR(INT0_vect) printf("I<%02X ", PIND); } +ISR(PCINT0_vect) +{ + printf("K "); +} + ISR(PCINT2_vect) { printf("J<%02X ", PORTD); @@ -105,6 +110,22 @@ int main() printf("P<%02X ", PIND); + // Test "write 1 to clear" on PORT B. + + DDRB = 0xff; + PCICR = (1 << PCIE0); /* Interrupt enable. */ + PCMSK0 = 3; /* Pins 0 and 1. */ + cli(); + PORTB = 1; + PCIFR = 1; /* Clear interrupt. */ + sei(); + printf("| "); + cli(); + PORTB = 3; + PCIFR = 6; + sei(); /* Interrupt. */ + printf("| "); + // this quits the simulator, since interupts are off // this is a "feature" that allows running tests cases and exit cli(); diff --git a/tests/test_atmega168_ioport.c b/tests/test_atmega168_ioport.c index 269a583..24e8c25 100644 --- a/tests/test_atmega168_ioport.c +++ b/tests/test_atmega168_ioport.c @@ -91,7 +91,8 @@ static void reg_read(struct avr_irq_t *irq, uint32_t value, void *param) /* This string should be sent by the firmware. */ -static const char *expected = "P<2A P<70 F<01 I