EtchedPixels/EmulatorKit でMIKBUGを動かしてみた(5)Altair 680 4K BASICのBUG?

BASICMASTER

emu6800にmikbug互換のルーチンを入れて Altair 4K BASICのテストを行ってみた。すると、なぜかSAVAGEベンチマークテストが途中で止まる。なんだこれ?

私が使っているのは、Vintage Computer Programming に投稿されたソースリストで、6502版を参考に解析されたものだ。


I/Oポートをアクセスしている

emu6800+mikbugでは、オリジナルのemu6800と同様に特定のI/Oポートを叩くことで特別な動作を行うようにしている。

$FEFEを読み込むと、標準入力から1文字読み込む。どうやら、それが実行されているようだ。1文字読むまで止まるので、プログラムも止まってしまう。

でも、ソースリストでは、標準入力から読むのはプログラム入力やINPUT文などだ。浮動小数点演算で止まるのはおかしい。

emu6800 -d で、追っかけてみると、$0A0D行で止まる。 インデックスレジスタが$FEF1なので、TST $0D,X は $FEFEを読みこむ。止まるわけだ。でもなんで?


18C5 : C--NIH 81|00 FEF1 4DC9 | PULA
18C6 : C--NIH 00|00 FEF1 4DCA | TSTA
18C7 : --Z-IH 00|00 FEF1 4DCA | BPL 18CC [0D]
18CC : --Z-IH 00|00 FEF1 4DCA | RTS
0B92 : --Z-IH 00|00 FEF1 4DCC | JMP 0A0D
0A0D : --Z-IH 00|00 FEF1 4DCC | TST 0D,X [FF]


1バイトスキップが罠だった

この部分はソースコードでは以下のように書かれている。メモリが希少な時代のhackで、CHKNUMに飛ぶとC=0にしてCHKVALに行き、CHKSTRだとC=1になる。

C=0にして1バイトスキップするために、TXT $0D,X を使っている。頭いいけど、これはバグる。


0A0D  6D                CHKNUM: FCB     $6D             ; TST $nn,X clears carry and skips next byte
0A0E  0D                CHKSTR: SEC
0A0F  76 005C           CHKVAL: ROR     >VALTYP

大抵の場合はIXレジスタはソースコードかワーク領域のどこかを指しているので大きな問題にはならない。今回の問題が発覚したのは、浮動小数点演算を使ったからだ。

たまたま浮動小数点演算の途中結果に$FEF1という結果があって、それを作成するのにインデックスレジスタを使っていた。
(ちなみに、仮数部を+1するコード INCFAC です)

浮動小数点演算でたまたま$FEF1が使われて、それがたまたまデバッグ用のI/Oになったから発覚したわけ。

オリジナルのMIKBUGやAltair 680システムなら、この位置にはROMがあるから問題にならなかったのだろう。

それでも、ACIAやPIAのアドレスに抵触すれば問題になる(読み込むことで状態が変化するようなデバイスはアウト)。


1279 : C--NIH 81|00 00AF 4DC5 | LDX B1 [FEF0]
127B : C--NIH 81|00 FEF0 4DC5 | INX
127C : C--NIH 81|00 FEF1 4DC5 | STX B1 [FEF0]
127E : C--NIH 81|00 FEF1 4DC5 | BNE 1283 [0D]
1283 : C--NIH 81|00 FEF1 4DC5 | RTS


どのように修正したら良いか

TST $0D,X を使っているのは、2バイト命令で、C=0にする命令だからだ。1バイトスキップによく使われるCMPA # などはフラグの変化が違うからダメ。
(ちなみにMC6803やMC6809で追加されたBRNでもCフラグが変化しないのでダメです。よくもこんなコードを思いつくもんだ)

そもそも無条件にC=0にする命令自体がCLR/TST/CLCしかなくて、2バイトだと off,X を使うしかないので詰んでいる。

1バイト増やしていいなら、CLC / BITB #$0D を使えば良さそうである。

ソースが無い場合は、CLC / JMP CHKVAL のコードをどこかに置いて、JSR CHKNUM を書き換えれば良さそう。
1箇所だけBSR CHKNUMがあるが、ここではインデックスはOPTABLEの領域にあるので大丈夫なはず。

修正後の動作確認

無事に動作しました。実行時間は 325,112,977cycで、6800@1MHzなら5分25秒ほどです。


$ emu6800  6800 basic680.b

MEMORY SIZE? 32768
TERMINAL WIDTH? 80
WANT SIN-COS-TAN-ATN? Y

26329 BYTES FREE

MITS ALTAIR 680 BASIC VERSION 1.1 REV 3.2
COPYRIGHT 1976 BY MITS INC.

OK
5 POKE 65275,0
100 REM Time and General Accuracy Test Program
120 ILOOP=2500
130 A=1
140 FOR I=1 TO ILOOP-1
150   A = TAN(ATN(EXP(LOG(SQR(A*A))))) + 1
160 NEXT I
170 PRINT A
175 POKE 65275,0
180 END

RUN
CPU cycles = 386789
 2504.1 
CPU cycles = 325499766

OK

ちなみにBASIC MASTER の L2 BASICだと722秒(12分2秒、j68にて測定)。clockが754.56KHzなのを差し引いても遅い。浮動小数点演算が内部では6バイト(指数8bit、符号1bit、仮数39bit)で処理させているせいだろう。その分精度は高い。

4K BASICは32bit浮動小数点で仮数部23bitなので、IEEE 32bit floatとほぼ同じ精度だ。


リンク

BASICMASTER

Posted by ず@沖縄