diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/intc/ibex_plic.c | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/hw/intc/ibex_plic.c b/hw/intc/ibex_plic.c index 578edd2..669247e 100644 --- a/hw/intc/ibex_plic.c +++ b/hw/intc/ibex_plic.c @@ -43,6 +43,14 @@ static void ibex_plic_irqs_set_pending(IbexPlicState *s, int irq, bool level) { int pending_num = irq / 32; + if (s->claimed[pending_num] & 1 << (irq % 32)) { + /* + * The interrupt has been claimed, but not compelted. + * The pending bit can't be set. + */ + return; + } + s->pending[pending_num] |= level << (irq % 32); } @@ -120,6 +128,10 @@ 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 */ + s->claimed[pending_num] |= 1 << (s->claim % 32); + + /* Return the current claimed interrupt */ ret = s->claim; /* Update the interrupt status after the claim */ @@ -155,6 +167,10 @@ static void ibex_plic_write(void *opaque, hwaddr addr, /* Interrupt was completed */ s->claim = 0; } + if (s->claimed[value / 32] & 1 << (value % 32)) { + /* This value was already claimed, clear it. */ + s->claimed[value / 32] &= ~(1 << (value % 32)); + } } ibex_plic_update(s); @@ -215,6 +231,7 @@ static void ibex_plic_realize(DeviceState *dev, Error **errp) int i; s->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); s->enable = g_new0(uint32_t, s->enable_num); |