我正在为Cortex M4设备编写一个Flashloader,我想使用断点指令的立即值为驱动PC应用程序“返回”一个值。
在对立即数进行硬编码时效果很好:
__asm("bkpt 0x70");
__asm("bkpt %0" : : "i" (0x70));
我想“返回”运行时相关的东西
uint8_t status = Flash_EraseAll();
__asm("bkpt %0" : : "i" (status));
编译失败,并显示
错误[Ta090]:立即操作数不是常量
我尝试使用具有不同串联设置的预处理器宏,但无济于事。
有人知道如何将运行时相关的状态标志作为立即输入到IAR中的__asm()
块吗?根据我读过的here,这是不可能的,但是这样做可能会有聪明的技巧。
P.S .:是的,作为一种解决方法,我可以使用switch语句在其中列出所有可能的状态并对其进行硬编码,但这很丑陋而且很长。
编辑:
基于以下公认的答案,这是我将来的实现方式:
uint32_t status = Flash_EraseAll();
__asm volatile ("str %0, [sp, #0]!" : : "r"(status));
__asm("bkpt 0x0");
执行嵌入式代码后,状态标志被压入堆栈(不减少SP以便于应用程序使用),并且CPU的“返回码” 0暂停。因此,通过读取最终SP值以下的地址,而不是8位,而是可以“向外界报告更多”内容(在这种情况下为32位)。
答案 0 :(得分:1)
我会将值压入堆栈,然后使用带有定义编号的foreach (var metric in metrics)
{
var added = context.Set(metric.GetType()).Add(metric);
foreach (var dbEntityEntry in context.ChangeTracker.Entries())
{
//If these entities exist, don't add them.
var metricContext = dbEntityEntry.Entity as MetricContext;
if (metricContext != null)
{
var found = context.MetricContext.FirstOrDefault(c => c.Context == metricContext.Context);
if (found != default(MetricContext))
{
dbEntityEntry.State = EntityState.Detached;
}
}
}
}
指令,以便调试器可以在堆栈中查看此状态。
类似这样的东西(伪代码):
bkpt
当然,您不应该忘记之后清理堆栈。
由于__asm("push %0" : : "i" (status));
__asm("bkpt %0" : : "i" (0x70));
仅使用立即数进行编码,因此您显然不能在运行时更改它,因为必须修改代码。
答案 1 :(得分:0)
基于@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”,并将该寄存器的内容存储在堆栈指针的递减地址下,然后以立即数0暂停CPU的执行。
如果目标被暂停(击中目标),则驾驶应用程序将轮询目标。如果暂停,则通过读取当前PC下的16位数据(__asm(“ bkpt 0x00”)-> 0xbe00-> #imm = 0xbe00&0x00ff = 0),应用程序可以确保执行在右侧停止地点。然后它将读取最终SP地址下的32位数据,以获取嵌入式代码执行的状态。
这样,人们可以动态地向外界“报告”更多的东西(在本例中为32位),而不是从bkpt的立即数生成静态的8位代码。
正如@PeterCordes强调的那样,push和bkpt语句必须在同一行内联汇编指令中,否则编译器可能决定在这些语句之间插入代码。另外,由于编译器仅对SP进行控制,因此必须将SP恢复为__asm()之前的值。