到目前为止,我使用了3个NOP来“清理”流水线。最近我遇到了ISB指令,它可以帮我做到这一点。查看arm信息中心时,我注意到该命令需要4个周期(在Cortex M0下),而3个NOP只需要3个周期。为什么要使用此命令?它与3个NOP有什么不同?
bjg7j2ky1#
下面是NOP(http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/CHDJJGFB.html)的问题:操作NOP不执行任何操作,并且不一定会很耗时。处理器可能会在它到达执行阶段之前将其从管道中删除。使用NOP进行填充,例如将后续指令放置在64位边界上。其他ARM Cortex设备的文档中也有相同的信息,因此将该指令用于除填充之外的 * 任何 * 目的都是不可靠的。您唯一可以保证的是,该指令将占用2(nop)或4字节(nop.w),并且不会执行任何操作-仅此而已。
nop
nop.w
c90pui9n2#
ISB指令为4个周期的原因非常简单。Cortex-M指令集是16位和32位指令的混合。Cortex-M设计(如Cortex-M0)支持六个32位指令:BL、MSR、MRS、ISB、DMB、DSB。所有这六条指令都可以在16位指令中混合使用。问题是处理器如何知道哪个指令是16位的,哪个是32位的?要回答这个问题,处理器会读取前16位并对其进行解码(1个周期)。如果操作码与32位指令匹配,则它知道下一个16位指令实际上是32位指令的后半部分,并尝试执行它(3个周期)。这使得Cortex-M内核中的所有32位指令都是1+3个周期= 4个周期。要清除流水线,如果您对内核实现有把握,可以使用3个NOP。您必须确保内核没有分支预测和动态指令优化,这会删除连续的NOP。如果您确定没有此功能,则使用3个NOP指令,这样可以保存1个周期。但是,如果您不使用,并且还希望ARM代码能够移植到其他架构(如ARMv7等),则必须使用ISB指令,这是一种32位指令,需要4个周期。
unftdfkk3#
您应该使用ISB指令来确保流水线畅通无阻。正如上面的注解所述,不同ARM处理器之间的流水线可能不同(例如,M7有6级流水线,而M3/4有3级流水线)。根据M4技术参考手册“对于ISB,最小周期数等于流水线重新填充所需的周期数。"为什么是4个周期而不是3个,我不确定,这可能与确保分支预测逻辑正确有关。不管你是否希望你的代码是可移植的,我会建议使用ARM提供的工作,如果他们认为你需要4个周期,那么我希望你这样做。如果你只有3个周期,在某些情况下你可能会得到错误的操作。
pxiryf3j4#
3个NOP并不保证会占用3个周期。在Cortex-M3* 上,它们肯定会占用2个周期 *,在这些情况下,您可能需要使用3个以上的NOP才能获得所需的效果。“有趣的”场景可能不会在普通代码中出现,或者还需要其他事件的特定时间--所以你可能不太可能观察到它们。关键点是没有保证,这类故障的可观察性通常很低。即使您在某个地方错误地只使用了2个NOP,您的代码也可能在大部分时间都能正常工作--直到其他地方的更改可能对对齐产生影响并暴露故障。
e3bfsja25#
有关“清洁”管道的确切信息,请访问:"ARM Cortex™-M Programming Guide to Memory Barrier Instructions" Application Note 321它适用于:Cortex-M3、Cortex-M4、Cortex-M0、Cortex-M0+和Cortex-M1处理器。如何清理管道取决于正在使用的指令,例如,__enable_irq()、__WFI()(sleep)等。据我所知,该文件没有提到使用NOP来清洁管道。
5条答案
按热度按时间bjg7j2ky1#
下面是NOP(http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/CHDJJGFB.html)的问题:
操作
NOP不执行任何操作,并且不一定会很耗时。处理器可能会在它到达执行阶段之前将其从管道中删除。
使用NOP进行填充,例如将后续指令放置在64位边界上。
其他ARM Cortex设备的文档中也有相同的信息,因此将该指令用于除填充之外的 * 任何 * 目的都是不可靠的。您唯一可以保证的是,该指令将占用2(
nop
)或4字节(nop.w
),并且不会执行任何操作-仅此而已。c90pui9n2#
ISB指令为4个周期的原因非常简单。Cortex-M指令集是16位和32位指令的混合。Cortex-M设计(如Cortex-M0)支持六个32位指令:BL、MSR、MRS、ISB、DMB、DSB。
所有这六条指令都可以在16位指令中混合使用。
问题是处理器如何知道哪个指令是16位的,哪个是32位的?要回答这个问题,处理器会读取前16位并对其进行解码(1个周期)。如果操作码与32位指令匹配,则它知道下一个16位指令实际上是32位指令的后半部分,并尝试执行它(3个周期)。
这使得Cortex-M内核中的所有32位指令都是1+3个周期= 4个周期。
要清除流水线,如果您对内核实现有把握,可以使用3个NOP。您必须确保内核没有分支预测和动态指令优化,这会删除连续的NOP。如果您确定没有此功能,则使用3个NOP指令,这样可以保存1个周期。但是,如果您不使用,并且还希望ARM代码能够移植到其他架构(如ARMv7等),则必须使用ISB指令,这是一种32位指令,需要4个周期。
unftdfkk3#
您应该使用ISB指令来确保流水线畅通无阻。正如上面的注解所述,不同ARM处理器之间的流水线可能不同(例如,M7有6级流水线,而M3/4有3级流水线)。根据M4技术参考手册“对于ISB,最小周期数等于流水线重新填充所需的周期数。"
为什么是4个周期而不是3个,我不确定,这可能与确保分支预测逻辑正确有关。不管你是否希望你的代码是可移植的,我会建议使用ARM提供的工作,如果他们认为你需要4个周期,那么我希望你这样做。如果你只有3个周期,在某些情况下你可能会得到错误的操作。
pxiryf3j4#
3个NOP并不保证会占用3个周期。在Cortex-M3* 上,它们肯定会占用2个周期 *,在这些情况下,您可能需要使用3个以上的NOP才能获得所需的效果。
“有趣的”场景可能不会在普通代码中出现,或者还需要其他事件的特定时间--所以你可能不太可能观察到它们。关键点是没有保证,这类故障的可观察性通常很低。
即使您在某个地方错误地只使用了2个NOP,您的代码也可能在大部分时间都能正常工作--直到其他地方的更改可能对对齐产生影响并暴露故障。
e3bfsja25#
有关“清洁”管道的确切信息,请访问:
"ARM Cortex™-M Programming Guide to Memory Barrier Instructions" Application Note 321
它适用于:Cortex-M3、Cortex-M4、Cortex-M0、Cortex-M0+和Cortex-M1处理器。
如何清理管道取决于正在使用的指令,例如,__enable_irq()、__WFI()(sleep)等。
据我所知,该文件没有提到使用NOP来清洁管道。