我已经阅读了ARM文档,看来他们在某些地方说Cortex M4可以重新排序内存写入,而在其他地方则表明M4不能。
具体地说,我想知道是否需要DBM指令,例如:
volatile int flag=0;
char buffer[10];
void foo(char c)
{
__ASM volatile ("dbm" : : : "memory");
__disable_irq(); //disable IRQ as we use flag in ISR
buffer[0]=c;
flag=1;
__ASM volatile ("dbm" : : : "memory");
__enable_irq();
}
答案 0 :(得分:1)
嗯,这取决于您的标志,并且每个芯片也不同。
如果该标志存储在内存中,则:
此处不需要DSB。要访问标志的中断处理程序必须先从内存中加载它。即使您之前的写操作仍在进行中,CPU也会确保按照正确的顺序进行存储后的加载。
如果您的标志存储在外围存储器中
现在变得有趣了。让我们假设标志在某些硬件外围设备中。对其进行写操作可能会使中断挂起或确认一个中断(也就是清除挂起的中断)。与上面的内存示例相反,这种效果发生在CPU不必先读取该标志的情况下。因此,自动订购商店和货物将无济于事。另外,由于CPU和外围设备之间的时钟域不同,对标志的写入可能会以惊人的长延迟生效。
因此可能发生以下情况:
flag=1
来清除已处理的中断。__enable_irq()
flag=1
生效。您现在正处在中断处理程序中,无所事事。在__enable_irq()
前面执行DSB可以避免此问题,因为flag=1
触发的任何操作都将在__enable_irq()
执行之前生效。
如果您认为此案纯粹是学术性的:不,那是真实的。
只需考虑一个实时时钟。这些通常以32khz运行。如果从运行于64Mhz的CPU写入外围空间,则写入可能要花费多达2000个周期。现在,对于实时时钟,数据表通常会显示特定的序列,以确保您不会遇到此问题。
但是,如果外围设备运行缓慢,也会发生相同的情况。
我个人的轶事是在项目后期实施节能时发生的。一切都很好。然后,我们将I²C和SPI外设的外设时钟速度降低到我们可以避免的最低速度。这样可以节省大量电量并延长电池寿命。我们发现突然的中断开始执行意外的事情。每次破坏时它们似乎开火两次。在每个受影响的中断处理程序的末尾放置一个DSB可以解决此问题,因为-您可以猜测-较低的时钟速度导致我们在清除中断源之前由于慢速的外设时钟而在清除中断源之前离开了中断处理程序。
答案 1 :(得分:0)
Cortex M4 generic device user guide的本部分列举了可能影响重新排序的因素。
如果不影响指令序列的行为,处理器可以重新排序一些内存访问以提高效率。
处理器具有多个总线接口
内存映射中的内存或设备具有不同的等待状态
某些内存访问是缓冲的或推测性的。
您还应该记住,通常同时需要DSB和ISB(以该顺序),并且C不能对顺序进行任何保证(线程内易失性访问除外)。
您将经常观察到,短的流水线和指令序列可以以某种方式组合在一起,使得特定的编译映像似乎无法达到竞争条件,但这并不是您可以依靠的。时序条件可能很少(但可能),或者随后的代码更改可能会改变最终的指令序列。