Add "clear interrupt on write 1 to flag" function to avr_ioport.c
authorga <ga@oldell.fish>
Sat, 17 Apr 2021 08:15:49 +0000 (09:15 +0100)
committerga <ga@oldell.fish>
Sat, 17 Apr 2021 08:54:53 +0000 (09:54 +0100)
and some code to test it in atmega168_ioport.c and friend.

simavr/sim/avr_ioport.c
tests/atmega168_ioport.c
tests/test_atmega168_ioport.c

index 13dfea6..ca43896 100644 (file)
 
 #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);
+       }
 }
index 401b170..96d1284 100644 (file)
@@ -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();
index 269a583..24e8c25 100644 (file)
@@ -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<E0 P<E0 J<03 J<00 P<E8 ";
+static const char *expected =
+    "P<2A P<70 F<01 I<E0 P<E0 J<03 J<00 P<E8 | K | ";
 
 /* This string is expected in variable log. */