wokwi / rp2040js

A Raspberry Pi Pico Emulator in JavaScript
MIT License
403 stars 46 forks source link

User generated interrupts (IRQ >= 26) keep firing forever #22

Closed urish closed 3 years ago

urish commented 3 years ago

Quoting the datasheet:

only the lower 26 IRQ signals are connected on the NVIC, and IRQs 26 to 31 are tied to zero (never firing). The core can still be forced to enter the relevant interrupt handler by writing bits 26 to 31 in the NVIC ISPR register.

The Pico SDK is using this feature for the STDIO USB driver.

Our NVIC implementation doesn't clear the pending interrupt flag when executing an interrupt. However, it seems that Pico SDK code expects the NVIC to clear the pending interrupt flag (as the SDK code doesn't take care of clearing the flag). The ARMv6 Datasheet seems to be in agreement with this (section B3.4.1 "NVIC operation"):

// NVIC behavior // ============= clearPend = ExceptionIN(INTNUM) || InterruptDeassertion; setPend = InterruptAssertion || WriteToRegField(ISPR, INTNUM); if clearPend && setPend then IMPLEMENTATION DEFINED whether NVIC_Pending[INTNUM] is TRUE or FALSE; else NVIC_Pending[INTNUM] = setPend || (NVIC_Pending[INTNUM] && !clearPend);

urish commented 3 years ago

Regarding hardware IRQ's, quoting @kilograham's comment from the Bug Squashing live stream on YouTube:

clearPend = ExceptionIN(INTNUM) || InterruptDeassertion;
setPend = InterruptAssertion || WriteToRegField(ISPR, INTNUM);

Note that for hardware IRQs the InterruptAssertion is always set until the hardware interrupt source is acknowledged via a write to the hardware specific interrupt register (basically level sensitive interrupts)... thus if the ISR doesn't do this you get another IRQ immediately on return from the ISR. For the write to ISPR case, the setPend only happens once.