ワンボードマイコンをつくろう!(パソコンの原点はここから始まった)
TK80ソフトコンパチブル!8080、Z80マシン語からBASICまでこれ1台でこなせます
当記事は2009年11月から「TTLでCPUをつくろう!」というタイトルの もとにほとんど毎日連載をしてきたものを再編集したものです。 2011.7.1
前へ
次へ
目次へ戻る
ホームページトップへ戻る
☆Z80アセンブラとZ80逆アセンブラ
ND80ZVには8080アセンブラのほかにZ80アセンブラとZ80逆アセンブラが附属しています。
そのZ80アセンブラ、Z80逆アセンブラの紹介です。

[第79回]

●ZDAS.COM(Z80逆アセンブラ)

[第73回]で8080アセンブラを改良しました、という説明を致しました。
8080アセンブラはMYCPU80組立キットのために新しく作ったアセンブラです。
ND80ZVのCPUはZ80ですが、Z80はマシン語コードレベルでは8080の命令をそのまま実行できますから、8080アセンブラも利用することは可能です。
ND80ZVは、TK80と同じ動作をさせるためのTK80モニタプログラムを実装しています。
その昔のTK80のために書かれたプログラムなどを参考にしてプログラムを作ってみたい、という場合などですと、そこで書かれているのは8080ニーモニックのプログラムのはずですから、8080アセンブラが使えると便利です。

しかし8080アセンブラではZ80固有の命令を使うことはできません。
ND80ZVはTK80モニタプログラムのほかに、ND80Zモニタプログラムも搭載しています。こちらはZ80CPUのためのモニタプログラムです。
Z80CPUの機能を有効に使うにはやっぱりZ80アセンブラが必要です。

というわけで、ND80ZV組立キットには附属ソフトウェアとして、8080アセンブラとZ80アセンブラの両方をCDROMで供給する予定です。
[第73回]では8080アセンブラについて説明を致しましたけれど、Z80アセンブラについてもご説明申し上げなくては片手落ちということになってしまいます。
そこで今回はZ80アセンブラについての説明、ということになるのですが、それについてはちょいとした趣向を考えました。

で、見出しの「Z80逆アセンブラ」について、まず先に説明をすることになります。

普通のアセンブラというのは、プログラムを人間が理解しやすいニーモニック命令で書いたものを、CPUが実行できるマシン語コードに翻訳するプログラムのことをいいます。
逆アセンブラというのは、その名前の通り、アセンブラの逆の働きをするプログラムです。
マシン語のプログラムを読み込んで、ニーモニック表現のプログラムに翻訳します。

たとえばソースプログラムが無くなってしまったがマシン語のプログラムだけは残っている、とかあるいはどなたか他の方が書かれたプログラムなのでマシン語のプログラムしかないけれども、それをなんとか解読してみたい、というような場合に、これがあると便利です。

Z80逆アセンブラですから、Z80のマシン語プログラムからZ80のニーモニックで書かれたソースプログラムを逆作成することができます。
プログラム名は、ZDAS.COMです。
このZDAS.COMもND80ZVの附属ソフトウェアとしてCDROMに入れて供給する予定です。

Z80逆アセンブラで何を始めるつもりなのでしょう?
実はちょいと面白いことを思いつきましたので、それをやってみよう、というわけです。

そのためにはちょいと前準備が必要です。

新しいフォルダを作って、そこにsound6.binをコピーして持ってきます。

sound6.binは[第73回]で8080アセンブラを使ってアセンブルして作ったマシン語のファイル(バイナリファイル)です。
新しいフォルダzdastestには、sound6.binしか入っていません。
dirコマンドでフォルダにあるファイルを表示させています。

そのsound6.binに対してzdas.comを実行しました。
zdas sound6.bin[Enter]と入力すると、
ENDと表示されました。

[第74回]で8080アセンブラ注記として書きましたように、8080アセンブラもZ80アセンブラも、そしてこのZ80逆アセンブラもWindowsパソコンのDOSプロンプトで実行しますが、Z80BASICと違って、ND80ZVをUSBで接続しておく必要はありません。
Z80BASICはND80ZVの上でZ80CPUがプログラムを実行しますから、USBでWindowsパソコンとND80ZVを接続しておく必要があるのですが、アセンブラや逆アセンブラはただの翻訳プログラムですから、パソコンの中だけで処理を行います。

zdas.comを実行した結果、どのようなファイルが作られたのか確認してみましょう。

さきほどと同じようにdirコマンドで確かめてみると、新たに、sound6.dtxとsound6.dlsという2つのファイルが作成されています。
それぞれのファイルの中身を見てみましょう。

まずは、sound6.dtxです。

      ORG $0000
      Z0247=$0247
      Z8000=$8000
      Z800E=$800E
      Z803F=$803F
      Z801F=$801F
      Z802D=$802D
      Z801A=$801A
      Z2C2F=$2C2F
      Z384B=$384B
      Z3720=$3720
      CALL Z0247
      INC A
      JP Z,Z8000
      DEC A
      CALL Z800E
      JP Z8000
      PUSH AF
      PUSH HL
      PUSH DE
      PUSH BC
      LD HL,Z803F
      ADD A,L
      LD L,A
      LD B,(HL)
      LD E,1A
      LD D,B
      LD A,EF
      OUT (98),A
      PUSH HL
      PUSH HL
      POP HL
      POP HL
      NOP
      DEC D
      JP NZ,Z801F
      LD D,B
      LD A,CF
      OUT (98),A
      PUSH HL
      PUSH HL
      POP HL
      POP HL
      NOP
      DEC D
      JP NZ,Z802D
      DEC E
      JP NZ,Z801A
      POP BC
      POP DE
      POP HL
      POP AF
      RET
      LD A,A
      LD (HL),A
      LD (HL),C
      LD L,D
      LD E,A
      LD E,C
      LD D,H
      LD C,A
      LD B,A
      LD B,E
      CCF
      DEC SP
      DEC (HL)
      LD (Z2C2F),A
      DEC H
      DAA
      LD HL,(Z384B)
      LD H,H
      INC HL
      LD HL,Z3720

このZDAS.COMはかなり以前に作ったソフトで、早い話が、使えればそれでよい、というモロ実用本位で作ったものですから、タイトルの表示もタイムスタンプもまるでありません。
でもしっかりとZ80ニーモニックに翻訳しています。

ところで、上にも書きましたように、このsound6.binは、8080ニーモニックで書いたソースプログラムを8080アセンブラでマシン語に翻訳して作ったバイナリファイルだったはずでした([第73回])。

そうなのです。
8080のためのマシン語プログラムは、このようにZ80逆アセンブラを使うことで、Z80ニーモニックのソースプログラムに変換してしまうことができるのです。
このsound6.dtxは、このままZ80アセンブラにかけることができるソースプログラムになっています。
拡張子はzdasで作成したソースプログラム(txt)という意味でdtxにしてあります。

ソースプログラムはこのような形になりますが、もとのマシン語コードに対応した形のリストもあると、プログラムがより理解しやすくなります。

sound6.dlsの中身です。

0000 CD4702         CALL $0247
0003 3C             INC A
0004 CA0080         JP Z,$8000
0007 3D             DEC A
0008 CD0E80         CALL $800E
000B C30080         JP $8000
000E F5             PUSH AF
000F E5             PUSH HL
0010 D5             PUSH DE
0011 C5             PUSH BC
0012 213F80         LD HL,$803F
0015 85             ADD A,L
0016 6F             LD L,A
0017 46             LD B,(HL)
0018 1E1A           LD E,1A
001A 50             LD D,B
001B 3EEF           LD A,EF
001D D398           OUT (98),A
001F E5             PUSH HL
0020 E5             PUSH HL
0021 E1             POP HL
0022 E1             POP HL
0023 00             NOP
0024 15             DEC D
0025 C21F80         JP NZ,$801F
0028 50             LD D,B
0029 3ECF           LD A,CF
002B D398           OUT (98),A
002D E5             PUSH HL
002E E5             PUSH HL
002F E1             POP HL
0030 E1             POP HL
0031 00             NOP
0032 15             DEC D
0033 C22D80         JP NZ,$802D
0036 1D             DEC E
0037 C21A80         JP NZ,$801A
003A C1             POP BC
003B D1             POP DE
003C E1             POP HL
003D F1             POP AF
003E C9             RET
003F 7F             LD A,A
0040 77             LD (HL),A
0041 71             LD (HL),C
0042 6A             LD L,D
0043 5F             LD E,A
0044 59             LD E,C
0045 54             LD D,H
0046 4F             LD C,A
0047 47             LD B,A
0048 43             LD B,E
0049 3F             CCF
004A 3B             DEC SP
004B 35             DEC (HL)
004C 322F2C         LD ($2C2F),A
004F 25             DEC H
0050 27             DAA
0051 2A4B38         LD HL,($384B)
0054 64             LD H,H
0055 23             INC HL
0056 212037         LD HL,$3720

拡張子は、zdasで作られたリストファイル(lst)の意味で、dlsにしました。

では念の為に、8080アセンブラで作られた、sound6.lstと比較してみましょう。
そのリストは[第73回]にありますが、下に再掲いたします。

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
              ;
800E F5       SNDSB:PUSH PSW
800F E5       	PUSH H
8010 D5       	PUSH D
8011 C5       	PUSH B
8012 213F80   	LXI H,SNDTBL
8015 85       	ADD L
8016 6F       	MOV L,A
8017 46       	MOV B,M
8018 1E1A     	MVI E,1A
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----
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----
8036 1D       	DCR E
8037 C21A80   	JNZ SNDS1
803A C1       	POP B
803B D1       	POP D
803C E1       	POP H
803D F1       	POP PSW
803E C9       	RET
              ;
              ; 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 

リストが長いので、比較しづらいかも知れませんが、よく見ていただきますと、どこかがおかしいことに気が付きませんでしょうか?

そうです。
オリジナルのプログラムは、アドレスが8000番地からはじまっています。
ところがそのプログラムをもとにして逆作成したプログラムリストのアドレスは0000からはじまっています。
これでは使い物になりません(じつは、そんなことはないのですけれど…。それについては、のちほど説明いたします)。

逆アセンブラには、人間が判断して加えてやらなければならない情報があるのです。
それがアドレスの情報です。

asm80.com(8080アセンブラ)やzasm.com(z80アセンブラ)で作られるバイナリファイルには、それがどのアドレスにloadされるべきかというアドレスの情報は含まれていません。
TK80モニタプログラムのLOAD、STOREで扱うシリアル入出力ファイルは、プログラムの先頭にそのアドレス情報が含まれています。
ND80ZVはその機能も使いますから、asm80.comやzasm.comではTK80モニタプログラムのためのバイナリファイルとして、通常のバイナリファイルの先頭にアドレス情報を付加したファイル(拡張子btk)も出力するようにしてあります。

しかしそのbtkファイルはあくまでTK80モニタプログラムのファイル形式です。
zdas.comはそのようなアドレス情報が含まれていない、つまりメモリの中から、任意のプログラム部分を切り取ってsaveしたバイナリコードだけのファイルを読み込むことを前提にしているのです。

当然のことながら、アドレスの情報がありませんから、0000からスタートする形で翻訳してしまうことになります。
なお、参考までに、オリジナルのsound6.binがND80ZVで実行されるときに、メモリの中にどのように読み込まれているのかをお見せすることにいたします。

>dm 8000,8056
8000  CD 47 02 3C CA 00 80 3D CD 0E 80 C3 00 80 F5 E5  ヘG.<ハ..=ヘ..テ....
8010  D5 C5 21 3F 80 85 6F 46 1E 1A 50 3E EF D3 98 E5  ユナ!?..oF..P>.モ..
8020  E5 E1 E1 00 15 C2 1F 80 50 3E CF D3 98 E5 E5 E1  .....ツ..P>マモ....
8030  E1 00 15 C2 2D 80 1D C2 1A 80 C1 D1 E1 F1 C9 7F  ...ツ-..ツ..チム..ノ
8040  77 71 6A 5F 59 54 4F 47 43 3F 3B 35 32 2F 2C 25  wqj_YTOGC?;52/,%
8050  27 2A 4B 38 64 23 21 CB 7F 0D 14 00 08 F2 24 00  '*K8d#!ヒ.....$.

sound6.binは上のメモリダンプリストの中の、バイナリデータの部分、CD 47 02 3C …というデータだけが記録されているファイルなのです。
ダンプリストの左にある8000、8010、…というアドレス情報は含まれていません。

それでは正しいリストにするにはどうすればよいのでしょうか?
それをこれからお見せするために、まずはさきほど作成されたファイルがもう一度zdas.comを実行することで上書きされてしまわないように、名前を変更しておきます。

実は、どうせ先に作成したファイルは使い物になりませんから(早トチリでした。決して使い物にならないわけではありませんでした。そのことにつきましては後ほどまたご説明いたします)、新しいファイルで上書きしてしまっても構わないのですけれど、そうするとこの説明で利用するつもりの材料が上書きされてしまって、都合が悪い、というだけの理由でした。

ren(rename)コマンドでファイル名を変更します。

念の為にdirコマンドで確認しました。

今度はzdas.comにアドレス情報をつけて再実行します。

zdas sound6.bin,8000[Enter]と入力しました。
そのように、プログラムが開始されるアドレスをパラメータとして与えることによって正しい逆アセンブルリスト、ソースプログラムファイルが作成されます。

それでは新しく作成されたファイルの中身を見てみましょう。
sound6.dtxです。

      ORG $8000
      Z0247=$0247
      Z2C2F=$2C2F
      Z384B=$384B
      ZFFD8=$FFD8
Z8000:CALL Z0247
      INC A
      JP Z,Z8000
      DEC A
      CALL Z800E
      JP Z8000
Z800E:PUSH AF
      PUSH HL
      PUSH DE
      PUSH BC
      LD HL,Z803F
      ADD A,L
      LD L,A
      LD B,(HL)
      LD E,1A
Z801A:LD D,B
      LD A,EF
      OUT (98),A
Z801F:PUSH HL
      PUSH HL
      POP HL
      POP HL
      NOP
      DEC D
      JP NZ,Z801F
      LD D,B
      LD A,CF
      OUT (98),A
Z802D:PUSH HL
      PUSH HL
      POP HL
      POP HL
      NOP
      DEC D
      JP NZ,Z802D
      DEC E
      JP NZ,Z801A
      POP BC
      POP DE
      POP HL
      POP AF
      RET
Z803F:LD A,A
      LD (HL),A
      LD (HL),C
      LD L,D
      LD E,A
      LD E,C
      LD D,H
      LD C,A
      LD B,A
      LD B,E
      CCF
      DEC SP
      DEC (HL)
      LD (Z2C2F),A
      DEC H
      DAA
      LD HL,(Z384B)
      LD H,H
      INC HL
      LD HL,ZFFD8

今度はうまく出来たようです。
sound6.dlsです。

8000 CD4702         CALL $0247
8003 3C             INC A
8004 CA0080         JP Z,$8000
8007 3D             DEC A
8008 CD0E80         CALL $800E
800B C30080         JP $8000
800E F5             PUSH AF
800F E5             PUSH HL
8010 D5             PUSH DE
8011 C5             PUSH BC
8012 213F80         LD HL,$803F
8015 85             ADD A,L
8016 6F             LD L,A
8017 46             LD B,(HL)
8018 1E1A           LD E,1A
801A 50             LD D,B
801B 3EEF           LD A,EF
801D D398           OUT (98),A
801F E5             PUSH HL
8020 E5             PUSH HL
8021 E1             POP HL
8022 E1             POP HL
8023 00             NOP
8024 15             DEC D
8025 C21F80         JP NZ,$801F
8028 50             LD D,B
8029 3ECF           LD A,CF
802B D398           OUT (98),A
802D E5             PUSH HL
802E E5             PUSH HL
802F E1             POP HL
8030 E1             POP HL
8031 00             NOP
8032 15             DEC D
8033 C22D80         JP NZ,$802D
8036 1D             DEC E
8037 C21A80         JP NZ,$801A
803A C1             POP BC
803B D1             POP DE
803C E1             POP HL
803D F1             POP AF
803E C9             RET
803F 7F             LD A,A
8040 77             LD (HL),A
8041 71             LD (HL),C
8042 6A             LD L,D
8043 5F             LD E,A
8044 59             LD E,C
8045 54             LD D,H
8046 4F             LD C,A
8047 47             LD B,A
8048 43             LD B,E
8049 3F             CCF
804A 3B             DEC SP
804B 35             DEC (HL)
804C 322F2C         LD ($2C2F),A
804F 25             DEC H
8050 27             DAA
8051 2A4B38         LD HL,($384B)
8054 64             LD H,H
8055 23             INC HL
8056 21D8FF         LD HL,$FFD8

今回作成された2つのリストを、さきほどお見せしたオリジナルのsound6.lstと比べてみてください。
注目していただきたい点が2つあります。
sound6.dtxでは、ジャンプ命令やコール命令の飛び先のアドレス位置にラベルが置かれています。
それからワークアドレスと思われるアドレスやこのプログラム範囲の外のアドレスをアクセスしているところも、ラベル、変数としてプログラムの先頭に列記しています。
もちろん人間がつけるような意味を含んだラベルをつけることはできませんから、アドレスの前にZを付加しただけのラベルにしています。
でもなかなかに賢いプログラムだとは思いませんでしょうか?

さて、もう1点は、プログラムの後半の部分です。
アドレス803Fから後ろの部分です。
ここには音階テーブルデータが置かれています。
マシン語の命令コードではありません。
でも逆アセンブラプログラムにはそんなことは判断できません。
データであろうと、なんであろうと、ひたすらZ80のマシン語命令コードだと解釈して無理やりニーモニックに翻訳してしまいます。
その結果はご覧のように、一応Z80の命令が並んでいますけれど、当然意味不明のデタラメなプログラムになってしまっています。

果たして、こんなプログラムがZ80アセンブラのソースプログラムとして通用するのでしょうか?
というところで本日は時間がなくなってしまいましたので、この続きは次回にすることに致します。
CPUをつくろう!第564回(2010.7.26upload)を再編集

ワンボードマイコンをつくろう![第79回]
2011.7.1upload

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