目次

テストデバッグ手法

 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 --  )

 スタックの内容が、どう変化するのを
 紙に書き出しておくと、実機がない時
 や交通機関での移動時に、短いワード
 の定義とテストデバッグが可能。

 ワードが実行されたとき、スタックの内容が
 どう変化していくのかを、頭の中でトレース
 できるようになります。しかし紙への書出し
 をしておく方が、途中経過がある分、見直し
 で役立ちます。


目次

inserted by FC2 system