IAR 汇编程序 BKPT 立即数作为输入操作数

IAR assembler BKPT immediate as input operand

我正在为 Cortex M4 设备编写闪存加载程序,我想 "return" 使用断点指令的立即值为驱动 PC 应用程序赋值。

虽然对立即数进行硬编码工作正常:

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

一旦我想要 "return" 一些东西 运行-时间依赖性喜欢

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

编译失败

Error[Ta090]: Immediate operand is not constant

我尝试使用具有不同连接设置的预处理器宏,但无济于事。

有没有人知道我如何将 运行 时间相关状态标志作为即时输入到 IAR 中的 __asm() 块?根据我读到的 here,这不太可能,但可能有一个聪明的 hacky 方法来做到这一点。

P.S.: 是的,作为一种解决方法,我可以使用 switch 语句,在其中列出并硬编码每个可能的状态,但这既丑陋又冗长。

我会将值压入堆栈,然后使用带有已定义数字的 bkpt 指令,以便调试器可以查看此状态的堆栈。

类似这样的东西(伪代码):

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

当然你不应该忘记事后清理堆栈。

由于 bkpt 仅使用立即数编码,您显然不能在运行时更改它,因为您必须修改代码。

根据@Devolus的想法,我得出以下结论:

    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()

汇编指令告诉编译器将状态变量放入一个方便的寄存器 "r",并将该寄存器的内容存储在堆栈指针的 pre-decremented 地址下,然后停止 CPU的执行立即数 0。

如果目标停止(bkpt 命中),驾驶应用程序将轮询目标。如果暂停,通过读取当前PC下的16位数据(__asm("bkpt 0x00") -> 0xbe00 -> #imm = 0xbe00 & 0x00ff = 0),应用程序可以确保执行停在了正确的地方。然后它会读取最终 SP 地址下的 32 位数据以获取嵌入式代码的执行状态。

这样一来,我们就可以 "report" 动态地向外界发送更多内容(在本例中为 32 位),而不是来自 bkpt 立即数的静态 8 位代码。

正如@PeterCordes强调的那样,push 和 bkpt 语句必须在同一内联汇编指令中,否则编译器可能会决定在语句之间插入代码。此外,SP 必须恢复为 __asm() 之前的值,因为编译器会单独控制 SP。