1、DBG、DMB、DSB 和 ISB指令介绍
调试指令、数据内存屏障指令、数据同步屏障指令和指令同步屏障指令。
语法
DBG{cond} {#option}
DMB{cond} {option}
DSB{cond} {option}
ISB{cond} {option}
cond : 是一个可选的条件代码(请参阅条件执行)。
option : 对提示操作的可选限制。
说明:如果指令未实现,则与 NOP 效果相同
(1)、DBG : 调试提示可向调试系统及其相关系统发送提示。
(2)、DMB :数据内存屏障可作为内存屏障使用。 它可确保会先检测到程序中位于 DMB 指令前的所有显式内存访问指令,然后再检测到程序中位于 DMB 指令后的显式内存访问指令。它不影响其他指令在处理器上的执行顺序
option 的允许值为:SY, 完整的系统DMB 操作。 这是缺省情况,可以省略
举个例子: 如下的操作,确保dmb之前的内存访问已经完成了,即数据读到了x1、x2、x3、x21,然后后面的inval_dcache_aera会使用这些参数。
(3)、DSB : 数据同步屏障是一种特殊类型的内存屏障。 只有当此指令执行完毕后,才会执行程序中位于此指令后的指令。 当满足以下条件时,此指令才会完成:
位于此指令前的所有显式内存访问均完成。
位于此指令前的所有缓存、跳转预测和 TLB 维护操作全部完成
允许的值为:
SY : 完整的系统 DSB 操作。 这是缺省情况,可以省略。
UN : 只可完成于统一点的DSB 操作。
ST : 存储完成后才可执行的DSB 操作。
UNST : 只有当存储完成后才可执行的DSB 操作,并且只会完成于统一点
(4)、ISB : 指令同步屏障可刷新处理器中的管道,因此可确保在 ISB 指令完成后,才从高速缓存或内存中提取位于该指令后的其他所有指令。这可确保提取时间晚于 ISB 指令的指令能够检测到 ISB 指令执行前就已经执行的上下文更改操作的执行效果,例如更改ASID 或已完成的 TLB 维护操作,跳转预测维护操作以及对 CP15 寄存器所做的所有更改。
此外,ISB 指令可确保程序中位于其后的所有跳转指令总会被写入跳转预测逻辑,其写入上下文可确保 ISB 指令后的指令均可检测到这些跳转指令。这是指令流能够正确执行的前提条件。
举个例子:如果上述代码中1和2处的之类,同时从icache中取的,那么2处位置sp的值感测不到1处对sp的修改。那么有了isb之类后,保证1处操作完成之后,再进行2处取指令,这样就不会乱了。
ARMv8指令集提供了3条内存屏障指令。
- 数据存储屏障(Data Memory Barrier,DMB)指令:仅当所有在它前面的存储器访问操作都执行完毕后,才提交(commit)在它后面的访问指令。DMB指令保证的是DMB指令之前的所有内存访问指令和DMB指令之后的所有内存访问指令的执行顺序。也就是说,DMB指令之后的内存访问指令不会被处理器重排到DMB指令的前面。DMB指令不会保证内存访问指令在内存屏障指令之前完成,它仅仅保证内存屏障指令前后的内存访问的执行顺序。DMB指令仅仅影响内存访问指令、数据高速缓存指令以及高速缓存管理指令等,并不会影响其他指令(例如算术运算指令等)的顺序。
- 数据同步屏障(Data Synchronization Barrier,DSB)指令:比DMB指令要严格一些,仅当所有在它前面的内存访问指令都执行完毕后,才会执行在它后面的指令,即任何指令都要等待DSB指令前面的内存访问指令完成。位于此指令前的所有缓存(如分支预测和TLB维护)操作需要全部完成。
- 指令同步屏障(Instruction Synchronization Barrier,ISB)指令:确保所有在ISB指令之后的指令都从指令高速缓存或内存中重新预取。它刷新流水线(flush pipeline)和预取缓冲区后才会从指令高速缓存或者内存中预取ISB指令之后的指令。ISB指令通常用来保证上下文切换(如ASID更改、TLB维护操作等)的效果。
总结:
- 乱序是处理器特性,和优不优化没太大关系。大部分mcu就2级,3级,并不支持乱序,所以你可以看到大部分mcu的这个操作是空操作,只是os为了移植性放的占位。乱序往往需要深度流水,当然这不是充分或必要关系。主要解决的是可见性问题。如果只有一个核,乱不乱,同不同步也没什么影响,反正数据或指令也就你一个人用。可加了多个核或者多个master比如dma的时候,其他的master看不到你的本地内容,往往就需要这个同步措施。
- @[TOC](__DSB() 指令的作用)
在一些ARM程序代码中,会用到__DSB() 指令,特别是在一些中断处理函数中。例如:
程序通过中断信号进入中断处理函数时,首先应当清除相应的中断标志位,但有些CPU的时钟太快,快于中断使用的时钟,就会出现清除中断标志的动作还未完成,CPU就又一次重新进入同一个中断处理函数,导致死循环,__DSB() 指令的作用就是避免上述情况的发生。—DSB()的原型是:
- __DSB() __ISB()命令
等待指令和数据同步,例如*ocramAddr = 0xCCU;执行完成后,实际单片机可能还未完成执行,使用__DSB() __ISB()命令可以确保该行代码执行完成
static void OCRAM_Access(void)
{
uint32_t *ocramAddr = (uint32_t *)APP_FLEXRAM_OCRAM_START_ADDR;
/* enable FLEXRAM OCRAM access error interrupt*/
FLEXRAM_EnableInterruptSignal(APP_FLEXRAM, kFLEXRAM_OCRAMAccessError);
for (;;)
{
*ocramAddr = 0xCCU;
/* Synchronizes the execution stream with memory accesses */
APP_DSB();
APP_ISB();
/* check ocram access error event */
if (s_flexram_ocram_access_error_match)
{
s_flexram_ocram_access_error_match = false;
PRINTF("\r\nOCRAM access to 0x%x boundary.\r\n", ocramAddr);
break;
}
ocramAddr ;
}
}
程序通过中断信号进入中断处理函数时,首先应当清除相应的中断标志位,但有些CPU的时钟太快,快于中断使用的时钟,就会出现清除中断标志的动作还未完成,CPU就又一次重新进入同一个中断处理函数,导致死循环,__DSB() 指令的作用就是避免上述情况的发生。以下代码是NXP RT1021 单片机解决上述问题的代码:
/*! @name ISR exit barrier
* @{
*
* ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
* exception return operation might vector to incorrect interrupt.
* For Cortex-M7, if core speed much faster than peripheral register write speed,
* the peripheral interrupt flags may be still set after exiting ISR, this results to
* the same error similar with errata 83869.
*/
#if (defined __CORTEX_M) && ((__CORTEX_M == 4U) || (__CORTEX_M == 7U))
#define SDK_ISR_EXIT_BARRIER __DSB()
#else
#define SDK_ISR_EXIT_BARRIER
#endif
- @[TOC](__DSB() 指令的作用)
在一些ARM程序代码中,会用到__DSB() 指令,特别是在一些中断处理函数中。例如:
程序通过中断信号进入中断处理函数时,首先应当清除相应的中断标志位,但有些CPU的时钟太快,快于中断使用的时钟,就会出现清除中断标志的动作还未完成,CPU就又一次重新进入同一个中断处理函数,导致死循环,__DSB() 指令的作用就是避免上述情况的发生。—DSB()的原型是:
作为应用程序开发,我们一般不需要详细了解到这一步。按照官方要求做就好了。
,