0
votes
void save_context(uint8_t index) {
    context *this_context = contextArray + index;
    uint8_t *this_stack = this_context->stack;


    asm volatile("st %0 r0":  "r"(this_stack));
}

I have something like this.

!!! I would like to store the registers r0 r1 r2... into my stack[] array.

What I am programming is the context switch. The context has the structure like this:

typedef struct context_t {
   uint8_t stack[THREAD_STACK_SIZE];
   void *pstack;
   struct context_t *next;
}context;

My problem is that I am not able to pass the c variable "this_stack" to inline assembly. My aim is to store all the registers, stack pointer and SREG on my stack.

After compiling, it gives error: Description Resource Path Location Type

`,' required    5_multitasking      line 754, external location: C:\Users\Jiadong\AppData\Local\Temp\ccDo7xn3.s C/C++ Problem

I looked up the avr inline assembly tutorial. But I don't quite get a lot. Could anyone help me?

2
"label" makes no sense, that should be a constraint. It also makes no sense trying to save the stack pointer into an array. It might make sense to load the stack pointer with the address of that array, but that's not the save_context.Jester
@Jester if you look at the constraints for lds, it is r,label. please have a look at the link atmel.com/webdoc/AVRLibcReferenceManual/inline_asm_1io_ops.htmljiadong
label is not a gcc constraint. See the manual.Jester
@jester actually I am doing is to save the stack pointer in the struct. but there are many tasks, let's say 3 tasks. Each task has a stack, that is why I created an array for the context.jiadong
But I assume each task has its own context, no? So each context only needs to store 1 stack pointer, not an array of them.Jester

2 Answers

0
votes

"label" makes no sense, that should be a constraint. It also makes no sense trying to save the stack pointer into an array. It might make sense to load the stack pointer with the address of that array, but that's not the save_context.

Anyway, to get the value of SPL which is the stack pointer you can do something like this:

asm volatile("in %0, %1": "=r" (*this_stack) : "I" (_SFR_IO_ADDR(SPL)));

(There is a q constraint but at least my gcc version doesn't like it.)

To get true registers, for example r26 you can do:

register uint8_t r26_value __asm__("r26");
asm volatile("": "=r" (r26_value));
0
votes

There is a constraint, "m", documented in the GCC manual, but it doesn't always work on AVR. Here is an example of how it should work from sanguino/bootloaders/atmega644p/ATmegaBOOT

asm volatile("...
    ...
    "sts    %0,r16      \n\t"
    ...
    : "=m" (SPMCSR) : ... );

I have found "m" to be fragile though. If a function uses a variable in C code, outside of the inline assembly, the compiler may choose to place it in the Z register and it will try to use Z in assembler too. This causes an assembler error when used with the sts instruction. Looking at the assembler output from the C compiler is the best way to debug this kind of problem.

Rather than using an "m" constraint, you can just put the literal address you want into your assembler code. For an example, see pins_teensy.c, where timer_0_fract_count is not included in the :

asm volatile(
    ...
    "sts    timer0_fract_count, r24"    "\n\t"