summary refs log tree commit diff stats
path: root/hw/intc/ibex_plic.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/intc/ibex_plic.c')
-rw-r--r--hw/intc/ibex_plic.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/hw/intc/ibex_plic.c b/hw/intc/ibex_plic.c
index 235e6b88ff..341c9db405 100644
--- a/hw/intc/ibex_plic.c
+++ b/hw/intc/ibex_plic.c
@@ -45,9 +45,10 @@ static void ibex_plic_irqs_set_pending(IbexPlicState *s, int irq, bool level)
 
     if (s->claimed[pending_num] & 1 << (irq % 32)) {
         /*
-         * The interrupt has been claimed, but not compelted.
+         * The interrupt has been claimed, but not completed.
          * The pending bit can't be set.
          */
+        s->hidden_pending[pending_num] |= level << (irq % 32);
         return;
     }
 
@@ -133,7 +134,7 @@ static uint64_t ibex_plic_read(void *opaque, hwaddr addr,
         int pending_num = s->claim / 32;
         s->pending[pending_num] &= ~(1 << (s->claim % 32));
 
-        /* Set the interrupt as claimed, but not compelted */
+        /* Set the interrupt as claimed, but not completed */
         s->claimed[pending_num] |= 1 << (s->claim % 32);
 
         /* Return the current claimed interrupt */
@@ -176,8 +177,21 @@ static void ibex_plic_write(void *opaque, hwaddr addr,
             s->claim = 0;
         }
         if (s->claimed[value / 32] & 1 << (value % 32)) {
+            int pending_num = value / 32;
+
             /* This value was already claimed, clear it. */
-            s->claimed[value / 32] &= ~(1 << (value % 32));
+            s->claimed[pending_num] &= ~(1 << (value % 32));
+
+            if (s->hidden_pending[pending_num] & (1 << (value % 32))) {
+                /*
+                 * If the bit in hidden_pending is set then that means we
+                 * received an interrupt between claiming and completing
+                 * the interrupt that hasn't since been de-asserted.
+                 * On hardware this would trigger an interrupt, so let's
+                 * trigger one here as well.
+                 */
+                s->pending[pending_num] |= 1 << (value % 32);
+            }
         }
     }
 
@@ -239,6 +253,7 @@ static void ibex_plic_realize(DeviceState *dev, Error **errp)
     int i;
 
     s->pending = g_new0(uint32_t, s->pending_num);
+    s->hidden_pending = g_new0(uint32_t, s->pending_num);
     s->claimed = g_new0(uint32_t, s->pending_num);
     s->source = g_new0(uint32_t, s->source_num);
     s->priority = g_new0(uint32_t, s->priority_num);