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

復活!CP/M ワンボードマイコンでCP/Mを!
CP/MがTK−80互換のワンボードマイコンの上で復活します
ND80ZVとMYCPU80の上でCP/Mが走ります

[第42回]

●メモリダンププログラム

このところとりあえずND80ZVの上で動くようになったCP/Mの動作テストのために、ファンクションコールを使ったテストプログラムの説明をしております。
今回もファンクションコール1、2、9を使ったプログラムですが、今回は実用的なプログラムを書いてみることにします。

タイトルに書きましたようにメモリダンププログラムです。
メモリダンプはZB3BASICのマシン語モニタの機能にもありますが、それと同じものをCP/M上で使えるようにしたい、という目的で作ってみることにしました。

●ソースプログラムリストです

; BDOS TEST3 DUMP MEMORY
;
     ORG $8100
     FCALL=$8005
;
TOP:LD H,00
LOOP:PUSH HL
        LD E,3F;?
        LD C,02
        CALL FCALL          
        LD C,01
        CALL FCALL
        CP 1A;^z?
        POP HL
        RET Z
        CP 0D;[enter]?
        JP Z,NEXT
        CALL HTOB1
        JP C,WHATDP
        RLCA
        RLCA
        RLCA
        RLCA
        LD H,A
        PUSH HL
        LD C,01
        CALL FCALL
        CP 1A;^z?
        POP HL
        RET Z
        CALL HTOB1
        JP C,WHATDP
        OR H
        LD H,A
NEXT:LD L,00
; memory dump
        CALL CRLF
        LD B,10;=16
LOOP1:CALL HEX4DP;address disp
        LD C,08
LOOP2:CALL SPDP;space disp
        LD A,(HL)
        CALL B2HEXDP;data disp
        INC HL
        DEC C
        JP NZ,LOOP2
        LD A,2D;"-"
        CALL ADP
        LD C,08
LOOP3:LD A,(HL)
        CALL B2HEXDP
        CALL SPDP
        INC HL
        DEC C
        JP NZ,LOOP3
        CALL CRLF
        DEC B
        JP NZ,LOOP1
        CALL CRLF
        JP LOOP
WHATDP:CALL CRLF
        LD DE,WHATT
        LD C,09
        CALL FCALL
        CALL CRLF
        JP TOP
WHATT:"what"
        DB 3F;?
        DB 24;$
;
;CR & LF
CRLF:LD A,0D
        CALL ADP
        LD A,0A
        JP ADP
;space disp
SPDP:LD A,20
;A disp
ADP:PUSH BC
        PUSH HL
        LD E,A
        LD C,02
        CALL FCALL
        POP HL
        POP BC
        RET
;binary to hex, 2bytes data to ascii 4charactors,HL to HL,DE
B2HEX4:LD A,H
        CALL B2HEX2
        EX DE,HL
        LD A,E
;binary to hex, 1byte data to ascii 2charactors,A to DE
B2HEX2:PUSH AF
        RRCA
        RRCA
        RRCA
        RRCA
        CALL B2HEX1
        LD D,A
        POP AF
        CALL B2HEX1
        LD E,A
        RET
;binary to hex, low 4bit to ascii 1charactor
B2HEX1:AND 0F
        ADD A,30
        CP 3A
        RET C;0-9
        ADD A,07;A-F
        RET
;hex to binary, ascii 1charactor to low 4bit 
HTOB1:CP 30;>="0"?
        RET C;no
        CP 3A;<="9"?
        JP C,HTOB1_2;yes,"0" to "9"
        CP 41;>="A" ?
        RET C;no
        CP 47;<="F"?
        JP C,HTOB1_1
        CP 61;>="a"?
        RET C;no
        CP 67;<="f"?
        CCF
        RET C;no
HTOB1_1:ADD A,09;41 to 46 -> 4A to 4F,or 61 to 66 -> 6A to 6F
HTOB1_2:AND 0F
        RET
;HL(bynary 2bytes) to asckii 4bytes & disp
HEX4DP:PUSH BC
        PUSH HL
        CALL B2HEX4;binary 2 bytes to ascii HEX 4bytes
        PUSH DE
        EX DE,HL
        CALL DEDP
        POP DE
        CALL DEDP
        POP HL
        POP BC
        RET
;A(binary) to asckii 2bytes HEX & disp
B2HEXDP:PUSH BC
        PUSH HL
        CALL B2HEX2
        CALL DEDP
        POP HL
        POP BC
        RET
;
;DE(asckii 2bytes) disp
DEDP:PUSH DE
        LD E,D
        LD C,02
        CALL FCALL
        POP DE
        LD C,02
        CALL FCALL
        RET
;

今回は、かなり長いプログラムです。
このプログラムを実行すると?が表示されます。
ここでアドレスを入力します。
ふつうは任意のアドレス範囲を入力します。
しかしメモリダンプはまとまった範囲のメモリ内容を一括して表示しますから、ほんとうは切りのいいアドレス(たとえば下位アドレスが00)から128バイトとか256バイトとかを表示するようにしたほうがわかりやすいものです。
そこで今回は、入力アドレスを上位2桁だけにします。
[Enter]の入力も不要です。

上位アドレスが入力されたら、下位アドレスを00にして、そこから256バイトを表示します。
サブルーチンをかなりたくさん使っています。
キーから入力されるASCII文字のアドレスをバイナリに変換したり、バイナリデータをASCII文字に変換して表示したりするために、いくつかのサブルーチンを使っています。
いずれもこのような用途に使える実用的なサブルーチンです。

プログラムを書いていて感じたのですが、CP/Mのファンクションコールは、システム内でレジスタを使ってしまうため、今回のようなプログラムではファンクションコールの度にレジスタを退避させるのがかなり面倒な仕事になります。
そのために、できるだけサブルーチン内でファンクションコールをして、そこでレジスタを退避するように考えてあります。

プログラムそのものは、それほど難しいものではありませんから、実行結果と見比べながら読んでいただければ、何をやっているかはおわかりいただけると思います。

下は、上のソースリストをND80ZVに附属の中日電工製のZ80アセンブラzasm.comでアセンブルして作成されたアセンブルリストです。
毎回書いておりますが、CP/Mソースをアセンブルするのに使った、zasm1.64を使うと、一部文法表現が異なっているため、エラーになってしまいます。

2012/2/23  20:51  ftest3dm.txt
END=81FF
              ; BDOS TEST3 DUMP MEMORY
              ;
                   ORG $8100
                   FCALL=$8005
              ;
8100 2600     TOP:LD H,00
8102 E5       LOOP:PUSH HL
8103 1E3F       LD E,3F;?
8105 0E02       LD C,02
8107 CD0580     CALL FCALL          
810A 0E01       LD C,01
810C CD0580     CALL FCALL
810F FE1A       CP 1A;^z?
8111 E1         POP HL
8112 C8         RET Z
8113 FE0D       CP 0D;[enter]?
8115 CA3581     JP Z,NEXT
8118 CDBA81     CALL HTOB1
811B DA6D81     JP C,WHATDP
811E 07         RLCA
811F 07         RLCA
8120 07         RLCA
8121 07         RLCA
8122 67         LD H,A
8123 E5         PUSH HL
8124 0E01       LD C,01
8126 CD0580     CALL FCALL
8129 FE1A       CP 1A;^z?
812B E1         POP HL
812C C8         RET Z
812D CDBA81     CALL HTOB1
8130 DA6D81     JP C,WHATDP
8133 B4         OR H
8134 67         LD H,A
8135 2E00     NEXT:LD L,00
              ; memory dump
8137 CD8481     CALL CRLF
813A 0610       LD B,10;=16
813C CDD681   LOOP1:CALL HEX4DP;address disp
813F 0E08       LD C,08
8141 CD8E81   LOOP2:CALL SPDP;space disp
8144 7E         LD A,(HL)
8145 CDE781     CALL B2HEXDP;data disp
8148 23         INC HL
8149 0D         DEC C
814A C24181     JP NZ,LOOP2
814D 3E2D       LD A,2D;"-"
814F CD9081     CALL ADP
8152 0E08       LD C,08
8154 7E       LOOP3:LD A,(HL)
8155 CDE781     CALL B2HEXDP
8158 CD8E81     CALL SPDP
815B 23         INC HL
815C 0D         DEC C
815D C25481     JP NZ,LOOP3
8160 CD8481     CALL CRLF
8163 05         DEC B
8164 C23C81     JP NZ,LOOP1
8167 CD8481     CALL CRLF
816A C30281     JP LOOP
816D CD8481   WHATDP:CALL CRLF
8170 117E81     LD DE,WHATT
8173 0E09       LD C,09
8175 CD0580     CALL FCALL
8178 CD8481     CALL CRLF
817B C30081     JP TOP
817E 77686174 WHATT:"what"
8182 3F         DB 3F;?
8183 24         DB 24;$
              ;
              ;CR & LF
8184 3E0D     CRLF:LD A,0D
8186 CD9081     CALL ADP
8189 3E0A       LD A,0A
818B C39081     JP ADP
              ;space disp
818E 3E20     SPDP:LD A,20
              ;A disp
8190 C5       ADP:PUSH BC
8191 E5         PUSH HL
8192 5F         LD E,A
8193 0E02       LD C,02
8195 CD0580     CALL FCALL
8198 E1         POP HL
8199 C1         POP BC
819A C9         RET
              ;binary to hex, 2bytes data to ascii 4charactors,HL to HL,DE
819B 7C       B2HEX4:LD A,H
819C CDA181     CALL B2HEX2
819F EB         EX DE,HL
81A0 7B         LD A,E
              ;binary to hex, 1byte data to ascii 2charactors,A to DE
81A1 F5       B2HEX2:PUSH AF
81A2 0F         RRCA
81A3 0F         RRCA
81A4 0F         RRCA
81A5 0F         RRCA
81A6 CDB081     CALL B2HEX1
81A9 57         LD D,A
81AA F1         POP AF
81AB CDB081     CALL B2HEX1
81AE 5F         LD E,A
81AF C9         RET
              ;binary to hex, low 4bit to ascii 1charactor
81B0 E60F     B2HEX1:AND 0F
81B2 C630       ADD A,30
81B4 FE3A       CP 3A
81B6 D8         RET C;0-9
81B7 C607       ADD A,07;A-F
81B9 C9         RET
              ;hex to binary, ascii 1charactor to low 4bit 
81BA FE30     HTOB1:CP 30;>="0"?
81BC D8         RET C;no
81BD FE3A       CP 3A;<="9"?
81BF DAD381     JP C,HTOB1_2;yes,"0" to "9"
81C2 FE41       CP 41;>="A" ?
81C4 D8         RET C;no
81C5 FE47       CP 47;<="F"?
81C7 DAD181     JP C,HTOB1_1
81CA FE61       CP 61;>="a"?
81CC D8         RET C;no
81CD FE67       CP 67;<="f"?
81CF 3F         CCF
81D0 D8         RET C;no
81D1 C609     HTOB1_1:ADD A,09;41 to 46 -> 4A to 4F,or 61 to 66 -> 6A to 6F
81D3 E60F     HTOB1_2:AND 0F
81D5 C9         RET
              ;HL(bynary 2bytes) to asckii 4bytes & disp
81D6 C5       HEX4DP:PUSH BC
81D7 E5         PUSH HL
81D8 CD9B81     CALL B2HEX4;binary 2 bytes to ascii HEX 4bytes
81DB D5         PUSH DE
81DC EB         EX DE,HL
81DD CDF281     CALL DEDP
81E0 D1         POP DE
81E1 CDF281     CALL DEDP
81E4 E1         POP HL
81E5 C1         POP BC
81E6 C9         RET
              ;A(binary) to asckii 2bytes HEX & disp
81E7 C5       B2HEXDP:PUSH BC
81E8 E5         PUSH HL
81E9 CDA181     CALL B2HEX2
81EC CDF281     CALL DEDP
81EF E1         POP HL
81F0 C1         POP BC
81F1 C9         RET
              ;
              ;DE(asckii 2bytes) disp
81F2 D5       DEDP:PUSH DE
81F3 5A         LD E,D
81F4 0E02       LD C,02
81F6 CD0580     CALL FCALL
81F9 D1         POP DE
81FA 0E02       LD C,02
81FC CD0580     CALL FCALL
81FF C9         RET
              ;
              
ADP          =8190  B2HEX1       =81B0  B2HEX2       =81A1  
B2HEX4       =819B  B2HEXDP      =81E7  CRLF         =8184  
DEDP         =81F2  FCALL        =8005  HEX4DP       =81D6  
HTOB1        =81BA  HTOB1_1      =81D1  HTOB1_2      =81D3  
LOOP         =8102  LOOP1        =813C  LOOP2        =8141  
LOOP3        =8154  NEXT         =8135  SPDP         =818E  
TOP          =8100  WHATDP       =816D  WHATT        =817E  


●実際の実行画面です

下の画面では、まずftest3dm.txtをアセンブルしています。



ftest3dm.binが作成されました。
そのあと、zb3[Enter]と入力して、ND80ZVとのUSB接続に成功しました。
ここで”z”を入力すると、ZB3BASICが起動します。

”z”を入力してZB3BASICが起動したあとの画面です。



ZB3BASICが起動したあと、/LDコマンドでftest3dm.binを8100Hにロードしています。
ちょうど256バイトのプログラムです。

そのあと、JP D233[Enter]でCP/Mが起動しました。

DIR[Enter]の入力で、ディレクトリを表示させています。

8100Hにロードしたプログラムをdm.comという名前でRAMディスクにSAVEします。
ふつうはメモリダンプといいますから、それならmd.comのほうがよさそうですが、ZB3BASICのマシン語モニタコマンドで、CM(change memory)と対にしてDM(dump memory)ということで使っていますから、それに合わせることにしました。

DIR[Enter]と入力して、dm.comが保存されたことを確認しています。

そのあと、dm[Enter]と入力して、プログラムを実行すると、
?が表示されました。

●DMプログラムの実行

ここで表示したいアドレスの上位2桁を入力すると、そのアドレスの下位2桁00から始まる256バイトのメモリの内容が表示されます。


88と入力してみました。
アドレス8800〜88FFのメモリ内容が表示されました。
ここはRAMディスクの先頭にあるディレクトリエリアです。

256バイトを表示し終わるとまた?が表示されます。

ここでただ[Enter]だけを入力すると、その次の256バイトが表示されます。



RAMディスクのデータファイルが格納されているエリアも表示してみました。



アドレス8C00からのメモリエリアには、最初にSAVEしたFILLE5.COMがあります。
画面左にFILLE5.COMのアセンブルリストを表示してみました。
両者を見比べてみますと、実際にRAMディスクにはこのような形でプログラム(またはデータ)が格納される、ということがよく理解していただけるのではないか、と思います。

ところで。
今回のダンプ表示を見て、物足りなさを感じられたかも知れません。
ふつうは、この表示の右側に、メモリ内容をASCIIコードとみなして、そのコードに対応する文字が表示されるものだからです。
マシン語プログラムの命令コードを文字で表示してみても全く意味はありませんが、しかしプログラム中にはいろいろな文字列が使われることが多く、それが読み取れるとプログラムの解析などに役立ちます。

そこで。
次回は、今回のメモリダンププログラムにASCIIダンプの機能を追加してみることに致します。
どのようにすればよいか、皆様も考えてみてください。

ワンボードマイコンでCP/Mを![第42回]
2012.2.23upload

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