マクロ処理ディレクティブ
構文
_args
ENDM
ENDR
EXITM
LOCAL symbol [,symbol] …
name MACRO [argument] [,argument] …
REPT expr
REPTC formal,actual
REPTI formal,actual [,actual] …
パラメータ
| 置換される文字列。 |
| シンボル引数名。 |
| 式 |
|
|
| マクロの名前 |
| マクロに対してローカルにするシンボル |
説明
これらのディレクティブを使用してマクロを定義できます。式でディレクティブを使用する際に適用される制限については、式の制限を参照してください。
ディレクティブ | 説明 | 式の制限 |
|---|---|---|
マクロに受け渡される引数の数に設定されます。 | ||
マクロ定義を終了します。 | ||
繰返し構造を終了します。 | ||
マクロが終了する前に抜け出します。 | ||
マクロに対してローカルなシンボルを作成します。 | ||
マクロを定義します。 | ||
指定回数だけ命令を繰り返します。 | 前方参照禁止 外部参照禁止 絶対 固定 | |
文字を繰り返し、置換します。 | ||
テキストを繰り返し、置換します。 |
マクロとは、1行以上のアセンブラソース行のブロックを表現するユーザ定義シンボルです。マクロを定義すると、アセンブラディレクティブやアセンブラニーモニックのようにプログラム内でこのマクロを使用できるようになります。
アセンブラがマクロを検出すると、マクロの定義が検索され、ソースファイルの当該位置にそのマクロが含まれているかのように、マクロに記述されている行が挿入されます。
マクロは単純なテキスト置換を効率的に行います。マクロにパラメータを指定することで、置換対象を制御することができます。
マクロプロセスは、以下の3つのフェーズで構成されます。
アセンブラはマクロ定義をスキャンし、保存します。
MACROとENDMの間のテキストは保存されますが、構文はチェックされません。インクルードファイルのリファレンス$fileが記録され、マクロの展開時にインクルードされます。マクロ呼び出しによりアセンブラはマクロプロセッサ(エクスパンダ)を起動します。マクロエクスパンダは、(マクロ内に存在しない場合)ソースファイルからのアセンブラ入力ストリームをマクロエクスパンダからの出力に切り替えます。マクロエクスパンダは、要求されたマクロ定義からの入力を取得します。
マクロエクスパンダは、ソースレベルでのテキスト置換のみを処理するため、アセンブラシンボルを認識できません。呼び出されたマクロ定義からの行がアセンブラに受け渡される前に、エクスパンダはシンボルマクロ引数のすべてのオカレンスの行をスキャンし、展開引数に置換します。
その後、展開された行は、その他すべてのアセンブラソース行と同様に処理されます。アセンブラへの入力ストリームは、現在のマクロ定義のすべての行が読み込まれるまで、マクロプロセッサからの出力となります。
マクロの定義
マクロの定義には以下の文を使用します。
nameMACRO[argument] [,argument] …
ここで、nameはマクロに対して使用する名前、argumentはマクロの展開時にマクロに受け渡す値の引数です。
たとえば、マクロerrMacroを次のように定義できます。
name errMacro
extern abort
errMac macro text
bl abort
data
dc8 text,0
endmこのマクロでは、パラメータtext (LRで渡されます)を使用して、ルーチンabortに対してエラーメッセージを設定しています。このマクロは、たとえば以下のような文で呼び出します。
section MYCODE:CODE(2)
arm
errMac 'Disk not ready'アセンブラはこれを以下のように展開します。
section MYCODE:CODE(2)
arm
bl abort
data
dc8 'Disk not ready',0
end1つ以上の引数から成るリストを省略すると、マクロを呼び出すときにユーザが指定する引数は\1~\9および\A~\Zと呼ばれます。
そのため、前の例は以下のように記述できます。
name errMacro
extern abort
errMac macro text
bl abort
data
dc8 \1,0
endmマクロが終了する前にマクロから抜け出すにはEXITMディレクティブを使用します。
EXITMは、REPT...ENDR、 REPTC...ENDR、REPTI...ENDRの各ブロックの内部で使用できません。
マクロに対してローカルなシンボルを作成するには、LOCALを使用します。LOCALディレクティブは、シンボルの使用前に使用する必要があります。
マクロを展開するたびに、ローカルシンボルの新しいインスタンスがLOCALディレクティブによって作成されます。したがって、繰返しマクロ内でローカルシンボルを使用することができます。
注記
マクロの再定義は不正です。
特殊文字の受渡し
マクロ呼び出し内で引用符<と>をペアで使用することにより、コンマや空間が含まれるマクロ引数を強制的に1 つの引数として解釈させることができます。
例えば:
name cmpMacro
cmp_reg macro op
CMP op
endmマクロは、マクロ引用符を使用して呼び出すことができます。
section MYCODE:CODE(2)
cmp_reg <r3,r4>
endマクロ引用符は、コマンドラインオプション-Mを使用して再定義できます(-Mを参照)。
定義済マクロシンボル
シンボル_argsには、マクロに引き渡される引数の数を設定します。以下の例は、_argsの使用方法を示します。
fill macro
if _args == 2
rept \2
dc8 \1
endr
else
dc8 \1
endif
endm
module filler
section .text:CODE(2)
fill 3
fill 4, 3
endこれにより、以下のコードが生成されます。
19 module fill
20 section .text:CODE(2)
21 fill 3
21.1 if _args == 2
21.2 rept
21.3 dc8 3
21.4 endr
21.5 else
21 00000000 03 fill 3
21.1 endif
21.2 endm
22 fill 4, 3
22.1 if _args == 2
22.2 rept 3
22.3 dc8 4
22.4 endr
22 00000001 04 dc8 4
22 00000002 04 dc8 4
22 00000003 04 dc8 4
22.1 else
22.2 dc8 4
22.3 endif
22.4 endm
23 end繰返し文
同じ命令ブロックを複数回アセンブルするには、REPT...ENDR構造を使用します。exprの評価結果が0である場合、何も生成されません。
文字列の各文字に対して1回だけ命令ブロックをアセンブルするには、REPTCを使用します。文字列にカンマが含まれる場合、引用符で囲む必要があります。
二重引用符には特別な意味があります- 反復処理する文字文字を囲むためだけに使用されます。一重用符には特別な意味はなく、通常の文字として処理されます。
一連の文字列内の各文字列に対して1回だけ命令ブロックをアセンブルするには、REPTIを使用します。文字列にカンマが含まれる場合、引用符で囲む必要があります。
以下の例は、文字列内の各文字をプロットするために、サブルーチンplotcへの一連の呼び出しをアセンブルしています。
name reptc
extern plotc
section MYCODE:CODE(2)
banner reptc chr, "Welcome"
movs r0,#'chr' ; Pass char as parameter.
bl plotc
endr
endこれにより、以下のコードが生成されます。
9 name reptc 10 extern plotc 11 section MYCODE:CODE(2) 12 13 banner reptc chr,"Welcome" 14 movs r0,#'chr' ; Pass char as parameter 15 bl plotc 16 endr 16.1 00000000 5700B0E3 movs r0,#'W' ; Pass char as parameter 16.2 00000004 ........ bl plotc 16.3 00000008 6500B0E3 movs r0,#'e' ; Pass char as 16.4 0000000C ........ bl plotc 16.5 00000010 6C00B0E3 movs r0,#'l' ; Pass char as parameter. 16.6 00000014 ........ bl plotc 16.7 00000018 6300B0E3 movs r0,#'c' ; Pass char as parameter. 16.8 0000001C ........ bl plotc 16.9 00000020 6F00B0E3 movs r0,#'o' ; Pass char as parameter. 16.10 00000024 ........ bl plotc 16.11 00000028 6D00B0E3 movs r0,#'m' ; Pass char as parameter. 16.12 0000002C ........ bl plotc 16.13 00000030 6500B0E3 movs r0,#'e' ; Pass char as parameter. 16.14 00000034 ........ bl plotc 17 18 end
以下の例では、REPTIを使用して複数のメモリロケーションをクリアしています。
name repti
extern a,b,c
section MYCODE:CODE(2)
clearABC movs r0,#0
repti location,a,b,c
ldr r1,=location
str r0,[r1]
endr
endこれにより、以下のコードが生成されます。
9 name repti 10 extern a,b,c 11 section MYCODE:CODE(2) 12 13 00000000 0000B0E3 clearABC movs r0,#0 14 repti location,a,b,c 15 ldr r1,=location 16 str r0,[r1] 17 endr 17.1 00000004 10109FE5 ldr r1,=a 17.2 00000008 000081E5 str r0,[r1] 17.3 0000000C 0C109FE5 ldr r1,=b 17.4 00000010 000081E5 str r0,[r1] 17.5 00000014 08109FE5 ldr r1,=c 17.6 00000018 000081E5 str r0,[r1] 18 19 end
インラインコーディングによる効率化
時間が重要なコードでは、ルーチンをインラインコーディングすることによりサブルーチンの呼び出しとリターンのオーバヘッドを避けることで、効率化を図ることができます。これはマクロを使用すると便利です。
以下の例では、バッファからポートへバイトが出力されます。
name ioBufferSubroutine
section MYCODE:CODE(2)
arm
play ldr r1,=buffer ; Pointer to buffer.
ldr r2,=ioPort ; Pointer to ioPort.
ldr r3,=512 ; Size of buffer.
add r3,r3,r1 ; Address of first byte
; after buffer.
loop ldrb r4,[r1],#1 ; Read a byte of data, and
strb r4,[r2] ; write it to the ioPort.
cmp r1,r3 ; Reached first byte after?
bne loop ; No: repeat.
bx lr ; Return.
ioPort equ 0x0100
section MYDATA:DATA(2)
data
buffer ds8 512 ; Reserve 512 bytes.
section MYCODE:CODE(2)
arm
main bl play
done b done
end効率化のため、次のマクロを使用して再コーディングできます。
name ioBufferInline
play macro buf,size,port
local loop
ldr r1,=buf ; Pointer to buffer.
ldr r2,=port ; Pointer to ioPort.
ldr r3,=size ; Size of buffer.
add r3,r3,r1 ; Address of first byte
; after buffer.
loop ldrb r4,[r1],#1 ; Read a byte of data, and
strb r4,[r2] ; write it to the ioPort.
cmp r1, r3 ; Reached first byte after?
bne loop ; No: repeat.
endm
ioPort equ 0x0100
section MYDATA:DATA(2)
data
buffer ds8 512 ; Reserve 512 bytes.
section MYCODE:CODE(2)
arm
main play buffer,512,ioPort
done b done
endloopラベルをマクロに対してローカルにするために、LOCALディレクティブが使用されています。さもなければ、loopラベルは既に存在しているため、マクロが2回使用されるとエラーが生成されます。