我正在尝试了解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
说明每个都需要1个周期。jra
指令需要两个周期。我认为在第一个周期中,指令高速缓存用下一个32位值填充,即在这种情况下只有nop
指令。而第二个周期实际上只是在解码下一条指令时CPU被停止。所以周期:
bres
清除图钉jra
,管道清除,nop
提取nop
解码,bset
抓取nop
执行,bset
解码,下一个nop
抓取bset
执行设置引脚nop
,bres
fetch nop
nop
,bres
解码bres
执行清除引脚据此,引脚应保持低电平4个周期,高电平保持4个周期,但保持高电平5个周期。
在任何其他对准情况下,引脚按预期的方式为低电平/高电平4个周期。
我认为,如果PIN在一个额外周期内保持高电平,这必然意味着执行管道在bset
指令后停止(此后nop
s提供足够的时间来确保{bres
1}}以后准备立即执行)。但根据我的理解nop
(对于6)已经在4中获取。
知道如何解释这种行为吗?我在manual找不到任何提示。
答案 0 :(得分:0)
在5.4节中进行了解释,该节基本上说在整个programming manual中,将使用“简化的约定,提供与现实的良好匹配”。根据我的经验,对于较长的序列来说,这种简化的约定确实是一个很好的近似值,但是即使在装配级和控件对齐上工作,也不能用于精确的每条指令时序。以“ SLA addr”为例。记录使用1个周期。依次放置其中三个以实现C等效的“ *(addr)<< 3”,您将需要增加5-6个周期。
用于解码和执行的实际周期未记录。除了明显的原因外,没有关于导致管道停顿的原因的全面文档。通过使用预分频器/ 1配置TIM2并在使用ST-LINK / V2逐步浏览代码的同时重新加载值0xFFFF,我能够对此有所了解。然后,您可以监视TIM2_CNTRL以查看消耗的周期(==执行前一条指令并解码当前指令的总值)。
需要注意的显然是跨越32位边界的指令。在某些情况下,从下一个32位字加载指令会导致一系列NOP出现意外的额外周期,这表明任何获取(即使对于当前指令或下一条指令而言并非必需)都花费1个周期吗?我已经看到调用目标对齐到32位边界需要4-7个周期,这表明CPU仍在忙于执行上一条指令或由于未知原因而暂停调用。在某些情况下,修改SP(push / pop或直接add / sub)似乎会导致停顿。
任何其他见解表示赞赏!