標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第256回]
●テストプログラムをつくりました
今までいくつかの命令回路を実装するたびに、それなりのテストプログラムを作って、正しく期待通りの動作をするかどうかをテストしてきました。
しかし、[第253回]で説明しましたように、とんでもないミスがあとから発見されたりすると、なんだか心配になってきてしまいます。
このまま基板を発注してしまって、基板が出来てきてしまってから、またとんでもないミスが発見されたりしたら、思いっきり後悔することになります。
じつは以前から、全ての命令をテストできるようなテストプログラムを作って、テストをしてみるべきだ、とは思っていました。
しかし、こういうプログラムはやたら面倒なだけで、面白くもなんともないのですよね。
で、場当たり的、細切れ的なテストプログラムをちょこちょこ作って適当にテストしただけできてしまいました。
でも、もういけません。
覚悟を決めて、全命令をテストするプログラムの作成にかかりました。
しかし、全命令をテストする、といっても、必ずしも1本のプログラムで全ての命令をテストしなければいけない、というものでもありません。
命令毎にプログラムを分けて作ってもよいわけです。
その方が作りやすい、と考えました。
●まず手始めに、MOV r,r’のテストプログラムです
まず手始めに、MOV r,r’の全ての命令をテストするプログラムを作りました。
これはやたら種類が多い命令です。
A、B、C、D、E、H、Lの7つのレジスタ間でのデータ転送命令ですから、MOV A,Aのように無意味な命令(NOPの代用には使えます)も含めると、7×7=49通りの命令があります。
これを全部テストすることにしました。
いろいろな考え方があると思いますが、これからあとのほかの命令をテストするプログラムにもできるだけ応用ができるように、テストの方法を決めました。
その命令の実行前のレジスタやフラグの状態を全部スタックに保存し、そして命令の実行後にも、また同じようにフラグやレジスタの値を保存します。
実際のプログラムでは、スタックはレジスタの値を一時保存するために使われますが、今回はテスト目的ですから、PUSH命令でスタックに保存した値は、必要な場合を除いては、POP命令で戻さず、どんどんスタックに蓄えていくだけにします。
そして最後に、スタックの値を順に読み出して、あらかじめプログラムのなかにチェックデータとして書いておいた値と比較します。
一致しなかったものがでてきたら、そのスタック位置を記録します。
作成したテストプログラム(ソースプログラム)は、[第180回]で作った8080アセンブラで、マシン語の命令コードに翻訳します。
おお。[第180回]を読みますと、ちゃんと、全命令をテストするプログラムを作らなければ、と書いておりますね。そのために、8080アセンブラも作りました、ですと。
もう、すっかり忘れておりました。
8080アセンブラで作成されるマシン語命令ファイルはバイナリファイルですけれど、バイナリファイルのままではRS232Cで「つくるCPU」の試作基板に送信することができません。
バイナリファイルと同時に、マシン語コードをASCII文字コードに置き換えたファイルも作成するようにしましたので、それを送信します。
「つくるCPU」にはUSBをRS232Cに変換するICを搭載することにしましたので、USBケーブルでパソコンと接続して、送信します。
送信プログラムも、Borland C++コンパイラで作ったものを使います([第189回])。
では、まず、MOV命令のテストプログラムのリストです。
2009/6/12 7:8 TEST1.TXT
END=40EB
;;; MYCPU80 TEST1
;;; MVI r,MOV r,r'
;;; 09/06/09 6/11 6/12
;
ORG $4000
;
STCK=$5000
ERBF=$6000
;
4000 310050 LXI SP,STCK
4003 0E00 MVI C,00
4005 C5 PUSH B
4006 F1 POP PSW;CLEAR FLAG REGISTER
;
; MVI
4007 CDA540 CALL MVI
400A C5 PUSH B
400B D5 PUSH D
400C E5 PUSH H
400D F5 PUSH PSW
;MOV r,r
400E 40 MOV B,B
400F 49 MOV C,C
4010 52 MOV D,D
4011 5B MOV E,E
4012 64 MOV H,H
4013 6D MOV L,L
4014 7F MOV A,A
4015 C5 PUSH B
4016 D5 PUSH D
4017 E5 PUSH H
4018 F5 PUSH PSW
;MOV1
4019 41 MOV B,C
401A 4A MOV C,D
401B 53 MOV D,E
401C 5C MOV E,H
401D 65 MOV H,L
401E 6F MOV L,A
401F 78 MOV A,B;=C
4020 C5 PUSH B
4021 D5 PUSH D
4022 E5 PUSH H
4023 F5 PUSH PSW
;MOV2
4024 CDA540 CALL MVI
4027 7D MOV A,L
4028 6C MOV L,H
4029 63 MOV H,E
402A 5A MOV E,D
402B 51 MOV D,C
402C 48 MOV C,B
402D 47 MOV B,A;=L
402E C5 PUSH B
402F D5 PUSH D
4030 E5 PUSH H
4031 F5 PUSH PSW
;MOV3
4032 CDA540 CALL MVI
4035 68 MOV L,B
4036 42 MOV B,D
4037 54 MOV D,H
4038 67 MOV H,A
4039 79 MOV A,C
403A 4B MOV C,E
403B 5D MOV E,L;=B
403C C5 PUSH B
403D D5 PUSH D
403E E5 PUSH H
403F F5 PUSH PSW
;MOV4
4040 CDA540 CALL MVI
4043 5F MOV E,A
4044 7A MOV A,D
4045 55 MOV D,L
4046 69 MOV L,C
4047 4C MOV C,H
4048 60 MOV H,B
4049 43 MOV B,E;=A
404A C5 PUSH B
404B D5 PUSH D
404C E5 PUSH H
404D F5 PUSH PSW
;MOV5
404E CDA540 CALL MVI
4051 61 MOV H,C
4052 4D MOV C,L
4053 6A MOV L,D
4054 57 MOV D,A
4055 7B MOV A,E
4056 58 MOV E,B
4057 44 MOV B,H;=C
4058 C5 PUSH B
4059 D5 PUSH D
405A E5 PUSH H
405B F5 PUSH PSW
;MOV6
405C CDA540 CALL MVI
405F 50 MOV D,B
4060 45 MOV B,L
4061 6B MOV L,E
4062 59 MOV E,C
4063 4F MOV C,A
4064 7C MOV A,H
4065 62 MOV H,D;=B
4066 C5 PUSH B
4067 D5 PUSH D
4068 E5 PUSH H
4069 F5 PUSH PSW
;;;
; CHECK MVI
406A 310060 LXI SP,ERBF
406D 210050 LXI H,STCK
4070 2B DCX H
4071 11BB40 LXI D,TBL1END
4074 D5 PUSH D
4075 0608 MVI B,08
4077 1A LOOP0:LDAX D
4078 BE CMP M
4079 CA7D40 JZ LOOP0_2
407C E5 PUSH H;ERR
407D 2B LOOP0_2:DCX H
407E 1B DCX D
407F 05 DCR B
4080 C27740 JNZ LOOP0
4083 D1 POP D
;CHECK MOV
4084 0E07 MVI C,07
4086 0608 LOOP1:MVI B,08
4088 1A LOOP2:LDAX D
4089 BE CMP M
408A CA8E40 JZ LOOP2_2
408D E5 PUSH H;ERR
408E 2B LOOP2_2:DCX H
408F 1B DCX D
4090 05 DCR B
4091 C28840 JNZ LOOP2
4094 E5 PUSH H
4095 211000 LXI H,$0010
4098 19 DAD D
4099 EB XCHG
409A E1 POP H
409B 0D DCR C
409C C28640 JNZ LOOP1
409F E5 PUSH H
40A0 210000 LXI H,$0000
40A3 E5 PUSH H
40A4 76 HLT
;
;SUBROUTINE
40A5 0612 MVI:MVI B,12
40A7 0E34 MVI C,34
40A9 1656 MVI D,56
40AB 1E78 MVI E,78
40AD 269A MVI H,9A
40AF 2EBC MVI L,BC
40B1 3EDE MVI A,DE
40B3 C9 RET
;
;COMPARE DATA TABLE
;MVI
40B4 00 TBL1:DB 00;F
40B5 DE DB DE;A
40B6 BC DB BC;L
40B7 9A DB 9A;H
40B8 78 DB 78;E
40B9 56 DB 56;D
40BA 34 DB 34;C
40BB 12 TBL1END:DB 12;B
;MOV1
40BC 00 DB 00;F
40BD 34 DB 34;A
40BE DE DB DE;L
40BF BC DB BC;H
40C0 9A DB 9A;E
40C1 78 DB 78;D
40C2 56 DB 56;C
40C3 34 DB 34;B
;MOV2
40C4 00 DB 00;F
40C5 BC DB BC;A
40C6 9A DB 9A;L
40C7 78 DB 78;H
40C8 56 DB 56;E
40C9 34 DB 34;D
40CA 12 DB 12;C
40CB BC DB BC;B;
;MOV3
40CC 00 DB 00;F
40CD 34 DB 34;A
40CE 12 DB 12;L
40CF DE DB DE;H
40D0 12 DB 12;E
40D1 9A DB 9A;D
40D2 78 DB 78;C
40D3 56 DB 56;B
;MOV4
40D4 00 DB 00;F
40D5 56 DB 56;A
40D6 34 DB 34;L
40D7 12 DB 12;H
40D8 DE DB DE;E
40D9 BC DB BC;D
40DA 9A DB 9A;C
40DB DE DB DE;B;
;MOV5
40DC 00 DB 00;F
40DD 78 DB 78;A
40DE 56 DB 56;L
40DF 34 DB 34;H
40E0 12 DB 12;E
40E1 DE DB DE;D
40E2 BC DB BC;C
40E3 34 DB 34;B
;MOV6
40E4 00 DB 00;F
40E5 9A DB 9A;A
40E6 78 DB 78;L
40E7 12 DB 12;H
40E8 34 DB 34;E
40E9 12 DB 12;D
40EA DE DB DE;C
40EB BC DB BC;B;
;
ERBF =6000 LOOP0 =4077 LOOP0_2 =407D
LOOP1 =4086 LOOP2 =4088 LOOP2_2 =408E
MVI =40A5 STCK =5000 TBL1 =40B4
TBL1END =40BB
MOV r,r’命令のテストプログラムです、と書きましたが、MVIもついでにテストしてしまっていますね。
各レジスタに初期値を設定するためにMVI命令を使いますから、ついでにテストしてしまおう、と考えたようです。
もう、忘れてしまいました。
せっかくTK80が動くようになったのですから、プログラムのLOADから実行まで、TK80モニタのキー操作を利用することにします。
しかし最初は、テストプログラムそのものが正しく実行されているかどうかも確認したい、という考えから、プログラムの最後はHLTで終わるようにして、TK80モニタには戻らないようにしました。
比較データのテーブルは、後先をしっかり考えないで、いきなり作成してしまったために、比較する順序がちょっとちぐはぐな順番になってしまいました。
4084からのMOV命令の結果のチェックを行っている部分がちょいとややこしくなっているのはそのためです。
●テストプログラムを実行するところを写真に撮りました
[LOAD DATA]キーを押して、パソコンからUSB経由でテストプログラムをLOADしたところです。
[RUN]キーを押すと、あっという間に実行は完了し、HLTで停止しました。
リセットしてTK80モニタに戻ったあと、結果の確認です。
もしエラーがある場合には、そのエラーが記録されているスタックアドレス(4FFFから前)が、5FFFから前に順に記録されます。
つまりテスト結果の値を保存するためと、比較結果を保存するためとに、別々に2つのスタックを使用しています。
比較結果が完了した最後には、テスト結果の値を格納しているスタックアドレス(4XXX)のスタックエンドアドレスを5XXXからのスタックの最後に記録し、さらにその最後には0000を記録して終わります。
うーん。なんだか、ややこしいですねぇ。
写真を見ますと、5FFF、5FFEには4FBFが記録されていることがわかります。
[5][F][F][F][ADRSSET][READ DECR]と操作したところです。
続けて[READ DECR]を2回押しました。
0000が表示されました。
ということは、この前の値、4FBFがデータエンドで、そして結果の値とテーブルデータを比較した結果、不一致はなかったことがわかります。
テストプログラムを実行して、結果の値の比較まで行って、あらかじめ用意した比較用の値と全て一致したわけですから、もうこれでOKなのですけれど、せっかく命令を実際に実行した結果の値がスタックに記録されたことですし、TK80モニタの[STORE DATA]の機能も使えるようにしてあるはずですから、それを利用して、スタックの中身をパソコンに送ってファイルとして保存するようにしてみましょう。
[STORE DATA]のために、送信開始アドレスと終了アドレスをセットしたところです。
実行結果の値のスタックエンドは4FBFでしたから、実際に値が記録されているのは、その1つ前の4FC0から4FFFです。
このあと、[STORE DATA]キーを押せば、USB経由でパソコンにデータが送信されますが、その前にパソコン側で受信プログラムを起動させておく必要があります。
●USB(RS232C)の受信プログラムもBorland C++コンパイラで作ってしまいました
送信プログラムの逆の動作をする、RS232C受信プログラムも作ってしまいました。
R232.exeです。
R232.exeを実行して、「つくるCPU」からのデータを受信したところの様子です。
TEST1DT.HTXというファイル名で保存しています。
受信の様子をモニタできるように、受信データをそのまま(ASCIIコード)表示させています。
その下は受信完了後のTEST1DT.HTXをTYPEコマンドで表示させています。
TEST1DT.HTXはメモ帳(notepad)などで開くこともできますが、受信直後に同じDOSプロンプトの中ですぐに確認するにはTYPEコマンドに勝るものはありません。
いまどきほとんど忘れ去られてしまったみたいですけれど、DOSコマンドというのは、なかなかに便利なものなのですよ。
それはともかく。
いかが、でしょうか。
[STORE DATA]も使える、となると、ぐっと機能が充実したように思えませんでしょうか?
あ。R232.exeについても詳細をお伝えいたしましょうかねぇ。
でも、それはまた、後日。
2009.6.22upload
前へ
次へ
ホームページトップへ戻る