cancel
Showing results for 
Search instead for 
Did you mean: 

Quick STREX question

dginsburg
Associate II
Posted on February 08, 2013 at 17:34

Hi,

I have a quick quiestion: my toolchain complains that instruction

strexb r2, r2, [r3]

is illegal (registers may not be the same), while

strex r2, r2, [r0]

is fine. The question is: is it toolchain's bug, or it is telling my the truth? Background info. I have a very straightforward read-modify-write code for 32-bit locations like:

uint32_t ttt1(volatile uint32_t *ptr) {
uint32_t temp;
do {
temp = __LDREXW(ptr);
} while(!__STREXW(temp + 15, ptr));
return temp;
}

which compiles to

.L2:
ldrex r3, [r0]
add r2, r3, #15
strex r2, r2, [r0]
cmp r2, #0
beq .L2
mov r0, r3
bx lr

This passes assembler just fine. And for 8-bits:

uint8_t ttt2(volatile uint8_t *ptr) {
uint8_t temp;
do {
temp = __LDREXB(ptr);
} while(!__STREXB(temp + 15, ptr));
return temp;
}

which translates to

mov r3, r0
.L9:
ldrexb r0, [r3]
uxtb r0, r0
add r2, r0, #15
strexb r2, r2, [r3] <<<<<<<
cmp r2, #0
beq .L9
bx lr

Now the assembler complains about the marked instruction.
3 REPLIES 3
dginsburg
Associate II
Posted on February 08, 2013 at 18:05

Well, it's not that it's a complete show-stopper. There's a work-around.

core_cmInstr.h defines __STREXB as

__attribute__( ( always_inline ) ) static __INLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr)
{
uint32_t result;
__ASM volatile (''strexb %0, %2, [%1]'' : ''=r'' (result) : ''r'' (addr), ''r'' (value) );
return(result);
}

As a work-around, I could make result early-clobber:

__attribute__( ( always_inline ) ) static __INLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr)
{
uint32_t result;
__ASM volatile (''strexb %0, %2, [%1]'' : ''=&r'' (result) : ''r'' (addr), ''r'' (value) );
return(result);
}

which will prevent the compiler from reusing the same register for value and result, so assembler won't complain. The solution is less than perfect, since an extra register has to be used. So, my question stands: does my toolchain have a bug?
Posted on February 08, 2013 at 19:07

So, my question stands: does my toolchain have a bug?

Yes, ask for your money back.. In Keil trying to assemble your code yields

assembling test.s...
..\test.s(10): error: A1477E: This register combination results in UNPREDICTABLE behaviour
..\test.s: 10 0000000c strexb r2, r2, [r3] ; <<<<<<<
..\test.s: 1 Error, 0 Warnings

A read through the ISA might prove enlightening
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
dginsburg
Associate II
Posted on February 08, 2013 at 19:52

Hmm.

Thanks for the pointer, clive1. This is what the architecture manual says: STREX<c> <Rd>,<Rt>,[<Rn>{,#<imm8>}] d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8:'00', 32); if d IN {13,15} || t IN {13,15} || n == 15 then UNPREDICTABLE; if d == n || d == t then UNPREDICTABLE; The ''d == t then UNPREDICTABLE'' condition applies to all three variants: STREX, STREXH, and STREXB. In other words, my toolchain does contain a bug, but a different one than I thought originally. That is, it should have complained about

strex r2, r2, [r0]

too. Which in turn means that CMSIS has a bug too, and they should have used early-clobber constraint in their definition of __STREX*