目次
前
次
テストデバッグ手法
Forthは、インタプリタ動作なので、ワードの
定義前に、ある程度の動作を確認できます。
SFR(Special Function Register)は、変数を利用し
仮想化すると、ワード「c@」と「c!」で内容を扱える
ので、テストとデバッグを、この2つのワードで済ま
せられます。
ポートB、C、Dの各ビットをセット、クリアするワード
を定義する前に、動作をテストしてみましょう。
Arduinoのハードウエアでは、ポートBの5ビット目に
LEDを接続しています。このビットを出力に設定した後
セットかクリアすると、点灯、消灯ができます。
この操作を拡張し、より使いやすくしてみます。
シフト、論理積、論理和、排他的論理和を使い
特定ビットのセット、クリアを、対応ワードで
操作できるようになります。
ポートBの指定ビットのセット、クリアを扱うワードは以下。
variable PORTB
: pbs 1 swap lshift PORTB @ or PORTB ! ;
: pbc 1 swap lshift $00ff xor PORTB @ and PORTB ! ;
この2ワードを利用すれば、ポートBの指定ビットの
セット、クリアは変数PORTBの内容を確認するだけで
テストできます。
LPC1114のForthで確認。
AmForthでは、変数PORTBを定義すると、SFRを
定数で扱う設定から、動作が変ってしまいます。
これでは、バグ入れることになるので、別の
Forthを使いました。
手持ちのLPC1114のForthを使い、ATmegaチップで動作する
Forthは利用しません。
ワードの定義前に、次のように動作確認しておきます。
指定ビットのセット
指定ビットのクリア
AmForthのワード動作確認に使った、LPC1114基板は以下。
ポートB、C、Dの各ビットをセット、クリアするワードは
以下のように定義しました。
: pbs 1 swap lshift PORTB c@ or PORTB c! ;
: pbc 1 swap lshift $00ff xor PORTB c@ and PORTB c! ;
: pb5s 5 pbs ;
: pb4s 4 pbs ;
: pb3s 3 pbs ;
: pb2s 2 pbs ;
: pb1s 1 pbs ;
: pb0s 0 pbs ;
: pb5c 5 pbc ;
: pb4c 4 pbc ;
: pb3c 3 pbc ;
: pb2c 2 pbc ;
: pb1c 1 pbc ;
: pb0c 0 pbc ;
: pcs 1 swap lshift PORTC c@ or PORTC c! ;
: pcc 1 swap lshift $00ff xor PORTC c@ and PORTC c! ;
: pc5s 5 pcs ;
: pc4s 4 pcs ;
: pc3s 3 pcs ;
: pc2s 2 pcs ;
: pc1s 1 pcs ;
: pc0s 0 pcs ;
: pc5c 5 pcc ;
: pc4c 4 pcc ;
: pc3c 3 pcc ;
: pc2c 2 pcc ;
: pc1c 1 pcc ;
: pc0c 0 pcc ;
: pds 1 swap lshift PORTD c@ or PORTD c! ;
: pdc 1 swap lshift $00ff xor PORTD c@ and PORTD c! ;
: pd7s 7 pds ;
: pd6s 6 pds ;
: pd5s 5 pds ;
: pd4s 4 pds ;
: pd3s 3 pds ;
: pd2s 2 pds ;
: pd1s 1 pds ;
: pd0s 0 pds ;
: pd7c 7 pdc ;
: pd6c 6 pdc ;
: pd5c 5 pdc ;
: pd4c 4 pdc ;
: pd3c 3 pdc ;
: pd2c 2 pdc ;
: pd1c 1 pdc ;
: pd0c 0 pdc ;
これらのワードを使うと、ポートのビット操作に
関するテストは、1ビットで充分。
機械的なコードを生成するには、スクリプト言語を
利用すれば簡単。AWKのスクリプトは、次のように
作成しました。
{
printf(": pd%ds %d pds ;\n",$1,$1)
}
スクリプト言語は、テキストファイルを扱うので
上のスクリプトのためのファイル内容は、以下。
7
6
5
4
3
2
1
0
単純に数値を並べているだけですが、スクリプト
言語で加工すると、ワード定義を生成できます。
AWKでは、次のようにタイプし、I/Oリダイレクトで
ワード定義をテキストファイルに転送。
awk -f mkword.awk nlist.txt > mkw.txt
Forthのワード定義を、スクリプト生成するは
手動よりも、ミスなく、素早く、目的を達成
できるので、自分は気に入ってます。
不要なワード定義が生成されたときには
それを使わなければよいだけ。
取捨選択の自由は、ワードを定義するユーザーに
あるので、その自由を躊躇無く行使しましょう。
スクリプトの一部を変更すれば、新しいワードを
生成する操作も簡単です。
{
printf(": pc%dc %d pdc ;\n",$1,$1)
}
としてみたり、次のように一部を変えます。
{
printf(": pc%ds %d pds ;\n",$1,$1)
}
テキストエディタを利用し、スクリプトの内容を
一部書き換えて、多くのワード定義を作成すると
より多くの考える時間を捻出できます。
テキストエディタ上でワードを定義し
端末ソフトで、クリップボード経由で
貼り付けると操作ミスを減らせます。
ワードは、ビルトインもユーザー定義も
一度入力すれば、分け隔てなく使えるので
階層構造をもつことやシーケンスを扱うよう
並べていくだけで、専用動作をつくれます。
計算の途中経過を確認したいときは、スタックに
入っている値をワード「dup」でコピー後、ワード
「.」あるいは「hex.」で表示させます。
シフトして特定ビットをクリアするような場合
次のように途中で動作がどうなっているのかを
確認すればよいでしょう。
この方法は、いわゆる「printf」デバッグと呼ばれます。
入力、加工、出力の各処理で、パラメータが正しく
渡っているか、加工して生成したデータが妥当か等
の途中経過を可視化で判断します。
可視化ができると、TDD(Test Driven Development)に
よるテストデバッグが可能に。
これで効率があがります。
スタックにデータが積みあがる状態を、紙に書き出して
可視化すると、机上でのテストデバッグができます。
次の入力で、スタックの変化をトレース。
$ff 1 4 lshift dup . xor hex.
Forthでは、スタック操作を括弧を利用して
コメントで残しておけるので、紙に書き出し
していきます。
$ff \ ( -- $ff )
$ff 1 \ ( $ff -- $ff 1 )
$ff 1 4 \ ( $ff 1 -- $ff 1 4 )
$ff 1 4 lshift \ ( $ff 1 4 -- $ff 16 )
$ff 1 4 lshift dup \ ( $ff 16 -- $ff 16 16 )
$ff 1 4 lshift dup . \ ( $ff 16 16 -- $ff 16 )
$ff 1 4 lshift dup . xor \ ( $ff 16 -- $ef )
$ff 1 4 lshift dup . xor hex. \ ( $ef -- )
スタックの内容が、どう変化するのを
紙に書き出しておくと、実機がない時
や交通機関での移動時に、短いワード
の定義とテストデバッグが可能。
ワードが実行されたとき、スタックの内容が
どう変化していくのかを、頭の中でトレース
できるようになります。しかし紙への書出し
をしておく方が、途中経過がある分、見直し
で役立ちます。
目次
前
次