8
votes

In the ARM documentation, it mentions that

The Cortex-M4 processor supports ARMv7 unaligned accesses, and performs all accesses as single, unaligned accesses. They are converted into two or more aligned accesses by the DCode and System bus interfaces.

It's not clear to me if this means the data access is atomic to the programmer or not. Then I found a StackOverflow comment interpreting the documentation as:

Actually some ARM processors like the Cortex-M3 support unaligned access in HW, so even an unaligned read/write is atomic. The access may span multiple bus cycles to memory, but there is no opportunity for another instruction to jump in between, so it is atomic to the programmer.

However, I looked around some more and found claims that contradicts the previous claim:

Another one is the fact that on cores beginning ARMv6 and later, in order for the hardware to “fix-up” an unaligned access, it splits it up into multiple smaller, byte loads. However, these are not atomic!.

So, who do I believe? For some context, I have setters/getters for each element in a packed struct in my project. In other words, some struct elements may be unaligned. I was wondering if accessing the struct elements will always be guaranteed to be atomic on Cortex-M4. If it's not, I am thinking I will have to enable/disable interrupts manually or add in some mutex, but I'd rather not if ARM Cortex M4 can just guarantee the data accesses to be atomic.

1
The exception behavior for these multiple access instructions means they are not suitable for use for writes to memory for the purpose of software synchronization.old_timer
above is a a quote from the arm docs. first off you need to know what instructions are being used and from that read the arm documentation for your core (armv7-m for the cortex-m4).old_timer
Are you short on memory? why are you using packed structs? I suspect to use structs across compile domains which is just bad news in general, unpredictable, etc. Best to enable trapping of unaligned accesses, and fix any code that performs such an access. Then you dont have to worry about it (unless the code generates instructions that can be restarted).old_timer
If your instruction generates a write for example to address 0x1002 and the bus is 32 bits wide (assume 32 or 64), it does not turn this into two instructions but it needs to generate a transaction at address 0x1000 with two byte lanes enabled and another at 0x1004 with two byte lanes enabled. Likewise for a read of 0x1002 a read of 0x1000 is done and a read of 0x1004 is done of which two bytes from each are kept and fed to the processor core to save in the register. there is a lot of language related to this in the documentation. the quote above is probably the one you should run with.old_timer
Quote from ARMv7-M reference manual "In ARMv7-M, the single-copy atomic processor accesses are: • All byte accesses. • All halfword accesses to halfword-aligned locations. • All word accesses to word-aligned locations "R S

1 Answers

1
votes

Nope, it isn't.

See section A3.5.3 at https://static.docs.arm.com/ddi0403/eb/DDI0403E_B_armv7m_arm.pdf

Quote from the ARMv7-M reference manual

In ARMv7-M, the single-copy atomic processor accesses are:
• All byte accesses.
• All halfword accesses to halfword-aligned locations.
• All word accesses to word-aligned locations

So, if you are copying a uint32 that isn't aligned to a 32-bit boundary (which is allowed in v7-M), the copy isn't atomic.

Also quoting,

When an access is not single-copy atomic, it is executed as a sequence of smaller accesses,
each of which is single-copy atomic, at least at the byte level.