简体   繁体   中英

IAR assembler BKPT immediate as input operand

I am writing a flashloader for a Cortex M4 device and I'd like to "return" a value for the driving PC application using the breakpoint instruction's immediate value.

While hardcoding an immediate works fine:

__asm("bkpt 0x70");
__asm("bkpt %0" : : "i" (0x70));

as soon as I want to "return" something run-time dependent like

uint8_t status = Flash_EraseAll();
__asm("bkpt %0" : : "i" (status));

The compilation fails with

Error[Ta090]: Immediate operand is not constant

I tried using preprocessor macros with different concatenate setups, but to no avail.

Has anybody got an idea of how I could input the run-time dependent status flags to the __asm() block in IAR as an immediate? Based on what I read here , this is not exactly possible, but there might be a clever hacky way to do it.

PS: Yes, as a workaround I could use a switch statement where I list and hardcode every possible state, but that's just ugly and long.

I would push the value on the stack, and then use the bkpt instruction with a defined number, so the debugger can look at the stack for this state.

Something like this (pseudocode):

__asm("push %0" : : "i" (status));
__asm("bkpt %0" : : "i" (0x70));

Of course you shouldn't forget to cleanup the stack afterwards.

Since bkpt is encoded with an immediate only, you can obviously not change that at runtime, as you would have to modify the code.

Based on @Devolus 's idea, I ended up with the following:

    uint32_t status = Flash_EraseAll();
    __asm volatile ("str %0, [sp, #-4]!\n\t"   // Push to stack
                    "bkpt 0x0\n\t"             // Halt CPU
                    "add sp, sp, #4\n\t"       // Restore SP
                    : : "r"(status));          // status as input to __asm()

The assembly instructions tells the compiler to put the status variable to a convenient register "r", and store that register's content under the stack pointer's pre-decremented address, then halt the CPU's execution with an immediate 0.

The driving application would poll the target if it was halted (bkpt hit). If halted, by reading the 16-bit data under the current PC (__asm("bkpt 0x00") -> 0xbe00 -> #imm = 0xbe00 & 0x00ff = 0), the application can make sure that the execution had stopped at the right place. It then would read the 32-bit data under the final SP address to fetch the status of the embedded code's execution.

This way, instead of a static 8-bit code from the bkpt's immediate, one can "report" more stuff to the outside world dynamically (32-bit in this case).

As @PeterCordes highlights, the push and bkpt statements must be in the same inline assembly instruction, otherwise the compiler might decide to insert code between the statements. Also, the SP must be restored to the value before the __asm() as the compiler assumes sole control over SP.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM