4.11.9. DBG、DMB、DSB 和 ISB
调试指令、数据内存屏障指令、数据同步屏障指令和指令同步屏障指令。
DBG{<em class="replaceable"><code>cond</code></em>} {#<em class="replaceable"><code>option</code></em>}
DMB{<em class="replaceable"><code>cond</code></em>} {<em class="replaceable"><code>option</code></em>}
DSB{<em class="replaceable"><code>cond</code></em>} {<em class="replaceable"><code>option</code></em>}
ISB{<em class="replaceable"><code>cond</code></em>} {<em class="replaceable"><code>option</code></em>}
其中:
-
是一个可选的条件代码(请参阅条件执行)。
-
对提示操作的可选限制。
cond
option
这些是提示指令。 是否实现这些指令是可选的。 只要其中任何一个指令未实现,则与 NOP
效果相同。
数据内存屏障可作为内存屏障使用。 它可确保会先检测到程序中位于 DMB
指令前的所有显式内存访问指令,然后再检测到程序中位于DMB
指令后的显式内存访问指令。它不影响其他指令在处理器上的执行顺序。
的允许值为:option
-
完整的系统DMB 操作。 这是缺省情况,可以省略。
SY
数据同步屏障是一种特殊类型的内存屏障。 只有当此指令执行完毕后,才会执行程序中位于此指令后的指令。 当满足以下条件时,此指令才会完成:
-
位于此指令前的所有显式内存访问均完成。
-
位于此指令前的所有缓存、跳转预测和 TLB 维护操作全部完成。
允许的值为:
-
完整的系统 DSB 操作。 这是缺省情况,可以省略。
-
只可完成于统一点的DSB 操作。
-
存储完成后才可执行的DSB 操作。
-
只有当存储完成后才可执行的DSB 操作,并且只会完成于统一点。
SY
UN
ST
UNST
指令同步屏障可刷新处理器中的管道,因此可确保在 ISB
指令完成后,才从高速缓存或内存中提取位于该指令后的其他所有指令。这可确保提取时间晚于ISB
指令的指令能够检测到 ISB
指令执行前就已经执行的上下文更改操作的执行效果,例如更改ASID 或已完成的 TLB 维护操作,跳转预测维护操作以及对 CP15 寄存器所做的所有更改。
此外,ISB
指令可确保程序中位于其后的所有跳转指令总会被写入跳转预测逻辑,其写入上下文可确保 ISB
指令后的指令均可检测到这些跳转指令。这是指令流能够正确执行的前提条件。
的允许值为:option
-
完整的系统DMB 操作。 这是缺省情况,可以省略。
SY
访问存储器指令
编译器不能用C语言直接生成的主存储器指令是用于装载和存储的专用指令(LDREX和STREX)。这些指令常常专用于存储器的存取操作,例如在不同的线程之间提供人工干预操作。
屏蔽指令
Cortex-M3,这种内核支持许多屏蔽指令。在下一个指令或者事件开始执行以前,这些屏蔽指令常常用于确保必然事件执行完成。
在处理器内部,指令同步屏蔽(ISB)刷新流水线;以致于这个指令执行完以后,紧接着从缓存或者存储器取出指令表。这个表会改变这个系统,例如MPU立即生效。
数据同步屏蔽(DSB)指令作为一种特殊的存储器屏蔽指令。访问外部存储器操作完成之前,执行完成数据同步屏蔽指令(DSB)。执行数据同步屏蔽指令,在该指令没有完成以前不再执行任何指令——换句话说,执行完成所有的挂起操作。
数据存储屏蔽(DMB)指令作为一种存储器屏蔽指令。数据存储屏蔽(DMB)指令和数据同步屏蔽(DSB)指令有微小的差别。数据存储屏蔽(DMB)指令确保:数据同步屏蔽(DSB)指令执行完成之前,访问任意存储器;执行数据同步屏蔽(DSB)指令后,紧接着执行访问任意存储器操作。
如例8所示,典型MPU代码的一部分显示如何这些屏蔽指令。用嵌入汇编完成一个小的功能,每个功能都含有一条屏蔽指令。编译时链接器将连接这些功能。
例8用预处理指令使用屏蔽指令的范例
/*pseudo_intrinsics.c */
/*Small embedded assembly functions for barrier instructions*/
/*Link with armlink --inline ... */
__asmvoid __ISB(void)
{
ISB
BXlr
}
__asmvoid __DSB(void)
{
DSB
BXlr
}
/*scs.c - Initialize System Control Space registers */
voidSCS_init(void)
{
/*Code to configure the MPU regions inserted here
…
*/
/*Enable the MPU */
SCS.MPU.Ctrl|= 1;
/*Force Memory Writes before continuing */
__DSB();
/*Flush and refill pipline with updated permissions */
__ISB();
}
4.3.5 汇编语言:指令隔离(barrier)指令和存储器隔离指令
CM3 中的另一股新鲜空气是一系列的隔离指令(亦可以译成“屏障”、“路障”,可互换使用——译者 注)。它们在一些结构比较复杂的存储器系统中是需要的(典型地用于流水线和写缓冲——译者注)。在 这类系统中,如果没有必要的隔离,会导致系统发生紊乱危象(race condition),(相当于数电中的“竞争 与冒险”——译者注).
举例来说,如果可以在运行时更改存储器的映射关系或者内存保护区的设置,(通过写 MPU 的寄存 器),就必须在更改之后立即补上一条 DSB 指令(数据同步指令)。因为对 MPU 的写操作很可能会被放 到一个写缓冲中。写缓冲是为了提高存储器的总体访问效率而设的,但它也有副作用,其中之一,就是 会导致写内存的指令被延迟几个周期执行,因此对存储器的设置不能即刻生效,这会导致紧临着的下一 条指令仍然使用旧的存储器设置——但程序员的本意显然是使用新的存储器设置。这种紊乱危象是后患 无穷的,常会破坏未知地址的数据,有时也会产生非法地址访问 fault。紊乱危象还有其它的表现形式, 后续章节会一一介绍。CM3 提供隔离指令族,就是要消灭这些紊乱危象(在有些讲解计算机体系体系结 构的书中,这类紊乱危象也被称为“存储器相关”——译注)。
CM3 中共有3 条隔离指令,如表4.27 所列
表4.27 隔离指令
指令名 | 功能描述 |
DMB | 数据存储器隔离。DMB 指令保证: 仅当所有在它前面的存储器访问操作 都执行完毕后,才提交(commit)在它后面的存储器访问操作。 |
DSB | 数据同步隔离。比 DMB 严格: 仅当所有在它前面的存储器访问操作 都执行完毕后,才执行在它后面的指令(亦即任何指令都要等待存储器访 问操作——译者注) |
ISB | 指令同步隔离。最严格:它会清洗流水线,以保证所有它前面的指令都执 行完毕之后,才执行它后面的指令。 |
DMB 在双口 RAM 以及多核架构的操作中很有用。如果 RAM 的访问是带缓冲的,并且写完之后
马上读,就必须让它“喘口气”——用 DMB 指令来隔离,以保证缓冲中的数据已经落实到 RAM 中。 DSB 比 DMB 更保险(当然也是有执行代价的),它是宁可错杀也不漏网——清空了写缓冲,使得任 何它后面的指令,不管要不要使用先前的存储器访问结果,通通等待访问完成。大虾们可以在有绝 对信心时使用 DMB,新手还是使用 DSB 比较保险。同 DMB/DSB 相比,ISB 指令看起来似乎最强悍,但是却一身都是“愣劲”,不由分说就“动粗”。
不过它还有其它的用场——对于高级底层技巧:“自我更新”(self-mofifying)代码,非常有用。举例 来说,如果某个程序从下一条要执行的指令处更新了自己,但是先前的旧指令已经被预取到流水线 中去了,此时就必须清洗流水线,把旧版本的指令洗出去,再预取新版本的指令。因此,必须在被 更新代码段的前面使用 ISB,以保证旧的代码从流水线中被清洗出去,不再有机会执行(译者觉得 这种做法太工于技巧,有点“作秀”,现实编程中应该极少会用到,因此读者不必太钻它)