Thanks very much David. I already disable interrupts when I need an atomic operation, such as a write to 32 bit variable or a read-modify-write on a 16bit variable.
Am I right to assume that simple writes to 16 bit variables are always atomic on MSP430? Eg done = 0xabcd, the CPU doesn't do two byte writes or anything dumb like that, the memory will be X (don't care) before the write and will be 0xabcd after, or should I disable interrupts for all writes to shared memory (shared with an ISR)? My colleague asserts that the compiler is even free to reorder volatile accesses, like volatile int a; volatile int b; int c; int main() { a = 5; b = 0; c = 1; return 0; } You are saying that the compiler will always write a before b, even without a memory barrier. Is that right? But in the above, the write to c can happen anywhere, as far as I understand. Lastly, this compiler (3.2.3) is only used on our legacy projects. More recently we are using the last LTS of mspgcc before Ti/RH started their port. I've not seriously tried to use the new RH compiler, and my company is largely moving away from MSP430 towards ARM Cortex now. Thanks - Wayne > On 27 Nov 2015, at 23:19, David Brown <da...@westcontrol.com> wrote: > >> On 27/11/15 12:32, Wayne Uroda wrote: >> Hello, >> >> I have a question about instruction reordering in the compiler. >> >> In this blog >> http://preshing.com/20120625/memory-ordering-at-compile-time/ It says >> that a compiler barrier should be used where writes to memory must >> not be reordered. > > Looks like good information. > >> >> My MSP430 code is all bare metal, foreground-background code and I am >> not using any type of RTOS, so it could be considered lock-free. >> >> Anyway, a new employee at my work pointed out that the compiler is >> free to reorder my memory writes, even those marked volatile. I said >> that I had never actually seen mspgcc do this, but now I am curious: >> will mspgcc reorder memory writes, eg to global variables? Is this >> dependent on the msp430 side of gcc (the backend), or more on the >> AST/RTL side? > > The compiler can re-order any reads or writes it likes, except volatile > accesses. The order of volatile accesses will always match the source > code. But the compiler can move non-volatile reads and writes back and > forth between volatile accesses. > > So if you have non-volatile variables a, b, c, and volatile variables u, > v, and source code like this: > > a = 1; > u = 100; > b = 2; > v = 200; > c = 3; > > Then the compiler can generate code like this: > > a = 1; > c = 3; > u = 100; > v = 200; > b = 2; > > But it may not generate code like this: > > a = 1; > v = 200; > b = 2; > u = 100; > c = 3; > > (The same applies to reads.) > > The volatile accesses must be exact, in the same number and the same > order with respect to other volatile accesses. But the non-volatile > accesses can be moved around as much as the compiler wants. > > Note that variable accesses can also be moved around with respect to > function calls, /if/ the compiler knows the function does not make > volatile accesses. > > The compiler can also eliminate "dead" stores, or unused reads. Given: > > a = 1; > u = 100; > a = 2; > v = 200; > a = 3; > > The compiler can generate: > > u = 100; > v = 200; > a = 3; > > or > > a = 3; > u = 100; > v = 100; > > >> >> Or to put it another way, should I be reviewing my shared (between >> background and ISR) variables and placing compiler barriers where >> variables must be stored in an exact order? > > Yes, these must be handled carefully. In particular, volatile accesses > give no indication about how non-volatile accesses are handled. > Sometimes people write code like this: > > int data[4]; > volatile bool newData; > > void update(int x) { > data[0] = data[1]; > data[1] = data[2]; > data[2] = data[3]; > data[3] = x; > newData = true; > } > > And they think that making the newData flag a volatile is sufficient. > It is /not/ sufficient - the compiler can set newData before doing > anything with the data[] array. And then your interrupt code will work > fine in all your testing, and hit a race condition when the customer is > watching. > > You have to make each access to "data" here volatile, or you need a > memory barrier between "data[3] = x;" and "newData = true;". A memory > barrier tells the compiler that all memory writes before the barrier > need to be completed, no writes after the barrier may be started, and > any data read before the barrier is now invalid. > > And note that even then, nothing in memory barriers or volatile access > will ensure that the reads or writes are atomic. > > Some useful macros/functions: > > #define volatileAccess(v) *((volatile typeof((v)) *) &(v)) > > static inline void compilerBarrier(void) { > asm volatile("" ::: "memory"); > } > > >> >> I am using a very old version of mspgcc, 3.2.3, I think it was the >> last stable Windows binary release before the CPUX instructions >> started making their way in, sorry I don't know the version, from >> 2008/2009 maybe? > > That was probably the final release before the mspgcc 4 project was > started. And now there is a new port msp430-elf from Red Hat and TI, > which is where you should go for moving on for the future. > > gcc 3.2.3 did not optimise as aggressively as newer gcc, so it will do a > lot less re-arrangement of code. In general, the compiler will > re-arrange the order of writes if it has good reason to do so - if the > result is smaller and/or faster. If it makes no difference, then it > will not re-order the writes. > > > > > > ------------------------------------------------------------------------------ > _______________________________________________ > Mspgcc-users mailing list > Mspgcc-users@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/mspgcc-users ------------------------------------------------------------------------------ _______________________________________________ Mspgcc-users mailing list Mspgcc-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mspgcc-users