標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第559回]
●電子オルガンプログラム
前回は8080アセンブラの実行例として、電子オルガンプログラムをアセンブルしてみました。
ND80ZVのキーを押すとそのキーに割り当てられた高さの音がスピーカーから出力される、というプログラムです。
このプログラムは、以前にどこかで紹介したことがあるような気がして捜してみましたら、[第363回]にありました。
MYCPU80の操作説明書の内容紹介のところです。
キーと音の高さの対応図もありますので、そちらのページも参照してみてください。
プログラムリストもそこに掲載してあります。
前回紹介しました電子オルガンプログラムとほとんど同じものですが、CPUクロックが異なっているために、その部分は違っています。
MYCPU80のCPUクロックは2MHzで、命令の実行クロック数もオリジナルの8080とは異なっています。
今回のND80ZVのCPUクロックは6MHzですし、CPUはZ80ですから、やはり命令によってクロック数は8080と違っているものもあります。
ただ今回紹介しました電子オルガンプログラムは、初心者の方の参考にもなるように、と考えて、ソースプログラムは、命令数の少ない8080用のプログラムとして、8080ニーモニック(インテルニーモニック)で書きました。
Z80は8080の命令をマシン語レベルでは8080と全く同じように実行しますから、ソースプログラムの命令を8080のニーモニックで書いても全く問題はありません。
あ。もちろん8080ニーモニックで書いたソースプログラムは8080アセンブラでなければ、マシン語コードに翻訳することはできません。
同様にZ80ニーモニック(ザイログニーモニック)で書いたソースプログラムはZ80アセンブラでなければ、マシン語に翻訳することはできません。
しかしどちらの手続きによっても、アセンブルされてマシン語に翻訳された結果は同じものになります。
もっともZ80にはあるけれども8080にはない命令もたくさんありますから、そのような命令はZ80アセンブラでなければマシン語に翻訳することはできません。
ND80ZVはマシン語やアセンブラを勉強中の方にもぜひ使っていただきたい、と思っております。
そう思って、あらためて[第363回]も読み直してみたのですけれど、プログラムリストと、プログラムの動作の説明がしてあるだけで、プログラムそのものの説明はないようです。
まあ。めちゃめちゃ忙しかったんですものねえ。
でも、せっかくサンプルとして電子オルガンのプログラムリストをお見せしたことですから、この機会にプログラムそのものの説明をしてみたいと思います。
とっても簡単なプログラムですから、どなたもご理解いただけることと思います。
あ。
そういえば、突然に思い出しました。
●8080アセンブラ注記
前回は、そのもうひとつ前の回でND80ZVとDOS/VパソコンをUSBで接続して、DOS窓上のリモートプログラムを実行して、ND80ZVのキー入力の代わりに、パソコンのキーから入力して、ND80ZVをリモート操作する、という説明をしたあとで、突然8080アセンブラの説明を割り込んではじめてしまいました。
今回もまだその続きで、またもや脱線したまま走っております。
リモートプログラムの実行も、8080アセンブラの実行も、同じDOS窓(DOSプロンプト)の中で行いますし、その前の回のリモートプログラムの説明の次にいきなり8080アセンブラの話になってしまったものですから、ひょっとすると、お読みいただいている方のなかには、8080アセンブラもUSBで接続したND80ZVが実行しているのではないか、と誤解された方もみえるかもしれません。
同じDOSプロンプトで実行しますけれど、8080アセンブラはDOS/Vパソコンの上だけで動作します。
8080アセンブラは8086の命令で書かれたプログラムです(8080の命令ではありません)。
うーん。ややこしーい。
8080アセンブラは、その実行によって、8080のマシン語コードファイルを生成しますが、その生成の過程では、ND80ZVの接続を全く必要としません。
8080アセンブラを使うときには、ND80ZVをUSBから切り離しておいても全く構いません。
●電子オルガンプログラムの説明
さて、では前回もお見せしましたsound6.lstを少しずつ切り分けながら説明をしていくことにいたします。
2010/7/20 21:25 sound6.txt END=8056 ;;;SOUND6.TXT ;;; sound for ND80Z3 clock=6MHz ;;; 10/3/18 10/6/15 7/20 ;;; ORG $8000 ; KEY=$0247 ; 8000 CD4702 SND:CALL KEY 8003 3C INR A 8004 CA0080 JZ SND 8007 3D DCR A 8008 CD0E80 CALL SNDSB 800B C30080 JMP SNDプログラムの本体、メインプログラムはこれだけです。
では、キーが押されているときは、といいますと、JZ SNDをスルーして、その下の命令を実行します。
DCR Aです。
FFコードをチェックするために、Aレジスタの値を一律に+1してしまいましたから、ここでもとの値に戻しているのです。
DCR AはAレジスタの値を−1します。
そうしておいて、サブルーチンSNDSBをCALLします。
SNDSBが電子オルガンプログラムのサウンド出力部分です。
SNDSBはAレジスタの値に対応した(つまりキーに対応した)高さの音を一定期間出力します。
その後再びキー入力を確認するため、8000に戻ります。
ではSNDSBの中身を見ていくことに致します。
; 800E F5 SNDSB:PUSH PSW 800F E5 PUSH H 8010 D5 PUSH D 8011 C5 PUSH B
SNDSBではA、HL、DE、BCの全てのレジスタを使いますから、最初にスタックに退避しておきます。
PUSHはレジスタをスタックに退避する命令です。
8080アセンブラのニーモニックでは、A、B、D、Hレジスタしか退避されないように思ってしまいますが、スタックへの退避は、AF(Aレジスタとフラグレジスタ)、BC、DE、HLの各ペアレジスタ単位で行われます。
ですからたとえばPUSH Hは、HLレジスタをスタックに退避します。
その点はZ80ニーモニックの方が直感的に把握できます。
Z80ニーモニックでは、PUSH HLと書きます。
ところで、実は、この電子オルガンプログラムでは、SNDSBでレジスタを退避させておく必要はありません。
さきほどのメインルーチンを見てみますと、SNDSBを実行したあとは、また8000のCALL KEYに戻っていますから、どのレジスタの値も保存しておく必要はないからです。
それではなぜ?
ということになるのですが、それはこのSNDSBを電子オルガンプログラム以外のプログラムでも利用する、という場合を考えたからです。
Aレジスタに音の高さを示すコードを入れて、SNDSBをCALLすることで、その高さの音をわずかな時間ですが出力することができます。
電子オルガンのプログラムでは、どのレジスタの値も保存しておく必要はなかったのですけれど、別のプログラムでは、SNDSBをCALLする前と後で、レジスタの値が変化してしまっては困る、ということも十分考えられます。
ここでのPUSH命令はそのためにあります。
なお、PUSHしたレジスタは、最後に、PUSHしたときと逆の順番でPOP命令を使って、もとの値に戻しておく必要があります。
8012 213F80 LXI H,SNDTBL 8015 85 ADD L 8016 6F MOV L,A 8017 46 MOV B,M 8018 1E1A MVI E,1A
LXI H,SNDTBLで、プログラムの終わりにあるサウンドテーブルの先頭のアドレスをHLレジスタに入れています。
サウンドテーブルの中身は音の高さを決定するデータです。
ADD L と次のMOV L,A でHLレジスタの値(つまりサウントテーブルのアドレス)がAレジスタの値だけ先に進みます。
ここで注意が必要なのは、このときのサウンドテーブルの上位アドレスが全部同じ(H=80)でなければならない、ということです。
マシン語のプログラムはこういう点に注意しなければならないときがあります。
もしもサウンドテーブルが、H=80とH=81にまたがっていた場合には、このプログラムの書き方では正しく実行されません。
さて、MOV B,Mで、選択したサウンドテーブルの値がBレジスタに入れられます。
その次の、MVI E,1Aは繰り返し回数です。
Eレジスタに1A(=26)が入れられます。
801A 50 SNDS1:MOV D,B 801B 3EEF MVI A,EF;sp out=H,DMAoff 801D D398 OUT 98 801F E5 SNDS2:PUSH H;11--------- 8020 E5 PUSH H;11 | 11+11+10+10+4+4+10=60 8021 E1 POP H;10 | 60/6=10 8022 E1 POP H;10 | 8023 00 NOP;4; | 10microsec 8024 15 DCR D;4 | 8025 C21F80 JNZ SNDS2;10----
いよいよ音を出力するところです。
ここでは、サウンドテーブルの値(Bレジスタに入っている)をダウンカウンタとして使い、一定の長さの時間を作り出します。
しかしBレジスタはこの後のところでも使いますから、ここで壊してしまわないように、MOV D,B命令で、Bレジスタの代わりにDレジスタをダウンカウンタとして使うためにBレジスタの値をDレジスタにコピーしています。
MOVはmoveですが、値がBレジスタからDレジスタに移動するのではなくて、Bレジスタの値がDレジスタにコピーされます。
I/Oアドレス98のビット5をHにすると、スピーカーへの出力がHになります。
と同時に音の高さを正確にするため、LED表示のためのDMAを禁止します。
I/Oアドレス98のビット4をLにするとDMAが禁止されます。
その次が、サウンドルーチンの中心になる部分です。
PUSH HからNOPまでの命令は、単に時間をかせぐためだけのダミー命令です。
次のDCR DとJNZ SNDS2で、この部分がサウンドテーブルの値の回数繰り返し実行されます。
PUSH HからDCR DとJNZ SNDS2までの部分を1回実行するのにかかる時間は、各命令の実行クロック数の合計から求めることができます。
合計は60クロックです。
ND80ZVのCPUクロックは6MHzですから、1クロックの時間は、1/6μsecです。
ですからこの部分を1回実行するのにかかる時間は、60/6=10μsecです。
ということは、Dレジスタの値(=Bレジスタの値)、つまりサウンドテーブルの値×10μsecの長さの時間がここで消費されることになります。
その時間、スピーカーへの出力がHになっています。
8028 50 MOV D,B 8029 3ECF MVI A,CF;sp out=L,DMAoff 802B D398 OUT 98 802D E5 SNDS3:PUSH H;11--------- 802E E5 PUSH H;11 | 11+11+10+10+4+4+10=60 802F E1 POP H;10 | 60/6=10 8030 E1 POP H;10 | 8031 00 NOP;4; | 10microsec 8032 15 DCR D;4 | 8033 C22D80 JNZ SNDS3;10----
ここも上と全く同じルーチンのようですが、繰り返しに入る前に、I/Oアドレス98にCFをOUTしています。
ビット5がLですから、ここでスピーカー出力がLになります。
つまりさきほどと同じ長さの時間、こんどはスピーカーへの出力がLになります。
上の部分と合わせると、同じ期間のHとLのパルスが出力されることになります。
8036 1D DCR E 8037 C21A80 JNZ SNDS1
そのH、L出力をEレジスタの値の回数1A(=26回)繰り返します。
この26回に深い意味はありません。
ここが余り短いと、キー入力を見に行く間、音が途切れる期間が無視できなくなります。
また余り長いと、キーを押しても、すぐに反応してくれません。
803A C1 POP B 803B D1 POP D 803C E1 POP H 803D F1 POP PSW 803E C9 RET
最後にスタックに退避しておいたレジスタの値をPOP命令でもとに戻してからメインルーチンにリターンします。
ここから下がサウンドテーブルです。
うーん。
これだけではわかりにくいですねえ。
; ; SOUND TABLE 803F 7F SNDTBL:DB 7F;so4 8040 77 DB 77;so#4 8041 71 DB 71;ra4 8042 6A DB 6A;ra#4 8043 5F DB 5F;do5 8044 59 DB 59;do#5 8045 54 DB 54;re5 8046 4F DB 4F;re#5 8047 47 DB 47;fa5 8048 43 DB 43;fa#5 8049 3F DB 3F;so5 804A 3B DB 3B;so#5 804B 35 DB 35;ra#5 804C 32 DB 32;si5 804D 2F DB 2F;do6 804E 2C DB 2C;do#6 804F 25 DB 25;mi6 8050 27 DB 27;re#6 8051 2A DB 2A;re6 8052 4B DB 4B;mi5 8053 38 DB 38;ra5 8054 64 DB 64;si4 8055 23 DB 23;fa6 8056 21 DB 21;fa#6 ;END KEY =0247 SND =8000 SNDS1 =801A SNDS2 =801F SNDS3 =802D SNDSB =800E SNDTBL =803F
ああ。
本日は時間がなくなってしまいましたので、ここの部分の詳細はまた次回にすることにいたします。
本日は、参考までに、アドレス8053のラ5についてのみ、簡単に説明を致します。
キーコード14に対応する音のデータです。
キーコード14は[READ INC]キーです。
ラ5はオクターブ5のラの音です。
オクターブ5のラの音の周波数は、880Hzです。
ということは、その逆数1/880≒0.001136secが周期になります。
1136μsecです。
その1/2の568μsecが、HまたはLのパルスの長さ、ということになります。
そこでアドレス8053の値を見ていただきますと、38になっています。10進数に直すと56です。
さきほどのパルス出力のところで、サウンドテーブルの長さ×10μsecがHまたはLのパルスの長さになります、という説明をしました。
ということは、56×10=560μsです。
880Hzから算出した値568μsecよりも8μsec短いですけれど、この部分は、クロックの計算からは落ちているスピーカーへの出力のH、Lを切り換えるためのOUT命令や、MOV D,B命令、DEC E、JNZ命令などの時間を考慮して、理論値を超えない値にしてあります。
スピーカーへのラ5の音(880Hz)の出力波形です。
2010.7.21upload
前へ
次へ
ホームページトップへ戻る