V20-MBCエミュレータの開発 その6

とても難しいバグの調査!

難しいバグという意味ではなくて、調査が難しいという意味!

先日からのバグがどーしても見つけられない!

あんまりにも見つけられなくて、このバグ探しは一旦中止にしようかとも思ったほど。

まずはこれを見て欲しい。

f:id:PocketGriffon:20200823140745p:plain

エミュレータ上で実行させたASCIART.BASの結果だ。

「おお!ちゃんと表示出来たじゃない!」と思うことなかれ。

実機で動かすとこうなる↓

f:id:PocketGriffon:20200823140843p:plain

そう、結果がだいーぶ違うのだ(T-T)

まさに「それっぽく動いちゃう系」のバグを踏んづけた!

 

それっぽく表示されてしまうのだから、何か誤差とかそういう問題なのかと思い調べていっところ、こんな状態でもバグが出る事が分かった↓

f:id:PocketGriffon:20200823141219j:plain

この頃には「あ、これはトンデモなく面倒なバグだぞ」と思い始めた。

プログラム的には単精度の数値を加算しているだけなのだが、結果がなぜか乗算された数字になっている。これが単純に「+」演算子と「*」の演算子の取り間違い程度で済むはずが無い。

 

さらに見ていくと、こんな事も分かった。

f:id:PocketGriffon:20200823141435p:plainf:id:PocketGriffon:20200823141457p:plain

「0.998 + 0.001」はちゃんと結果が表示されて、

「0.999 + 0.001」の結果が間違える。

ここからなんとなく分かるのは、加算の処理自体はちゃんと出来てるっぽい。

そして表示(というか数値を利用しようと)する時に間違えた数字に変換されてしまうのでは…と推測。

 

探せど探せど見つからないバグ

そして調べる事、まる1日!

うん、分からん!(T-T)

単精度の計算処理に間違いがある事は間違いないんだと思うんだけどなぁ…。

メモリ内のFAC(Floating Accumulaterの略?インタプリタの計算はこのメモリを介して行われる)を見ても、実数は読みづらい形式で格納されていて良く分からないので、変換出来るツールなんぞ作ってみた。

f:id:PocketGriffon:20200824130243j:plain

コマンド名の後ろに4つの数値を渡せば実数値に変換してくれるw

さらにエミュレータ内部にもこの機能を入れて、常にFACが見られるようになった!

これでプログラムが追いやすくなったはずだ!

 

$FADDSという関数があり、これはレジスタBX:DXと[FAC]を加算して[FAC]へ戻す処理だ。

ここの処理がおかしいはずだ…と睨んで探していくが、やはりどうしても見つからない…。

万策尽きた…そう思った。

 

V20-MBC上でMBASICを起動し、

  A=.999+.001

とすることで、メモリ上のFAC上に数値を残すことが出来る。

SYSTEMでMBASICから抜け、DDT86でF000:05B9からの4バイトがFACだ。

そこには「00 00 00 81」という数字が並んでいる。

これを先ほどのfacに入れてみると、なるほど確かに1.000...だ。

最後の「81」というのは指数が入っている。

この数字を何気に替えてみた。

……!!!!!

f:id:PocketGriffon:20200824131255j:plain

値が半分の0.500...になり、どっかで見た数字になる!

上の「.999+.001」を計算すると0.5になっちゃうアレだ。

もしかして指数の計算に失敗しているのでは……。

ついにバグの尻尾をつかんだ瞬間!!!

 

バグの種明かし

$FADDSルーチンの指数を計算しているところを解読する。

  ADC BL,AL

いかにもキャリーフラグが使われていて危険な香りがする。

しかし…これはもう何度も何度もチェックしているし、事実ここに飛んでくるプログラムを追い掛けてみても、きちんとキャリーフラグを加えた加算をしてくれている。

問題なしだ。

 

そう思った矢先、こんなパターンで飛び込んできた。

f:id:PocketGriffon:20200824131923j:plain

BL=00h、AL=FFh、CY=1なので答えが00で正しい。

答えは正しいが…! 計算結果に基づいて立つはずのキャリーフラグが立ってない!!

本来であれば、00h+FFh+01で100hとなり、桁あふれが起きているのでキャリーフラグは立つはずだ。

ここに来てようやくピンときた!

私はADD関数をこんな感じで作っていた。

 

static unsigned char AddB(unsigned char src, unsigned char dest)

 

この関数をしっかりとデバッグして信頼度を高めた上で、ADC命令はこの関数を利用していたのだ。

 

static unsigned char AdcB(unsigned char src, unsigned char dest)

 {

  return AddB(src, dest + Carry);

}

 

なんとなく問題なさそうに見えるが……

そう、dest + Carryの時点で桁あふれを起こしてしまい、unsigned char の引数には100hではなく00hが渡っていたのだ!!!

ものすごい初歩的なミス!(^^;;;;

まさに1ビットに泣いた(T-T)

同じミスをSBCにもしてしまっていたので、同時に修正する事に!

 

そして動いたマンデルブロ

f:id:PocketGriffon:20200824132801p:plain

…見て欲しい…これが夢にまで見た数字の「1」だ!!!!

ついにこのエミュレータは足し算を克服した!!!!(^^;;;;

 

いやもう……こんなバグに何日かかってるの(T-T)

若い頃だったらあっさり直していた気もするなー……(イイワケ)

 

そしてマンデルブローのBASICプログラム(ASCIART.BAS)を動かしてみる。

f:id:PocketGriffon:20200824133001p:plain

…完璧!

バグを修正した結果、計算は正しく行われていると思って良いだろう。

 

ついでに実行速度も測ってみた。

CP/M-86が起動し、MBASICを立ち上げてASCIART.BASの処理が終わるまでで2.3秒。

この速度で動いてくれるとホントに開発がし易い(^^)

この先、このエミュレータを重宝していけるといいなぁ。

 

エミュレータの完成度から言ったら3〜40%くらいのイメージ?

命令実装数は128くらいまで上がってきた。

まだ割り込みも無ければキー入力すら出来ないハリボテだけど、結構動いてきました(^^)

 

まだまだ開発は続きますが、別の話題も差し込みながら進めますね(^-^;

それではまた次回!(^-^)ノ