Tatara

第9章
命令

この章では、Z80の命令と、R800が追加した2つの命令を、TATARA向けにどう書くかを説明します。オペランドの形、インデックス・レジスターとディスプレースメント、相対ジャンプ、そしてオペランドが正しくないときに TATARAが表示するメッセージです。それぞれの命令が何をするかは説明しません。それは、Z80のプログラミングを学ぶ本や講座の役目です。参考のため、付録Bに命令を種類ごとに一覧にしてあります。

9.1 命令セット

TATARAが受け付けるのは、ザイログが書くとおりの形で書いたZ80の命令、ザイログが公表しなかったもののどのZ80でも動く未公開命令(undocumented instruction、9.5節)、そしてR800のMULUBとMULUW (9.4節)で、全部で70個のニーモニックです。6章で説明したように、ニーモニックはオペレーション・フィールドに、そのオペランドはコンマで区切ってオペランド・フィールドに書きます。

9.2 オペランド

オペランドは、表9.1のどれかの形をしています。どの命令がどの形をとるかはZ80によって決まっていて、Z80の本に一覧があります。表のバイトは、それぞれの例に対してTATARAが書き出すものです。

形 例 バイト
レジスター ld a,b 78
即値 ld a,5 3E 05
ld hl,1234h 21 34 12
レジスター間接 ld a,(hl) 7E
ex (sp),hl E3
jp (hl) E9
インデックス ld a,(ix+5) DD 7E 05
ld a,(ix-1) DD 7E FF
ld a,(iy) FD 7E 00
メモリのアドレス ld a,(1234h) 3A 34 12
ld hl,(1234h) 2A 34 12
ポート in a,(98h) DB 98
out (c),a ED 79
条件 jr nz,$ 20 FE
ビット番号 set 0,(ix+3) DD CB 03 C6
決まった値 rst 38h FF
im 1 ED 56
表 9.1: オペランドの形

9.2.1 値とかっこ

命令が数、アドレス、ポートをとる場所には、どんな式でも書けます(8章)。かっこのないオペランドは即値(immediate value)で、その数そのものが命令の中に入ります。かっこで囲んだオペランドはメモリのアドレスで、INとOUTではポートです。ld a,5はAに数5を入れ、ld a,(5)はアドレス5に格納されているバイトをAに入れます。

ld a,5のように1バイトを占める即値は、式の下位バイトです。TATARAは、値がそこに収まるかどうかを確かめません。ld a,-1は意図したとおり0FFhを書き出しますが、ld a,300は300の下位バイトである2Chを、何も表示せずに書き出します。また、1バイトには、TANRENがあとで仕上げる必要のあるアドレスを入れられないので、1バイトの値はアブソリュートでなければなりません(8.6節)。ld hl,msgのような2バイトの値は、リロケータブルでも外部でもかまいません。

9.2.2 インデックス・レジスター

インデックスのオペランドは(IX+d)または(IY+d)で、dはディスプレースメント (displacement)です。これはインデックス・レジスターに加える−128から 127までの符号付きの数で、+でも-でも書けます。また、(ix-1)や(ix+count*2)のように、アブソリュートな式であれば何でもかまいません。(IX)だけのときは(IX+0)の意味です。範囲外のディスプレースメントがあると、TATARAは止まります。

DISP.AS(2): ERROR: an index displacement must be -128 to 127.
 

9.3 相対ジャンプ

JRとDJNZは相対ジャンプ (relative jump)です。命令の中には、ジャンプ先のアドレスではなく、そこまでの距離が符号付きの1バイトで入ります。ソースには、JPと同じようにジャンプ先を書けば、TATARAが距離を計算します。たとえばjr nz,loopやdjnz loopです。

距離は次の命令から測り、−128から127バイトまででなければなりません。自分自身にジャンプするjr $は距離−2で、18 FEにアセンブルされます。それより遠いジャンプ先があると、TATARAは止まります。

JR.AS(2): ERROR: a JR or DJNZ can only reach -128 to 127.
 

ジャンプ先は、ジャンプと同じセグメントにあるか、アブソリュートなアドレスでなければなりません。TANRENが別の場所に置くコードまでの距離は、プログラムをリンクするまでわからないからです。遠すぎるジャンプ先や、別のモジュールにあるジャンプ先にはJPを使ってください。

9.4 R800の命令

MSX turbo RのプロセッサーであるR800は、Z80の命令に2つのかけ算の命令を加えています。TATARAが受け付ける3つの形を表9.2に示します。

命令 バイト 働き
mulub a,r ED C1+8r A ×r、結果はHL
muluw hl,bc ED C3 HL × BC、結果はDE:HL
muluw hl,sp ED F3 HL × SP、結果はDE:HL
表 9.2: R800の命令

rは8ビットのレジスターで、mulub a,bはED C1です。TATARAはどのレジスターでも受け付けますが、R800の資料が結果を保証しているのはB、C、D、Eだけです。最初のオペランドは、MULUBではA、MULUWではHLでなければなりません。

警告.  TATARAはどのMSXでもこれらの命令をアセンブルしますが、それを使ったプログラムが正しく動くのはturbo Rだけです。Z80では、かけ算を行いません。

9.4.1 R800のニーモニック

命令は、それぞれ数バイトとして格納されます。最初の1バイト、またはDDやEDのようなプレフィックスがある場合は最初の2バイトが、どの命令なのかを表します。この部分をオペコード (opcode)といいます。残りの部分があれば、そこには数、アドレス、ディスプレースメントなどのオペランドが入ります。プロセッサーが読むのはバイトだけです。LDやDJNZのようなニーモニック(mnemonic)は、数を覚えなくてもプログラムが書けるように、人がオペコードに付けた名前です。

ニーモニックは名前にすぎないので、同じオペコードに別の名前の組を付けることもできます。『MSX-Datapack』に収められているアスキーのR800の資料は、命令全体に新しいニーモニックを付けています。JPはbr (branch)、DJNZはdbnz、EXはxch、RESはclr、LDIRはmovemです。レジスター名はドットで始まり、角かっこはメモリを表し、アキュムレーターも必ず書きます。ザイログのSUB Bはsub .a,.bになります。2つのかけ算を除けば、R800の命令はすべて、名前を変えたZ80の命令と同じオペコードを持ち、同じ動作をします。

256バイトのメモリを0にする短いルーチンを、両方の書き方で表9.3に示します。バイトは同じです。

Z80 R800 バイト
clear: ld hl,buffer ld .hl,buffer 21 nn nn
ld b,0 ld .b,0 06 00
xor a xor .a,.a AF
loop: ld (hl),a ld [.hl],.a 77
inc hl inc .hl 23
djnz loop dbnz loop 10 FC
ret ret C9
表 9.3: 同じルーチンのZ80とR800のニーモニック

Bは256回目の減算でようやく0になるので、ld b,0とするとDJNZは256回繰り返します。

この文章を書いている時点では、TATARAが受け付けるのはZ80のニーモニックだけです。R800のニーモニックで書かれたプログラムは、TATARAでアセンブルする前にZ80のニーモニックに書き直す必要があります。そうしてできるプログラムは同じものです。

9.5 未公開命令

ザイログはZ80の命令を公表しましたが、プロセッサーが実行するオペコードのすべてではありませんでした。残りのうちのいくつかは役に立つ働きをし、どのZ80でも同じように動き、何十年もMSXのプログラムで使われてきました。TATARAは、そのうちの次の4つのグループを受け付けます。

R800の命令と同じように、これらはどのMSXでもアセンブルされ、有効にするオプションはありません。M80にはどれもありません(付録J)。表9.4にその書き方を示します。付録Bには、104の書き方すべてをバイトとともに挙げます。

書き方

バイト

sll r(B、C、D、E、H、L、A)

CB 30+r

sll (hl)

CB 36

sll (ix+d)、sll (iy+d)

DD CB d 36、FD CB d 36

ld x,rとld r,x(B、C、D、E、A)

IXならDD、IYならFDのあとに、上位の半分ならH、下位の半分ならLにした同じ命令のバイト。ld ixh,bはDDと、ld h,bの60

ld x,y(同じレジスターの半分どうし)

同じ。ld ixh,ixlはDD 65

ld x,n

同じ。ld ixl,5はDD 2E 05

inc x、dec x

同じ。inc iyhはFD 24

add a,x、adc a,x、sub x、sbc a,x、and x、xor x、or x、cp x

同じ。cp ixlはDD BD

in f,(c)

ED 70

out (c),0

ED 71

表 9.4: 未公開命令。rは8ビットのレジスターで、コードは付録Bのもの。xとyはインデックス・ハーフ

9.5.1 インデックス・ハーフの仕組み

IXHのためのオペコードはありません。命令の前にDDを置くと、その命令はHLの代わりにIXを使い、それが半分にも及びます。HはIXHに、LはIXLになります。ld a,hは7Cなので、ld a,ixhはDD 7Cです。FDなら、同じ命令がIYを使います。

プレフィックスは1つのオペランドではなく命令全体にかかり、それでどの書き方があるかが決まります(図9.1)。

PIC

図 9.1: プレフィックスは命令全体にかかる。DDが2つの命令にどう働くか

Z80にその書き方がない場所でも、インデックス・ハーフは拒否されます。ローテートとシフト、BIT、SET、RES、INとOUT、そしてld (ix+5),ixhのようにインデックス付きのアドレスと並ぶ場合です。どれも、TATARAはnot a form this instruction has.で止まります。

9.5.2 プログラムが当てにできないこと

警告.  MSX turbo RでのSLL。R800はCB 30からCB 37を実行しますが、SLAとして実行し、ビット0は0のままです。Bが81hのとき、sll bはZ80では03h、R800では02hを残します。キャリーはどちらでも同じなので、違いが見えるのはビット0だけです。SLLを使うプログラムは、turbo Rでは同じように動きません。インデックス・ハーフ、IN F,(C)、OUT (C),0は、R800でも Z80と同じように動きます。

警告.  OUT (C),0はいつも0を書くとは限りません。NMOSのZ80は0を書き、CMOSのZ80は0FFhを書きます。openMSXでは、どちらのプロセッサーも0FFhを書きました。プログラムは書かれる値を当てにできません。

IN F,(C)はAを変えず、IN A,(C)と同じようにフラグを設定します。使い道は、ポートのビットをフラグで調べることだけです。

9.5.3 綴りと名前

これらの命令の綴りはそれぞれ1つだけです。SL1やSLIAではなくSLL、HX、LX、HY、LYではなくIXHなど、IN (C)ではなくIN F,(C)、そして00hや式ではなく数字の0そのものを書いたOUT (C),0です。ほかの綴りでは、TATARAが知らない語に対するいつものメッセージが出ます。

IXH、IXL、IYH、IYLはレジスターなので、もう名前には使えません。M80はこれらをラベルとして受け付けますが、TATARAでそのようなラベルがあると、ld a,ixhの意味がメッセージなしで変わってしまいます。そのためTATARAはこれを拒否し、PUBLICとEXTRNでも拒否します。

IXHNAM.AS(2): ERROR: IXH, IXL, IYH and IYL are registers, not names.
 

HX、LX、HY、LYはふつうの名前のままなので、これらを座標に使っているプログラムはこれまでどおりアセンブルできます。

ほかの2つのグループの未公開オペコードは受け付けません。rlc (ix+2),bのように、結果をメモリとレジスターの両方に入れる書き方と、EDグループの中でNEG、RETN、NOPを繰り返す余分なオペコードです。

9.6 オペランドが正しくないとき

TATARAが使えないオペランドに対して表示するメッセージを、それぞれの原因となる行とともに表9.5に示します。

行

メッセージ

ld hl,a

not a form this instruction has.

mulub b,c

not a form this instruction has.

ld a,(ix+200)

an index displacement must be -128 to 127.

jr far

a JR or DJNZ can only reach -128 to 127.

rst 5

RST takes 0, 8, 10h and so on to 38h.

im 3

IM takes 0, 1 or 2.

bit 8,a

a bit number must be 0 to 7.

表 9.5: オペランドについてのメッセージ

not a form this instruction has.は一般的なメッセージで、命令はあるものの、そのオペランドの形はないという意味です。Z80は8ビットのレジスターを16ビットのレジスターにコピーできないので、ld hl,aがその例です。その命令にどの形があるかは、Z80の本か付録Bで確かめてください。