2017-11-23 11 views
-1

online delay loop generatorは、16MHzで動作するチップの実行時間0.5sのこの遅延ループを私に与えます。AVRアセンブリBRNE遅延ループはどのように機能しますか?

私の心の質問は以下のとおりです。レジスタが負になった場合

  1. は枝が分岐しておくのですか?
  2. 最初に読み込まれた値はどのくらい正確に計算されますか?

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

1.命令セットリファレンスで 'brne'が何を行うかを調べます。結果が正か負かにかかわらず、ゼロでない場合はそれがとられていると仮定します。だから、ループを符号なしカウンターを使用するものと考えてください。 –

+1

参照[this](https://stackoverflow.com/a/23478769/547981)と[this](https://stackoverflow.com/q/35750663/547981) – Jester

+0

計算するために命令サイクルを計算する必要がありますこのループが消費する時間。このループはラベル「L1: '0x00299680(2,725,504)回」を繰り返します。 (0x29 = 41d、0x96 = 150d、0x80 = 128d)。ループ中にISR(割り込みサブルーチン)が実行された場合、サイクルを使用して計算する時間は無効です。遅延ループ中にISRをディセーブルするには、opportune命令を使用します。 –

答えて

0

どのように正確に一つは、最初にロードされた値を計算していますか?

* 16000000 = 8000000 0.5秒

そう完全ループは、AVRレジスタは8ビットであり、(ゼロからゼロへ)R20およびR19ループの合計サイクルを知って> =サイクルの総量を計算256回(dec 0 = 255)。 decは1サイクルです。 brneは、条件(分岐)が発生した場合は2サイクル、発生しない場合は1サイクルです。

だから、最も内側のループ:255 *(1 + 2)+ 1 *(1 + 1)= 767サイクル(255倍分岐がある:

L1: dec r20 
    brne L1 

は、ゼロからゼロ(r20=0)することです1回は通過する)。


r19を扱う第二包装ループはである:255×(767 + 1 + 2)+ 1×(767 + 1 + 1)= 197119サイクル

単一r18ループ分岐がある場合197119 + 1 + 2 = 197122サイクルとなる。 (分岐が取られていない197121 =遅延ループの最後の終了、私は次のステップでこれを-1とします)。

ここでは、最初にr18を計算するのに十分ですが、最初にO(1)コードで合計サイクルを調整してみましょう。これは、1サイクルを要するldi命令の3倍です:total2 = 8000000 - (1 + 1 + 1) + 1 = 7999998 ...待って、そこに最後の+1は何ですか?それは、最後のr18ループが最終的でない、すなわち197122サイクルと同じ費用を負うようにするために、遅延するための偽の追加サイクルです。 r18 = (7999998 + 197122 - 1) div 197122 = 41

そして、それはこれだけです、初期r18少なくとも 7999998サイクルを待つために十分でなければなりません。 "+ 197122 - 1"の部分は、豊富なサイクルが拘束条件を満たすことを確認します: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回だけ退出することを考慮に入れます - > 383 => 382を剃ること。 382 div 3 = 127、残りは1。r20 = 256 - 127 = 129であり、残りの3つのサイクルを削るために1つ少ない(残りの部分をカバーする)= 128です。それから、2サイクル(3-1)の待ち時間がなくなり、完全な8ミルになります。

ので(他の何かによって中断されていない場合)私の計算によると

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サイクル (すなわち、最終的な一つである149回のフルタイムr20サイクル-1によるbrneを出ると、次いで、r20不完全サイクル一度初期'S)
r18合計:1 * (115115 + 1 + 2)+39 *(197119 + 1 + 2)+ 1 *(197119 + 1 + 1)= 7999997サイクルである。

そして3 ldiは3サイクル= 7999997 + 3 = 80000000.

され、不足している2サイクルが見られることをどこにもありませんので、私はどこかでミスを犯しました。

あなたが見ることができるように、背後にある数学が合理的にシンプルですが、手で行うことは非常に世俗的な、そしてミスを起こしやすい...

ああ、私は間違いをしたところ、私が知っていると思います。私が豊富なサイクルを削り取っているとき、終了ループは関与していません(それは実際の遅延プロセスの一部です)。したがって、to_shave_offサイクルを-1で調整すべきではありません。その後、r19 = 106の後、私はまだ384サイクルを削り取る必要があり、それはちょうどr20 = 256-128 = 128から削り取るために、正確に384/3 = 128ループです。余り、欠けていないサイクル、完璧な8ミル。

この逆の計算に従うのが難しい場合は、2ビットレジスタ(0..3値のみ)を想像し、r18 = r19 = r20 = 2の紙の同様のループで行い、それがどのように進化しているかを見るために手動で循環させる。つまり、3xldi = +3、dec r20、brne、dec r20、brne(スキップ)= +5サイクル、dec r19、brne = +3、...など。

編集:彼のリンクでJesterによって。そして、私はあなた自身のオンライン電卓を作成する簡単な数式にこれをクリーンアップするにはあまりにも怠惰です。

+1

明らかに、この計算はMCUがISRを実行しない場合にのみ有効です。:) –

+1

@SergioFormigginiええと、単純な方法はありませんが、時間管理が単純なサイクルカウントであれば、それは絶望的です。より正確ではないがより信頼できる時間遅延ループを作成するためには、ある種のタイマーオンチップデータが必要である。また、もしこれがある種の非常に特化したシステムであり、完璧なタイミングを必要とするのであれば、すべての割り込みを無効にし、完全にタイムコードを実行するだけの有効な方法です。精度は水晶周波数と同じになりますCPUの正確さ(それはそれほど大きくないかもしれませんか?私はおそらくそれを何か重要なものに使用しないでしょう)。 – Ped7g

+1

AVR MCUには、多くの設定で良好なカウンタがあります。プログラマが使用できる1つの機能は、カウントが経過するとISRをトリガするカウント数を設定することです;) –

2

正確にあなたの質問に答えるために:

1:DEC命令は「署名」の番号を知っていない、それだけで8ビットのレジスタをデクリメント。 2の補数演算の奇跡は、ラップアラウンド(0x00 - > 0xFF、0 - > -1と同じビットパターン)でこの作業を行います。また、DEC命令はステータスレジスタにZフラグを設定します。この場合、BRNEは分岐が発生するかどうかを判断するために使用します。

2:AVRのマニュアルから、DECは1サイクルの命令であることがわかります。 BRNEは、分岐しない場合は1サイクル、分岐の場合は2サイクルです。したがって、ループの時間を計算するには、各パスを取る回数をカウントする必要があります。このループは、768サイクルの合計のため、正確に12月の256サイクル、及びBRNEの512サイクルで256回実行する

ldi r8 0 
L1: dec r8 
    brne L1 

は、単一のDEC/BRNEループを考えます。 16MHzでは48usです。

ldi r7 10 
    ldi r8 0 
L1: dec r8 
    brne L1 
    dec r7 
    brne L1 

あなたは外側のループカウンタは内部ループカウンタが私たちの例では、このようにDEC/BRNEが起こる外側のループを0に当たるたびにデクリメントすることを見ることができます。外側の遅延ループであること

ラッピング10回(768サイクル)、内部ループは10 * 256回発生するので、このループの合計時間は528sの場合10 * 48us + 48usです。 3つのネストされたループについても同様です。

ここから、希望する遅延を達成するために各ループが何回実行されるべきか把握するのは簡単です。これは、アウターループが希望する時間よりも短い時間を実行してから、そのタイムアウトを取り、次のネストされたループに対して同じ処理を繰り返します。

関連する問題