電子計算機工学 I

NAGASAKA Yasunori

2003/04/04

http://edu.isc.chubu.ac.jp/naga/index.html で公開中

1   はじめに
 1.1   目標
 1.2   コンピュータの分類
 1.3   マイクロプロセッサの歴史

2   Z80アーキテクチャ
 2.1   CPU の内部構成
  2.1.1   各部の機能
  2.1.2   レジスタの役割による分類
  2.1.3   PC における命令の番地計算の特徴
 2.2   スタック
  2.2.1   概要
  2.2.2   スタックの使用例
  2.2.3   練習問題
 2.3   プロセッサの動作原理
  2.3.1   CPU の動作例
  2.3.2   練習問題

3   インタフェース信号とタイミング
 3.1   インタフェース信号
  3.1.1   各インタフェース信号の機能
 3.2   DMA
  3.2.1   DMA を使わない、使えない場合
  3.2.2   DMA を使った場合
 3.3   CPU の動作タイミング
 3.4   命令実行サイクルと制御信号の変化
  3.4.1   M1 サイクル, フェッチサイクル
  3.4.2   主記憶データの読み出し/書き込みサイクル
  3.4.3   入出力装置のデータの読み出し/書き込みサイクル
  3.4.4   バス要求及び確認サイクル

4   アドレス方式
 4.1   固有アドレス指定形式
 4.2   直接数値指定形式
 4.3   拡張直接数値指定形式
 4.4   レジスタアドレス指定形式
 4.5   レジスタ間接アドレス指定形式
 4.6   拡張アドレス指定形式
 4.7   ページ 0 アドレス指定形式
 4.8   相対アドレス指定形式
  4.8.1   相対アドレスと絶対アドレスの違い
  4.8.2   プログラムの再配置
 4.9   インデックスアドレス指定形式
 4.10   ビット指定形式
 4.11   練習問題

5   命令の種類
 5.1   8 ビットのデータ移動
 5.2   16 ビットのデータ移動
 5.3   交換、ブロック転送、検索
  5.3.1   交換命令
  5.3.2   ブロック転送命令
  5.3.3   検索命令
 5.4   8 ビット算術論理演算
 5.5   汎用算術演算、CPU 制御
 5.6   16 ビット算術演算
 5.7   循環、桁移動
 5.8   ビット操作、判定
 5.9   飛び越し
  5.9.1   絶対アドレス指定
  5.9.2   相対アドレス指定
 5.10   サブルーチン接続、戻り
 5.11   入出力
 5.12   練習問題
  5.12.1  
  5.12.2  

6   フラグと算術演算
 6.1   ゼロフラグ Z
 6.2   符号フラグ S
 6.3   桁上げフラグ CY
 6.4   パリティ / あふれフラグ P/V
 6.5   練習問題

7   Z80 用アセンブリ言語
 7.1   記述方法
  7.1.1   プログラムの書き方
 7.2   使用できる文字
 7.3   定数の表現
 7.4   ラベル記述のルール
 7.5   予約語
 7.6   オペランドとして書ける内容
 7.7   疑似命令
 7.8   アセンブリ言語によるプログラミングの例
  7.8.1   DATA1 番地から MAX 個のデータを足して RESULT に記録する
  7.8.2   DATA1 番地のデータを 4 倍して RESULT に記録する
  7.8.3   (DATA1) と (DATA2) の大きい方を RESULT に記録する
  7.8.4   DATA1 × DATA2 を求める
 7.9   ハンドアセンブルの方法
 7.10   練習問題



1   はじめに


1.1   目標

標準的な 8 ビットマイクロプロセッサである Z80 の内部構造、機械語、アセンブリ言語 の学習を通して、コンピュータの心臓部である CPU (Central Processing Unit, 中央処理装置) の構造、動作原理、プログラミングを理解する。

1.2   コンピュータの分類



1.3   マイクロプロセッサの歴史


インテル、ザイログ、モトローラのプロセッサ

ビット数 インテル ザイログ モトローラ
4 4004 - -
8 8008 - -
- 8080 Z80 6800
- 8085 - 6809
16 8086 Z800 68000
- 80186 - -
- 80286 - 68010
32 80386 Z8000 68020
- i486 (80486) - 68030
- Pentium (80586) - 68040
- Pentium Pro (80686) - 68060
- Pentium II, III - PowerPC
- Pentium 4 - -

現在のパーソナルコンピュータは安価だが、一昔前の大型コンピュータよりも 演算性能が高い。

4, 8 bit マイクロプロセッサは、コンピュータシステムとしては使われなくなったが、 制御用のマイクロコンピュータとして、 電気機器などに組み込まれて現在でも広く利用されている。

プロセッサの基本的な動作原理は 4 bit CPU でも、32 bit CPU でもほとんど同じである。 よって 8 bit CPU の Z80 についての知識でも、 最近の高性能な 32 bit CPU の機能の理解に役立つ。

4, 8, 16, 32, 64 bit プロセッサの違い
→ プロセッサ内部のレジスタのビット数の違い
→ 扱える数値 (整数) の大きさが異なる。

CPU のレジスタ長と直接扱える数値の範囲

ビット数 扱える数値の範囲
4 24 = 16
8 28 = 256
16 216 = 65536
32 232 = 4.295 × 109
64 264 = (232)2





2   Z80アーキテクチャ


2.1   CPU の内部構成



内部構成


2.1.1   各部の機能


命令数の変化

プロセッサ 命令数
8008 48
8080 +30
Z80 +80
未使用 90



2.1.2   レジスタの役割による分類



レジスタ


(ヒント):リフレッシュとは : DRAM, Dynamic RAM はコンデンサに蓄えた電荷でデータを記録する ため、一定時間アクセスがないと放電により内容が消えてしまう。そのため記憶データを 使わない時でも時々読み出して同じ内容を書き込む操作が必要となる。この操作を リフレッシュと呼ぶ。



8bit 演算



16bit 演算


F レジスタの内容

S Z X H X P/V N CY


F レジスタの各ビットの意味

記号 意味 説明
S 符号 演算結果の正負 負:1, 正:0
Z ゼロ 演算結果が「ゼロ」か ゼロ:1, 非ゼロ:0
H 半桁上 2 進化 10 進数の桁上 有:1, 無:0
P パリティ 1 の個数 偶数:1, 奇数:0
V オーバフロー 桁あふれ 有:1, 無:0
N BCD 減算 2 進化 10 進数の減算 行う:1, 行わない:0
CY 桁上 演算結果の桁上 有:1, 無:0



2.1.3   PC における命令の番地計算の特徴



メモリ

Z80 の命令は 1 〜 4 Bytes の可変長である。 そのため PC は読み込んだ命令のバイト数を判断して自動的に +1 〜 +4 だけ変更される。

例としてメモリ内が以下のようになっていたとする。
3A  3A  2A  47  3A  80  25  4F
----------  --  ----------  --
LD A,(2A3A) LD B,A          LD C,A
                LD A,(2580)
    ----------  ----------  --
    LD A,(472A)

命令を取り出す位置によって全く意味が異なる

メモリの内容が実行対象のプログラムか、計算対象のデータであるかは見ただ けではわからない。実行を開始する番地に依存して決まる。


2.2   スタック


2.2.1   概要

スタックとは、レジスタを別の用途に使いたい時に、現在のレジスタの値を一 時的にメモリに退避するための仕組みである。

スタックを使う時には、使い始める前に SP (スタックポインタ) を初期化す る必要がある。SP はスタックの領域をどこまで使ったか管理するためのアド レス (=最後に使った領域を指す) を保持する。

スタックの領域はアドレスの大きい方から使われ始めて、使用量が増えるにし たがってアドレスの小さい方に増えていく。



スタック

アドレスの値の小さい領域は通常 ROM, OS, ユーザのプログラムが配置されるため、 スタックはアドレスの値の大きい領域に配置されることが多い。


2.2.2   スタックの使用例



スタックの内容の変化

  1. 最初の時点で A, B, C, D レジスタにはそれぞれ図中に示す値が入っている。

  2. PUSH AF を実行すると、A, F レジスタの値が SP の指す上の場所から スタックに書き込まれる(図中(2))。この場合レジスタペアの先に書かれ るレジスタ(この場合は A)がアドレスの大きい方に書き込まれる。F レジスタ の値は (F) と表している。

  3. その後続けて PUSH BC, PUSH DE を実行すると図のように値が記録される。 SP はスタックが消費されるのにつれてアドレスの値の小さい方を指し示す ように変更される。

  4. この時点で各レジスタの値はスタックに記録されているので、他の用途にレジ スタを使用して値が変化してしまっても後から復活させることができる。

  5. レジスタの値を戻す時には PUSH を実行した順番と逆に POP を実行する。POP DE を実行するとスタックの最後に使った 領域から値が取り出されて D, E レ ジスタに値が代入される。SP は値を取り出した領域の前の領域を指すように 内容が変更される。

  6. その後続けて POP BC, POP AF を実行すると各レジスタに値が代入されて スタックは元の状態に戻る。



2.2.3   練習問題

各レジスタの初期値が A=0, B=1, C=2, D=3, E= 4, F=5 となっている状態で、次のスタック 操作を行なった後に各レジスタの値がどうなるか答えなさい。
(1)	PUSH	AF
   	PUSH	BC
	PUSH	DE
	POP	AF
	POP	BC
	POP	DE	の一連の操作を ★ とする。★ を 2 回繰り返す。

(2) ★ を 3 回繰り返す。

(3)	PUSH    AF	(4)	PUSH    AF
	PUSH    BC		PUSH    BC
	PUSH    DE		POP     DE
	PUSH    AF		POP     BC
	POP     DE		POP     AF
	POP     BC
	POP     AF



2.3   プロセッサの動作原理



CPU とメモリ

  1. PC に実行開始番地をセットする。

  2. AB に PC の内容を出力して番地を指定する。

  3. DB から指定した番地の内容を読み取り、IR にセットする。 これをフェッチと呼ぶ。 PC ← PC + 1

  4. システム制御部により IR の内容が解読される。これをデコード と呼ぶ。1 バイト命令なら 6 へ進む。

  5. 2 バイト以上の命令については、(2),(3) を必要な回数繰り返す。読み込んだ データは CPU 内部のバッファに保持する。

  6. 命令を実行する。

  7. 2 に戻る。


2.3.1   CPU の動作例

(2000) のデータと (2001) のデータを加算して (2002) に格納するプログラムが 1000 番地から配置されている場合
(* Z80 ではメモリへの入出力、算術論理演算はA レジスタでしか行えないという制約がある)


プログラムとデータの配置


 命令実行時のデータの流れ

1000 → AB
IR ← DB (3A) 
解読すると 3 バイト命令なので残り 2 バイトを読む
1001 → AB
バッファ ← DB (00)
1002 → AB
バッファ ← DB (20)
2000 → AB     ; LD  A, (2000)
A ← DB

1003 → AB
IR ← DB
B ← A         ; LD  B, A

1004 → AB
IR ← DB
同様に (1004), (1005) から 01, 20 を読む
2001 → AB     ; LD  A, (2001)
A ← DB

1007 → AB
IR ← DB
A ← A + B     ; ADD  A, B

1008 → AB
IR ← DB
同様に (1009), (100A) から 02, 20 を読む
2002 → AB     ; LD (2002), A
A → DB

100B → AB
IR ← DB
終了           ; HALT


2.3.2   練習問題

次のプログラムを実行する時の、プログラムとデータのメモリ上の配置、実行 中のデータの流れを上記の例と同じ形式で示しなさい。プログラムはいずれも 1000 番地から配置されているものとする。
  1. (3000) のデータを (2000), (2001), (2002) に格納する。

  2. (3000), (3001), (3002), (3003) のデータの和を求める。

  3. (3000) のデータと (2000) のデータを交換する。






3   インタフェース信号とタイミング


3.1   インタフェース信号



Z80CPU の信号線

もともとは 40pin DIL : Dual Inline Package 形式のパッケージで提供され ていた。現在は、周辺の SIO, PIO, DMA, CTC, その他の回路等を 1 chip に 集積した形で提供されることが多い。



パッケージの違い


3.1.1   各インタフェース信号の機能




3.2   DMA

DMA は Direct Memory Access の略で、周辺装置とメモリ間の大量のデータ転送が必要な場合、 CPU にやらせないでデータ転送専用の回路を使って行うことを表す。そのような回路は通常 データ転送を高速に、効率よく実行できるように設計してある。



DMA


3.2.1   DMA を使わない、使えない場合

データの転送を 1 バイトずつ CPU が行う。CPU では次のような手順になり効率が悪い。
  1. 繰り返し回数を設定する命令をメモリから読み込む。(2, 3 Bytes)

  2. 繰り返し回数を設定する。

  3. !!! 周辺装置からデータを読み込む命令をメモリから読み込む。(2, 3 Bytes)

  4. !!! 周辺装置からデータを読み込む。

  5. !!! メモリにデータを書き込む命令をメモリから読み込む。(3 Bytes)

  6. !!! メモリにデータを書き込む。

  7. !!! 繰り返しの処理を行う命令をメモリから読み込む。(2, 3 Bytes)

  8. !!! 繰り返しの処理を行う。

(!!! は実行される回数が多いことを表す。)



DMA を使わない場合のデータの流れ



3.2.2   DMA を使った場合

データの転送は DMA に任せる。DMA は大量のデータを効率よく転送する機能を備えている。 データ転送中は CPU はお休みして DB をアクセスしない。(BUSRQ, BUSAK で設定)
  1. DMA にデータ転送に関する設定 (どの周辺装置から読み出すか、 メモリのどこに書き込むか、データ量等) を行う命令をメモリから読み込む。

  2. DMA にデータ転送に関する設定を行う。

  3. !!! DMA がデータを周辺装置から読み出す。

  4. !!! DMA がメモリにデータを書き込む。



DMA を使う場合のデータの流れ


(ヒント): データ転送中も CPU は休まずに別の仕事をさせる場合もある。このような方式を チャネル制御といい、大型計算機などでは一般的に行なわれている。


3.3   CPU の動作タイミング

CPU における命令実行は 2 種類の時間の長さの表現を基準にして説明される。


T サイクルと M サイクル

1 個の命令の実行には 1 〜 6 M サイクルが必要となる。必要な M サイクル数は命令によって 異なり、一般に命令語長が長い命令は M サイクル数が多くなる。

(ヒント): 同じ実行結果が得られる命令でも、命令毎に実行時間は多少の違いが ある。プログラムの処理速度を高速にしたい場合は実行時間を考えて 命令を選択することもできる。
例	LD   A, 0       T サイクル   7
	XOR  0          T サイクル   4
上記の命令はどちらも A レジスタを 0 にするという点で結果は同じであるが、 実行時間はかなり異なる。処理速度を重視する場合は XOR を使うこともでき るが、反面プログラムの内容がわかり難くなる。LD では A レジスタを 0 に するという内容が直接理解できるが、XOR ではわからない。通常 はプログラムの読み易さを重視すべきであり、上記のような命令 の使い方はどうしても処理速度を改善したい時に限定すべきである。



3.4   命令実行サイクルと制御信号の変化


3.4.1   M1 サイクル, フェッチサイクル



M1 サイクルのタイムチャート

  1. PC を AB に出力する。M1 を出力する。

  2. 次に MREQ, RD を出力し、 メモリに読み出し要求を伝える。

  3. WAIT の状態を調べ、もしアクティブなら 1 クロック後に 再び WAIT を調べる。 WAIT がアクティブでなければ、メモリからは、 DB に AB から指定した番地の内容が出力される。

  4. 1/2 クロック後に CPU はその内容を取り込んで IR に記憶する。 その後 M1, MREQ, RD を H に戻す。

  5. リフレッシュ対象の番地を AB にセットし、RFSH を 出力する。

  6. 少し後に MREQ を出力して、それに合わせてリフレッシュ が行われる。この間に CPU 内部では IR の内容が解読され、 実行すべき動作が決まる。



3.4.2   主記憶データの読み出し/書き込みサイクル



メモリ READ サイクルのタイムチャート

  1. 読み出す対象の番地を AB に出力する。

  2. 1/2 クロック後に MREQ, RD を出力し、 メモリに読み出し要求を伝える。

  3. WAIT の状態を調べ、もしアクティブなら 1 クロック後に 再び WAIT を調べる。 WAIT がアクティブでなければ、メモリから DB に AB から指定した番地の内容が出力される。

  4. 1 クロック後に CPU はその内容を取り込んでレジスタに記憶する。 その後 MREQ, RD を H に戻す。



メモリ WRITE サイクルのタイムチャート

  1. 書き込む対象の番地を AB に出力する。

  2. 1/2 クロック後に MREQ を出力し、 メモリにアクセス要求を伝える。

  3. WAIT の状態を調べ、もしアクティブなら 1 クロック後に 再び WAIT を調べる。 WAIT がアクティブでなければ、CPU は WR を出力し、メモリはそれを認識した後に DB からデータを 取り込み AB から指定した番地にその内容を記録する。

  4. 1 クロック後に CPU は MREQ, RD を H に戻す。 さらにその 1/2 クロック後に DB の出力を止める。



3.4.3   入出力装置のデータの読み出し/書き込みサイクル



IO READ サイクルのタイムチャート

  1. 入力対象の装置の番地を AB に出力する。

  2. 1 クロック後に IORQ, RD を出力し、 装置に読み出し要求を伝える。

  3. タイミング調整の Wait サイクルが 1 個挿入される。Wait サイクル中のクロック波形の 立ち下がりで WAIT の状態を調べ、もしアクティブなら 1 クロック後に 再び WAIT を調べる。 WAIT がアクティブでなければ、装置から DB にデータが出力される。

  4. 1 クロック後に CPU はその内容を取り込んでレジスタに記憶する。 その後 IORQ, RD を H に戻す。



IO WRITE サイクルのタイムチャート

  1. 出力対象の装置の番地を AB に出力する。少し後に DB にデータを出力する。

  2. 1 クロック後に IORQ, WR を出力し、 装置に書き込み要求を伝える。

  3. タイミング調整の Wait サイクルが 1 個挿入される。Wait サイクル中のクロック波形の 立ち下がりで WAIT の状態を調べ、もしアクティブなら 1 クロック後に 再び WAIT を調べる。 WAIT がアクティブでなければ、少し後に装置が DB の データを取り込む。

  4. 一定時間後に CPU は IORQ, WR を H に戻す。 さらにその 1/2 クロック後に DB の出力を止める。



3.4.4   バス要求及び確認サイクル



バス要求サイクルのタイムチャート

  1. 命令実行時の最後の T サイクルの立ち上がりで、BUSRQ の 状態を調べる。

  2. もし BUSRQ がアクティブなら 1 クロック後に BUSAK をアクティブにして、同時に DB, AB, MREQ, IORQ, RD, WR, RFSH をハイインピーダンス状態にしてバスと信号線を解放する。 その後は各 T サイクルの立ち上がりで BUSRQ の状態を調べる。

  3. BUSRQ が H に戻されると、

  4. その次の T サイクルの立ち上がりで検出する。 同じ T サイクル中に BUSAK を H に戻す。 バスと信号線は少し後に通常の状態に戻る。

  5. 次の T サイクルから命令実行を再開する。






4   アドレス方式

処理対象のデータがある場所を指定する方法で、 これをアドレスと呼ぶ。

例として、特定のレジスタ、任意のレジスタ、メモリのどこか、 レジスタの指定するメモリの場所、数値自体などがある。 データの種類は 8bits, 16 bits に大別される。

ここでは以下の 10 種類に分類する。


アドレス指定方法の分類

固有アドレス指定形式 拡張アドレス指定形式
直接数値指定形式 ページ 0 アドレス指定形式
拡張直接数値指定形式 相対アドレス指定形式
レジスタアドレス指定形式 インデックスアドレス指定形式
レジスタ間接アドレス指定形式 ビット指定形式


4.1   固有アドレス指定形式

命令コードが固定されていて変化しない。命令毎に特定のレジスタが使用される。
例
命令                   機械語          説明
-------+-------+-------+-------+-------+-------+-------+-------+
CPL                    2F              A レジスタの反転


4.2   直接数値指定形式

命令コードとともに数値そのものを指定する。
例
命令                   機械語          説明
-------+-------+-------+-------+-------+-------+-------+-------+
ADD    A, 10           C6 0A           A ← A + 10


4.3   拡張直接数値指定形式

2 バイトの数値そのものを指定する。
例
命令                   機械語          説明
-------+-------+-------+-------+-------+-------+-------+-------+
LD     BC, 1000H       01 00 10        BC ← 1000H


4.4   レジスタアドレス指定形式

データの入っているレジスタを指定する。 よく使われるアドレス方式で様々な命令で利用される。
例
命令                   機械語          説明
-------+-------+-------+-------+-------+-------+-------+-------+
AND    B               A0              A ← A and B


この指定形式の命令は 1 バイトで表現され、上位 5 bits が命令を表し、下 位 3 bits がレジスタを表す (10100???)。例として AND 演算の場合は、上位 5 bits が 10100 である。


レジスタアドレス指定形式におけるレジスタの指定

下位 3 bits の値 選択されるレジスタ
000 B
001 C
010 D
011 E
100 H
101 L
110 レジスタ間接アドレス
111 A



4.5   レジスタ間接アドレス指定形式

データの入っているメモリの番地をレジスタペアによって指定する。メモリ中 の連続した領域をアクセスする場合は拡張アドレスよりもプログラムサイズが 小さい。また繰り返しの処理を利用すると、処理速度はやや遅くなるが更にメ モリの使用量が少なくなる。
例
命令                   機械語          説明
-------+-------+-------+-------+-------+-------+-------+-------+
LD     A, (BC)         0A               A ← (BC)


メモリの連続した領域

LD      BC, 2000H         LD      A, (2000H)
LD      A, (BC)           LD      A, (2001H)
INC     BC                LD      A, (2002H)
LD      A, (BC)           LD      A, (2003H)
INC     BC                LD      A, (2004H)
LD      A, (BC)
INC     BC
LD      A, (BC)
INC     BC
LD      A, (BC)
LD A, (BC) は 1 バイト命令で 7 クロック、INC BC は 1 バイト命令で 6 クロック、LD A, (lm) は 3 バイト命令で 13 クロックなので実行時間は同じであるが、プログラムサイズが 2/3 になる。



4.6   拡張アドレス指定形式

データの入っているメモリの番地そのものを指定する。
例
命令                   機械語          説明
-------+-------+-------+-------+-------+-------+-------+-------+
LD     A, (1000H)      3A 00 10        A ← (1000H)


4.7   ページ 0 アドレス指定形式

プロセッサの再起動時にメモリの先頭の特定の番地にジャンプする。 特殊な指定方式で一般の命令では使えない。
例
命令                   機械語          説明
-------+-------+-------+-------+-------+-------+-------+-------+
RST    38H             FF              PC ← 0038H


この指定形式の命令は 1 バイトで表現され、上位 2 bits、下 位 3 bits が 1 となる (11???111)。その間の 3 bits で番地を指定する。


ページ 0 アドレス指定形式における番地の指定

番地指定 3 bits の値 選択される番地
000 0000H
001 0008H
010 0010H
011 0018H
100 0020H
101 0028H
110 0030H
111 0038H



4.8   相対アドレス指定形式

現在の PC の示す値から近い番地にジャンプする場合に使われる。 8 bits の数値による番地指定である。絶対アドレスとの違いを理解する必要がある。
例
命令                   機械語          説明
-------+-------+-------+-------+-------+-------+-------+-------+
JR     Z, 10H          28 10       if (Zflag == 1) PC ← PC + 10H



4.8.1   相対アドレスと絶対アドレスの違い

絶対アドレス指定 :
16 bits で番地を指定するので、メモリの全体を指定できるが、命令が長くなる。 プログラムの再配置はできない。
相対アドレス指定 :
8 bits で番地を指定するので、メモリの一部しか指定できないが、命令が短い。 プログラムの再配置が可能。


相対アドレスと絶対アドレスによる番地指定



4.8.2   プログラムの再配置

プログラムが再配置可能とは、プログラムがメモリに置かれる位置に依存しな いで正しく動作できることを表す。一般にプログラム内で番地指定をする部分 がすべて相対アドレス指定形式であると、そのプログラムは再配置可能となる。


 再配置が可能な場合

        ORG     1000H   ;          ; 実行開始番地を 1000H に指定
        SUB     B       ; 90       ; A ← A - B
        JR      NZ, L1  ; 20 01    ; L1 に相対ジャンプ
        INC     A       ; 3C       ; A ← A + 1
L1      LD      C, A    ; 4F       ; C ← A
        HALT            ; 76       ; 終了
この場合はアドレス指定が相対アドレスなので再配置可能となり、 メモリのどこに置いても正しく動作する。プログラム中には実行開始番地 1000H に 依存した値は存在しない。
 再配置が不可能な場合

        ORG     1000H   ;          ; 実行開始番地を 1000H に指定
        SUB     B       ; 90       ; A ← A - B
        JP      NZ, L1  ; C2 05 10 ; L1 に絶対ジャンプ
        INC     A       ; 3C       ; A ← A + 1
L1      LD      C, A    ; 4F       ; C ← A
        HALT            ; 76       ; 終了
この場合はアドレス指定が絶対アドレスなので再配置はできず、 1000H 番地以外に置いた場合正しく動作しない。プログラム中には実行開始番地 1000H に依存した値1005H があるため、 プログラムをどこに置いてもこの命令を実行すると必ず 1005H にジャンプする。




4.9   インデックスアドレス指定形式

インデックスレジスタ IX, IY と偏位置でメモリ中の番地を指定する。 レジスタ間接アドレスの発展形。
例
命令                   機械語          説明
-------+-------+-------+-------+-------+-------+-------+-------+
LD     (IX + 10H), B   DD 70 10        (IX + 10H) ← B


4.10   ビット指定形式

8 bit データ中の特定のビットを指定して操作を行う場合の指定法。 特殊な指定方式で一般の命令では使えない。
例
命令                   機械語          説明
-------+-------+-------+-------+-------+-------+-------+-------+
SET    2, C            CB D1           C の 2 bit目 ← 1
RES    3, A            CB 9F           A の 3 bit目 ← 0
BIT    4, D            CB 62           D の 4 bit目を調べて F をセット


4.11   練習問題

次の命令に含まれるアドレス指定方式を挙げなさい。
  1. LD A, B

  2. LD A, 10

  3. LD A, (1000H)

  4. LD A, (HL)

  5. LD HL, 1000H

  6. LD HL, (1000H)

  7. LD A, (IX + 10)

  8. JP NZ, 1000H

  9. JR NZ, 1000H

  10. NEG





5   命令の種類

命令を機能別に分類すると以下のようになる。
  1. 8 ビットのデータ移動

  2. 16 ビットのデータ移動

  3. 交換、ブロック転送、検索

  4. 8 ビット算術論理演算

  5. 汎用算術演算、CPU 制御

  6. 16 ビット算術演算

  7. 循環、桁移動

  8. ビット操作、判定

  9. 飛び越し

  10. サブルーチン接続、戻り

  11. 入出力

この中で使用頻度が高く重要なのは、1, 2, 4, 6, 9, 10 である。 次に重要なのが 5, 7 である。


5.1   8 ビットのデータ移動

一般形  LD      *, *            ; * はレジスタ、数値、メモリ中のデータなど

例      LD      A, 23           ; A ← 23
        LD      B, H            ; B ← H
        LD      C, (HL)         ; C ← (HL)
        LD      (IX + 30H), D   ; (IX + 30H) ← D
        LD      (1000H), A      ; (1000H) ← A


5.2   16 ビットのデータ移動

一般形  LD      *, *            ; * はレジスタ(ペア)、数値、メモリ中のデータなど

例      LD      BC, 100         ; BC ← 100
        LD      DE, (0010H)     ; DE ← (0010H)
        LD      SP, FF00H       ; SP ← FF00H
        LD      (1000H), HL     ; (1000H) ← HL


5.3   交換、ブロック転送、検索


5.3.1   交換命令

例      EX      DE, HL          ; DE と HL の内容を入れ換える
        EX      AF, AF'         ; AF について表と裏レジスタを入れ換える
        EXX                     ; BC, DE, HL について表と裏を入れ換える


5.3.2   ブロック転送命令

LDI, LDD, LDIR, LDDR がある。これらの命令を使う時には、前もって BC に 転送バイト数、DE に送り先の先頭番地、HL にもとデータの先頭番地をセット しておく。LDI は DE, HL が + され、LDD は - される。


LDI と LDD の違い

転送後、BC != 0 なら P/V フラグ = 1 となり、次のデータを転送するか判定 する際に使用される。プログラムは次のような形式になる。
LOOP   LDI
       JP     PE, LOOP ; BC が 0 でなければ転送を続ける
なぜ LDI, LDD の 2 種類があるか ? → 転送領域が重なっていてもいいように。


転送領域が重なっている場合

もし転送領域が重なっている場合は、重なっている領域から転送を始める必要がある。

LDIR, LDDR は BC = 0 になったら転送を終了する。



5.3.3   検索命令

CPI, CPD, CPIR, CPDR がある。BC, DE, HL の設定は LDI 等と同じ。A レジスタと同じ値が メモリ中で見つかると Z フラグが 1 になる。CPIR, CPDR では同じ値が見つかるか、指定した バイト数検索した時に終了する。


5.4   8 ビット算術論理演算

一般形  ADD     A, *            ; A ← A + *
        AND     *               ; A ← A and *

ADD, ADC, SBC は 16 ビット算術演算に同じ命令があるので、区別するために
A レジスタの指定が必要

例      ADD     A, 10           ; A ← A + 10
        ADC     A, B            ; A ← A + B + CY
        SBC     A, C            ; A ← A - C - CY
        SUB     5               ; A ← A - 5
        AND     B               ; A ← A and B
        OR      C               ; A ← A or C
        XOR     10              ; A ← A xor 10
        CP      5               ; A - 5 の結果によりフラグを設定する
        INC     B               ; B ← B + 1
        DEC     D               ; D ← D - 1


5.5   汎用算術演算、CPU 制御

例      CPL                     ; A ← A の 0/1 反転の結果
        NEG                     ; A ← A の 2 の補数
        SCF                     ; CY ← 1 、キャリフラグを 1 にする
        CCF                     ; CY ← CY の 0/1 反転の結果
        NOP                     ; 何もしない
        DI                      ; IFF ← 1 、割り込みを許可しない
        EI                      ; IFF ← 0 、割り込みを許可する
        IM0 (IM1, IM2)          ; 割り込みモードを 0 (1,2) にする
        DAA                     ; A を BCD 数に変換する


5.6   16 ビット算術演算

例      INC     BC              ; BC ← BC + 1
        DEC     DE              ; DE ← DE - 1
        ADD     HL, BC          ; HL ← HL + BC
        ADC     HL, BC          ; HL ← HL + BC + CY
        SBC     HL, BC          ; HL ← HL - BC - CY


5.7   循環、桁移動


 A レジスタの循環(回転)

例      RLA (RRA)       ; A と CY を合わせて左(右)回転
        RLCA (RRCA)     ; A を左(右)回転、押し出されたビットは CY に


A レジスタの循環(回転)


 2 進化 10 進数の循環(回転)

例      RLD (RRD)       ; A と (HL) で 4 ビットずつ左(右)回転、BCD 数用


2 進化 10 進数の循環(回転)


 レジスタの循環(回転)

例      RL (RR) B       ; B と CY を合わせて左(右)回転
        RLC (RRC) C     ; C を左(右)回転、押し出されたビットは CY に


レジスタの循環(回転)


 レジスタの桁移動(シフト)

例      SLA     C       ; C を左に算術シフト、押し出されたビットは CY に
        SRA     B       ; B を右に算術シフト、押し出されたビットは CY に
        SRL     D       ; D を右に論理シフト、押し出されたビットは CY に


レジスタの桁移動(シフト)



5.8   ビット操作、判定

例      BIT     2, C    ; C の 2 ビット目を判定し、Z フラグをセットする
        SET     3, B    ; B の 3 ビット目を 1 にする
        RES     4, D    ; D の 4 ビット目を 0 にする


5.9   飛び越し


5.9.1   絶対アドレス指定

例      JP      1000H           ; PC ← 1000H, 1000 番地に無条件ジャンプ
        JP      NZ, 1000H       ; if (0 == Zflag) PC ← 1000H

条件付ジャンプの条件は次のものがある。
NZ : ノンゼロ   Z : ゼロ        NC : 桁上げ無   C : 桁上げ有
PO : 奇数       PE : 偶数       P : 正数        M : 負数


5.9.2   相対アドレス指定

例      JR      1000H           ; 相対番地指定により 1000 番地にジャンプ
        JR      NZ, 1000H       ; if (0 == Zflag) 1000 番地に

条件付ジャンプの条件は NZ, Z, NC, C となる。

        DJNZ    1000H           ; B ← B - 1, if (0 != B) PC ← 1000H



5.10   サブルーチン接続、戻り

例      CALL    1000H           ; スタック ← PC, PC ← 1000H
        CALL    Z, 1000H        ; if (1 == Zflag) 
                                ;    スタック ← PC, PC ← 1000H
        RET                     ; PC ← スタック
        RET     NC              ; if (0 == CYflag) PC ← スタック

指定できる条件は条件付ジャンプと同じ 8 種類である。

        RETI                    ; 割り込み処理ルーチンから戻る
        RETN                    ; NMI 処理ルーチンから戻る

        RST     38H             ; スタック ← PC, PC ← 38H, リスタート


5.11   入出力

例      IN      A, (0F0H)       ; 0F0H で表される機器からデータを読み込む
        IN      B, (C)          ; C で表される機器からデータを読み込む
        OUT     (0F0H), A       ; 0F0H で表される機器にデータを出力する
        OUT     (C), B          ; C で表される機器にデータを出力する


5.12   練習問題


5.12.1  

次の機能を実現する命令を書きなさい。1 命令で実現できない場合は複数の命令を 組み合わせて実現しなさい。
  1. A ← 10

  2. A ← C

  3. A ← (1000H)

  4. A ← (BC)

  5. A ← (HL)

  6. A ← (IX + 10)

  7. C ← 10

  8. C ← A

  9. C ← (1000H)

  10. C ← (BC)

  11. C ← (HL)

  12. C ← (IX + 10)

  13. (2000H) ← 10

  14. (2000H) ← C

  15. (2000H) ← (1000H)

  16. (2000H) ← (BC)

  17. (2000H) ← (HL)

  18. (2000H) ← (IX + 10)

  19. (BC) ← 10

  20. (BC) ← C

  21. (BC) ← (1000H)

  22. (BC) ← (DE)

  23. (BC) ← (HL)

  24. (BC) ← (IX + 10)

  25. (HL) ← 10

  26. (HL) ← C

  27. (HL) ← (1000H)

  28. (HL) ← (DE)

  29. (HL) ← (IX + 10)

  30. BC ← 1000H

  31. BC ← DE

  32. BC ← (1000H),(1001H)

  33. (2000H) ← 1000H

  34. (2000H) ← DE

  35. (2000H) ← (1000H),(1001H)

  36. A ← B + C

  37. A ← B - C - CY

  38. A ← A AND 3

  39. A ← A XOR 1

  40. B ← B - 1

  41. A ← A の 0/1 反転

  42. A ← A の 2 の補数

  43. HL ← BC + DE

  44. A を右に算術シフト

  45. A を右に論理シフト

  46. A を左に算術シフト

  47. 1000H にジャンプ

  48. Z なら 1000H にジャンプ

  49. NC なら 1000H にジャンプ

  50. 1000H に相対ジャンプ



5.12.2  

A レジスタが 11010010B, CY フラグが 1 のとき、次の操作を行なった後の A, CY の値 を示しなさい。
  1. RLA

  2. RRCA

  3. SRA A

  4. SLA A

  5. SRL A






6   フラグと算術演算

Z80CPU は F レジスタに 6 種の flag (Z, S, CY, P/V, H, N)を持つ。 この中で、Z, S, CY, P/V の 4 個は条件付ジャンプなどで利用される。 H, N は BCD 数の演算に関する flag であるが使用する機会は少ない。

一般的には flag に影響を与える命令の直後に条件判断を行う命令を実行する。 しかし flag に影響を与えない命令なら途中に実行してもよい。
例      ADD     A, 10           ; flag がセットされる
                                ; flag に影響なければ命令を実行してよい
        JP      NZ, LOOP        ; ここで Zflag を参照している

6.1   ゼロフラグ Z


 内容 :

命令の実行結果が 0 なら 1 に、0 以外なら 0 になる。
転送したデータが 0 のとき

演算結果が 0 のとき

指定したビットが 0 のとき

などに 1 になる。


 利用される場合 :

  1. 比較した二つの数が等しいかどうか

  2. ビット判定におけるゼロ判定

  3. 算術演算、論理演算の実行結果のゼロ判定

  4. 命令の実行結果のゼロ判定

例      CP      10	; A レジスタが 10 かどうか
        JP      NZ, L1	; もしゼロでなければ L1 に飛ぶ


6.2   符号フラグ S


 内容 :

命令の実行結果が負数なら 1、正数なら 0 になる。
演算、桁移動、比較命令などに影響を受ける。


 利用される場合 :

  1. 二つの演算数の大小判定

  2. 算術演算、論理演算の実行結果の正負の判定

  3. 命令の実行結果の正負の判定

例      CP      10      ; A レジスタが 10 より大きいか
        JP      P, L1	; 10 <= A なら L1 に飛ぶ


6.3   桁上げフラグ CY


 内容 :

加減算で桁上がり、桁借りがあれば 1、なければ 0 になる。
算術演算、桁移動命令にのみ影響を受ける。論理演算では常にゼロになる。


 利用される場合 :

  1. 二つの演算数の大小判定

  2. 桁移動の結果はみ出したビットの判定

  3. 多重精度算術演算を実現する時

  4. 符号無数の算術演算で表現可能範囲を超えていないか

例	CP	10	; A レジスタが 10 より大きいか
	JP	NC, L1	; 10 <= A なら L1 に飛ぶ


6.4   パリティ / あふれフラグ P/V


 内容 :

演算結果のビットパターンで 1 の個数が偶数なら 1、奇数なら 0 になる。
算術演算の結果あふれが発生したら 1、発生していなければ 0 になる。
論理演算、桁移動命令ではパリティを表し、算術演算ではあふれを表す。


 利用される場合 :

  1. 論理演算の結果で 1 の個数の判定

  2. 桁移動の結果で 1 の個数の判定

  3. 符号付数の算術演算で表現可能範囲を超えていないか

例	AND	0FH	; A レジスタの下位 4 ビットの 1 の個数を数える
	JP	PE, L1	; 1 の個数が偶数なら L1 に飛ぶ

	ADD	A, 100	; A レジスタ に 100 を加える
	JP	PE, L1  ; 符号付数としてあふれていたら L1 に飛ぶ


6.5   練習問題

次の条件判断を実現する命令列を示しなさい。条件に合わなければ L2 にジャンプする ようにしなさい。
例	A が 0 なら L1 にジャンプする。

	CP	0
	JP	Z, L1
	JP	L2
  1. A と B を比較して A < B なら L1 にジャンプする。

  2. A と B を比較して A <= B なら L1 にジャンプする。

  3. A と B を比較して A == B なら L1 にジャンプする。

  4. A と B を比較して A != B なら L1 にジャンプする。

  5. A と B を比較して B < A なら L1 にジャンプする。

  6. A と B を比較して B <= A なら L1 にジャンプする。

  7. 符号付数として A + B を計算した時、あふれがあれば L1 にジャンプする。

  8. 符号無数として A + B を計算した時、あふれがあれば L1 にジャンプする。

  9. A の上位 6 桁の 1 の個数が奇数なら L1 にジャンプする。

  10. A を 1 ビット左にシフトした時、はみ出したビットが 1 なら L1 にジャンプする。





7   Z80 用アセンブリ言語


7.1   記述方法

Z80 用アセンブリ言語の 1 行は以下の 4 つのフィールドで構成される。

ラベル(:)     オペコード     オペランド     ; コメント


LOOP     LD     A, 30     ; A レジスタに 30 を代入する
7.1.1   プログラムの書き方

		ORG	1000H

		LD	A, 10		; LD のサンプル
		LD	B, 10
		ADD	A, B
		LD	(2000H), A
		HALT
		END



7.2   使用できる文字

A -- Z, 0 -- 9, +, -, (, ), ","
;   コメントの始まり
:   ラベルとオペコードの区切り, 書かない処理系も存在する
'   文字定数を表す
空白, TAB   オペコードとオペランドの区切り
CR   行の終り


7.3   定数の表現


表現可能な定数の種類

形式 記号
10 進定数 0 -- 9 123D
16 進定数 0 -- 9, A -- F 3AH, 0FA00H
8 進定数 0 -- 7 123O
2 進定数 0, 1 01011110B
文字定数 引用符で囲む 'ABCD'



7.4   ラベル記述のルール

ラベル : プログラム中で番地の数値を直接記述する代わりに記号で番地を表したもの。 数値への変換はアセンブラが自動的に行う。
 ラベルを使わない書き方

		ORG	1000H

		LD	A, 10		; 1000H
		LD	B, 10		; 1002H
		ADD	A, B		; 1004H
		CP	100		
		JR	M, 1004H	; 1004H を自分で書く必要がある
		HALT			
		END

ラベルを使った書き方
		ORG	1000H

		LD	A, 10
		LD	B, 10
LOOP		ADD	A, B
		CP	100
		JR	M, LOOP		; 番地を直接書かなくてもよい
		HALT
		END


7.5   予約語

予約語 : プログラムを書く時にラベル等に使ってはいけない単語

A, B, C, D, E, F, H, L, AF, BC, DE, HL, IX, IY, SP C, NC, Z, NZ, M, P, PE, PO

命令語は予約語にされる場合とされない場合がある。(処理系依存)



7.6   オペランドとして書ける内容

レジスタ名			LD	A, B
				ADD	HL, BC
フラグの状態			JR	NZ, LOOP
数値定数			LD	A, 10H
文字定数			LD	A, 'B'
命令(定数)に付けたラベル	(DATA	EQU	100)
				ADD	A, DATA
リファレンスカウンタの値	JP	$ - 5
算術式				LD	A, DATA + 10
				LD      A, 30 + 10
数値定数			LD	(0FF12H), BC
命令(定数)に付けたラベル	LD	BC, (DATA)
算術式				LD	BC, (DATA + 10)

(リファレンスカウンタ : その時点の PC の値)


7.7   疑似命令

機械語には変換されない(対応しない)が、アセンブリ言語で効率的にプログラ ムが記述できるように用意されている命令で以下の種類がある。

	ORG	n
	END
n1	EQU	n2
(Label)	DEFB	n	; DB とも書く
(Label)	DEFW	n	; DW とも書く
(Label)	DEFS	n	; DS とも書く
(Label)	TXT	string	; DEFM, DM とも書く

ORG : プログラムの開始番地を指定する
例 
	ORG	1000H

END : プログラムの終りを表す

EQU : 記号を数値に対応させる ($:PC も指定可能)
例
MAX	EQU	100

DEFB : 1 バイトの領域を確保し、値を n にする
例
	DEFB	10 ; ('A' という書き方が可能な場合もある)

DEFW : 1 ワード(16 ビット)の領域を確保し、値を n にする
例
	DEFW    10 ; ('AB' という書き方が可能な場合もある)

DEFS : n バイトの領域を確保する。初期化はしない。
例
	DEFS	10

TXT : 指定された文字列の長さ分の領域を確保し、文字列を書き込む
例
	TXT	'ABCD' ; ($ABCD$ という書き方もある)


7.8   アセンブリ言語によるプログラミングの例


7.8.1   DATA1 番地から MAX 個のデータを足して RESULT に記録する

MAX     EQU     5               ; データの個数

        ORG     1000H           ; 1000H 番地からスタート

START   XOR     A               ; 答を入れる A をゼロクリア
        LD      IX, DATA1 + MAX - 1   ; IX にデータの最後の番地
        LD      B, MAX          ; 個数のカウンタをセットする
LOOP    ADD     A, (IX)         ; データの最後から足していく
        DEC     IX              ; アドレスを 1 前にずらす
        DEC     B               ; 1 回足したので個数を 1 減らす
        JP      NZ, LOOP        ; ゼロでなければ繰り返し
        LD      (RESULT), A     ; 答の記録
        HALT                    ; ストップ

DATA1   DEFB    3               : MAX 個のデータ
        DEFB    7
        DEFB    5
        DEFB    1
        DEFB    2
RESULT  DEFS    1               ; 答を入れる場所

        END


7.8.2   DATA1 番地のデータを 4 倍して RESULT に記録する

        ORG     1000H           ; 1000H 番地からスタート

START   LD      A, (DATA1)      ; A に (DATA1) をセット
        SLA     A               ; 2 倍
        SLA     A               ; 2 倍
        LD      (RESULT), A     ; 答の記録
        HALT                    ; ストップ

DATA1   DEFB    3               : もとのデータ
RESULT  DEFS    1               ; 答を入れる場所

        END


7.8.3   (DATA1) と (DATA2) の大きい方を RESULT に記録する

        ORG     1000H           ; 1000H 番地からスタート

START   LD      A, (DATA1)      ; A に (DATA1) をセット
        LD      B, A
        LD      A, (DATA2)      ; A に (DATA2) をセット
        CP      B               ; A, B の比較
        JP      NC, L1          ; A >= B なら CY は立たず、L1 へ
        LD      A, B            : A < B なら A ← B
L1      LD      (RESULT), A     ; 答の記録
        HALT                    ; ストップ

DATA1   DEFB    3               : もとのデータ
DATA2   DEFB    5               :
RESULT  DEFS    1               ; 答を入れる場所

        END


7.8.4   DATA1 × DATA2 を求める

        ORG     1000H

START   LD      A, (DATA1)
        LD      C, A
        LD      A, (DATA2)
        LD      B, A            ; B は繰り返し回数とする
        LD      A, 0            ; 答を入れる A をゼロクリア
        INC     B               ; DEC B でフラグを立てるため
        JR      L2
L1      ADD     A, C            ; C を足していく
L2      DEC     B               ; 繰り返し回数を 1 減らす
        JR      NZ, L1          ; B != 0 なら繰り返し
        LD      (RESULT), A     ; 答を記録
        HALT

DATA1   DEFB    3
DATA2   DEFB    5
RESULT  DEFS    1               ; 結果は C+C+C+...+C となる

        END



7.9   ハンドアセンブルの方法

  1. 各命令のバイト数を調べる

  2. アドレスを割り当てる

  3. 命令語を探して書く

                                   (1)    (2)     (3)
START   LD      A, (DATA1)      ; 3     1000    3A 0B 10
        SLA     A               ; 2     1003    CB 27
        SLA     A               ; 2     1005    CB 27
        LD      (RESULT), A     ; 3     1007    32 0C 10
        HALT                    ; 1     100A    76

DATA1   DEFB    3               : 1     100B    03
RESULT  DEFS    1               ; 1     100C    ??

        END


7.10   練習問題

次の機能を実現するプログラムを Z80CPU のアセンブリ言語で作成しなさい。 (????) はメモリの ???? 番地のデータを表す。== は値が等しいこと、 != は等しくないことを表す。
  1. A + B + C - D を (DATA1) に入れる

  2. (DATA1) + 100 を (DATA2) に入れる

  3. (DATA1) + (DATA2), (DATA1) - (DATA2) を (DATA3), (DATA4) に入れる

  4. (DATA1) * 3 を (DATA2) に入れる

  5. (DATA1) * 5 を (DATA2) に入れる (シフト命令を使うこと)

  6. (DATA1), (DATA2) の小さい方を (DATA3) に入れる

  7. (DATA1), (DATA2), (DATA3) の最小の値を (DATA4) に入れる

  8. (DATA1) == (DATA2) なら 0 を、(DATA1) != (DATA2) なら 0 以外を (DATA3) に入れる

  9. (DATA1) == 3 なら +1 して、(DATA1) != 3 なら -1 して (DATA2) に入れる

  10. (DATA1) が奇数なら 1 を、偶数なら 0 を (DATA2) に入れる

プログラムの例「(DATA1) と (DATA2) の大きい方を RESULT に記録する」をハンドアセンブルして 機械語のプログラムを示しなさい。