標準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ですから、2つまり×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

前へ
次へ
ホームページトップへ戻る