プログラムにバグはつきもの.今日もバグの話を一つ.今回やらかしたバグは原因究明に苦労した.会社の仕事で簡単な通信ソフトウェアが必要になった事と,「ATLAS」をCで書き直すために,C言語によるRS_232_Cの制御モジュールを作成した.まずは手元のRXで動作確認,ねらいどおりにうまく動く.それではとVXで動かすとPCがハングアップする,LVでもだめ.LXやLS,M2ではすんなり動く.モジュールはRS/CSフローを行うために,MS−DOSのIO.SYSやBIOSは一切使わず,直接LSIを制御するようにした.マシンの機種毎のクロックやCPUタイプが違うからと思い,LSIの初期化部分などを見直すが不審な点が見つからない.色々プログラムをいじくってみるが症状は全然変わらない.動く機種では動くが動かぬものはまったくだめ.ハードウェアの機種互換で定評のPC9801である.まったくもって不可思議な現象だ.
悩む事三日目,今日なにげなしにリストを見ていてあれっと思った.
一文字送信ハンドラの中に次のような記述が見つかった.
while(!(inp(0x32 & 0x40));
ここは本来,次のように記述すべきところだ.
while(!(inp(0x32) & 0x40);
")" の位置が違っている.この部分は,モデムのCSがオフならオンになるのを待つ処理である. inp(0x32 & 0x40) では,IOポートの0番を見てしまうことになる.32番をみるところが0番を見ているのだ.もし,0番を読んだ結果が非0ならば無限ループ,外部現象としてはまさにハングアップ状態になる.
さて原因はここにありそうだが,ではなぜ機種によって動作したりしなかったりするのか.このIOポート0番は割り込みコントローラに割当てられている.そして0番のリードオペレーションは有効な操作として存在する.ただし,手順がある. outp(0x0, 0x0a); i = inp(0x0);
のように,ライトオペレーション(LSI内臓のレジスタを読みだすコマンドの発行)の次に行うものである.コマンド発行なしにリードするとどうなるか,読みだした値は不定である.0であるか非0であるか,それはシステムバスの状態次第,バスがプルアップされていれば 0xff ,プルダウンされていれば 0x00 となるはず.どうもこの辺りが機種によって振舞いが違ったようだ.アップダウンされていなければ運まかせ天まかせ.いかに機種互換のPC98でもイリーガルオペレーションの部分までは同じとはいかないようだ.
実はこのようなバグが一番たちが悪い.バグがあって動きがおかしくなるべきものが,一見あたかも正常に動いてしまう.すべての機種でハングアップ症状を呈していれば,もっと早く原因箇所が発見できていただろうにと悔やまれる.