PICマイコンの開発環境であるMPLAB X IDEに備わっているデバッグ用のプログラミング言語Stimulus Control Languageを使って、自作のPICプログラムをデバッグしてみる記録です。今回はプロセスとwaitについて調べてみます。
プロセス
デバッグ用のコードはprocess
ブロックに記述する。僕の趣味で、公式ユーザーズガイドとインデントの付け方が違っています。なんかSCLは懐かしのPascal言語っぽいので、Pascal流のインデント方式に統一しています。
process is begin // プロセスをここに記述する。 end process;
testbench
ブロックの中には、1個以上のprocess
ブロックを含む。2個以上のプロセスを記述する場合は並べて書けばよい。こんな感じ。process
を1個も含まないからのtestbench
も一応許されるみたい。
testbench for "PIC16F1705" is process is begin // 1個目のプロセス end process; process is begin // 2個目のプロセス end process; end testbench;
2つめのprocess
ブロックは1つ目のprocess
ブロックの実行が終了し次第実行されるようだ。ちなみにこのプロセスの動作はマニュアルに書いてないので、推測が入っています。
プロセスには名前を付けることができる。名前は任意で良いがtestbench
中で重複してはならない。現在のバージョンではプロセス名自体に意味を持たないが、将来のバージョンで何かに使われるかもしれないらしい。
プロセス名の書き方は2種類ある。
プロセス名: process is begin // プロセスの処理 end process プロセス名
またはこれ。プロセス名の後ろに"is"が付くか付かないかの違い。僕の趣味的には前者の方が好きかな。
プロセス名: is process is begin // プロセスの処理 end process プロセス名
上の例では「プロセス名」と日本語で書いているが、実際に日本語が使えるかは今のところ不明。半角英文字だけにしておくのが無難かもしれない。
wait
ここからprocess
ブロックの中で記述する具体的な文が出てきます。まず命令実行を一時停止するwait
文について。
SCLが普通の言語と違うのは、ループ構造を指定しなくてもprocess
ブロック内の文を上から順に実行し、一番下の文を実行するとまた先頭に戻って繰り返すということです。
process is begin statement1 statement2 statement3 end
この例では、statement1→statement2→statement3と実行すると自動的に先頭に戻って再びstatement1から実行することになります。
そこでprocess
ブロックの実行を一時停止するか終了するにはwait
文を実行する必要があります。もしprocess
ブロック中にwait
文が無いとprocess
ブロックの実行が止まりません。これはデバッガがハングアップすることを意味ます。
ここでデバッガ内部の動作を見てみます。
シングルステップ (1) ユーザ命令を1つ実行する (2) 命令で必要としたサイクル数分に対して: (2-1) ストップウィッチを増分する (2-2) PICの内蔵モジュールを実行する (2-3) SCLプロセスを実行する
デバッガはユーザプログラムを1命令ずつ実行します。そして1目入れ実行するごとに、SCLのプロセスを実行するのですが、もしSCLプロセスが止まらなければ永遠に(2-3)の処理を続けてしまうため、次のユーザ命令を実行することができなくなります。そこでprocess
中にwait
文を挿入することによって、(2-3)から抜け出すタイミングを作ることができるのです。
予期しないハングアップを防ぐため、IDEがSCLを読み込む際にprocess
ブロック内のwait
文有無をチェックし、もし無いとエラーとなるようになっています。
SIM004: Failed to parse SCL SCL022: Process contains neither a wait statement nor a sensitivity list line(#)
さて、wait文には4つの形式とその組み合わせの形式があります。
簡素Sait (Unadorned Wait)
プロセスを終了させます(現在のprocess
ブロックから抜けるということ)。
process is begin wait; // プロセスを終了する。 end process;
感度Wait (Sensitivity Wait)
値が変化するまで一時停止します。
wait on RD1; // RD1ピンの状態が変化するまで待つ wait on userVar; // ユーザ定義変数userVarの値が変化するまで待つ wait on STATUS; // STATUSレジスタの値が変化するまで待つ wait on PORTD.RD0; // ポートDのRD0ピンの状態が変化するまで待つ
条件Wait (COndition Wait)
真偽値が真になるまで一時停止します。
wait until PORTA == 128; // PORTAレジスタの値が128 (0x80)になるまで待つ wait until RD1 == '1'; // RD1がHighになるまで待つ wait until ADCON.ADON == '1'; // ADCONレジスタのADONビットが1になるまで待つ wait until PC == 4; // プログラムカウンタが4になるまで待つ。
タイムアウトWait (Timeout Wait)
指定した時間が経過するまで一時停止します。
wait for 10 ic; // 10命令サイクル待つ wait for 10 ms; // 10ミリ秒待つ
組み合わせWait (Combined Wait)
タイムアウトWaitと、感度Waitまたは条件Waitを組み合わせていずれかが真になるまで一時停止することができます。要するに各種条件にタイムアウトを設定できるということですね。
wait on RD1 for 10 ms; // RD1ピンが変化するか、10ミリ秒経過するまで待つ wait until PC = 20 for 20 ic; // プログラムカウンタが20になるか、20命令サイクル経過するまで待つ
コメント