Z80アセンブラプログラミング |
 
実行環境 |
メモリモニタ を利用します、 Z80は 図1 のように接続されています。 メモリモニタは BUSREQ でZ80とメモリを切り離します。 また RESET でZ80の初期化も行います。
図1:構成 |
![]() |
 
プログラムの作成 |
アセンブラでプログラムを作るのに次のフリーソフトのアセンブラが勧められます。
最終的にはプログラムをインテルへクスファイルにすればメモリモニタの
HEXコマンド
でメモリに展開できます。
CP/MのアセンブラでCOMファイルのときは
バイナリファイル→HEXファイル変換ツール
を使ってください。
 
プログラムの実行 |
Z80は初期化すると0番地から実行を始めます。
そのときそこにプログラムがなければZ80は暴走してしまいます。
メモリモニタの
HEXコマンド
がメモリに書き込みしている間はメモリはZ80から切り離されていますが
書き込みが終わるとZ80に接続されます。
このときに暴走しているZ80にプログラムを壊される可能性があります。
CP/Mアダプタは
0〜100h番地
と
F000〜FFFFh番地
を使いますが事前に
EEPROM
に書き込んでおけば電源投入後にはZ80ではCP/Mアダプタが実行されてい
るので前期以外へのメモリ番地の書き込みは支障なく行えます。
CP/Mアダプタは
GOコマンド
を実装していますので
GO 番地
とすれば番地で指定した位置にあるプログラムを実行できます。
プログラムは最後に
0番地
への分岐を実行すればCP/Mアダプタに実行を戻せます。
 
プログラム |
 
メモリに書き込む |
ORG 100H 0100: 3E 55 LD A,55H 0102: 32 00 80 LD (8000H),A 0105: C3 00 00 JP 0 END |
  |
レジスタに値を設置して直接番地を指定して書き込みます。
>D 8000 >8000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >8010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >8020 00 00 00 00 00 00 00 > > >GO 100 >CP/M ADAPTER Ver 0.1a >D 8000 >8000 55 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >8010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >8020 00 00 00 00 00 00 00 > > |
  |
プログラムの実行後の8000h番地に55hが書き込まれています。
 
メモリを読み出す |
ORG 100H 0100: 3A 00 80 LD A,(8000H) 0103: 32 01 80 LD (8001H),A 0106: C3 00 00 JP 0 END |
  |
先のプログラムで書き込んだ8000h番地の値を読み出して8001h番地に書き込みます。
>GO 100 >CP/M ADAPTER Ver 0.1a >D 8000 8000 55 55 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8020 00 00 00 00 00 00 00 00 00 > > |
  |
プログラムの実行後に8001h番地に8000h番地と同じ値が書き込まれています。
Z80では LD (メモリ),(メモリ) の命令はありません。
 
IO操作 |
通信ポートを利用してIO操作のプログラムを作ってみます。 CNTP のビット1が1のときは送信中なのでこのビットが0のときに SENDP に送信データを書き込むとメモリモニタが送信してくれます。
![]() |
IO操作も専用の IN や OUT の命令を使うだけでメモリ操作と似ています。
![]() |
STRING から始まった文字列を1文字ずつ読み出して 0 で無ければ送信します、 0 なら文字列の終端に達したのでプログラムを終わらせます。
 
システムコール |
XASM でも CP/M のプログラムを作ることができます。 コンソールへ1文字を送るシステムコールを使って文字列を送るプログラムを書いてみます。 システムコールは次の手順で発行します。
![]() |
![]() |
![]() |
 
8ビット足し算 |
Z80は8ビットの加算の命令を持っています。 メモリにある2個の8ビットの値を加算して結果をメモリに書き込みます。 プログラムはメモリの値をレジスタに記憶してそのレジスタを加算する書き方にしました。 8ビット同士の加算結果は9ビットです、9ビット目は フラグレジスタ の C に記憶されます。
![]() |
10進数で 12 と 34 を加算しています。 結果は 202H 番地から書き込まれています。 フラグCは第0ビットですから9ビット目は 0 です。
![]() |
NAを10進数で 255 にNBを 1 にして同プログラムを実行するとNA+NB=256ですが16進数では 100H になります。 赤枠 で示した部分がフラグの値ですがフラグ C が 1 になっています。
![]() |
 
16ビット足し算 |
Z80は16ビットの加算の命令を持っています。 メモリにある2個の16ビットの値を加算して結果をメモリに書き込みます。 プログラムはメモリの値をレジスタに記憶してそのレジスタを加算する書き方にしました。 16ビット同士の加算結果は17ビットです、17ビット目は フラグレジスタ の C に記憶されます。
![]() |
10進数で 1234 と 5678 を加算しています。 結果は 204H 番地から書き込まれています。 フラグCは第0ビットですから17ビット目は 0 です。
![]() |
NAを10進数で 65535 にNBを 1 にして同プログラムを実行するとNA+NB=65536ですが16進数では 10000H になります。 赤枠 で示した部分がフラグの値ですがフラグ C が 1 になっています。
 
32ビット足し算 |
Z80は16ビットの加算命令を持っているので32ビットの加算においても16ビットの加算を2回行えば32ビットの計算ができます。 基本的にはいくらビット数が多いときでもそれに必要な計算を繰り返すことで結果は求められます。
![]() |
12345678+87654321=99999999 は16進数で 5F5E0FFH になります。
![]() |
 
8ビット引き算 |
Z80は8ビットの減算の命令を持っています。 メモリにある2個の8ビットの値を減算して結果をメモリに書き込みます。 プログラムはメモリの値をレジスタに記憶してそのレジスタを減算する書き方にしました。 8ビット同士の減算結果は9ビットです、9ビット目は フラグレジスタ の C に記憶されます。
![]() |
引き算は A-B の場合はBを補数にすると A+(-B) の計算と同じなので論理的にはBの補数を加算することになります。 フラグCの値は9ビット目が反転されたものですがAがBよりも小さくて桁借りがあったことを示します。
![]() |
 
16ビット引き算 |
Z80は16ビットの減算の命令を持っています。 メモリにある2個の16ビットの値を減算して結果をメモリに書き込みます。 プログラムはメモリの値をレジスタに記憶してそのレジスタを減算する書き方にしました。 16ビット同士の減算結果は17ビットです、17ビット目は フラグレジスタ の C に記憶されます。
![]() |
![]() |
 
32ビット引き算 |
Z80は16ビットの減算命令を持っているので32ビットの減算においても16ビットの減算を2回行えば32ビットの計算ができます。 基本的にはいくらビット数が多いときでもそれに必要な計算を繰り返すことで結果は求められます。
![]() |
87654321-12345678=75308643 は16進数で 47D1E63H になります。
![]() |
 
8ビット掛け算 |
Z80は乗算の命令を持っていませんので加算を繰り返して乗算の結果を得ます。 下のプログラムは筆算の計算手順と同じことを2進数で行っています。
![]() |
12×34=408 は16進数で 198 です。
![]() |
 
16ビット掛け算 |
![]() ![]() |
1234×5678=7006652 は16進数で 6AE9BC です。
![]() |
 
32ビット掛け算 |
![]() ![]() |
12345678×87654321=1082152022374638 は16進数で 3D83626E2F8EE です。
![]() |
 
8ビット割り算 |
![]() |
234÷12=19余り6 は16進数で 13H余り6H です。
![]() |
 
16ビット割り算 |
![]() ![]() |
56789÷1234=46余り25 は16進数で 2EH余り19H です。
![]() |
 
32ビット割り算 |
![]() ![]() |
987654321÷123456=8000余り6321 は16進数で 1F40H余り18B1H です。
![]() |
 
文字列受信 |
通信プログラムを端末として文字列を通信し改行までをメモリに蓄えるプログラムです。 文字列は SIZE で示した文字数を超えた場合は改行と同じくプログラムを終わらせます。 制御文字 では改行の 0DH と後退の 08H が使えます。
![]() ![]() |
![]() |
 
10進数の文字列をBCDに変換 |
10進数の文字列の個数は2桁で1バイトに数値化するので偶数個にします。
![]() |
![]() |
 
10進数の文字列を数値に変換 |
10進数の文字列を数値に変換します。
10進数なので文字コードは
0〜9
が
30H〜39H
ですから
30H
を引くと一桁の10進数の数値が取り出せます。
これを過去に取り出した分を10倍してから加算することを終了文字まで連続していくと数値化できます。
10倍するプログラムはサブルーチンにしました。
計算方法は
8倍+2倍=10倍
です8倍は上位に3ビットの移動した値で2倍は上位に1ビット移動した値です。
![]() ![]() |
10進数の 123456 は16進数で 1E240H です。
![]() |
 
16進数の文字列を数値に変換 |
16進数の文字列を数値に変換します。 16進数は 0〜9 と A〜F と a〜f の文字を使いますこれ以外の文字があった場合はプログラムを終了します。 16進数の文字列の先頭から1文字ずつ数値化してこれを過去に取り出した分を16倍してから加算することを終了文字まで連続していくと数値化できます。 16倍は上位に4ビットの移動した値です。
![]() ![]() |
![]() |
 
2進数の文字列を数値に変換 |
2進数の文字列を数値に変換します。 2進数は 0 と 1 の文字を使いますこれ以外の文字があった場合はプログラムを終了します。 2進数の文字列の先頭から1文字ずつ数値化してこれを過去に取り出した分を2倍してから加算することを終了文字まで連続していくと数値化できます。 2倍は上位に1ビットの移動した値です。
![]() ![]() |
2進数の 10100101 は16進数で A5H です。
![]() |
 
数値を10進数の文字列に変換 |
数値を10で割って余りを文字化します、その除数を数値にして除数が0になるまで繰り返すと文字化できます。 プログラムでは文字化を完了後に送信してみました。
![]() ![]() ![]() |
![]() |
 
数値を16進数の文字列に変換 |
数値を16で割って余りを文字化します、その除数を数値にして除数が0になるまで繰り返すと文字化できます。 プログラムでは文字化を完了後に送信してみました。
![]() ![]() ![]() |
![]() |
 
数値を2進数の文字列に変換 |
数値を2で割って余りを文字化します、その除数を数値にして除数が0になるまで繰り返すと文字化できます。 プログラムでは文字化を完了後に送信してみました。
![]() ![]() |
![]() |
 
数値を大きさで並び替える |
11個のバイト値を比較して大きい方を下位の番地に入れ替えます。
![]() |
![]() |