Byte by byte access to 32bit peripheral registers causes issues
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
GNU Arm Embedded Toolchain |
New
|
Undecided
|
Unassigned |
Bug Description
Hi,
Normally I am working on our application project with ARM-GCC 4.9. While adding a bootloader, I switched to 5.4 and things started to go out of track. Trace narrowed down the problem to an assignment into a peripheral register.
I've seen that the 4.9 version creates 6 lines of assembly but the same simple statement was creating 15 lines of assembly with 5.4. Then I tried the most recent one, 6-2017-q2-update. The result was the same. Although version 6 creates substantially smaller code compared to 5.4, the particular peripheral was not working at all.
Here's the working output:
101 NVM_SPI->CTRL = USART_CTRL_SYNC | USART_CTRL_MSBF;
00023fd6: ldr r2,[pc,#0x74] ; 0x24048
00023fd8: ldr r3,[r2]
00023fda: movs r3,#0x0
00023fdc: orr r3,r3,#0x400
00023fe0: orr r3,r3,#0x1
00023fe4: str r3,[r2]
And here's the problematic output (both 5 and 6 branch):
101 NVM_SPI->CTRL = USART_CTRL_SYNC | USART_CTRL_MSBF;
20001682: ldr r3,[pc,#0xf8] ; 0x20001778
20001684: ldrb r2,[r3]
20001686: movs r2,#0x0
20001688: orr r2,r2,#0x1
2000168c: strb r2,[r3]
2000168e: ldrb r2,[r3,#0x1]
20001690: movs r2,#0x0
20001692: orr r2,r2,#0x4
20001696: strb r2,[r3,#0x1]
20001698: ldrb r2,[r3,#0x2]
2000169a: movs r2,#0x0
2000169c: strb r2,[r3,#0x2]
2000169e: ldrb r2,[r3,#0x3]
200016a0: movs r2,#0x0
200016a2: strb r2,[r3,#0x3]
****
NVM_SPI: (void*) (0x4000C400UL)
CTRL: volatile uint32_t at offset 0
USART_CTRL_SYNC: (0x1UL << 0)
USART_CTRL_MSBF: (0x1UL << 10)
****
There is no optimization (-O0). Things could get better with other optimization options due to assignment simplification, but I haven't tried it, yet.
Regards,
Additional Info:
Compilers: 5.4.3 and 6-2017-q2-update
OS: Ubuntu 17.10
P.S: Second assembly could be seen to work on RAM. The result is the same when set to work on flash.
Looks like the compiler is accessing NVM_SPI->CTRL one byte at a time. There must be something in the declaration of NVM_SPI->CTRL and maybe in the compiler command line options that make it do it.