2

我试图了解 STM8 流水线,以便能够预测我的代码需要多少周期。

我有这个例子,我在每个 GPIO 引脚上切换 4 个周期。IFFloop在 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字节指令,nop1字节。
  • nop//指令每个需要 1bsetbres周期。
  • jra指令需要两个周期。我认为在第一个周期中,指令缓存被下一个 32 位值填充,即在这种情况下nop只有指令。第二个周期实际上只是 CPU 在解码下一条指令时被停止。

所以在循环中:

  1. bres清除引脚
  2. jra,管道刷新,nop获取
  3. nop解码,bset获取
  4. nop执行、bset解码、下一次nop获取
  5. bset执行设置引脚
  6. nop,bres
  7. nop
  8. nop,bres解码
  9. bres执行清除引脚

据此,该引脚应在 4 个周期内保持低电平,在 4 个周期内保持高电平,但在 5 个周期内保持高电平。

在任何其他对齐情况下,引脚按预期为低/高 4 个周期。

我认为,如果 PIN 在一个额外的周期内保持高电平,那一定意味着执行管道在bset指令之后停止(nop此后的 s 提供了足够的时间来确保bres稍后可以立即执行)。但根据我的理解nop(对于 6.)已经在 4 中获取。

知道如何解释这种行为吗?我在手册中找不到任何提示。

4

1 回答 1

1

它在 5.4 节中进行了解释,它基本上说在整个编程手册中,将使用“提供与现实良好匹配的简化约定”。根据我的经验,这种简化的约定对于较长的序列确实是一个很好的近似值,但对于精确的每条指令时间是不可用的,即使您正在处理汇编级别和控制对齐。以“SLA addr”为例。记录使用 1 个周期。将它们中的三个按顺序放置以实现“*(addr) << 3”的 C 等效项,您将计时 5-6 个周期。

用于解码和执行的实际周期没有记录。除了显而易见的原因之外,没有关于导致管道停止的原因的全面文档。在使用 ST-LINK/V2 单步执行我的代码时,我可以通过使用预分频器 /1 配置 TIM2 并重新加载 0xFFFF 值来对此有所了解。然后,您可以监视 TIM2_CNTRL 以查看消耗的周期(== 执行前一条指令和解码当前指令的总值)。

需要注意的显然是跨越 32 位边界的指令。在某些情况下,从下一个 32 位字加载指令会导致 NOP 序列中出现意外的额外周期,这表明任何取指(即使当前或下一条指令不需要)都需要 1 个周期?我已经看到对与 32 位边界对齐的目标的调用需要 4-7 个周期,这表明 CPU 仍在忙于执行前一条指令或由于未知原因暂停调用。在某些情况下,修改 SP(推送/弹出或直接添加/订阅)似乎会导致停顿。

任何额外的见解表示赞赏!

于 2018-11-20T04:34:26.567 回答