Architecture v5TE and later processors provide LDRD and STRD instructions to load/store 64-bit data, e.g. to access 64-bit peripherals. These behave similarly to LDM/STM of two registers. On processors with 32-bit buses (such as ARM926EJ-S), LDRD/STRD (and LDM/STM of two regs) access data using two word-sized bus accesses, which may potentially be interrupted by another bus master, so cannot be guaranteed atomic. On processors with 64-bit buses (such as ARM11), these instructions are atomic. Unfortunately, there is an issue with the RVCT 3.x compilers whereby they are not always able to generate an LDRD/STRD (or LDM/STM) instruction when expected, e.g., accessing a 64-bit peripheral. For example, the following piece of code stores the 64-bit value 0x0123456789ABCDEF to address 0xA0000000: void perip_64bitaccess(void) { unsigned long long value = 0x0123456789ABCDEF; *((volatile unsigned long long*) (0xA0000000)) = value; } You might expect this code built with the following command line options to generate a double word store (STRD) instruction or a store multiple (STM) instruction: armcc -c foo.c --cpu 6 -o foo.o fromelf -c foo.o However, at present, the 3.x compilers may generate two STR instructions instead. To workaround this issue with RVCT 3.0 you could simply write the LDRD/STRD instructions in assembly language and build the code using the ARM assembler. The RVCT 3.0 linker is able to inline such small instruction sequences. However, unfortunately the RVCT 3.1 linker is unable to inline LDRD/STRD instructions, but can inline the equivalent LDM/STM of two registers. A workaround for both RVCT 3.x compilers is to write LDM/STM (of two reg) instructions in embedded assembler and pass the linker command line option --inline to ensure that the embedded assembly function is inlined by the linker, for example: __asm void stm_llout(unsigned long long* addr, unsigned long long value) { STM r0, {r2,r3} BX LR } __asm unsigned long long ldm_llin(unsigned long long* addr) { LDM r0, {r0,r1} BX LR } unsigned long long perip_64bitaccess(void) { unsigned long long ullvalue = ldm_llin((unsigned long long*)0x40004000); stm_llout((unsigned long long*)0x40000000, ullvalue); return ullvalue; } built with: armcc -c foo.c --cpu 6 -o foo.o armlink foo.o --inline -o foo.axf fromelf -c foo.axf generates inlined LDM/STM instructions.
|