標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第657回]
●ルート計算プログラム(TK−80応用プログラム)(その4)
前回はTK−80用に書かれたルート計算プログラムのサブルーチンHIKUSUADD2の中で使われている
RLA
AND 01
という命令について、「実に巧妙なテクニックです」と書きました。
実は昨晩そのように書きまして、ホームページにUPしてから、帰宅するため夜道を歩いていましたら、
「あれま、私としたことが」
思い違いをしてしまったことに気が付きました。
巧妙なテクニックではありませんでした。
そのようなプログラムになったのは、おそらくこのプログラムを書いた方が思い違いをされたためだと思います。
おかしなことをやってるなあ、と思ったものですから、
「それにはきっとそれなりの訳があるに違いない」
とまあそのように考えて、それで、つい乗せられてしまいました。
HIKUSUADD2サブルーチンのプログラムリストです。
; ; HIKUSU=HIKUSU+2 ; 8093 0603 HIKUSUADD2:LD B,03 8095 21B382 LD HL,HIKUSU78 8098 7E LD A,(HL) 8099 C602 ADD A,02 809B 27 DAA 809C 77 LD (HL),A 809D 17 HIKUSUADD2_2:RLA 809E E601 AND 01 80A0 2B DEC HL 80A1 86 ADD A,(HL) 80A2 27 DAA 80A3 77 LD (HL),A 80A4 05 DEC B 80A5 C29D80 JP NZ,HIKUSUADD2_2 80A8 C9 RET
アドレス809D以下の部分は、その前の、アドレス8099の
ADD A,02
DAA
およびアドレス80A1の
ADD A,(HL)
DAA
の計算の結果、上位桁へのキャリーが発生した場合にその繰り上げを計算するためのパートです。
それなら、普通は
; ; HIKUSU=HIKUSU+2 ; 8093 0603 HIKUSUADD2:LD B,03 8095 21B382 LD HL,HIKUSU78 8098 7E LD A,(HL) 8099 C602 ADD A,02 809B 27 DAA 809C 77 LD (HL),A 809D 2B HIKUSUADD2_2:DEC HL 809E 7E LD A,(HL) 809F CE00 ADC A,00 80A1 27 DAA 80A2 77 LD (HL),A 80A3 05 DEC B 80A4 C29D80 JP NZ,HIKUSUADD2_2 80A7 C9 RET
というように書けばよいはずです。
じつは、そのように書いてから、たった今気がついたのですが、このルート計算プログラムには同じような計算をしているところが他にもあって、そこではちゃんとごく普通のプログラムになっています。
; ;TISU=TISU-HIKUSU ; 8070 21B382 HIKIZAN:LD HL,HIKUSU78 8073 11AF82 LD DE,TISU78 8076 0604 LD B,04 8078 AF XOR A 8079 1A HIKIZAN_2:LD A,(DE) 807A 9E SBC A,(HL) 807B 27 DAA 807C 12 LD (DE),A 807D 2B DEC HL 807E 1B DEC DE 807F 05 DEC B 8080 C27980 JP NZ,HIKIZAN_2 8083 C9 RET
むむむ。
これは一体どういうことなのでしょう。
はて、このように普通に書いてあるところもあるということになりますと、先ほどのHIKUSUADD2サブルーチンの書き方はいよいよもって理解しがたいことになります。
が。
多分、DAAで発生したキャリーフラグが、そのあとで実行されるDEC Bによって影響を受けてしまうのではないかと、つい思い違いをしてしまったのではないか、としか思えません。
RLA命令を実行すると、Aレジスタの値がキャリーフラグを含めて左にローテイトします。
Aレジスタのビット7がキャリーフラグに入って、キャリーフラグの値がAレジスタのビット0に入れられます。
その後で、AND 01を実行すると、キャリーフラグが立っていたときにはAレジスタの値が01になり、キャリーフラグが立っていなかったときには、Aレジスタの値は00になります。
ですからその後で
DEC HL
ADD A,(HL)
とすることで、確かに下位桁からの繰り上げが上位桁に伝わります。
しかし。
ここは、わざわざそんなことをしなくても、普通に書けばいいのです。
8080、Z80では、8ビットレジスタA〜Lに対するDEC、INC命令は、キャリーフラグだけは変化しないのです。
[出典]Intel社「8080 Microcomputer Systems User’s Manual September 1975」
8080のManualですから、INR、DCR命令になっていますが、8080でもZ80でも命令としての動作は同じです。
Note:のところにちゃんと書いてあります。
All condition flags except CY are affected.
です。
●HIKUSUADD2サブルーチンを直しました
ということで、HIKUSUADD2サブルーチンを直しました。
変更後のソースプログラムです。
;;; root program for ND80Z3 ;;; for ND80Z monitor ; 2010/11/08 11/09 11/10 ; ORG $8000 ; SEGCG=$05C0 KEYIN=$0616 ; LEDDP1=$FFF4 LEDDP3=$FFF6 ; LED1=$FFF8 LED2=$FFF9 LED3=$FFFA LED4=$FFFB LED5=$FFFC ; TISU12=$82AC TISU78=$82AF HIKUSU78=$82B3 KOTAE12=$82B4 KOTAE34=$82B5 ; START:LD B,0A LD HL,TISU12 XOR A ; ;TISU CLEAR ; TISUCLR:LD (HL),A INC HL DEC B JP NZ,TISUCLR ; ;TISU KEYIN ; CALL KEYIN RLCA RLCA RLCA RLCA LD HL,TISU12 LD (HL),A PUSH HL CALL KEYIN POP HL ADD A,(HL) LD (HL),A LD A,(HL) LD DE,LEDDP1 LD (DE),A ; ;KEISAN START ; LD A,01 LD (HIKUSU78),A KEISAN_LOOP:CALL HIKIZAN JP C,KEISAN_END CALL KOTAE_ADD1 CALL HIKUSUADD2 JP KEISAN_LOOP ; ;KEKKA NO HYOJI ; KEISAN_END:LD HL,KOTAE12 LD B,02 LD DE,LEDDP3 HYOJI_LOOP:LD A,(HL) LD (DE),A INC HL INC DE DEC B JP NZ,HYOJI_LOOP CALL SEGCG ; ;LED HYOJI O HENSYU SURU ; LD HL,LED3 LD DE,LED2 LD A,(DE) LD (HL),A LD HL,LED2 LD DE,LED1 LD A,(DE) LD (HL),A LD HL,LED4 LD A,48;"=" LD (HL),A LD HL,LED1 LD A,0E;"root" LD (HL),A LD HL,LED5 LD A,80;"." OR (HL) LD (HL),A JP START ; ;subroutine ; ; ;TISU=TISU-HIKUSU ; HIKIZAN:LD HL,HIKUSU78 LD DE,TISU78 LD B,04 XOR A HIKIZAN_2:LD A,(DE) SBC A,(HL) DAA LD (DE),A DEC HL DEC DE DEC B JP NZ,HIKIZAN_2 RET ; ;KOTAE_ADD1 ; KOTAE_ADD1:LD HL,KOTAE34 LD A,(HL) ADD A,01 DAA LD (HL),A DEC HL LD A,(HL) ADC A,00 DAA LD (HL),A RET ; ; HIKUSU=HIKUSU+2 ; HIKUSUADD2:LD B,03 LD HL,HIKUSU78 LD A,(HL) ADD A,02 DAA LD (HL),A HIKUSUADD2_2:DEC HL LD A,(HL) ADC A,00 DAA LD (HL),A DEC B JP NZ,HIKUSUADD2_2 RET
Z80アセンブラZASMでアセンブルして作成されたアセンブルリストです。
2010/11/10 8:32 root4.txt END=80A7 ;;; root program for ND80Z3 ;;; for ND80Z monitor ; 2010/11/08 11/09 11/10 ; ORG $8000 ; SEGCG=$05C0 KEYIN=$0616 ; LEDDP1=$FFF4 LEDDP3=$FFF6 ; LED1=$FFF8 LED2=$FFF9 LED3=$FFFA LED4=$FFFB LED5=$FFFC ; TISU12=$82AC TISU78=$82AF HIKUSU78=$82B3 KOTAE12=$82B4 KOTAE34=$82B5 ; 8000 060A START:LD B,0A 8002 21AC82 LD HL,TISU12 8005 AF XOR A ; ;TISU CLEAR ; 8006 77 TISUCLR:LD (HL),A 8007 23 INC HL 8008 05 DEC B 8009 C20680 JP NZ,TISUCLR ; ;TISU KEYIN ; 800C CD1606 CALL KEYIN 800F 07 RLCA 8010 07 RLCA 8011 07 RLCA 8012 07 RLCA 8013 21AC82 LD HL,TISU12 8016 77 LD (HL),A 8017 E5 PUSH HL 8018 CD1606 CALL KEYIN 801B E1 POP HL 801C 86 ADD A,(HL) 801D 77 LD (HL),A 801E 7E LD A,(HL) 801F 11F4FF LD DE,LEDDP1 8022 12 LD (DE),A ; ;KEISAN START ; 8023 3E01 LD A,01 8025 32B382 LD (HIKUSU78),A 8028 CD7080 KEISAN_LOOP:CALL HIKIZAN 802B DA3780 JP C,KEISAN_END 802E CD8480 CALL KOTAE_ADD1 8031 CD9380 CALL HIKUSUADD2 8034 C32880 JP KEISAN_LOOP ; ;KEKKA NO HYOJI ; 8037 21B482 KEISAN_END:LD HL,KOTAE12 803A 0602 LD B,02 803C 11F6FF LD DE,LEDDP3 803F 7E HYOJI_LOOP:LD A,(HL) 8040 12 LD (DE),A 8041 23 INC HL 8042 13 INC DE 8043 05 DEC B 8044 C23F80 JP NZ,HYOJI_LOOP 8047 CDC005 CALL SEGCG ; ;LED HYOJI O HENSYU SURU ; 804A 21FAFF LD HL,LED3 804D 11F9FF LD DE,LED2 8050 1A LD A,(DE) 8051 77 LD (HL),A 8052 21F9FF LD HL,LED2 8055 11F8FF LD DE,LED1 8058 1A LD A,(DE) 8059 77 LD (HL),A 805A 21FBFF LD HL,LED4 805D 3E48 LD A,48;"=" 805F 77 LD (HL),A 8060 21F8FF LD HL,LED1 8063 3E0E LD A,0E;"root" 8065 77 LD (HL),A 8066 21FCFF LD HL,LED5 8069 3E80 LD A,80;"." 806B B6 OR (HL) 806C 77 LD (HL),A 806D C30080 JP START ; ;subroutine ; ; ;TISU=TISU-HIKUSU ; 8070 21B382 HIKIZAN:LD HL,HIKUSU78 8073 11AF82 LD DE,TISU78 8076 0604 LD B,04 8078 AF XOR A 8079 1A HIKIZAN_2:LD A,(DE) 807A 9E SBC A,(HL) 807B 27 DAA 807C 12 LD (DE),A 807D 2B DEC HL 807E 1B DEC DE 807F 05 DEC B 8080 C27980 JP NZ,HIKIZAN_2 8083 C9 RET ; ;KOTAE_ADD1 ; 8084 21B582 KOTAE_ADD1:LD HL,KOTAE34 8087 7E LD A,(HL) 8088 C601 ADD A,01 808A 27 DAA 808B 77 LD (HL),A 808C 2B DEC HL 808D 7E LD A,(HL) 808E CE00 ADC A,00 8090 27 DAA 8091 77 LD (HL),A 8092 C9 RET ; ; HIKUSU=HIKUSU+2 ; 8093 0603 HIKUSUADD2:LD B,03 8095 21B382 LD HL,HIKUSU78 8098 7E LD A,(HL) 8099 C602 ADD A,02 809B 27 DAA 809C 77 LD (HL),A 809D 2B HIKUSUADD2_2:DEC HL 809E 7E LD A,(HL) 809F CE00 ADC A,00 80A1 27 DAA 80A2 77 LD (HL),A 80A3 05 DEC B 80A4 C29D80 JP NZ,HIKUSUADD2_2 80A7 C9 RET HIKIZAN =8070 HIKIZAN_2 =8079 HIKUSU78 =82B3 HIKUSUADD2 =8093 HIKUSUADD2_2 =809D HYOJI_LOOP =803F KEISAN_END =8037 KEISAN_LOOP =8028 KEYIN =0616 KOTAE12 =82B4 KOTAE34 =82B5 KOTAE_ADD1 =8084 LED1 =FFF8 LED2 =FFF9 LED3 =FFFA LED4 =FFFB LED5 =FFFC LEDDP1 =FFF4 LEDDP3 =FFF6 SEGCG =05C0 START =8000 TISU12 =82AC TISU78 =82AF TISUCLR =8006
念の為に、変更後のプログラムをND80ZVで実行してみましたが、もとのプログラムと全く同じ結果が表示されました。
●HIKUSUADD2サブルーチンを検証してみました
8080 Manualの記載と、そのように変更して実行してみた結果から、以上のように考えてよい、ということははっきりしました。
しかし、DAA命令で発生した上位桁への桁上げが、間にDEC命令やそのほかの命令をはさんでもちゃんと実行される様子が確認できれば、なおのこと納得がいくのではありませんでしょうか?
ということで、実際にHIKUSUADD2サブルーチンだけを取り出して、そのあたりの動きを確認してみることにしました。
動作の確認はZB3BASICのマシン語デバッグ機能利用して行なうのが簡単です。
ZB3BASICもND80ZV組立キットに付属しています。
まずはテストを行なうために、HIKUSUADD2サブルーチンだけを取り出してソースプログラムファイルにしました。
rootsbt.txtです。
;;; root subroutine HIKUSUADD2 test ;;; for ND80Z monitor ; 2010/11/10 ; ORG $8000 ; HIKUSU78=$82B3 ; ; HIKUSU=HIKUSU+2 ; HIKUSUADD2:LD B,03 LD HL,HIKUSU78 LD A,(HL) ADD A,02 DAA LD (HL),A HIKUSUADD2_2:DEC HL LD A,(HL) ADC A,00 DAA LD (HL),A DEC B JP NZ,HIKUSUADD2_2 RET
rootsbt.txtをzasmでアセンブルして、バイナリファイルrootsbt.binを作成したあと、ZB3BASICを起動します。
ZB3BASICを起動したら、rootsbt.binをアドレス8000にLOADします。
4バイトのワークレジスタ82B0〜82B3に8桁の10進数(BCD数)が入れられているとき、rootsbt.binを実行すると、そのワークレジスタの値に2が加算されます。
その計算は最下位の2桁(アドレス82B3)に02を加算し、その結果桁上げが発生すれば、上位桁に対して桁上げの計算を行なうというように行なわれます。
桁上げの動作がはっきり確認できるように、アドレス82B0〜82B3には、00099999という値を入れておきます。
00099999+2の計算が行なわれるはずですから、計算の結果は、00100001になることが期待されます。
メモリに値を書き込むにはcm(cheng memory)コマンドを使います。
上のコマンドプロンプト画面で、cm 82b0を実行して、82B0〜82B3に00099999を書き入れています。
プログラムを実行して、その様子を確認するためにはブレークポイントを設定して、実行の途中でブレークさせてそのときのレジスタの値を確認する、という方法が効果的です。
下はZ80アセンブラ(ZASM)でアセンブルしたrootsbt.txtのアセンブルリストです。
2010/11/10 8:48 rootsbt.txt END=8014 ;;; root subroutine HIKUSUADD2 test ;;; for ND80Z monitor ; 2010/11/10 ; ORG $8000 ; HIKUSU78=$82B3 ; ; HIKUSU=HIKUSU+2 ; 8000 0603 HIKUSUADD2:LD B,03 8002 21B382 LD HL,HIKUSU78 8005 7E LD A,(HL) 8006 C602 ADD A,02 8008 27 DAA 8009 77 LD (HL),A 800A 2B HIKUSUADD2_2:DEC HL 800B 7E LD A,(HL) 800C CE00 ADC A,00 800E 27 DAA 800F 77 LD (HL),A 8010 05 DEC B 8011 C20A80 JP NZ,HIKUSUADD2_2 8014 C9 RET HIKUSU78 =82B3 HIKUSUADD2 =8000 HIKUSUADD2_2 =800A
あとはまた、さきほどのコマンドプロンプト画面の説明をしていきます。
プログラムを実行したら、最初の加算ADD A,02の直前でまずブレークさせてみることにします。
ADD A,02はアドレス8006ですから、
bp 8006
と入力します。
bpはブレークポイントをセットするコマンドです。
今回のテストプログラムrootsbt.binはマシン語サブルーチンですから、ZB3BASICのマシン語サブルーチンコール命令のUSR()を使います。
usr($8000)
と入力すると、アドレス8000からのマシン語サブルーチンが実行されます。
ブレークポイントが設定されていますから、アドレス8006でブレークします。
先ほどのコマンドプロンプト画面を見ていただければ、ブレークした結果の表示も確認できるのですが、何回も戻るのは面倒なことですから、画面表示と同時に作成保存されるログファイルから切り取ってその部分を下に示します。
>bp 8006 >usr($8000) A F B C D E H L A'F' B'C' D'E' H'L' PC SP IX IY I SZ H PNC 996A 0306 4FCD 82B3 0044 0000 0000 0000 8006 F7FA 0000 F1A1 FF 01101010
アドレス8000〜8005までのプログラム(下記)が実行された結果、HLレジスタには82B3が入り、Bレジスタには03が入り、そしてAレジスタにはHLレジスタで示されるアドレス82B3の値99が入れられています。PC(プログラムカウンタ)はブレークしたアドレス8006になっています。
そのあたりのプログラムリストをしたに示します。
8000 0603 HIKUSUADD2:LD B,03 8002 21B382 LD HL,HIKUSU78 8005 7E LD A,(HL) 8006 C602 ADD A,02 8008 27 DAA 8009 77 LD (HL),A
次にブレークポイントを8008にセットして、ADD A,02を実行させてからブレークさせます。
>bp 8008 >rt A F B C D E H L A'F' B'C' D'E' H'L' PC SP IX IY I SZ H PNC 9B88 0306 4FCD 82B3 0044 0000 0000 0000 8008 F7FA 0000 F1A1 FF 10001000
rtはもとのマシン語プログラムにリターンして、ブレークしたところから実行を再開するためのコマンドです。
先にbp 8008を入力してブレークポイントを設定してからrtコマンドを実行しましたから、8006のADD A,02が実行されるとすぐにまたブレークします。
99に02が加算されましたから、Aレジスタの値は9Bになっています。
ここはまだ十進数の加算ではなくて2進数の加算になっています。
そのあと、DAA(Decimal Adjast十進補正)命令の実行結果を確認するために、ブレークポイントをアドレス8009にセットしてからrtコマンドを実行します。
>bp 8009 >rt A F B C D E H L A'F' B'C' D'E' H'L' PC SP IX IY I SZ H PNC 0111 0306 4FCD 82B3 0044 0000 0000 0000 8009 F7FA 0000 F1A1 FF 00010001
DAAが実行された結果、Aレジスタの値が十進数加算99+02の結果に正しく補正されて、01になりました。
また上位桁に桁上げがあることを示すキャリーフラグ(右端のC)がセットされて1になっています。
説明の途中ですが時間がなくなってしまいましたので、続きは次回にすることにいたします。
2010.11.10upload
前へ
次へ
ホームページトップへ戻る