-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
I've been getting paranoid about compiler barriers, particularly as people have been looking at Link-Time Optimisation.
NVIC_DisableIRQ has the DSB/ISB sequence needed by the architecture, and they act as the necessary "acquire" compiler barrier to keep following code in line - don't access RAM until that IRQ disable has completed.
But NVIC_EnableIRQ has nothing - it's just a volatile memory access. If code does something like:
NVIC_DisableIRQ(devx);
// modify some RAM accessed by devx IRQ handler
NVIC_EnableIRQ(devx);
Nothing is ensuring that RAM access occurs before the IRQ is enabled. volatile doesn't say anything about ordering of non-volatile accesses. Eg gcc manual:
Accesses to non-volatile objects are not ordered with respect to volatile accesses. You cannot use a volatile object as a memory barrier to order a sequence of writes to non-volatile memory.
If NVIC_DisableIRQ acts as a barrier, it makes sense that NVIC_EnableIRQ should also have one, so that the pair can function as a "lock/unlock" like above.
So my suggestion is:
_STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) >= 0)
{
__COMPILER_BARRIER();
NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
__COMPILER_BARRIER(); // not sure if 2nd needed - better safe than sorry
}
}
Would need a barrier macro in the compiler-specific stuff.