標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第544回]
●STEP値のセット(FOR NEXTのデバッグの続きです)
前回までのFOR文のデバッグで、TOの値をFTOに格納するところまで進みました。
次はSTEPの値です。
STEP値はFOR変数の値の増分ですが、今回のテストプログラムではSTEPは省略しています。
STEPを省略したときは、STEP値は1になります。
FSTPのアドレスはF0DF〜F0E2です。
前回のTOの値のときと同じ要領で、まずF0DF〜F0E2にFFを書き込んだあと、25D5にブレイクポイントを設定してから、rtコマンドを実行しました。
アドレス25C2のCALL GTONEは、実数型の1を演算レジスタFACCに読み込むためのサブルーチンコールです。
そしてそのあとのCALL APKはFSTP(F0DF〜F0E2)に実数型の1を格納するために実行しています。
このあとはブレイク後にアドレスF0DF〜F0E2の値を確認して、実数型の1がそこにちゃんと書き込まれていることを確認する、つもりだったのですが…。
●やっとバグに気付きました
ここまできてやっとバグに気付いたようです。
あ。テストプログラムを実行してもPRINT文による画面表示が全く行われない、という異常動作の原因について、ではありません。
ユーザープログラムが格納されるアドレスが、本来ならば8004からでなければならないのに、いつのまにか4004からになってしまっていた([第541回])、ということにやっと気が付きました。
4004〜はBASICシステムプログラムのアドレスです。
当然そこの部分のプログラムは破壊されてしまっています。
うわあ。えりゃあこっちゃあ。
というわけで、FOR NEXTのデバッグなど、もうどこかに吹っ飛んでしまいました。
このバグは急遽プログラムを確認して修正しましたし、プログラムを4004〜に誤書き込みしてしまったために破壊されてしまったBASICプログラムも元通りに修復いたしました。
しかしながら、一時はパニック、パニックでしたから、FSTP(F0DF〜F0E2)の値を確認することなど、もうすっかり忘れてしまいました。
ええ。でもこのテストプログラムはブレイクポイントを設定してデバッグを始める前にも何回か実行していますから、F0DF〜F0E2には、もともとすでに実数型の1が書き込まれてしまっています。
この部分にはバグがないことはわかっていますから、わざわざこの部分のデバッグを再現して、F0DF〜F0E2に実数型の1が書き込まれているところをあらためて確認する、というのもなんだかなあ、と思います。
ですから、あらためてデバッグをやり直すことはいたしません。
ここの部分につきましては、FFを書き込む前の値が実数型の1になっている、ところを見ていただくということにいたします。
上の画面で、cm f0dfでFFを書き込む前の値をみますと、
F0DF 00
F0E0 00
F0E1 40
F0E2 01
になっています。
これをデータの上位バイト〜下位バイトの順に並び替えます。
01 40 00 00
になります。
最上位バイトは指数部です。ここは01ですから、21つまり×2です。
仮数部の下位2バイトは00ですから省略して上位1バイトのみを2進数で表現します。
01000000
です。
前回と同じやり方で、この値が1であることを確認してみます。
と言うほどのことも無くて、これは簡単です。
小数点を表示させてみると、
0.1000000
になります。前回も書きましたが、10進数の0.1ではなくて、2進数に小数点位置を仮に表示させているだけです。
指数部が1ですから
0.1000000 ×2 です。
×2をなくすために、仮数部を左に1ビットシフトさせます(2進数を左に1ビットシフトすると、もとの数の2倍になります)。
すると
1.0000000
になります。
確かに 01 40 00 00 が実数型の1であることがわかりました。
●NEXT命令のデバッグ
テストプログラムをアドレス8004に入れ直して、デバッグの続きを再開いたしました。
NEXT命令のデバッグを大急ぎでやります。
テストプログラムが4004〜のBASICシステムのアドレスに書かれてしまっていて、BASICプログラムを破壊してしまっていたことで、かなり泡を食ってしまったらしく、NEXT命令の部分のリストを表示している画面コピーがありません。
それでは何をやっているのかさっぱりわかりませんから、下にNEXT命令の部分のアセンブルリストを表示いたします。
かなり長いプログラムです。
上の画面では、最初のブレイクポイントを設定するところがスクロールして消えてしまっています。
しかしブレイク後のレジスタダンプリストのPC(プログラムカウンタ)にはブレイクアドレスが表示されますから、それを見ることで、最初のブレイクアドレスを知ることができます。
最初のブレイクアドレスは25D5です。
ここはさきほどのSTEPの値を格納し終わったあとのアドレスです(今回の一番最初の画面コピーを参照してください)。
JP STENDは命令行の最後の処理へのジャンプ命令です。
これでFOR文の解読実行は終了です。
次のブレイクアドレスは2600です。
これ以後は上の画面コピーと下のプログラムリストを共に参照してください。
アドレス2600はNEXT命令の最初のところです。
NEXT命令の次に書かれている変数の型を確認しています。
F0ですから実数型です。
まっすぐ下の処理に進みます。
次のブレイクアドレスは260Fです。
その直前のアドレス260CのCALL HENSBはNEXT変数(FOR変数と一致)のアドレスをHLレジスタに入れるためのサブルーチンCALLです。
HLレジスタには変数AのアドレスDFFCが入っています。
つぎのブレイクアドレスは2619です。
この直前に、さきほどのCALL HENSBで得たNEXT変数のアドレスを EX DE,HL命令で、HLからDEに入れ替えています。
そうしておいて、FOR文で保存したFOR変数のアドレスをHLレジスタに読み出しています。
ブレイクした結果、DEレジスタもHLレジスタもDFFCになっています。
ここが不一致の場合は、FOR文とNEXT文に食い違いがあると考えられますから、エラーになります。
次のブレイクアドレスは2625です。
この直前にAレジスタの値がF0であるかどうかを確認しています。
Aレジスタの値はさらにその前のEX AF,AF’命令で裏レジスタに置かれていた値を表に置き換えたものです。
この時より前の各ブレイク時のレジスタダンプリストのAとA’の値を確認してみてください。
サブルーチンHENSBは、変数アドレスをHLレジスタに入れると共に、その後の変数型の参照に備えて、変数型コード(今回のテストプログラムの例では実数型を示すF0)を裏レジスタA’に保存します。
Aレジスタの値(A’に保存されていた値)はF0ですから、このあとは実数型のNEXT処理が行われます。
NXTR(アドレス264E)にジャンプします。
;;;NEXT 25FF 1A NEXT:LD A,(DE) 2600 E6FB AND FB 2602 FEF0 CP F0 2604 DAEF31 JP C ER12 2607 FEF3 CP F3 2609 D2EF31 JP NC,ER12 260C CD782D CALL HENSB 260F 2275F0 LD (NEXTR),HL 2612 D5 NXT1:PUSH DE 2613 EB EX DE,HL 2614 2A61F0 LD HL,(FORVL) 2617 7C LD A,H 2618 B5 OR L 2619 CAF431 JP Z,ER13 261C ED52 SBC HL,DE 261E C2F931 JP NZ,ER14 2621 EB EX DE,HL 2622 08 EX AF,AF' 2623 FEF0 CP F0 2625 CA4E26 JP Z,NXTR 2628 FEF1 CP F1 262A CA9226 JP Z,NXTDD 262D 5E LD E,(HL) 262E 23 INC HL 262F 56 LD D,(HL) 2630 2ADFF0 LD HL,(FSTP) 2633 E5 PUSH HL 2634 19 ADD HL,DE 2635 EB EX DE,HL 2636 2A61F0 LD HL,(FORVL) 2639 73 LD (HL),E 263A 23 INC HL 263B 72 LD (HL),D 263C 2AF1F0 LD HL,(FTO) 263F F1 POP AF 2640 B7 OR A 2641 F24526 JP P,NXT22 2644 EB EX DE,HL 2645 ED52 NXT22:SBC HL,DE 2647 D1 POP DE 2648 FA8C26 JP M,NXT5 264B C37F26 JP NXT4 264E E5 NXTR:PUSH HL 264F 21DFF0 LD HL,FSTP 2652 CD043E CALL AUPK 2655 E1 POP HL 2656 3AFFF1 LD A,(FA8) 2659 F5 PUSH AF 265A CD073E CALL BUPK 265D CDD43D CALL FADD2 2660 2A61F0 LD HL,(FORVL) 2663 CD0A3E CALL APK 2666 21F1F0 LD HL,FTO 2669 CD073E CALL BUPK 266C 08 EX AF,AF' 266D F1 POP AF 266E B7 OR A 266F FA7726 JP M,NEXT1 2672 08 EX AF,AF' 2673 CDCE3D CALL XAB 2676 08 EX AF,AF' 2677 08 NEXT1:EX AF,AF' 2678 CDF53D CALL FCMP2 267B D1 POP DE 267C FA8C26 JP M,NXT5 267F 2A5DF0 NXT4:LD HL,(FORLR) 2682 2271F0 LD (PADRS),HL 2685 ED5B5FF0 LD DE,(FORBR) 2689 C3C52F JP STEND 268C CD132F NXT5:CALL FORS 268F C3C52F JP STEND 2692 C3936D NXTDD:JP NXTD
NEXTR(アドレス264E以後)では、FSTPの値(今回のテストプログラムでは1)を演算レジスタFACCに入れます(アドレス2652のCALL AUPK)。次に先ほどHLレジスタに入れられた変数Aのデータアドレスを引用して、その値を演算レジスタFBCCに入れます(アドレス265AのCALL BUPK)。
そしてそのあとFACCとFBCCを加算します(アドレス265DのCALL FADD2)。
●ついにバグを見つけました!
どうもこのあたりが怪しい…。
で、よーく確認をしてみましたら…。
265D CALL FADD2のアドレス(3DD4)がおかしいことに気が付きました。
このアドレスはBASICプログラムの先頭で、下のように定義されていました。
;;; ACLR=$3DC8 TAZR=$3DCB XAB=$3DCE FADD2=$3DD4 FNORZ=$3DDD FMUL2=$3DE9
ここが間違っていたのです。
正しくは、下のリストのように、FADD2=$3DD7であるべきでした。
プログラムのアドレスを移動するときに、書き間違えてしまったようです。
このために、実数型の2数の加算がまともに行われていませんでした。
;;; ACLR=$3DC8 TAZR=$3DCB XAB=$3DCE FADD2=$3DD7 FNORZ=$3DDD FMUL2=$3DE9
このことが原因で、加算がまともに行われていなかったことがはっきりしました。
[第541回]で受信バッファに溜まっていても、それが画面に表示されない場合がある点を修正しましたから、それまで全く何も表示しないでハングアップしているようになっていたテストプログラムが、大量の表示データを吐き出すようになりました。
下のリストは、FADD2サブルーチンのアドレスを修正する前に実行したものです。
>list 10 FOR A=0 TO 10 20 NEXT A >15print a, >run 0 1.06252 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024 1.00024
Aレジスタの+1加算がまともに行われないために無限ループになっていたのでした。
FOR NEXTではなくて、もっとシンプルな加算命令を実行してバグの影響を確認してみました。
A+Bの結果は1にならなくてはいけないのですが、FADD2アドレスが間違っていたために、まともな加算が行われなくて、0.500244などというでたらめな値になっています。
バグを修正してFADD2のアドレスを正しいアドレスに直した結果、計算が正しく行われるようになりました。
上の画面はちょっと見るとおかしいように見えるかもしれませんが、これは以前にも説明しましたスクリーンエディタを使って、プログラムを変更して再実行しているのです。
最初のlistコマンドで表示されたプログラムは
10 A=0
20 B=1
です。
それをそのすぐ下のrunコマンドで実行しています。
実行したあとで、カーソルを上のプログラムリスト表示の10 A=0の後ろへ移動して、0の後ろに .123を追加し、その後、その下の20 B=1の後ろにカーソルを移動して、 .456を追加したのです。
あらためて、FOR NEXT文を実行してみました。
正しく実行されました。
やっとのことで、これにて一件落着、です(やれやれ)。
2010.7.6upload
前へ
次へ
ホームページトップへ戻る