vPortYield and barriers on Cortex M0 port

I have a question regarding vPortYield and the _asm volatile( “dsb” ); instructions. As I understand it that is purely a hardware memory barrier that prevents the CPU from reordering instructions as it executes them. Shouldn’t there also be a _asm volatile(“” ::: “memory”); (in the GCC case) to prevent the compiler from reordering instructions at compile time?

vPortYield and barriers on Cortex M0 port

I think in the case of the M0 the barrier instructions are not necessary – in fact that is true for the majority of M3 and M4 implementations on the market too. Although barriers are required to be strictly in conformance with what a Cortex-M core could do, in a different implementation, it is only really now with the M7 cores that there are actual implementations that need them.
Shouldn’t there also be a __asm volatile(“” ::: “memory”); (in the GCC case) to prevent the compiler from reordering instructions at compile time?
Please elaborate on your rationale for that – so we can determine if it is necessary, as your comment seems to be related more to the compiler than the hardware. Regards.

vPortYield and barriers on Cortex M0 port

I’m no sure about this but since the compiler could do instruction scheduling at compile time for some optimization levels, maybe a hardware barrier instruction is not sufficient in all cases. Or maybe the software barrier is implied when using a hardware barrier instruction? I’m sorry I can’t be more specific but I’m trying to figure this out myself.

vPortYield and barriers on Cortex M0 port

I believe the “volatile” keyword in the ASM call signals the compiler to not reorder in such a way where causality is broken for that function.

vPortYield and barriers on Cortex M0 port

Yes, as I understand it (from this source for example http://www.ethernut.de/en/documents/arm-inline-asm.html) that is only for the asm instructions in that asm statement, without a memory barrier the setting of portNVICINTCTRL could actually be moved (by the compiler) to after the asm instructions. Unless the compiler implicitly see the hardware barriers as a software barrier as well.

vPortYield and barriers on Cortex M0 port

No, that is not what the volatile storage class qualifier explicitly does. It tells the compiler that it cannot assume that a previously read value of the volatile variable is still valid, and so it must be re-read, so the second or subsequent read in the code must not be optimised out. An obvious example is when the variable is a hardware status register that is being polled for a bit to change state. It does not guarantee that ‘out of order execution’ will not occur. The dsb and dmb ARM assembler instructions will guarantee that all memory accesses will happen before any subsequent memory accesses or instructions, respectively. The isb instruction will guarantee that the subsequent instructions will be re-fetched, bypassing any pipeline. None makes any guarantee about the order before or after. The use of these instructions in relation to the volatile keyword is entirely compiler dependent, so if this is important for your application, you will have to include these instructions as required in your code. I clearly (even painfully) remember having to scatter EIEIO* instructions all over some PowerPC code that was heavily interractive with hardware via a bus-bridge with a posted write capability. I have had no such problems (yet) with ARM Cortex-M based processors, but I’ve only used M3/4. * ™ Old MacDonald Farm Enterprises Inc.

vPortYield and barriers on Cortex M0 port

Here is the docs on the use of volatile with an asm statement: https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile

vPortYield and barriers on Cortex M0 port

Admittedly, although I understand the volatile storage class qualifier I did not understand the use of it as a qualifier to an ASM function and took a low-grade guess at it. Thank you for the clarification.

vPortYield and barriers on Cortex M0 port

Yes, and that doc contains the statement that “Note that the compiler can move even volatile asm instructions relative to other code, including across jump instructions.” So basically, unless the “dsb” and “isb” instructions imply a software barrier, the vPortYield code:
/* Set a PendSV to request a context switch. */                                                       
*( portNVIC_INT_CTRL ) = portNVIC_PENDSVSET;                                                          

/* Barriers are normally not required but do ensure the code is completely                            
within the specified behaviour for the architecture. */                                               
__asm volatile( "dsb" );                                                                                                     
__asm volatile( "isb" );   
could potentially be rearanged by the optimizer to be equivalent to
/* Barriers are normally not required but do ensure the code is completely                            
within the specified behaviour for the architecture. */                                               
__asm volatile( "dsb" );                                                                              
__asm volatile( "isb" );

/* Set a PendSV to request a context switch. */                                                       
*( portNVIC_INT_CTRL ) = portNVIC_PENDSVSET;                                                          
Or could it? A barrier like: asm volatile(“”:::”memory”); would guarantee it, but I don’t know enough about GCC to say for sure that it is needed. I just noted that this is how linux kernel does it:
173 #define isb() __asm__ __volatile__ ("isb" : : : "memory")
174 #define dsb() __asm__ __volatile__ ("dsb" : : : "memory")