SSブログ
English Version

Z80GALの構想(その9)簡易モニタの製作(その2)ブレーク機能の実装 [Z80]

 「Z80GALの構想(その4)簡易モニタの製作」の記事で書いたように今回はZ80GALに移植したGAME言語を使って作成した簡易モニタを使ってプログラムをダウンロードしディバッグを行いました。
 始めからブレーク機能を実装してディバッグに使えば良かったようなものですが、ブレーク機能無しでも今回の開発作業は問題ないと考えていました。
 今回のプログラム開発で残りはIPLくらいしかありませんが、実装方法を考えるのが面白そうだったのでブレーク機能を追加してみました。

 まずはモニタにおけるテスト対象プログラム実行時に期待する機能として、RET命令でモニタに戻ってきた際のレジスタの値などを確認する使い方と、ブレークポイントを設定して実行プログラムがブレークポイントに到達した時点でのレジスタ内容などを確認したい場合の二通りあるのではないかと思います。

 また、いずれの場合もプログラム実行前にはレジスタの値を事前に設定したいものです。

 今回は上記の2つの使い方に対応できるようにしました。それぞれの機能について以下に概要を説明します。

  1. 実行プログラムリターン時のレジスタ確認機能
     事前に任意のレジスタの値を設定して指定した番地からプログラムを実行し、RET命令でモニタに戻ってくる。
     この場合にスタック上にはモニタへの戻り値を積んだうえで対象プログラムを実行します。
     対象プログラムから戻ってきたら、その時点のレジスタを保存し、確認できるようにします。この戻り時の処理は次に述べるブレーク機能と同じ処理になります。
     試験プログラムの実行方法としては「Gaaaa」になります(aaaaは開始アドレス)。

  2. ブレーク機能
     試験対象プログラムの複数個所にブレークポイント(今回はRST 30H(F7H)を使用)を設定後、プログラムを実行し、ブレークポイントに達した時点でモニタに戻し、レジスタ内容の確認などができるようにする。
     今回はブレークポイントを5個まで設定可能で、ブレークした時点で置き換えたF7Hのコードを元のコードに戻す(ブレークポイントを自動的にクリアする)ことで継続して試験プログラムを実行できるようにしました。
     試験プログラムの実行方法はPC(プログラムカウンタ)に実行アドレスを設定後、「G」コマンドで試験対象プログラムを実行します。


 下記のサンプルプログラムを用いて、今回追加した機能についての概要を書いてみます。

使用したサンプルプログラム
  8000    32 800F	LD	(800FH),A
  8003    3E 55  	LD	A,55H
  8005    06 11  	LD	B,11H
  8007    CD 8010	CALL	8010H
  800A    D9     	EXX
  800B    C9     	RET
  800C    00     	NOP
  800D    00     	NOP
  800E    00     	NOP
  800F    00     	NOP
  8010    0E 22  	LD	C,22H
  8012    21 1234	LD	HL,1234H
  8015    C9     	RET


 文字でいろいろ書くよりも操作例を示した方が判り易いと思います。
 ブレークを設定後に最初だけ「Gxxxx」コマンドで対象プログラムを実行し、ブレーク後は「G」コマンドで継続して実行しています。
 最後にRET命令によりモニタに戻ってきますが、この場合、PCの値が不明(ステップ動作すれば判るようになるがそのためには命令長情報が必要になる)なのでPCの表示値は実行開始のアドレス値を表示するようにしました。

 また、今回追加したレジスタ管理機能とブレーク設定/解除機能はいずれもマルチステートメント対応にしているで複数命令を一度に(場合によってはコピペで)実行可能です。

モニタでのブレーク操作例(水色:入力部)
]h *DUMP: D[aaaa[,aaaa]] *FILL : Faaaa,aaaa,dd *GO : G[aaaa] *SET : S[aaaa[,dd]] *IN : Iaa *OUT : Oaa,dd *Reg : X[reg[dddd]] *Break: B[Sn[,aaaa]|Cn|L] n=0..4 READ: R WRITE: Waaaa,aaaa QUIT: Q HELP : H *:can use multi statement separated with ':' command set:= exec:! display:? ]=d8000,801f ]? d8000,801f ]! 8000 : 32 0F 80 3E 55 06 11 CD - 10 80 D9 C9 00 00 00 00 2..>U... - ........ 8010 : 0E 22 21 34 12 C9 00 00 - 00 00 00 00 00 00 00 00 ."!4.... - ........ ]bs,8003:bs1,8007:bs2,8012 adr0:8003 adr1:8007 adr2:8012 ]bs3 adr3:800a ]bl adr0:8003(3E) adr1:8007(CD) adr2:8012(21) adr3:800A(D9) ]! 8000 : 32 0F 80 F7 55 06 11 F7 - 10 80 F7 C9 00 00 00 00 2...U... - ........ 8010 : 0E 22 F7 34 12 C9 00 00 - 00 00 00 00 00 00 00 00 .".4.... - ........ ]xa --.-.--- AF=0000:aa00 ]x --.-.--- AF=AA00 BC=0000 DE=0000 HL=0000 PC=8000 SP=0340 --.-.--- AF'0000 BC'0000 DE'0000 HL'0000 IX=0000 IY=0000 ]g8000 G:8000 at adr0 --.-.--- AF=AA00 BC=0000 DE=0000 HL=0000 PC=8003 SP=033C --.-.--- AF'0000 BC'0000 DE'0000 HL'0000 IX=0000 IY=0000 ]! 8000 : 32 0F 80 3E 55 06 11 F7 - 10 80 F7 C9 00 00 00 AA 2..>U... - ........ 8010 : 0E 22 F7 34 12 C9 00 00 - 00 00 00 00 00 00 00 00 .".4.... - ........ ]bl adr1:8007(CD) adr2:8012(21) adr3:800A(D9) ]g G:8003 at adr1 --.-.--- AF=5500 BC=1100 DE=0000 HL=0000 PC=8007 SP=033C --.-.--- AF'0000 BC'0000 DE'0000 HL'0000 IX=0000 IY=0000 ]g G:8007 at adr2 --.-.--- AF=5500 BC=1122 DE=0000 HL=0000 PC=8012 SP=033A --.-.--- AF'0000 BC'0000 DE'0000 HL'0000 IX=0000 IY=0000 ]g G:8012 at adr3 --.-.--- AF=5500 BC=1122 DE=0000 HL=1234 PC=800A SP=033C --.-.--- AF'0000 BC'0000 DE'0000 HL'0000 IX=0000 IY=0000 ]! 8000 : 32 0F 80 3E 55 06 11 CD - 10 80 D9 C9 00 00 00 AA 2..>U... - ........ 8010 : 0E 22 21 34 12 C9 00 00 - 00 00 00 00 00 00 00 00 ."!4.... - ........ ]g G:800A --.-.--- AF=5500 BC=0000 DE=0000 HL=0000 PC=8000 SP=0340 --.-.--- AF'0000 BC'1122 DE'0000 HL'1234 IX=0000 IY=0000 ]■

★変更 2011/11/22 操作例をアップデート

 このような機能はGAME言語だけでは記述できないので上記の二通りの実行機能(GO:がブレーク用、GOxx:がRET時レジスタ確認用の実行開始モジュール)とモニタへリターン時のレジスタ格納処理(RSTENT:)をアセンブラで記述しました。
 先頭のジャンプ命令とワークメモリアドレスはGAME言語とのインターフェース用です。

ブレーク処理用のアセンブラ記述部分(Z80アセンブラ)
ORG HEXST 0200 C3 0283 RSTJMP: JP RSTENT 0203 C3 02A6 enGO: JP GO 0206 C3 02C7 enGOxx: JP GOXX 0209 00 DB 0 020A 02ED RegWrk: DW SavAFb  ~~ 途中省略 !! Omit the middle!! ;+++++++++++++++++++++++++++++++++++ ; RST break test ; 2020/11/17 by skyriver ;+++++++++++++++++++++++++++++++++++ 0283 22 02FF RSTENT: LD (SavHL),HL 0286 E1 POP HL 0287 2B DEC HL 0288 22 0301 LD (SavPC),HL 028B ED 73 0303 LD (SavSP),SP 028F F3 DI 0290 31 02FF LD SP,SavHL 0293 D5 PUSH DE 0294 C5 PUSH BC 0295 F5 PUSH AF 0296 FD E5 PUSH IY 0298 DD E5 PUSH IX 029A D9 EXX 029B E5 PUSH HL 029C D5 PUSH DE 029D C5 PUSH BC 029E 08 EX AF,AF' 029F F5 PUSH AF 02A0 FB EI 02A1 ED 7B 0305 LD SP,(SavGSP) 02A5 C9 RET 02A6 ED 73 0305 GO: LD (SavGSP),SP 02AA F3 DI 02AB 31 02ED LD SP,SavAFb 02AE F1 POP AF 02AF C1 POP BC 02B0 D1 POP DE 02B1 E1 POP HL 02B2 08 EX AF,AF' 02B3 D9 EXX 02B4 DD E1 POP IX 02B6 FD E1 POP IY 02B8 F1 POP AF 02B9 C1 POP BC 02BA D1 POP DE 02BB E1 POP HL 02BC E1 POP HL ; PC 02BD FB EI 02BE ED 7B 0303 LD SP,(SavSP) 02C2 E5 PUSH HL 02C3 2A 02FF LD HL,(SavHL) 02C6 C9 RET ; Gxxxx command ; SavPC <- xxxx 02C7 ED 73 0305 GOxx: LD (SavGSP),SP 02CB F3 DI 02CC 31 02ED LD SP,SavAFb 02CF F1 POP AF 02D0 C1 POP BC 02D1 D1 POP DE 02D2 E1 POP HL 02D3 08 EX AF,AF' 02D4 D9 EXX 02D5 DD E1 POP IX 02D7 FD E1 POP IY 02D9 F1 POP AF 02DA C1 POP BC 02DB D1 POP DE 02DC FB EI 02DD ED 7B 0303 LD SP,(SavSP) 02E1 21 0283 LD HL,RSTENT 02E4 E5 PUSH HL 02E5 2A 0301 LD HL,(SavPC) 02E8 E5 PUSH HL 02E9 2A 02FF LD HL,(SavHL) 02EC C9 RET 02ED SavAFb: DS 2 ; 0 02EF SavBCb: DS 2 ; 1 02F1 SavDEb: DS 2 ; 2 02F3 SavHLb: DS 2 ; 3 02F5 SavIX: DS 2 ; 4 02F7 SavIY: DS 2 ; 5 02F9 SavAF: DS 2 ; 6 02FB SavBC: DS 2 ; 7 02FD SavDE: DS 2 ; 8 02FF SavHL: DS 2 ; 9 0301 SavPC: DS 2 ;10 0303 0340 SavSP: DW PRGST ; save SP 0305 SavGSP: DS 2 ; GAME's SP


 下のリストが今回機能追加したGAME言語のモニタ(Gamon)のソースです。GAME言語を移植できる環境があるのであれば、モニタの移植も容易だと思います。

Gamon(Game Monitor)ソース(GAME言語)
1' simple monitor(Gamon) V003a 2020/11/19 by skyriver 10 #=10000 100'*** init 110 M=&+1 120 M:1)=$DB M:3)=$32 M(2)=M M:6)=$C9 130 M:7)=$3E M:9)=$D3 M:11)=$C9 140 M:12)=$3E M:14)=$E6 M:15)=$0F M(8)=$3200 M(9)=M M:20)=$C9 150 M:21)=$3E M:23)=$0F M(12)=$0F0F M(13)=$320F M(14)=M M:30)=$C9 160 W=M+31 B=W+20 I=0,9 W(I)=0 @=I+1 162 Y=B+256 164 R=$30 R:0)=$C3 R=R+1 R(0)=$200 R=$20A R=R(0) 170 /"** Gamon(Game Monitor) V0.03a 2020/11/19 by skyriver H:Help **"// 180 ] 200'*** get line 210 P=B Q=B $=Z 220 @ 230 C=$ ;=C<>8 #=260 240 ;=Q=B $=Z #=260 250 Q=Q-1 " " $=8 260 ;=(C=$18)*(Q>B) @ $=8 " " $=8 Q=Q-1 @=(Q=B) 262 ;=Q-B>253 $=8 " " $=8 #=280 270 ;=C>=" " Q:0)=C Q=Q+1 280 @=(C=13) 290 ] 300'** Getc from buf 310 C=0 ;=P<Q C=P:0) P=P+1 ;=(C>="a")*(C<="z") C=C-("a"-"A") 320 ] 350'unpuc 360 ;=C P=P-1 370 ] 400'** Get Hex byte D-> 0..15, -1:NG 410 D=-1 420 !=300 430 ;=(C>="0")*(C<="9") D=C-"0" 440 ;=(C>="A")*(C<="F") D=C-"A"+10 450 ] 500'** Get value A->value F->1:OK,0:NG 510 A=0 F=0 520 @ 530 !=400 ;=D>=0 A=16*A+D F=1 540 @=(D=-1) 550 ] 600'** PutHex byte D<-data,G<-sum 610 M:22)=D >=M+21 M:13)=M:0) >=M+12 620 M:13)=M:0) >=M+12 C=M:0) 630 C=C+"0" ;=C>"9" C=C+"A"-"0"-10 640 $=C 650 M:13)=D >=M+12 C=M:0) 660 C=C+"0" ;=C>"9" C=C+"A"-"0"-10 670 $=C G=G+D 680 ] 710 J=R-U*2+31 I=0,V $=M:J) $=M:J+1) ":" ??=U(0) " " U=U+2 J=J+2 @=I+1 720 ] 800'** Dsp reg 802 ;=U=0 !=880 "AF'" 803 ;=U=1 "BC'" 804 ;=U=2 "DE'" 805 ;=U=3 "HL'" 806 ;=U=4 "IX=" 807 ;=U=5 "IY=" 808 ;=U=6 !=880 "AF=" 809 ;=U=7 "BC=" 810 ;=U=8 "DE=" 811 ;=U=9 "HL=" 812 ;=U=10 "PC=" 813 ;=U=11 "SP=" 820 ??=R(U) 830 ] 880 M:13)=R(U) 882 M:15)=$80 >=M+12 T="-" ;=M:0) T="S" 884 $=T M:15)=$40 >=M+12 T="-" ;=M:0) T="Z" 886 $=T "." M:15)=$10 >=M+12 T="-" ;=M:0) T="H" 888 $=T "." M:15)=$04 >=M+12 T="-" ;=M:0) T="P" 890 $=T M:15)=2 >=M+12 T="-" ;=M:0) T="N" 892 $=T M:15)=1 >=M+12 T="-" ;=M:0) T="C" 894 $=T " " M:15)=$F 896 ] 1000'** dump 1010 ;=P<Q !=500 S=A 1020 U=S M:13)=S >=M+12 S=S-M:0) 1030 E=U+$7F ;=P<Q !=500 ;=A>S E=A 1040 @ ??=S " :" 1050 I=0,15 1060 " " 1070 ;=(S+I>E)+(S+I<U) " " #=1090 1080 ?$=S:I) 1090 ;=I=7 " -" 1100 @=I+1 1110 " " 1120 I=0,15 1130 T=S:I) ;=(T<" ")+(T>"z") T="." 1140 ;=S+I<U T=" " 1150 $=T ;=I=7 " - " 1160 ;=S+I>=E I=15 1170 @=I+1 1180 / S=S+I 1190 @=(S>E) 1200 S=E+1 1210 ] 2000'** Set Memory 2010 ;=P<Q !=500 S=A 2012 ;=P<Q !=500 ;=F ??=S " " ?$=S:0) S:0)=A " - " ?$=A / #=2100 2020 @ 2030 ??=S " " ?$=S:0) " -" 2040 Z=" " !=200 / 2050 ;=P=Q S=S+1 F=1 #=2090 2060 !=500 2070 ;=F S:0)=A S=S+1 2080 ;=C="-" S=S-1 F=1 2090 @=(F=0) 2100 ] 3000'** Fill 3010 G=-1 3020 ;=P<Q !=500 S=A ;=P<Q !=500 ;=A>S E=A+1 !=500 ;=F G=A 3030 ;=G=-1 " ?"/ 3040 ;=G>=0 @ S:0)=G S=S+1 @=(S=E) 3050 ] 4000'** Go 4010 F=0 4012 ;=P=Q "G:" ??=R(10) >=$203 !=4200 !=9394 / ] 4020 ;=P<Q !=500 ;=F "G:" ??=A R(10)=A >=$206 !=4200 !=9394 / ] 4030 " ?"/ 4040 ] 4200'** clear BP 4210 T=R(10) 4220 I=0,9 4230 ;=W(I)=T T:0)=W(I+1) W(I)=0 " at adr" ?=I/2 I=9 4240 @=I+2 / 4250 ] 5000'** IN 5010 !=500 ;=F M:2)=A >=M+1 ?$=A " -> " ?$=M:0) / 5020 ] 6000'** OUT 6010 !=500 ;=F S=A !=500 ;=F M:8)=A M:10)=S >=M+7 #=6030 6020 " ?"/ #=6040 6030 ?$=S " <- " ?$=A / 6040 ] 7000'** Help 7010 " *DUMP: D[aaaa[,aaaa]] *FILL : Faaaa,aaaa,dd"/ 7020 " *GO : G[aaaa] *SET : S[aaaa[,dd]]"/ 7030 " *IN : Iaa *OUT : Oaa,dd"/ 7040 " *Reg : X[reg[dddd]] *Break: B[Sn[,aaaa]|Cn|L]" 7042 " n=0..4"/ 7050 " READ: R WRITE: Waaaa,aaaa"/ 7060 " QUIT: Q HELP : H"/ 7070 " *:can use multi statement separated with ':'"/ 7080 " command set:= exec:! display:?"/ 7090 ] 8000'** Write 8010 !=500 ;=F=0 #=8900 8020 S=A !=500 ;=F=0 #=8900 8030 ;=S>A #=8900 8040 @ 8050 G=0 E=32 ;=A-S+1<E E=A-S+1 8060 ":" D=E !=600 D=S/256 !=600 D=S !=600 D=0 !=600 8070 @ D=S:0) S=S+1 E=E-1 !=600 @=(E=0) 8080 D=-G !=600 / 8090 @=(S>A) 8100 ":00000001FF"/ 8110 ] 8900 " ?"/ 8910 ] 9000'** set cmd 9010 Y:0)=Q-P ;=P<Q I=1 @ Y:I)=P:0) I=I+1 P=P+1 @=(P=Q) 9020 ] 9100'** Display cmd 9110 ;=Y:0)>0 " " I=1,Y:0) $=Y:I) @=I+1 / 9120 ] 9200'** exec cmd 9210 P=B+1 Q=P 9220 ;=Y:0)>0 I=1,Y:0) Q:0)=Y:I) Q=Q+1 @=I+1 9230 C=":" 9240 ] 9300'** Xcmd 9312 !=300 9314 ;=(C=0)+(C=":") !=9394 / ] 9316 U=-1 ;=(C>="A")*(C<="B") U=C-"A"+6 9317 ;=C="D" U=8 9318 ;=C="H" U=9 9320 ;=U<0 #=9330 9322 !=300 ;=C="'" U=U-6 #=9324 9323 !=350 9324 #=9370 9330 ;=C<>"I" #=9350 9332 !=300 ;=C="X" U=4 #=9370 9340 ;=C<>"Y" "?"/ ] 9342 U=5 9350 ;=C="P" U=10 9352 ;=C="S" U=11 9360 ;=U<0 "?"/ ] 9370 ;=P<Q !=500 S=A ;=F !=800 ":" ??=A R(U)=A / ] 9372 !=800 Z=":" !=200 !=500 ;=F R(U)=A 9380 !=300 / 9390 ] 9394 U=6,11 " " !=800 @=U+1 / U=0,5 " " !=800 @=U+1 ] 9400'** Break 9410 !=300 ;=C<>"L" #=9420 9412 I=0,9 9414 ;=W(I) " adr" ?=I/2 ":" ??=W(I) "(" ?$=W(I+1) ")" / 9416 @=I+2 !=300 9418 ] 9420 T=C !=500 ;=(A>4)+(A<0) "?"/ ] 9430 ;=T<>"C" #=9450 9432 T=A*2 A=W(T) ;=A W(T)=0 ;=A:0)=$F7 A:0)=W(T+1) ] 9434 "?"/ ] 9450 ;=T<>"S" "?"/ ] 9452 T=A*2 9454 ;=W(T) "?"/ ] 9456 "adr" ?=T/2 ;=P<Q !=500 ":" ??=A #=9458 9457 Z=":" !=200 !=500 ;=F=0 #=9460 9458 / ;=A:0)<>$F7 W(T)=A W(T+1)=A:0) A:0)=$F7 ] 9460 "?"/ 9470 ] 10000'** main 10010 !=100 10020 @ 10030 Z="]" !=200 !=300 / 10040 ;=C="H" !=7000 #=11000 10050 ;=C="R" >=$20C / #=11000 10060 ;=C="W" !=8000 #=11000 10070 ;=C="=" !=9000 #=11000 10080 ;=C="?" !=9100 #=11000 10090 ;=C="!" !=9200 #=11000 10100 ;=C="G" !=4000 #=11000 10110 ;=C="D" !=1000 #=11000 10120 ;=C="S" !=2000 #=11000 10130 ;=C="F" !=3000 #=11000 10140 ;=C="I" !=5000 #=11000 10150 ;=C="O" !=6000 #=11000 10160 ;=C="X" !=9300 #=11000 10170 ;=C="B" !=9400 #=11000 10180 ;=(C<>"Q")*(C>0) $=C " ??"/ 11000 ;=C=":" !=300 #=10100 11010 @=(C="Q")

★変更 2011/11/19
 Ver0.03a "Gxxxx"と"G"の混在使用を可能にしました。

★追記 2024/02/28
 GAMON の最新版は「GAME言語で作った簡易モニタ(Gamon)」の記事からダウンロードできます。


[TOP] [ 前へ ] 連載記事 [ 次へ ]

nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。