Jan 13, 2014

Saving SP in atmega328p

Context switching is one of the core component of parallel processing. I was trying to implement one such. Storing the SP to data space is something noteworthy.


I wanted to save  my main stack pointer into the RAM - data space. For that I initialized a buffer to store the stack pointer and a pointer  variable to point to the buffer.

uint8_t buffer[2]; /* or uint16_t buffer */
uint8_t *ptr;

and my main have ptr = &buffer[0];

here is my savecontext asm

                        "lds    r26, ptr        \n\t"   \
                        "lds    r27, ptr + 1    \n\t"   \
                        "in     r0, 0x3d        \n\t"   \
                        "st     x+, r0          \n\t"   \
                        "in     r0, 0x3e        \n\t"   \
                        "st     x+, r0          \n\t"   \

and in the restore context macro I have

                        "lds    r26, ptr        \n\t"   \
                        "lds    r27, ptr + 1    \n\t"   \
                        "ld     r28, x+         \n\t"   \
                        "out    __SP_L__, r28   \n\t"   \
                        "ld     r29, x+         \n\t"   \
                        "out    __SP_H__, r29   \n\t"   \

The disassemble code has

Save Context ()

  ec:   a0 91 24 01     lds     r26, 0x0124
  f0:   b0 91 25 01     lds     r27, 0x0125
  f4:   0d b6               in      r0, 0x3d        ; 61
  f6:   0d 92               st      X+, r0
  f8:   0e b6               in      r0, 0x3e        ; 62
  fa:   0d 92               st      X+, r0

Restore Context ()

 100:   a0 91 24 01     lds     r26, 0x0124
 104:   b0 91 25 01     lds     r27, 0x0125
 108:   cd 91               ld      r28, X+
 10a:   cd bf                out     0x3d, r28       ; 61
 10c:   dd 91               ld      r29, X+
 10e:   de bf                out     0x3e, r29       ; 62

Atmega328P has the following memory spec.

32KB of flash
2KB of RAM i.e. 2048 bytes (0x100 - 0x8FF). That means two registers are required to store an address (i.e. why we have buffer[2] )
Consider, I have a stack pointer 0x04FC which I wanted to store into the memory.

uint8_t buffer[2];
uint8_t *ptr;
ptr = &buffer[0];

which initialize location 0x02F3 as buffer[0] and location 0x02F4 as buffer[1] and
location 0x124 and location 0x125 as ptr ( because of 10 bit wide address we need two locations to store one address ) and ptr will have addreess of buffer[0]

location 0x0124 contains 0xF3 and 0x0125 contains 0x02 ( little endian style check Figure 1 )

Figure 1

Now lets see the disassembled code.

lds     r26, 0x0124  
lds     r27, 0x0125 

which loads address of buffer[0] into X pointer which is 16 bit 
so the X pointer has 0x02F3

Then we have 

  f4:   0d b6               in      r0, 0x3d        ; 61
  f6:   0d 92               st      X+, r0
 10c:   dd 91               ld      r29, X+
 10e:   de bf                out     0x3e, r29       ; 62

i.e. to X pointed address ( X pointer has 0x02F3 ) we store content of 0x3D which is SPL and then to the next address i.e. 0x02F4 we store SPH

Now that the stack pointer "0x04FC" is copied to ram 0x02F3 and 0x02F4 in little endian style.

Endianess is very important here. As we can see in the X pointer 0x1A has 0xFC, 0x1B contains 0x04 ( Figure 1

For Web Developer

  open -a "Google Chrome" --args --disable-web-security