• 締切済み

16F84A アセンブラに関する質問です。

使用環境はWindows10(64bit)、統合開発環境MPLAB X IDE v3.26、MPASMX v5.66,16F84Aによるアセンブルプログラムです。TIM0、TIM1、TIM2はGPRの初めのレジスタ3つ(0CH~0EH)に割り当ててあります。 ; ----- WAIT 0.1Sec WAIT_01S     ; {4x(y+1)+3}*0.4*(10/f) [uS] OSC:f=10MHz MOVLW 0FAH ; x=250(FAH) y=249(F9H) => 100001.2uSec(=0.1Sec) MOVWF TIM1 W1S_1 MOVLW 0F9H MOVWF TIM2 W1S_2 NOP DECFSZ TIM2,F GOTO W1S_2 DECFSZ TIM1,F GOTO W1S_1   RETURN 1.NOPを外して、TIM2を0FAHとすることはできないのでしょうか。 2.”DECFSZ TIM1,F" は、TIM1 を一つずつ減らしていきその結果を TIM1 に格納し、TIM1 がゼロになったら次の行の”GOTO~”を飛ばし( NOP に強制的に読み替え)、次の行の"RETURN"へ進む、という意味だと思いますが、 DECFSZ の第2パラメーターの F はファイルレジスタを示す F なのでしょうか。この F が W だとワーキングレジスタに関して同じ処理をする、という意味になるのでしょうか。検索して出てきた書式がいまいち理解できません。 3.ラベル WAIT01_S の2重ループですが、 10MHz で作動させこの逆数の周期×4の長さを1サイクルとしたとき、内側のループのTIM2に初期値249を与え、このTIM2を一つずつ減らしていく過程で249サイクル消費し、TIM2がゼロとなった時点でもう1サイクル、それとNOPが1サイクルの合わせて251サイクルを、この内側のループで消費すると考えたのですが、コメントを読む限りどうも違うようです。いったいこのルーチンで消費するサイクル数をどう数えるべきなのでしょうか。コメントも違うような気がします。 4.最後のRETURNはどの行に対応しているのでしょうか。()などと同じように階層的ネスティングを構成するとすれば、最も手前にあるラベルW1S_2に対応しそうですが、それでは無限ループに落ちいてしまうと思います。それとも一行を丸々ラベルだけ使ったWAIT01_Sに対応するとかの何らかのルールが存在するのでしょうか。 5.シミュレータを指定してデバッグモードで走らせたときストップウォッチで模擬的に測定してみたのですが、仮想の動作周波数が1MHzであるにもかかわらず、どこにブレークポイント行にしても表示サイクルが1uSの4倍の4uSの整数倍になりません。ブレークポイントを示す行頭の四角の真ん中にひびが入っているマークも理解できません。 もしよろしかったらお分かりのところだけでも結構です。どなたかお教えくださいませんでしょうか。よろしく願いします。

みんなの回答

  • MSZ006
  • ベストアンサー率38% (390/1011)
回答No.3

#2訂正です。 3. 内側のループがy(249)回、外側のループがx(250)回廻ります。 内側のループは、 NOP →1サイクル DECFSZ →1サイクル GOTO →2サイクル 3命令合計4サイクルがy回とループを抜ける最後に1サイクル余分にかかるので、 4y+1サイクル。さらに最終回はGOTO(2サイクル)は実行されないのでその分をマイナスすると、4y-1サイクルとなります。 外側のループは、 MOVLW →1サイクル MOVWF →1サイクル DECFSZ →1サイクル GOTO →2サイクル の4命令合計5サイクルがx回とループを抜ける際に1サイクルで5x+1ですが、内側ループ同様、最終回はGOTO(2サイクル)は実行されないので5x-1です。ループの中に内側ループがあるので、内側ループと外側ループを合わせると、 ((4y-1)+5)x-1ということになります。 これにこのサブルーチンの最初の、 MOVLW →1サイクル MOVWF →1サイクル と、最後の、 RETURN →2サイクル を加えると、 (4y+4)x+3 サイクル という計算になると思います。 x=250, y=249を代入して計算すると、合計250,003サイクルとなります。 1サイクル=4クロックで、1,000,012クロック。クロック周波数10MHzだと、0.1000012Secということになります。

poor_Quark
質問者

お礼

ステップバイステップでプログラムの進捗を考えてみてどうにか理解できる と思います。たびたびお手数おかけして申し訳ありません。

  • MSZ006
  • ベストアンサー率38% (390/1011)
回答No.2

1. W1S_2 NOP DECFSZ TIM2,F GOTO W1S_2 の三行で一つのループを作っています。NOPもTIM2回実行されることになるので、NOPを取ってTIM2を1増やす、というのとは意味合いが違うと思います。 2. 私の調べたところでは、DECFSZ TIM1,F のFは、1もしくは0の値で、0のときはワーキングレジスタに上書き、1のときはファイルレジスタ(このケースではTIM1)に上書きとなるようです。どこかでF=1という定義がされているのではないでしょうか。 3. 内側のループがy(249)回、外側のループがx(250)回廻ります。 内側のループは、 NOP →1サイクル DECFSZ →1サイクル GOTO →2サイクル 3命令合計4サイクルがy回とループを抜ける最後に1サイクル余分にかかるので、 4y+1サイクル。 外側のループは、 MOVLW →1サイクル MOVWF →1サイクル DECFSZ →1サイクル GOTO →2サイクル の4命令合計5サイクルがx回とループを抜ける際に1サイクルで5x+1ですが、ループの中に内側ループがあるので、内側ループと外側ループを合わせると、 ((4y+1)+5)x+1ということになります。 これにこのサブルーチンの最初の、 MOVLW →1サイクル MOVWF →1サイクル と、最後の、 RETURN →2サイクル を加えると、 (4y+6)x+5 サイクル という計算になると思います。 x=250, y=249を代入して計算すると、合計250,505サイクルとなります。 1サイクル=4クロックで、1,002,020クロック。クロック周波数10MHzだと、0.100202Secということになります。 4.最後のRETURNは、このWAIT_01Sはサブルーチンで、呼び出した元に帰るためのものだと思います。

poor_Quark
質問者

お礼

1と3に関してはいただいたご回答の内容をヒントによく考えてみます。 おかげさまで大きく理解が進んだと思います。 2と4はおおむね理解できたと思います。 ありがとうございました。

  • koujikuu
  • ベストアンサー率43% (429/993)
回答No.1

1) NOP を減らすと内側ループが、3*249-1=746 にしかなりません 4*249-1=995 TIM2レジスタ代入分を合わせて 995+2=997 が内側クロック数です 2) DECFSZ TIM2,F のFは演算結果をF=ファイルレジスタTIM2へ格納するか、W=Wレジスタへへ格納するかの違いです Wの時はTIM2は更新されません 3) 内側サイクルは、4*249-1+2=997 で外側サイクル (997+3)*250-1+2=250001 に RETURN を追加すると 250003 が正式クロックで 10MHz 時CPU実行クロックは2.5MHz 400μS なので 250003 × 0.0000004S ≒0.1S になります 4) WAIT_01S はサブルーチンとして、CALL で呼び出され RETURN で復帰します C言語の関数と同じです WAIT_01S();

poor_Quark
質問者

お礼

いただいたご回答を手がかりに一生懸命考えてやっと理解できそうです。 DECFSZ命令の使い方も説明いただいた内容でわかりました。 ご親切にご回答いただき感謝します。

関連するQ&A