アセンブリ言語でプログラムを組む場合にはCPU自体の仕組みもある程度知っておかないといけません。まあ、内部動作や、外部のバス仕様などのの話はそのうちするとして今回はソフト的に見たCPUの概略を話題にしたいと思います。Cなどの高級言語を使っている分にはメモリ上のプログラムが実行されて、メモリ上のデータを操作していると言う概念さえ知っていればとりあえず何とかなります。しかし、アセンブリ言語ではそれからひとつ踏み込んでレジスタと言うCPU直属の記憶装置を常に頭においておかねばなりません。今回はレジスタを中心にZ80CPUに切り込んでいきたいと思います。
レジスタとはCPUが内部に持っているメモリのようなものです。Z80の場合はメモリ対メモリの演算を行うことは基本的にできないため、メモリ上のデータをいったんレジスタに読み込んでから操作を行います。
その他にもスタックレジスタによるスタックの機構や条件分岐命令のなどで用いるフラグレジスタの機構など知っておく必要があります。レジスタの理解はアセンブリ言語でのプログラミングの第一歩と言えるでしょう。
Z80のレジスタは下の表のような感じになっており、それぞれのレジスタが特定の機能を持っています。
表レジスタ | 裏レジスタ | 16bit | |||
---|---|---|---|---|---|
8bit | 8bit | 8bit | 8bit | I | R |
A | F | A' | F' | IX | |
B | C | B' | C' | IX | |
D | E | D' | E' | SP | |
H | L | H' | L' | PC |
Z80で一般に演算で利用するレジスタには表と裏があります(大変独特な機能です)。裏レジスタには後ろに'(ダッシュ)を付けることによって区別しますが、実際には EX AF,AF'命令と、EXX命令によって入れ替わるだけで、表レジスタがマップされているときに裏レジスタにアクセスすることはできません(PC98のVRAMみたいですね)。恐らく割り込みなどでレジスタを退避する手間を軽減する目的のものだと思われます(多重割り込みにはつかえないけど)。使い方はいろいろでしょうが、私はC言語と組み合わせて使うことも多いのでめったに利用しません。機能的には表も裏も同じものです。
最近はアキュムレーターを持たないCPUも増えてきましたが、Z80では常に意識する必要のある重要なレジスタです。多くの演算命令の結果が格納されるのがこのアキュムレーターです。Z80によって拡張された命令などのなかにはアキュムレーター以外のレジスタに結果を格納できるものもありますが、そうでないものの結果は暗黙のうちにこのレジスタに格納されると思っていてください。結果が暗黙にアキュムレーターに格納される命令に関してはニモニックにAは指定しませんので注意が必要です。
フラグレジスタ | ||||||||
---|---|---|---|---|---|---|---|---|
ビット位置 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
内容 | S | Z | - | H | - | P/V | N | C |
加算命令で最上位ビットが桁上がりしたときと、減算命令で桁借り(ボロー Borrow)が起こったときに1にセットされます。とどのつまりは演算によって 00h と FFh の間を(8bit演算の場合)回ってしまうとセットされます。
直前に実行された命令が加算命令だと0にクリアされ、減算命令だと1にセットされます。
命令によってパリティーをあらわすか、オーバーフローをあらわすかに変わります。加減算命令の場合、7Fh と 80h の間を(8bit演算の場合)回るとセットされます。つまり符号付整数の場合のキャリーフラグとみなせます。また、AND,ORなどの命令の場合結果が偶数の場合に1がセットされます。
キャリーフラグが最上位ビットを見張っているのに対して、こちらは3bit目のけた上がり(桁借り)を見張っています。BCD(Binary Coded Decimal 2進化10進数)演算で利用されます。
演算結果が0だった場合に1にセットされます。
演算結果が負だった場合に1にセットされます。コンピューターでは符号付整数を2の補数で表しますから、結果としてこのビットには演算結果の最上位ビットが入ることになります。
Z80の場合特定の命令でのみ使うレジスタもあるので完全に汎用とは言えないのですが、他の専用レジスタと区別すると言う意味で汎用という言葉を使います。6つのレジスタは8bitのレジスタとして使えますし、BC,DE,HLをそれぞれペアにして16bitレジスタとしても使うことができます。多くの命令で演算の対象として自由に扱うことができますのでどれをどう使うかはプログラマの腕次第です。
C言語で言うポインタのような動作を行うのに向いているレジスタです。HLレジスタも同じような用途にはつかえますが、こちらはHLとはちがい他の汎用レジスタとは独立している印象が強いです。
スタックの先頭を指すポインタです。このレジスタを利用してZ80はスタック機能を提供します。PUSH 命令を実行するとSP減算してそのアドレスにレジスタの内容を入れます。また POP 命令を行うとSPのアドレスからデータを読み出し、SPを加算します。メモリアドレス上を下位アドレスに向けて伸びていきます。
現在実行中のアドレスを格納しているレジスタです。直接読み書きするものではありませんが、相対ジャンプ命令ではこれを元に次のアドレスを計算します。サブルーチンコールの場合はSPがスタックに退避されますし、概念として理解しておく必要のあるレジスタです。
Z80の割り込みモード2で利用する割り込みベクタを指すポインタです。このレジスタは8bitでありアドレスの上位8bitを指します。下位8bitは割り込みを発生したLSIなどから受け取り、そのアドレスに書かれた番地に分岐します。
DRAMをリフレッシュする際のアドレスを保持しているレジスタです。個人で使う場合にはSRAMを使う場合がほとんどだと思いますのであまり意識する必要ないです。自動的にインクリメントされリフレッシュサイクル時にアドレスバスの下位8bitに出力されます。