●アセンブリ言語の表記
機械語の解説をしてきましたが、コードやデータの集まりですから当然、こんなのがたくさん並んだら、見るのが大変ですし、人間にはわかりにくいですよね。
そこで、CPUメーカーさんが仕様書になかに、ニーモニックと呼ばれる表記法を作っています。これは機械語の動作を人間がわかりやすいようにするためのもので、それを使った言語がアセンブリ言語です。
当然このニーモニックはメーカーがCPU用のものを作りますからにそれぞれ違いますので注意が必要です。(ニーモニックはメーカーの著作物であり同じ表記だと著作権の問題になるため同じになることはまず無いです)
さてZ80命令の仕様書には次のようなニーモニックが記載されています。
コード | オペレーション | ニーモニック |
---|---|---|
00h | Non OP | NOP |
3Eh | A ← n | LD A,n |
80h | A ← A+B | ADD A,B |
さて、このニーモニックという部分がアセンブリ言語での表記法です。このLD A,nでAレジスタにnで指定した値を入れる動作をCPUにさせる命令を表します。
機械語表記をニーモニックを使ってアセンブリ言語に書き換えてみましょう。
番地 | データ | アセンブリ言語 |
---|---|---|
0000h | 00h | NOP |
0001h | 3Eh | LD A,10h |
0002h | 10h | |
: : |
: : |
番地 | データ | アセンブリ言語 |
---|---|---|
0000h | 3Eh | LD A,10 |
0001h | 0Ah | |
0002h | 06h | LD B,20 |
0003h | 16h | |
0004h | 80h | ADD A,B |
まずいくつかの命令を紹介ながら、実際の仕様書の読み方も説明しましょう。
ニーモニック | オペレーション |
---|---|
LD r,n | r ← n |
LD r,r' | r ← r' |
ADD A,r | A ← A+r |
LD rr,nn | rr ← nn |
表の2行目のLD r,r' も同様に
LD A,B
といったようにレジスタ同士を指定することでレジスタ間の移動が行えます。
さて、表の2行目までは移動命令でした。3行目は演算命令となります。
これはAレジスタとrレジスタに保存されている値を加算しその結果をAレジスタに格納するという命令を実行します。
これら以上からたとえば、
LD A,2Eh
LD B,52h
ADD A,B
と記述すれば、Aレジスタに2Ehの値を入れ、Bレジスタに52hの値を入れる。それてA,Bレジスタの値を加算し、アキュムレータへ保存という動作を行うわけです。
最後に
LD rr,nn
というのがあります。これはレジスタの説明でBC、DE、HLはそれぞれ2つのレジスタを繋げて16ビットとして扱うことができるとお話ししました。このrrは繋げることが可能なレジスタを指定して、値を16ビット(2バイト)で扱うことができるものです。ですから
LD HL,1234h
は
LD H,12h
LD L,34h
と同様の動作となるわけです。
●アセンブリ言語のメモリアクセス
さて、ここまではアセンブリの予備知識でした。ここからがC言語に関わる重要な知識です。
まずは次の仕様を見てください。
ニーモニック | オペレーション |
---|---|
LD A,(nn) | A ← (nn) |
LD (nn),A | (nn) ← A |
この( )でくくられている部分は「メモリとの転送」を意味する記述です。今まではレジスタ内部でのデータの転送が行われたわけですが、このように表記することでメモリへの格納や読み出しができます。
たとえば
LD A,(0010h)
と表記した場合、メモリの0010h番地の値をAレジスタへ転送するという動作を表します。
逆も同様に
LD (0010h),A
と表記すれば、Aレジスタの値をメモリの0010h番地へ転送するというものです。
さてこれらは直接メモリのアドレスを( )の中で指定してメモリとCPUがデータのやりとりを行っています。この方法を「直接アドレス指定」とか「直接アドレッシング」と呼ばれます。
ニーモニック | オペレーション |
---|---|
LD r,(HL) | r ← (HL) |
LD (HL),r | (HL) ← r |
今度はアドレスを指定する場所がレジスタになっています。 これはレジスタHLに格納されている値のメモリアドレスにある値と指定したレジスタrとの移動する命令となります。
たとえば
LD HL,0010h
LD A,(HL)
と表記した場合、0010hという値をHLレジスタへ転送し、そのHLレジスタが示す値のアドレスからAレジスタへ値を転送する。
逆も同様に
LD (HL),A
と表記すれば、Aレジスタの値をメモリのHLレジスタの示す値のアドレスへ転送するというものです。
今度は直接、()の中へ直接、メモリのアドレスを指定しないで、HLというレジスタを介して指定したメモリアドレスとCPUがデータのやりとりを行っています。この方法の場合を「間接アドレス指定」とか「間接アドレッシング」と呼ばれます。
なぜ、このようにアドレスを指定するのにレジスタを介して行うのか。理由は簡単です。
メモリ上に100バイトのデータが並んで格納されている場合、それを続けてCPUに読み込むという処理をするような場合、100回LD命令を書くより、HLへ先頭のアドレスを指定して、HLの値を+1しながら100回繰り返して読んだ方が効率的で、プログラムの大きさを考えても有効であることは言うまでも無いでしょう。
そして、このような場合にHLレジスタのことを「ポインタ」と呼んでいます。このことは、C言語で登場するポインタとなんら変わりはありません。アドレスの値をレジスタに入れ、その値をポインタとしてアドレスを指定する(示す)、この間接アドレッシングをC言語で表現するものとして同じポインタという手法が使われるのです。