2019/04/26(金) [n年前の日記]
#1 [pc] Z80のアセンブラでHello Worldをしてみたり
Z80のアセンブラで何かしらを書いて、アセンブルしてバイナリを作って、MZ-700 のエミュレータ上で動かす、といった作業が実際にできるのかどうか気になったので、少し調べて試してみたり。環境は Windows10 x64。
◎ 必要なもの。 :
必要になるのは、
MZ-700 のエミュレータは、以前は MZ700WIN が入手できたけど、もはや入手が難しいので、EmuZ-700 を利用させてもらうことにした。
_EmuZ-700 / EmuZ-800 / EmuZ-1500 謎WIPページ
_Common Source Code Project
binary.zip をダウンロードして解凍すると、100種類以上のレトロPCエミュレータが入ってるので…。mz700.txt と binary/mz700.exe を、任意のフォルダにコピーする。この mz700.exe が、EmuZ-700。
mz700.exe を実行するためには、IPL.ROM と FONT.ROM が必要になる。
IPL.ROM は、MZ-700/80K/C/1200用互換モニタ MZ-NEW MONITOR を利用させてもらう。
_MZ-NEW MONITOR 使用許諾条件
_MZ-NEW MONITOR 使用許諾条件 (Internet Archive)
(※ 2019/04/28追記。上記リンク先が404になったので、Internet Archive のページを追加。)
mz_newmon.zip をDLして解凍すると、ROMSフォルダの中に、NEWMON.ROM、NEWMON7.ROM があるので…。MZ-700版の NEWMON7.ROM を mz700.exe と同じフォルダにコピーして、IPL.ROM にリネームする。
FONT.ROM は、以下のページを参考にして作成。
_MZ-700WIN フォントデータの作成
MKFNT.zip をDLして解凍。DOS窓を開いて、解凍したフォルダをカレントディレクトリにして、以下を実行。
この状態で、mz700.exe を実行すると、EmuZ-700 が起動する。
これでエミュレータは動いた。ありがたや。
次に、Windows上で利用できる Z80アセンブラを入手する。今回は、Z80AS を利用させてもらう。
_We Love MZ-700
上記リンク先ページの真ん中あたりで Z80AS が公開されているので、z80as_012.zip をDL。解凍すると、中に z80as.exe というファイルがあるので、パスが通った場所にコピーする。
これで環境は整った。
- MZ-700 エミュレータ
- MZ-700 モニタROM (IPL.ROM)
- MZ-700 フォントROM (FONT.ROM)
- Z80用のアセンブラ(Windows上で動くもの)
MZ-700 のエミュレータは、以前は MZ700WIN が入手できたけど、もはや入手が難しいので、EmuZ-700 を利用させてもらうことにした。
_EmuZ-700 / EmuZ-800 / EmuZ-1500 謎WIPページ
_Common Source Code Project
binary.zip をダウンロードして解凍すると、100種類以上のレトロPCエミュレータが入ってるので…。mz700.txt と binary/mz700.exe を、任意のフォルダにコピーする。この mz700.exe が、EmuZ-700。
mz700.exe を実行するためには、IPL.ROM と FONT.ROM が必要になる。
IPL.ROM は、MZ-700/80K/C/1200用互換モニタ MZ-NEW MONITOR を利用させてもらう。
_MZ-NEW MONITOR 使用許諾条件 (Internet Archive)
(※ 2019/04/28追記。上記リンク先が404になったので、Internet Archive のページを追加。)
mz_newmon.zip をDLして解凍すると、ROMSフォルダの中に、NEWMON.ROM、NEWMON7.ROM があるので…。MZ-700版の NEWMON7.ROM を mz700.exe と同じフォルダにコピーして、IPL.ROM にリネームする。
FONT.ROM は、以下のページを参考にして作成。
_MZ-700WIN フォントデータの作成
MKFNT.zip をDLして解凍。DOS窓を開いて、解凍したフォルダをカレントディレクトリにして、以下を実行。
mkfnt mz700fonMZ700FON.DAT というファイルができるから、mz700.exe と同じフォルダにコピーして、FONT.ROM にリネームする。
この状態で、mz700.exe を実行すると、EmuZ-700 が起動する。
これでエミュレータは動いた。ありがたや。
次に、Windows上で利用できる Z80アセンブラを入手する。今回は、Z80AS を利用させてもらう。
_We Love MZ-700
上記リンク先ページの真ん中あたりで Z80AS が公開されているので、z80as_012.zip をDL。解凍すると、中に z80as.exe というファイルがあるので、パスが通った場所にコピーする。
これで環境は整った。
◎ Hello wroldのソースを書く。 :
まずはとにかく Hello world だろう…。ということで、画面に「HELLO WORLD」と表示するだけのソースを書いてみる。
適当なエディタで、Z80向けのアセンブラソースを書く。アセンブラソースの拡張子は .asm にしておけばいいのだろうか。
今回は、以下のソースを参考に書いてみたり。ありがたや。
_marukun700/tinyimas700_v1_src: TinyIMAS for MZ-700 source
_tinyimas700_v1_src/tinyimas.asm at master - marukun700/tinyimas700_v1_src
_helloasm.asm
簡単に説明しておくと…。
その他の仕様は、Z80AS のドキュメントを参照のこと。
_Z80 Abusolute Assembler 'Z80AS'
Z80のニーモニック(命令?)については、以下が参考になりそう。
_Z-80の命令の簡単な解説(1)
_Z-80の命令の簡単な解説(2)
_8ビットCPU Z80 (命令セット)
_Z80 Code Refference -
_Z80 MNemonic Refference -
さて。MZ-700 のモニタROMには、改行をしてくれるサブルーチンや、メッセージを表示してくれるサブルーチンが用意されてるので、今回はソレを使わせてもらう。前述のソース内では、CALL LETNL や CALL MSG が、それらのサブルーチンを呼び出している行。
モニタROMにどんなサブルーチンが用意されているかは、以下を眺めればおおよそ分かる。たぶん。
_1Z-009Amonitor_note.pdf
_SP-1002 - Enri's Home PAGE (mz-80K)
1Z-009A が、MZ-700のモニタの型番で、SP-1002 が、MZ-80K のモニタの型番。MZ-700 のモニタは、MZ-80K のモニタと中身が完全に同じではないけれど、サブルーチンを呼び出す際のアドレスが合わせてあったりするので、ある程度は互換性がある。
プログラム側のメインルーチンで RET が呼ばれると、モニタの処理に戻ってくる模様。
適当なエディタで、Z80向けのアセンブラソースを書く。アセンブラソースの拡張子は .asm にしておけばいいのだろうか。
今回は、以下のソースを参考に書いてみたり。ありがたや。
_marukun700/tinyimas700_v1_src: TinyIMAS for MZ-700 source
_tinyimas700_v1_src/tinyimas.asm at master - marukun700/tinyimas700_v1_src
_helloasm.asm
; Display "HELLO WORLD" in MZ-700 ; define monitor subroutine LETNL EQU 0006h MSG EQU 0015h ORG 1200h ; start CALL LETNL ; newline LD DE,MSGDT0 CALL MSG ; display "HELLO WORLD" CALL LETNL LD DE,MSGDT1 ; display "IN MZ-700" CALL MSG RET MSGDT0: DB "- HELLO WORLD -" DB 0Dh MSGDT1: DB "- IN MZ-700 -" DB 0Dh END
簡単に説明しておくと…。
- ORG 1200h で、「このプログラムは 1200h番地から始まるプログラムだよ」と指定する。
- MZ-80K や MZ-700 は、1200h番地以降にユーザの作ったプログラムを読み込むので、ほとんどの場合、ORG 1200h を最初に書くことになるはず。
- xxx EQU yyyyh で、xxx というシンボルに、yyyyh という数値を定義する。
- ソースの最後には、END と書いておく。
- xxxx: はラベル。
- DB "HOGE" で、HOGE をASCIIコードにしたバイナリ列を記述できる。
- DB 01h,02h,03h と書けば、01h,02h,03h というバイナリを記述できる。
- 16進数を記述する時は、0003h とか 0D000h のように、最後に h をつける。
その他の仕様は、Z80AS のドキュメントを参照のこと。
_Z80 Abusolute Assembler 'Z80AS'
Z80のニーモニック(命令?)については、以下が参考になりそう。
_Z-80の命令の簡単な解説(1)
_Z-80の命令の簡単な解説(2)
_8ビットCPU Z80 (命令セット)
_Z80 Code Refference -
_Z80 MNemonic Refference -
さて。MZ-700 のモニタROMには、改行をしてくれるサブルーチンや、メッセージを表示してくれるサブルーチンが用意されてるので、今回はソレを使わせてもらう。前述のソース内では、CALL LETNL や CALL MSG が、それらのサブルーチンを呼び出している行。
モニタROMにどんなサブルーチンが用意されているかは、以下を眺めればおおよそ分かる。たぶん。
_1Z-009Amonitor_note.pdf
_SP-1002 - Enri's Home PAGE (mz-80K)
1Z-009A が、MZ-700のモニタの型番で、SP-1002 が、MZ-80K のモニタの型番。MZ-700 のモニタは、MZ-80K のモニタと中身が完全に同じではないけれど、サブルーチンを呼び出す際のアドレスが合わせてあったりするので、ある程度は互換性がある。
プログラム側のメインルーチンで RET が呼ばれると、モニタの処理に戻ってくる模様。
◎ アセンブルする。 :
ソースを書いたのでアセンブルする。DOS窓上で以下を打つ。
Z80の各命令が、Z80用のバイナリに変換されて並んでいることが分かる。アセンブルはできているっぽい。
このままだと、MZ-700のエミュレータでは読み込めないので、.mzt 形式(カセットテープ相当のファイル)として出力させる。
Z80AS は、-m オプションをつけることで、アセンブル結果を .mzt 形式にして出力することができる。
MZ-80系の場合、テープに保存する際のファイル名は英数大文字にしておいたほうが良さそう。元々は小文字が存在しないPCだったようだし…。
z80as helloasm.asmhelloasm.bin という、Z80用のバイナリファイルができた。バイナリエディタの類で中身を覗いてみると…。
Z80の各命令が、Z80用のバイナリに変換されて並んでいることが分かる。アセンブルはできているっぽい。
このままだと、MZ-700のエミュレータでは読み込めないので、.mzt 形式(カセットテープ相当のファイル)として出力させる。
z80as -mHELLOASM helloasm.asmhelloasm.mzt が出力された。
Z80AS は、-m オプションをつけることで、アセンブル結果を .mzt 形式にして出力することができる。
- -mHOGE とつければ、テープに保存されたファイルのファイル名は「HOGE」になるし、
- -mFUGA とつければ、テープに保存されたファイルのファイル名は「FUGA」になる。
MZ-80系の場合、テープに保存する際のファイル名は英数大文字にしておいたほうが良さそう。元々は小文字が存在しないPCだったようだし…。
◎ エミュレータ上で実行。 :
MZ-700のエミュレータ、EmuZ-700 上で、先ほどアセンブルして出来上がったファイルを読み込んで実行してみる。
EmuZ-700 を起動すると、
メニューの、CMT → Play を選択。ファイル選択ダイアログが開くので、先ほど生成した helloasm.mzt を選択してやる。実機であれば、データレコーダにカセットテープを入れて、データレコーダのPlayボタンを押した状態に相当する。
EmuZ-700 画面下部のステータスバーに、テープの読み込み状況が表示される。ある程度進むと、画面上に、「LO. HELLOASM」と表示される。「テープに入っているファイル名(HELLOASM)は認識したよ」「このまま読み込みを続けるよ」ということ。
ロードが終わると、読み込んだプログラムが自動で実行される。
「HELLO WORLD」が表示された。動いたっぽい。
ちなみに、再度実行したい時は、
EmuZ-700 を起動すると、
MZ-700 *と表示されて入力待ちになる。L[Enter] と打ち込んで、「テープからロードせよ」と指示する。(L は LOAD の L。)
メニューの、CMT → Play を選択。ファイル選択ダイアログが開くので、先ほど生成した helloasm.mzt を選択してやる。実機であれば、データレコーダにカセットテープを入れて、データレコーダのPlayボタンを押した状態に相当する。
EmuZ-700 画面下部のステータスバーに、テープの読み込み状況が表示される。ある程度進むと、画面上に、「LO. HELLOASM」と表示される。「テープに入っているファイル名(HELLOASM)は認識したよ」「このまま読み込みを続けるよ」ということ。
ロードが終わると、読み込んだプログラムが自動で実行される。
「HELLO WORLD」が表示された。動いたっぽい。
ちなみに、再度実行したい時は、
GOTO$1200と打ち込む。1200h番地にジャンプするらしい。
◎ 別のプログラムを書いてみる。 :
調子に乗って別のプログラムを書いてみる。画面全体を何度も書き換える処理を書いてみよう…。
_fillscrn.asm
_tinyimas700_v1_src/tinyimas.asm を参考にさせてもらいました。ありがたや。
実行結果は以下。
Qキーか SHIFT+BREAKキーで処理を抜ける。
一応簡単な説明を。MZ-700 は、0D000h からVRAMが、0D800hからアトリビュートVRAMが割り当てられているので、そのあたりに何かを書き込めば、文字を表示したり、色を変更したり等ができる。
_Programming MZ-700: Display
また、MZ-700は、1文字 8x8ドット、40x25文字のキャラクタ画面しか持ってないので、ドット単位のスクロールなんてできないのだけど。文字の中に1ドットずつずれてる横線があるので、今回はソレを使って画面を埋め尽くすことで、ドット単位のスクロールをしているような気分だけをほのかに味わっているという、なんだかちょっと悲しさが漂うプログラムだったりもする。
ということで、Z80のアセンブラでソースを書いて、アセンブルして、MZ-700のエミュレータ上で動かせることが確認できた。とメモ。
_fillscrn.asm
; Fill screen in MZ-700 ; ; EXIT : Q key or SHIFT + BREAK GETKY EQU 001Bh BRKEY EQU 001Eh ?BLNK EQU 0DA6h VRAM EQU 0D000h VRAMA EQU 0D800h ORG 1200h ; start ; attribute VRAM fill LD A,70h LD HL,VRAMA LD BC,40*25 CALL MEMFIL LD IX,CHRLIST LD A,(IX) LOOP0: CALL ?BLNK ; wait VBLANK LD HL,VRAM LD BC,40*25 CALL MEMFIL ; fill screen CALL GETKY CP 81 ; check ASCII 'Q' Key JP Z,SCRCLR CALL BRKEY ; check SHIFT + BREAK JP Z,SCRCLR INC IX LD A,(IX) ; get new display code CP 0 JR NZ,LOOP0 LD IX,CHRLIST LD A,(IX) JR LOOP0 SCRCLR: LD A,0 LD HL,VRAM LD BC,40*25 CALL MEMFIL ; screen clear RET MEMFIL: LD D,H LD E,L INC DE DEC BC LD (HL),A LDIR RET CHRLIST: DB 70h,30h,74h,34h,78h,38h,7Ch,3Ch DB 00 END
z80as -mFILLSCRN fillscrn.asm
_tinyimas700_v1_src/tinyimas.asm を参考にさせてもらいました。ありがたや。
実行結果は以下。
Qキーか SHIFT+BREAKキーで処理を抜ける。
一応簡単な説明を。MZ-700 は、0D000h からVRAMが、0D800hからアトリビュートVRAMが割り当てられているので、そのあたりに何かを書き込めば、文字を表示したり、色を変更したり等ができる。
_Programming MZ-700: Display
また、MZ-700は、1文字 8x8ドット、40x25文字のキャラクタ画面しか持ってないので、ドット単位のスクロールなんてできないのだけど。文字の中に1ドットずつずれてる横線があるので、今回はソレを使って画面を埋め尽くすことで、ドット単位のスクロールをしているような気分だけをほのかに味わっているという、なんだかちょっと悲しさが漂うプログラムだったりもする。
ということで、Z80のアセンブラでソースを書いて、アセンブルして、MZ-700のエミュレータ上で動かせることが確認できた。とメモ。
◎ EmuZ-700について少しメモ。 :
EmuZ-700 は、実機動作の再現度を高めたエミュレータなので、実機と同程度の速度でテープ(.mzt)からプログラムを読み込むため、プログラムのロードに数分かかったりするのだけれど。
メニューの、Control → Full Speed にチェックを入れると、動作速度が上がってテープの読み込み時間も短くなることに今頃気づいた。とメモ。もちろん、ロード後は、件の項目のチェックを外さないとアレだけど。
メニューの、Control → Full Speed にチェックを入れると、動作速度が上がってテープの読み込み時間も短くなることに今頃気づいた。とメモ。もちろん、ロード後は、件の項目のチェックを外さないとアレだけど。
[ ツッコむ ]
#2 [pc][windows] Z80のアセンブラソースを書くエディタを物色
Z80用のアセンブラソースを書けそうなエディタを探したり。環境は Windows10 x64。
◎ Vsiaul Studio Code + 拡張 :
Microsoft が公開している Visual Studio Code に、Z80アセンブラ用の拡張を追加すると、イイ感じになる…と以下の記事で知った。
_Visual Studio CodeでZ80の開発環境を作るまで - Qiita
_Visual Studio Code - Code Editing. Redefined
_Z80 Assembly - Visual Studio Marketplace
試してみたところ、たしかにイイ感じ。コレでいいんじゃないかな…。
_Visual Studio CodeでZ80の開発環境を作るまで - Qiita
_Visual Studio Code - Code Editing. Redefined
_Z80 Assembly - Visual Studio Marketplace
試してみたところ、たしかにイイ感じ。コレでいいんじゃないかな…。
◎ xyzzy + asm-mode :
自分は普段、xyzzy というエディタを使っているので、xyzzy でも書けないものかなと。
ググってみたところ、asm-mode を公開されている方が居ると知り。ありがたや。基本的には RISC CPU に合わせて書かれたモードらしい。
_ムトー研究所【asm-mode for xyzzy】
更に、以下のページで、asm-mode のキーワードファイルを増やしたり切り替えたりする lisp があることを知り、利用させてもらったり。
_私のsiteinit.l #xyzzy
Asm-Z80 というファイルも必要になるっぽいけど…。とりあえず今回は自分で作ってみたり。まだ足りてないキーワードがありそうだけど。
_Asm-Z80
それと、Z80のアセンブラソースは、コメント文が「;」で始まるので、以下の設定も ~/.xyzzy に追加。これで「;」以降はコメントとして表示されるようになった。
ググってみたところ、asm-mode を公開されている方が居ると知り。ありがたや。基本的には RISC CPU に合わせて書かれたモードらしい。
_ムトー研究所【asm-mode for xyzzy】
- asm.0.02.lzh と asm-keywords.lzh をDLして解凍。
- 中に入ってる asm-mode.l を xyzzyインストールフォルダ/site-lisp/ にコピー。
- Asm、及び Asm-* ファイルを、xyzzyインストールフォルダ/etc/ にコピー。
- ~/.xyzzy に設定を追加。
更に、以下のページで、asm-mode のキーワードファイルを増やしたり切り替えたりする lisp があることを知り、利用させてもらったり。
_私のsiteinit.l #xyzzy
Asm-Z80 というファイルも必要になるっぽいけど…。とりあえず今回は自分で作ってみたり。まだ足りてないキーワードがありそうだけど。
_Asm-Z80
それと、Z80のアセンブラソースは、コメント文が「;」で始まるので、以下の設定も ~/.xyzzy に追加。これで「;」以降はコメントとして表示されるようになった。
(set-syntax-start-comment *asm-mode-syntax-table* #\;)
[ ツッコむ ]
以上、1 日分です。