AVR Assembly BRNE延迟循环如何工作?

时间:2017-11-23 10:52:25

标签: loops assembly delay avr

对于运行频率为16MHz的芯片,online delay loop generator给出了运行时间为0.5s的延迟循环。

我的想法是:

  1. 如果寄存器变为负数,分支是否保持分支?
  2. 如何计算开头加载的值?

        ldi  r18, 41
        ldi  r19, 150
        ldi  r20, 128
    L1: dec  r20
        brne L1
        dec  r19
        brne L1
        dec  r18
        brne L1
    

1 个答案:

答案 0 :(得分:2)

  

如何计算开头加载的值?

计算总循环次数=> 0.5s * 16000000 = 8000000

知道r20和r19循环的总周期(从零到零),AVR寄存器为8位,因此完整循环为256次(dec 0 = 255)。 dec是1个周期。条件(分支)发生时brne为2个周期,不发生时为1个周期。

所以最内在的循环:

L1: dec  r20
    brne L1

从零到零(r20=0):255 *(1 + 2)+ 1 *(1 + 1)= 767个循环(分支的255倍,经过1次)。< / p>

使用r19的第二个包裹循环是:255 *(767 + 1 + 2)+ 1 *(767 + 1 + 1)= 197119个周期

分支时的单r18循环则为197119 + 1 + 2 = 197122个循环。 (197121当没有采取分支=延迟循环的最终退出时,我将在下一步中通过一个技巧避免这个-1。)

现在这几乎足以计算初始r18,让我们先用O(1)代码调整总周期,这是ldi指令的三倍,需要1个周期:total2 = 8000000 - (1 + 1 + 1)+ 1 = 7999998 ...等等,那里的最后一个+1是什么?这个假的额外周期延迟,使最终r18循环假装它与非最终成本相同,即197122个周期。

就是这样,最初的r18必须足以等待至少 7999998个周期:r18 = (7999998 + 197122 - 1) div 197122 = 41。 &#34; + 197122 - 1&#34;部分将确保丰富的周期符合约束:0 <= abundant_cycles < 197122(剩余的197122除法)。

41 * 197122 = 8082002 ...这太多了,但现在我们可以通过将r19r20设置为特定值来减少额外周期,以微调延迟。那么剃掉多少钱? 8082002 - 7999998 = 82004个周期。

单个r19循环在分支时需要770个循环,在退出时需要769个循环,所以再次让我们通过将82004调整为仅82003来避开769循环。 82003 div 770 = 106:可以跳过106 r19个循环,r19 = 256 - 106 = 150。现在这将削减81620个周期,因此82003 - 81620 = 383个周期将被削减。

单个r20循环在分支时需要3个循环,在退出时需要2个循环。我将再次考虑退出循环只有2个循环 - &gt; 383 =&gt; 382刮胡子。并且382 div 3 = 127,余数为1. r20 = 256 - 127 = 129并且少做一次以减少额外的3个周期(以覆盖剩余部分)= 128.然后2个周期(3-1)等待失败使其达到完整的8mil

所以:

    ldi  r18, 41
    ldi  r19, 150
    ldi  r20, 128
L1: dec  r20
    brne L1
    dec  r19
    brne L1
    dec  r18
    brne L1

根据我的计算,应该等待8000000-2个周期(如果没有被其他东西打断)。

让我们尝试验证:

初始r20:127 * 3 + 1 * 2 = 383个周期
初始r19:1 *(383 + 1 + 2)+ 148 *(767 + 1 + 2)+ 1 *(767 + 1 + 1)= 115115个周期 (该初始r20个未完成周期一次,然后是149次全时r20周期,最后一个因为退出brne而为-1 总共r18:1 *(115115 + 1 + 2)+ 39 *(197119 + 1 + 2)+ 1 *(197119 + 1 + 1)= 7999997个周期。

三个ldi是+3个周期= 7999997 + 3 = 80000000。

缺少的两个周期无处可见,所以我犯了一个错误。

正如你所看到的,背后的数学相当简单,但手工做的很平凡,容易出错......

啊,我想我知道我犯了哪个错误。当我刮掉丰富的循环时,不涉及终止循环(这是实际延迟过程的一部分),因此我不应该将to_shave_off循环调整为-1。然后在r19 = 106之后,我仍然需要削减384个周期,并且正好是384/3 = 128个循环从r20 = 256-128 = 128中剃掉。没有剩余,没有遗漏周期,完美的8mil。

如果您无法遵循此反向计算,请尝试其他方式,想象2位寄存器(仅限0..3值),并在纸上进行类似的循环,其中r18 = r19 = r20 = 2,并计算循环次数手动查看它是如何演变的。 ..即3x ldi = + 3,dec r20,brne,dec r20,brne(skip)= +5个循环,dec r19,brne = + 3,......等。

编辑:以前Jester在他的链接中解释过这个问题。而且我懒得把它清理成一些简单的公式来创建你自己的在线计算器。