在Cortex-M3指令集中,存在一系列LDREX/STREX指令,这样,如果使用LDREX指令读取位置,则只有在已知地址未被触及的情况下,后续STREX指令才能写入该地址。通常,结果是,如果自LDREX以来未发生任何中断(ARM用语中的“异常”),则STREX将成功,否则将失败。

在Cortex M0中模拟这种行为的最实用方法是什么?我想为M3编写C代码并将其移植到M0。在M3上,您可以这样说:

__inline void do_inc(unsigned int * dat)
{
while(__ strex(__ ldrex(dat)+ 1,dat)){}
}

执行原子增量。我可以想到的在Cortex-M0上实现类似功能的唯一方法是:

  • 使“ldrex”禁用异常并让“strex”和“clrex”重新启用它们,要求每个“ldrex”之后都必须紧随其后的是“strex”或“clrex”。
  • 在内存中,“ldrex”,“strex”和“clrex”是非常小的例程,其中“ldrex”的一条指令被修补为“str r1,[r2]”或“mov r0,#1” 。让“ldrex”例程将“str”指令插入“strex”例程,并让“clrex”例程将“mov r0,#1”插入。具有所有可能会使“ldrex”序列调用“clrex”无效的异常。

  • 根据ldrex/strex函数的使用方式,禁用中断可能会合理地起作用,但是更改“负载独占”的语义似乎很棘手,如果放弃它,则会造成不良的副作用。代码修补的想法似乎可以实现所需的语义,但是似乎很笨拙。

    (顺便说一句,附带的问题:我想知道为什么M3上的STREX将成功/失败指示存储到寄存器而不是简单地设置标志吗?它的实际操作需要操作码中有四个额外的位,要求有一个寄存器来保存成功/failure指示,并要求使用“cmp r0,#0”来确定它是否成功。是否期望编译器如果无法从寄存器中获取结果,就无法合理地处理STREX内部函数。 ?进行注册需要两个简短的说明。)

    最佳答案

    好吧...您仍然需要保留SWP,但这是一个功能较弱的原子指令。

    中断禁用当然可以工作。 :-)

    编辑:

    -m0上没有SWP,对不起, super 猫。

    好的,看来您只剩下中断禁用功能了。
    您可以使用gcc-compilable内联汇编作为指导来禁用和正确还原它:
    http://repo.or.cz/w/cbaos.git/blob/HEAD:/arch/arm-cortex-m0/include/lock.h

    10-08 20:09