I'm using IAR Embedded Workbench for ARM 6.50.4 Functional Safety Version 6.50 and I can't seem to get an assembly inline instruction working.
For the background: I'm trying to implement a context switch on an ARM7TDMI using the PIT Interrupt. When saving the current context I have to get the address of the stack of the interrupted function, which is saved inside a global C variable, which is declared in the same c file:
unsigned int* ptTask_CurrentTask;
__irq void SysIrqHandler( void )
{
// ... saving registers
__asm volatile( "LDR R0, %0\n\t" ::"r"(ptTask_CurrentTask) );
//... save the new top of stack
//select new task and restore associated registers
}
From what I could gather from the EWARM_DevelopmentGuide.ENU.pdf the instruction above should be using the correct syntax. Also I have tried different ways of formating the instruction but all I get is:
Error[og006]: Syntax error in inline assembly: "Error[401]: Operand syntax error"
.
Now when I export the complete context saving assembly routine into a seperate .s file and call the function from c the following instruction is working just fine.
LDR R0, =ptTask_CurrentTask
Since the assembly instructions on their own work, there has to be a problem with the way I'm doing the inline assembly instruction but I can't see what is wrong.
The "r" constraint indicates a general-purpose register, so it ends up emitting LDR R0, Rx
which is indeed invalid syntax. If you really want to do the actual pointer dereference in the assembly code, either embed the correct syntax directly:
__asm volatile( "LDR R0, [%0]\n\t" ::"r"(ptTask_CurrentTask));
Or, better, use the appropriate constraint to indicate that it is a memory operand (pointer) and leave the syntax to the compiler:
__asm volatile( "LDR R0, %0\n\t" ::"m"(ptTask_CurrentTask));
Or waste an extra instruction and let the compiler worry about the load:
__asm volatile( "MOV R0, %0\n\t" ::"r"(*ptTask_CurrentTask));
Whichever way, touching r0
directly without declaring it on the clobber list is probably a bad idea...