Weird SPSR behaviour

I was trying to write a register context saving/restoring when I came across a weird behaviour.

My code (sorry, tried to format tens of times, but the editor WANTS to make asm a table):

asm volatile (
...
"pop {r0 - r3}"
"push {r0 - r3}"
"mov r0, r3"
"bl dbg_out" - outputs 60000013
"pop {r0 - r3}"
"msr cpsr_fsxc, r2"
"@dsb"
"@isb"
"msr spsr_fsxc, r3" - set value
"@dsb"
"@isb"
"mov lr, r1"
"mov sp, r0"
"push {r0 - r4, lr}"
"mov r0, lr"
"bl dbg_out"
"mov r0, sp"
"bl dbg_out"
"mrs r2, cpsr"
"mrs r3, spsr" - read value
"mov r0, r2"
"bl dbg_out"
"mov r0, r3" - outputs 00000002
"bl dbg_out"
...
);

When the exception is returned from, the calling function:

asm volatile ("svc #0\n\t");

    msg = "returned from SVC\r\n";

    serial_io.put_string(msg, util_str_len(msg)+1);

    asm volatile (

"mrs %[retreg], cpsr\n\t"
:[retreg] "=r" (tmp1) ::

    );

    msg = "cpsr = ";

    serial_io.put_string(msg, util_str_len(msg)+1);

    util_word_to_hex(scratchpad, tmp1);

    serial_io.put_string(scratchpad, 9);

    serial_io.put_string("\r\n", 3);

outputs "returned from SVC" and "cpsr = 60000013".

Why the "00000002"? the barriers don't seem to have any effect.

Parents
  • Uhm, what I mean is that a single LDM is approximately twice as fast as the two instructions POP + PUSH.

    -Thus you will not have to use POP+PUSH, but can just read the contents of the stack and avoid writing to it.

    The registers need to be loaded from the stack, that is correct, because they do not contain any defined value on interrupt entry.

    Thus instead of ...

       pop {r0-r3}

       push {r0-r3}

    ... you can write ...

       ldm sp,{r0-r3}

    ... which only reads the registers.

    dbg_out is allowed to corrupt r2 and r3 as well, which I think is why you see the strange value you mentioned earlier.

    I did not know about the 8-byte alignment requirement.

    -But remember to restore SP to its original value before you return; either by saving the entire value of SP or by adding the difference back, otherwise you'll get a crash.

Reply
  • Uhm, what I mean is that a single LDM is approximately twice as fast as the two instructions POP + PUSH.

    -Thus you will not have to use POP+PUSH, but can just read the contents of the stack and avoid writing to it.

    The registers need to be loaded from the stack, that is correct, because they do not contain any defined value on interrupt entry.

    Thus instead of ...

       pop {r0-r3}

       push {r0-r3}

    ... you can write ...

       ldm sp,{r0-r3}

    ... which only reads the registers.

    dbg_out is allowed to corrupt r2 and r3 as well, which I think is why you see the strange value you mentioned earlier.

    I did not know about the 8-byte alignment requirement.

    -But remember to restore SP to its original value before you return; either by saving the entire value of SP or by adding the difference back, otherwise you'll get a crash.

Children