我正在努力理解STM8流水线,以便能够预测我的代码需要多少周期。
我有一个例子,其中我切换一个GPIO引脚,每个周期4个周期。Iff loop在4字节边界+ 3对齐,引脚保持活动5个周期(即比它应该的多一个)。我想知道为什么?
// Switches port D2, 5 cycles high, 4 cycles low
void main(void)
{
__asm
bset 0x5011, #2 ; output mode
bset 0x5012, #2 ; push-pull
bset 0x5013, #2 ; fast switching
jra _loop
.bndry 4
nop
nop
nop
_loop:
nop
bset 0x500f, #2
nop
nop
nop
bres 0x500f, #2
jra _loop
__endasm;
}更多一些背景:
bset/bres为4字节指令,nop为1字节。nop/bset/bres指令每个循环一个周期。jra指令需要两个周期。我认为在第一个周期中,指令缓存中填充了下一个32位值,即在这种情况下只填充nop指令。第二个周期实际上是CPU在解码下一个指令时被停止。所以在循环中:
bres清除引脚jra,流水线冲洗,nop提取nop解码,bset提取nop执行,bset解码,下一个nop提取bset执行设置引脚nop,bres提取nopnop,bres解码bres执行清除引脚据此,引脚应保持低4个周期和高4个周期,但它保持高5个周期。
在任何其他对齐情况下,引脚是低/高的4个周期,如预期。
我认为,如果PIN在一个额外的周期内保持在较高的位置,这必然意味着执行管道在bset指令之后被停止(nop随后提供足够的时间来确保bres稍后可以立即执行)。但根据我的理解,nop (用于6.)已经被四人录取了。
你知道怎么解释这种行为吗?我在手册中找不到任何提示。
发布于 2018-11-20 04:34:26
第5.4节对此作了解释,该节基本上说,在整个编程手册中,将使用“一种与现实很好地匹配的简化公约”。根据我的经验,这种简化的约定确实是较长序列的一个很好的近似,但是对于每条指令的精确定时是不可用的,即使您正在处理组装级别和控制对齐。以"SLA addr“为例。它被记录为使用一个周期。将其中的三个按顺序排列,以实现C等效的"*(addr) << 3",然后您将计时5-6个周期。
用于解码和执行的实际周期是无文档的。除了明显的原因外,没有关于造成管道阻塞的全面文件。在使用ST-LINK/V2执行代码时,我能够通过配置TIM2和/1预分频器并重新加载0xFFFF值来了解这一点。然后,您可以监视TIM2_CNTRL以查看所消耗的周期(==是执行前一个指令和解码当前指令的聚合值)。
需要注意的事情显然是跨越32位边界的指令。还有一些情况是,从下一个32位字加载指令会在NOPs序列中造成意外的额外循环,这意味着任何获取(即使对于当前或下一个指令不需要)都要花费一个周期?我看到了对32位边界对齐目标的调用,周期为4-7个周期,这表明CPU仍在忙着执行先前的指令或由于未知的原因而延迟调用。修改SP (push/pop或直接添加/转接)似乎会在某些条件下造成阻塞。
任何额外的洞察力都很感谢!
https://stackoverflow.com/questions/46629607
复制相似问题