Commit 2f136762ea1e9d7fdd84413c09503ae9920b42cc
authorga <ga@oldell.fish>
Fri, 4 Mar 2022 14:09:57 +0000 (14:09 +0000)
committerga <ga@oldell.fish>
Fri, 4 Mar 2022 14:09:57 +0000 (14:09 +0000)
Change the way I/O register IRQs are called so that they report
changes made by peripheral code as well as the core.
Also, do not call them for reads.  Add some test code.

3 files changed:
simavr/sim/avr_ioport.c
simavr/sim/sim_core.c
tests/test_atmega168_ioport.c

index ca43896b39a03d88efc9f6578fb5a92818846639..91cf106d3a1d712d0bec1e232b0bfe9931bde4e6 100644 (file)
@@ -173,9 +173,9 @@ avr_ioport_irq_notify(
        } else {
                // Set the real PIN bit. Ignore DDR as it's masked when read.
 
-               avr->data[p->r_pin] &= ~mask;
-               if (value)
-                       avr->data[p->r_pin] |= mask;
+               avr_core_watch_write(avr, p->r_pin,
+                                                        (avr->data[p->r_pin] & ~mask) |
+                                                               (value ? mask : 0));
 
                /* BUG: If DDR bit is set here, there should be no
                 * interrupt.  But a spurious IRQ call by the user
index 4bb254334a80e1284f9a8465878d5b51940f8377..cc7285b27b0354c64fa93d3ca0d1e50859be4521 100644 (file)
@@ -121,6 +121,20 @@ _avr_flash_read16le(
        return(avr->flash[addr] | (avr->flash[addr + 1] << 8));
 }
 
+static inline void _call_register_irqs(avr_t * avr, uint16_t addr)
+{
+       if (addr > 31 && addr < 31 + MAX_IOs) {
+               avr_io_addr_t io = AVR_DATA_TO_IO(addr);
+
+               if (avr->io[io].irq) {
+                       uint8_t v = avr->data[addr];
+                       avr_raise_irq(avr->io[io].irq + AVR_IOMEM_IRQ_ALL, v);
+                       for (int i = 0; i < 8; i++)
+                               avr_raise_irq(avr->io[io].irq + i, (v >> i) & 1);
+               }
+       }
+}
+
 void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v)
 {
        if (addr > avr->ramend) {
@@ -155,6 +169,7 @@ void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v)
        }
 
        avr->data[addr] = v;
+       _call_register_irqs(avr, addr);
 }
 
 uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr)
@@ -172,6 +187,7 @@ uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr)
                avr_gdb_handle_watchpoints(avr, addr, AVR_GDB_WATCH_READ);
        }
 
+//     _call_register_irqs(avr, addr);
        return avr->data[addr];
 }
 
@@ -192,14 +208,15 @@ static inline void _avr_set_r(avr_t * avr, uint16_t r, uint8_t v)
        }
        if (r > 31) {
                avr_io_addr_t io = AVR_DATA_TO_IO(r);
-               if (avr->io[io].w.c)
+               if (avr->io[io].w.c) {
                        avr->io[io].w.c(avr, r, v, avr->io[io].w.param);
-               else
+               } else {
                        avr->data[r] = v;
-               if (avr->io[io].irq) {
-                       avr_raise_irq(avr->io[io].irq + AVR_IOMEM_IRQ_ALL, v);
-                       for (int i = 0; i < 8; i++)
-                               avr_raise_irq(avr->io[io].irq + i, (v >> i) & 1);
+                       if (avr->io[io].irq) {
+                               avr_raise_irq(avr->io[io].irq + AVR_IOMEM_IRQ_ALL, v);
+                               for (int i = 0; i < 8; i++)
+                                       avr_raise_irq(avr->io[io].irq + i, (v >> i) & 1);
+                       }
                }
        } else
                avr->data[r] = v;
@@ -266,13 +283,14 @@ static inline uint8_t _avr_get_ram(avr_t * avr, uint16_t addr)
 
                if (avr->io[io].r.c)
                        avr->data[addr] = avr->io[io].r.c(avr, addr, avr->io[io].r.param);
-
+#if 0
                if (avr->io[io].irq) {
                        uint8_t v = avr->data[addr];
                        avr_raise_irq(avr->io[io].irq + AVR_IOMEM_IRQ_ALL, v);
                        for (int i = 0; i < 8; i++)
                                avr_raise_irq(avr->io[io].irq + i, (v >> i) & 1);
                }
+#endif
        }
        return avr_core_watch_read(avr, addr);
 }
index 24e8c25a8cddf967b44b70fb0f48590ca90a6882..d4da24a03f5a818ee2af69e0873b78e4dded4e9a 100644 (file)
@@ -3,6 +3,8 @@
 #include "tests.h"
 #include "avr_ioport.h"
 
+#define DDRB_ADDR (0x4 + 32) // From ATM168 header file.
+
 /* Start of the IOPORT's IRQ list. */
 
 static avr_irq_t *base_irq;
@@ -22,6 +24,16 @@ static void monitor_5(struct avr_irq_t *irq, uint32_t value, void *param)
     LOG("5-%02X ", value);
 }
 
+/* IRQ call-back for changes to the simulated DDRB register.
+ * This is to test an IRQ returned by avr_iomem_getirq() and not really
+ * specifically for GPIO.
+ */
+
+static void monitor_ddrb(struct avr_irq_t *irq, uint32_t value, void *param)
+{
+    LOG("BD-%02X ", value);
+}
+
 /* This monitors the simulator's idea of the I/O pin states.
  * Changes this program makes to inputs are not reported,
  * presumably because the simulator "knows" we made them.
@@ -97,10 +109,11 @@ static const char *expected =
 /* This string is expected in variable log. */
 
 static const char *log_expected =
-    "d-0F P-00 o-0A P-0A I-0A 5-01 o-09 P-29 d-3C 5-00 P-09 o-F0 5-01 P-F0 "
-    "I-70 "                                     // Interrupts off testing.
+    "BD-01 d-0F P-00 o-0A P-0A I-0A 5-01 o-09 P-29 d-3C 5-00 P-09 o-F0 5-01 "
+    "P-F0 I-70 "                                // Interrupts off testing.
     "o-E0 P-E0 I-E0 I-E0 "                      // External interrupt test.
-    "d-03 o-01 P-E1 o-03 P-E3 o-00 P-E8 I-E8 "; // Pin change interrupt test.
+    "d-03 o-01 P-E1 o-03 P-E3 o-00 P-E8 I-E8 "  // Pin change interrupt test.
+    "BD-FF ";                                   // iomem IRQ test.
 
 
 int main(int argc, char **argv) {
@@ -114,6 +127,8 @@ int main(int argc, char **argv) {
                                 monitor_5, NULL);
         avr_irq_register_notify(base_irq + IOPORT_IRQ_PIN_ALL,
                                 monitor, NULL);
+        avr_irq_register_notify(avr_iomem_getirq(avr, DDRB_ADDR, NULL, 8),
+                                monitor_ddrb, NULL);
         avr_irq_register_notify(base_irq + IOPORT_IRQ_DIRECTION_ALL,
                                 reg_write, NULL);
         avr_irq_register_notify(base_irq + IOPORT_IRQ_REG_PORT,
@@ -121,6 +136,12 @@ int main(int argc, char **argv) {
         avr_irq_register_notify(base_irq + IOPORT_IRQ_REG_PIN,
                                 reg_read, NULL);
 
+        /* Tweak DDRB to confirm IO-memory based IRQs are working. */
+
+        avr_core_watch_write(avr, DDRB_ADDR, 1);
+
+        /* Run ... */
+
         tests_assert_uart_receive_avr(avr, 100000, expected, '0');
 
         if (strcmp(log, log_expected))