EtchedPixels/EmulatorKit でMIKBUGを動かしてみた(5)Altair 680 4K BASICのBUG?
emu6800にmikbug互換のルーチンを入れて Altair 4K BASICのテストを行ってみた。すると、なぜかSAVAGEベンチマークテストが途中で止まる。なんだこれ?
私が使っているのは、Vintage Computer Programming に投稿されたソースリストで、6502版を参考に解析されたものだ。
- zu2/emu6800-mikbug: emu6800 for mikbug
- Altair 680b BASIC merged with 6502 source | Vintage Computer Federation Forums
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とほぼ同じ精度だ。







ディスカッション
コメント一覧
まだ、コメントがありません