公開日:2021/02/20
15th Season
#15-3 マイコンを作るよ(付録)
このページは、本HPで作成したオリジナルCPUコアMoscoviumシリーズ用アセンブラマニュアルです。
詳細については、以下リンクから本文を参照してください。
本文へ戻る。
Moscovium series Macro assembler Manual
Moscoviumシリーズのアセンブラ(asm_mcvm.olv)は以下リンクからダウンロードできます。
Olive+のスクリプトですので、実行にはWindowsにOlive+のインストールが必要です。Olive+はこちらのダウンロードコーナから入手できます。
以下に、MoscoviumシリーズCPUコアの命令セットマニュアルをリンクしておきます。
アセンブラ記法
- アセンブラファイル内の大文字・小文字は区別されない。出力データは小文字に変換される。
- ただし、dats疑似命令の引数で、二重引用符(”)で括られた文字列に関しては、大文字・小文字が区別される。
- 定義した識別子などは全て小文字となる。
- 命令・疑似命令・組み込みマクロなどを含め、基本的に小文字で記述することを推奨する。
- 語: 空白またはタブ(以降、空白類)で区切られる。先頭の空白類は無視する。
- オペランドの区切りは空白類またはカンマ(,)。
- 連続する区切り文字は1個の区切り文字と見なされる。
- オペランドに数式を記述可能だが、上のルールによって数式内に空白類を含むことはできない。
- 各行、最初の語は命令(ニーモニック)または疑似命令、アドレスラベルのいずれか。
- 後ろに複数のオペランドを持つ場合がある。
- 最初の語がコロン(:)で終わる場合、コロンを除いた文字をアドレスラベルとみなす。
- アドレスラベルの後ろに命令等を続けることはできない。→アドレスラベルは独立した行で定義する。
- アドレスラベルは、Olive+の変数"lab_"+アドレスラベル名の形式で、宣言された時のプログラムカウンタ値が記憶される。
- 分岐命令からは、そのまま参照可能(「bra loop」、「jalw get_line」等)。
- その他アセンブラ命令からは、「ldwi r0,lab_somewhere」等の様に参照できる(アドレスラベル名の前に"lab_"の追加が必要)。
- オペランドに含まれる数式は、Olive+によって評価される。
- 従って、数値表現や演算子、関数などが使用可能。
- 文法はOlive+に準ずる(Olive+のスクリプトマニュアルで確認のこと)。
- ただし、オペランド中に空白類を含むことが出来ないことに注意。
- オペランド値の範囲は、32ビット符号付整数であること。
- Olive+が評価するオペランドは、32ビット符号付整数なので、32ビット符号無整数を記述すると、正常にアセンブルできない。
- 例)datl 3221225470
- 16進数表記では0xBFFFFFFEと、32ビット符号無整数なので、不正な数値。
- datl 0xBFFFFFFE、または、
- datl -1073741826、と記せば合法。
- [r0]形式でレジスタ間接を表して、アセンブラの可読性を向上する記述が使用可能。
- この記述は、可読性向上の為だけにあって、文法上は無視される。
- 文法上無視するので、本来関係のない場所に現れても、エラーとならない場合がある。
- 例)stw [r7],r0
- 汎用レジスタr0をr7の指し示すアドレスに書き込む。
- 「stw r7,r0」と、記述しても命令の意味は変わらない(エラーとならない)。
- [sp+r0]または[sp,r0]形式でスタックポインタ相対間接を表して、アセンブラの可読性を向上する記述が使用可能。
- この記述は、可読性向上の為だけにあって、文法上は無視される。
- 文法上無視するので、本来関係のない場所に現れても、エラーとならない場合がある。
- 例)ldwsp r0,[sp+r1]
- Sp+r1で示されるアドレスからワードデータを読み込んでr0に転送する。
- 「ldwsp r0,r1」または「ldwsp r0,[r1]」等と記述しても命令の意味は変わらない(エラーとならない)。
- [tr:r0]または[tr,r0]形式で32ビット拡張アドレス間接を表して、アセンブラの可読性を向上する記述が使用可能。
- この記述は、可読性向上の為だけにあって、文法上は無視される。
- 文法上無視するので、本来関係のない場所に現れても、エラーとならない場合がある。
- 例)stwx [tr:r7],r0
- 一時レジスタtrを上位16ビット、汎用レジスタr7を下位16ビットアドレスとする32ビット拡張アドレスへ汎用レジスタr0の値を書き込む。
- 「stwx r7,r0」または「stwx [r7],r0」等と記述しても命令の意味は変わらない(エラーとならない)。
- 文字列オペランド: 文字列オペランドは、二重引用符(”)で括る。
- 文字列には、"\0"/"\t"/"\r"/"\n"/"\”"の書式で、ゼロ(NIL)コード、タブコード、復帰(CR)コード、改行(LF)コード、二重引用符(”)を含むことが出来る。
- 文字列オペランドはdats疑似命令のみが使用する。
- 各行内、ナンバマーク(#)または、"//"以降はコメントとして無視される。
- コメントは最終出力ファイル(MIF,V,DATWなど)には含まれない。
- ただし、行頭の"//"で始まるコメントだけは、最終出力ファイルに反映される。
- 分岐命令:
- 分岐命令のオペランドは、アドレスラベルでなくてはならない。
- 次命令をスキップする目的で「beq +2」とすると、エラーとなる。
- このケースでは、特殊アドレスラベル「pcnt」を使用でき、「beq pcnt+2」は合法。
- pcntは、現在の命令の格納アドレス+2番地を指す。
- オペランド最初の文字列はアドレスラベルである必要があるので、「beq 2+pcnt」はエラーとなる。
- 特殊アドレスラベル「pcnt」は、他の命令からも「lab_pcnt」で参照可能。
- 同様に「bra somewhere+0x10」等、アドレスラベルからのオフセット記述は合法。
疑似命令
- asm <出力ファイル名>[,<オプション>]
- 指定した<出力ファイル名>で、Verilog-HDLの$readmemh()システムタスクから読み込み可能なデータファイル(拡張子".datw")を出力する。
- <出力ファイル名>には、拡張子まで含まれている必要があり、指定された拡張子によって、出力ファイルフォーマットが決まる。
- 以下、認識する拡張子一覧:
- ".mif": TD IDEでFPGAボードに書き込む時、コンパイルに使用するデータファイル(Memory Initialization File)
- ".v": Verilog-HDLのRTL(組み合わせ論理ROM)
- ".mem": Verilog-HDLの$readmemh()システムタスクで読み込み可能なデータファイル(シミュレーション実行用)
- ".dat2": ブートローダを使って、シリアルモニタ経由でプログラムをダウンロードすることが可能なデータファイル
- ".datw": 廃止
- ".dat": 廃止
- <オプション>には、以下の機能を指定可能。
- "list":
- アセンブルリスト(LIS)ファイルを出力する。
- LISファイルは、<出力ファイル名>の拡張子を".lis"に変更した物となる。
- <出力ファイル名>には、アセンブル後のオブジェクトデータしか含まれないため、ソフトウェアのデバッグなどに必要となるファイル。
- "list"オプションが指定されなかった場合、LISファイルの内容が<出力ファイル名>にコメントとして埋め込む。
- "moscovium": Moscoviumで使用できない命令をアセンブルした時に警告メッセージを出力する。
- 定数ラベルasm.target=asm.core.mcがセットされる。
- 以下の文字列マクロが設定される。
-
def target_mc,""
def target_nh,"#"
def target_mn,""
def target_ts,"#"
- "nihonium": Nihoniumで使用できない命令をアセンブルした時に警告メッセージを出力する。
- 定数ラベルasm.target=asm.core.nhがセットされる。
- 以下の文字列マクロが設定される。
-
def target_mc,"#"
def target_nh,""
def target_mn,""
def target_ts,"#"
- "tennessine": Tennessineで使用できない命令をアセンブルした時に警告メッセージを出力する。
- 定数ラベルasm.target=asm.core.tsがセットされる。
- 以下の文字列マクロが設定される。
-
def target_mc,"#"
def target_nh,"#"
def target_mn,"#"
def target_ts,""
- "bit16": 16ビット幅のデータを出力する。
- "bit32": 32ビット幅のデータを出力する。
- Moscoviumシリーズの命令ROMを32ビット化したので、デフォルト設定は"bit32"となっている。
- 従来の16ビット幅出力も可能"bit16"。
- romsiz <ROM容量>
- 対象となるROMのサイズを指定して、実際のデザインで作成したROM容量と合わせておく必要がある。
- アセンブル後のコードサイズが<ROM容量>を超えた場合、アセンブラがエラー終了する。
- <ROM容量>は、ROMのサイズをバイト単位で記したもの。
- romsiz疑似命令を省略した場合、<ROM容量>=4,096となる。
- incl <ファイル名>
- <ファイル名>のファイルを取り込む。
- I/Oレジスタアドレスを列記したヘッダファイルなどの取り込みを想定。
- incl疑似命令を使い、ファイルを循環参照するとアセンブル処理が終了しなくなるので注意。
- org <アドレス>
- org <サイズ>,align
- org疑似命令にalignオプションを指定した書式では、プログラムカウンタ値が<サイズ>の倍数になる様に調整する。
- <サイズ>は、正の偶数整数でなければならない。
- 例)org 16,align
- プログラムカウンタが16の倍数となる、最近値に調整される。
- org疑似命令実行時点のプログラムカウンタと、調整後の新しいプログラムカウンタの間のデータは不確定値なので、プログラム領域で使用してはならない。
- align <サイズ>[,<コード>]
- プログラム領域で、プログラムカウンタ値が<サイズ>の倍数となる様に調整する。
- この時、align疑似命令実行時点のプログラムカウンタと、調整後の新しいプログラムカウンタの間は、<コード>で埋められる。
- <コード>が省略されると、<コード>=0x0000とみなす。
- 例)align 16,0x0000
- <コード>=0x0000は、nop命令に相当するので、プログラム領域でプログラムカウンタの調整に使用することができる。
- equ <定数ラベル>,<16ビットデータ>
- <定数ラベル>に<16ビットデータ>を割り当てる。
- <定数ラベル>の大文字・小文字は区別しない。
- Olive+の予約語や、アセンブラスクリプト内で使用している変数名と同名の<定数ラベル>名を指定すると、正常動作しない場合がある。
- 以下リンクは、asm_mcvm.olv内で使用している変数であるため、アセンブラソース内での使用は禁止。
- equh <定数ラベル>,<浮動小数値>
- <浮動小数値>をhalf型16ビットバイナリ値に変換して、<定数ラベル>に割り当てる。
- 本疑似命令では、<浮動小数値>として±INF,−0,NaNを指定することが出来ない。
- 例)equh m_pi,3.141592
- 3.141592をhalf型バイナリに変換すると0x4248なので、定数ラベルm_pi=0x4248となる。
- この時点で通常のuint16値なので、「ldwi r0,m_pi」等として使用可能。
- なお、half型の有効数字は3桁程度なので、0x4248を浮動小数値に戻すと、3.14063となり、指定値3.141592が表現可能な値に丸められている。
- <定数ラベル>に使用できない名前などはequ疑似命令と同じ。
- equf <定数ラベル>,<浮動小数値>
- <浮動小数値>をfloat型32ビットバイナリ値に変換して、<定数ラベル>に割り当てる。
- 本疑似命令では、<浮動小数値>として±INF,−0,NaNを指定することが出来ない。
- <定数ラベル>に使用できない名前などはequ疑似命令と同じ。
- def <文字列マクロ>,"文字列"
- <文字列マクロ>を宣言して、そこに"文字列"を割り当てる。
- <文字列マクロ>名は小文字変換後に定義されるので、大文字アルファベットの使用は禁止。
- 宣言した文字列マクロは、「$(<文字列マクロ>)」の書式で、登録した"文字列"と置換される。
- 文字列マクロの置換は、アセンブラの構文とは無関係に、どの場所に現れても置換される。
- 例)「def a,"#"」と宣言した場合、
- $(a)ldwi r0,0x1234 // は、$(a)が"#"に置換されて、
- ↓
- #ldwi r0,0x1234 // となり、結果として、コメントとして扱われる。
- 例)「def a,""」と宣言した場合、
- $(a)ldwi r0,0x1234 // は、$(a)が""(空文字列)に置換されて、
- ↓
- ldwi r0,0x1234 // となり、結果として、r0=0x1234が代入される。
- 置換したくない場合には、バックスラッシュ(\または\)記号を使ったエスケープによって回避可能。
- 例)「def abc,"XYZ"」と宣言した場合、
- 「$(abc)」を置換したくない場合には、「$\(abc)」とすることで回避可能。ただし、エスケープ(\または\)は文字列("〜")の中だけで有効。
- dats "this is a string $(abc) or $\(abc)"
- ↓
- dats "this is a string XYZ or $(abc)"
- dats "文字列"
- 二重引用符(”)で括られた文字列をデータとしてプログラムメモリに格納する。
- 文字列長が奇数バイト数だった場合、末尾にNILコード(0x00)が追加され、16ビットワード境界に調整される。
- 文字列長が偶数バイト数だった場合、NILコードは追加されない。従って、NIL終端されたC言語文字列にしたい場合には、明示的に"\0"で終端する必要がある。
- "文字列"内にシフトJIS(S-JIS)形式のマルチバイト文字を記述可能。S-JISコードの半角カタカナ文字(1バイトコード)も、使用可能。
- バックスラッシュ(\または\)で始まる以下のエスケープシーケンスを記述可能。
- \0: NILコード(0x00)に置換する。
- NIL終端されたC言語文字列にする場合、このエスケープシーケンスで明示的に終端記号を指定する必要がある。
- \t: タブコード(0x09)に置換する。
- \n: 改行コード(0x0a)に置換する。
- \r: 復帰コード(0x0d)に置換する。
- \": 二重引用符(”)に置換する。
- \xhh: 文字コード(0xhh)に置換する。hhは2桁16進数である必要がある。
- 例)dats "hello, world\r\n\0"
- NIL終端された文字列で、Windowsの改行コード(CR+LF)が付いた文字列"hello, world"。
- 明示的に「\0」を指定しないと、NIL終端されない場合があるので、注意。
- datb <8ビットデータ#1>[,<8ビットデータ#2>[,……]]
- カンマ(,)で区切られた8ビットデータをプログラムメモリに格納する。
- データ数が奇数バイトだった場合、末尾に0x00が追加され、16ビットワード境界に調整される。
- datw <16ビットデータ#1>[,<16ビットデータ#2>[,……]]
- カンマ(,)で区切られた16ビットデータをプログラムメモリに格納する。
- datl <32ビットデータ#1>[,<32ビットデータ#2>[,……]]
- カンマ(,)で区切られた32ビットデータをプログラムメモリに格納する。
- dath <浮動小数値#1>[,<浮動小数値#2>[,……]]
- カンマ(,)で区切られた浮動小数値をhalf型バイナリ値に変換後、プログラムメモリに格納する。
- データは、<浮動小数値>1個当たり、16ビットのhalf型バイナリ値となる。
- 本疑似命令では、<浮動小数値>として±INF,−0,NaNを指定することが出来ない。
- datf <浮動小数値#1>[,<浮動小数値#2>[,……]]
- カンマ(,)で区切られた浮動小数値をfloat型バイナリ値に変換後、プログラムメモリに格納する。
- データは、<浮動小数値>1個当たり、32ビットのfloat型バイナリ値となる。
- 本疑似命令では、<浮動小数値>として±INF,−0,NaNを指定することが出来ない。
-
rept <繰り返し回数>
<繰り返し定義行>
:
endr
- rept疑似命令からendrまでの間に記述したアセンブラソースを<繰り返し回数>で指定した回数繰り返して展開する。
- rept疑似命令中にrept疑似命令を入れ子にすることはできない。
- <繰り返し定義行>の中で、以下に示す特殊識別子は、各々相当する文字列に置換して展開される。
- $(reptn): <繰り返し回数>を10進数値とした文字列で置換される。
- $(repti): 0から始まって繰り返し展開の度にインクリメント(+1)されるシリアル番号の10進数文字列で置換される。$(repti)=0〜<繰り返し回数>−1である。
- $(reptr): <繰り返し回数>−1から始まって繰り返し展開の度にデクリメント(−1)されるシリアル番号の10進数文字列で置換される。$(reptr)=<繰り返し回数>−1〜0である。
- 繰り返し定義行の展開よりも、文字列マクロ(参考def疑似命令)置換の方が優先される。
- 特殊識別子"reptn"や"repti"、"reptr"の名前を持った文字列マクロがdef疑似命令で宣言されていた場合、そちらが先に置換されてしまうので注意。
- <繰り返し定義行>内では、文字列("〜")中も含めて、全て小文字に変換される。
-
例)
rept 4
ldbiu r$(repti),$(reptr)*$(reptn)
endr
↓
ldbiu r0,3*4
ldbiu r1,2*4
ldbiu r2,1*4
ldbiu r3,0*4
-
ifexp <式>[,<オプション>]
<式成立行>
[elsi <式2>
<式2成立行>
]
[elsi
<式非成立行>
]
endi
- 条件付きアセンブルを実行する。
- ifexp疑似命令中にifexp疑似命令を入れ子にすることはできない。
- <式>が成立(真)した時、<条件成立行>が有効となって、アセンブルされる。
- アセンブルされなかった行については、命令コードが出力されない。
- C言語の「#ifdef」、Verilog-HDLの「`ifdef」をイメージ。
- ifexp疑似命令中にelsi疑似命令が見つかった場合、新たに指定された<式2>が評価される。
- <式2>が成立(真)した時、<式2成立行>が有効となって、アセンブルされる。
- <式2>が省略されると、直前に評価した<式>が非成立(偽)だった場合に、<式非成立行>がアセンブルされる。
- <式>は、Olive+によって評価される。
- <式>に空白類を含むことは出来ない。
- <式>に使える定数ラベルは、「equ num,1」等の様に、定数を定義した物に限る。
- 「equ num_NG, last_data」等の様に、定数以外の物や、
- 「equ numNG2, 0x44+32」等の様に、数式を含んだ物は使用不可。
-
例)
equ num, 13
ifexp num=1|num>10
ldbiu r0,0x11 // <式>が真の時
elsi
ldbiu r0,0x22 // <式>が偽の時
ende
- <オプション>は省略可能。
- "print"を指定すると、条件不成立の行などがコメントとしてアセンブルリストに出力される。
組み込みマクロ命令
- ldwi <汎用レジスタ>,<16ビットデータ>
- <汎用レジスタ>に<16ビットデータ>を転送する。
-
例)「ldwi r7,idrgcode」は、以下の様な命令に展開される。
ldbih r7,((idrgcode)>>8)
ldbil r7,((idrgcode)&0xff)
- ldwi疑似命令の別名としてldi疑似命令を引き続き使用可能。
- ldc <制御レジスタ>,<16ビットデータ>
- <制御レジスタ>に<16ビットデータ>を転送する。
-
例)「ldc sp,rambtm」は、以下の様な命令に展開される。
ldch sp,((rambtm)>>8)
ldcl sp,((rambtm)&0xff)
- hldi <汎用レジスタ>,<浮動小数値>
- <浮動小数値>を16ビットhalf型バイナリデータに変換して、<汎用レジスタ>に転送する。
- 本マクロ命令では、<浮動小数値>として±INF,−0,NaNを指定することが出来ない。
-
例)「hldi r0,3.141592」は、以下の様な命令に展開される。
ldbih r0,((0x4248)>>8)
ldbil r0,((0x4248)&0xff)
- 3.141592をhalf型バイナリデータに変換すると、0x4248となる。
- なお、half型の有効数字は3桁程度なので、0x4248を浮動小数値に戻すと、3.14063となり、指定値3.141592が表現可能な値に丸められている。
- fldi <汎用レジスタ>,<浮動小数値>
- <浮動小数値>を32ビットfloat型バイナリデータに変換して、<汎用レジスタ>に転送する。
- 本マクロ命令では、<浮動小数値>として±INF,−0,NaNを指定することが出来ない。
- 本マクロ命令は、ldli命令に展開される。
- jmprX <アドレスラベル>
- jalwrX <アドレスラベル>
- jallrX <アドレスラベル>
- <アドレスラベル>へjmp命令またはjalw命令、jall命令する疑似命令。
- Xは0〜7の汎用レジスタ番号。分岐先アドレスを指定するのに汎用レジスタXを使用する。
-
例)「jalwr7 get_line」は、以下の様な命令に展開される。
ldbih r7,(lab_get_line)>>8
ldbil r7,(lab_get_line)&0xff
jalw r7
- pushwm <レジスタ1>[,<レジスタ2>[,……]]
- <レジスタ>を列記された順に、スタックに積む。
- <レジスタ>には汎用レジスタ(r0〜r7)、制御レジスタ(sr,pc,iv,tr)を指定可能。
- 各々、対応するpushw命令、pushcw命令に展開される。
- pushwm疑似命令の別名としてpushm疑似命令を引き続き使用可能。
- popwm <レジスタ1>[,<レジスタ2>[,……]]
- <レジスタ>を列記された順に、スタックから取り出す。
- <レジスタ>には汎用レジスタ(r0〜r7)、制御レジスタ(sr,iv,tr)を指定可能。
- 各々、対応するpopw命令、popcw命令に展開される。
-
例)「列記された順」なので、以下の順に列記すると元のレジスタにpopできる。
pushwm r0,r1,sr
popwm sr,r1,r0
- popwm疑似命令の別名としてpopm疑似命令を引き続き使用可能。
- pushlm <レジスタ1>[,<レジスタ2>[,……]]
- <レジスタ>を列記された順に、スタックに積む。
- <レジスタ>には汎用レジスタ(r0〜r7)、制御レジスタ(sr,pc,iv,tr)を指定可能。
- 各々、対応するpushl命令、pushcl命令に展開される。
- poplm <レジスタ1>[,<レジスタ2>[,……]]
- <レジスタ>を列記された順に、スタックから取り出す。
- <レジスタ>には汎用レジスタ(r0〜r7)、制御レジスタ(sr,iv,tr)を指定可能。
- 各々、対応するpopl命令、popcl命令に展開される。
-
例)「列記された順」なので、以下の順に列記すると元のレジスタにpopできる。
pushlm r0,r1,r2
poplm r2,r1,r0
- sesr <ビット番号>
- clsr <ビット番号>
- seie
- clie
- 状態レジスタsrの割り込み許可IEビットをセット(seie)/クリア(clie)する。
- 各々、「sesrl 3」/「clsrl 3」に展開される
- srie <ビットフィールド>
- 状態レジスタsrのIEフィールド(2ビット)に値<ビットフィールド>を設定する。
- <ビットフィールド>は、0〜3の整数値だが、IEフィールドのビット位置(第3,2ビット)に合わせて、0x0,0x4,0x8,0xcの何れかを指定することも可能。
- 各々、sesrl命令とclsrl命令を組み合わせた2個の命令に展開される。
- Srの他のビットを破壊することなく、割り込み許可レベルIEフィールドに任意の値を設定できる。
- srbk <ビットフィールド>
- 状態レジスタsrの{BK1,BK0}フィールドに、値<ビットフィールド>を設定する。
- <ビットフィールド>は、0〜3の整数値。
- 各々、sesrl命令とclsrl命令を組み合わせた2個の命令に展開される。
- Srの他のビットを破壊することなく、汎用レジスタバンクBKフィールドに任意の値を設定できる。
- lsli <レジスタ>,<即値>
- lsri <レジスタ>,<即値>
- asli <レジスタ>,<即値>
- asri <レジスタ>,<即値>
- csli <レジスタ>,<即値>
- csri <レジスタ>,<即値>
- <レジスタ>の内容を<即値>に従ってシフトする組み込みマクロ命令。
- {Logical/Arithmetical/rotate with C} Shift {Left/Right} Immediateであり、それぞれ、lsfti命令/asfti命令/csfti命令に展開される。
- <即値>≧0でなければならない。
-
block <条件>[,<オプション>]
<条件成立行>
[elsb
<条件非成立行>
]
[brkb]
[cntb]
endb
- <条件>が成立した時、<条件成立行>が実行される。
- block疑似命令中にblock疑似命令を入れ子にすることはできない。
- <条件>には、「ne」、「eq」、「cc」、「cs」、「hs」、「lo」、「pl」、「mi」、「vc」、「vs」、「ge」、「lt」の、いずれかの文字列を指定可能。
- 各文字列の先頭に"b"を付けて完成する分岐命令と同じ条件となる。
- 条件付きアセンブルifexp疑似命令と異なり、Moscoviumシリーズのアセンブラに展開される。
- block疑似命令中にelsb疑似命令が見つかった場合、elsb疑似命令から後ろの行(<条件非成立行>)は、<条件>非成立時に実行される。
- block疑似命令中に許されるelsb疑似命令は、最大1個(省略は可能)。
- block疑似命令中にbrkb疑似命令が見つかった場合、endb疑似命令の次の命令に制御が移る。
- block疑似命令中にcntb疑似命令が見つかった場合、block疑似命令の先頭に制御が戻る。
- <オプション>には、"loop"を指定可能。
- "loop"が指定されると、<条件>が成立している間、<条件成立行>を繰り返し実行し続ける。
- C言語に当てはめると、whileループに相当する。
-
例)
cmpi r0,0xaa
block eq
addi r1,1
elsb
subi r1,1
endb
- 以下の様な命令列に展開される。
-
cmpi r0,0xaa
__bcnt_0003:
bne __bels_0003
addi r1,1
bra __bbrk_0003
__bels_0003:
subi r1,1
__bbrk_0003:
- 一々アドレスラベルを定義して、分岐する手間が省けることが長所。
- ラベル名はシリアル番号で自動的に割り振られるため、プログラマはラベル名の管理から解放される。
- 入れ子にできないので、大きく複雑なブロックを記述する事には不向き。
ユーザマクロ定義
-
macro <マクロ名>[,<パラメータ1>[,<パラメータ2>[,……]]
<マクロ定義行>
:
endm
- macro疑似命令から、endmまでの間に記述したアセンブラソースをマクロとして定義する。
- macro疑似命令中にmacro疑似命令を入れ子にすることはできない。
- 既に同名のユーザマクロ<マクロ名>が定義されていた場合、「上書き再定義」となる。
- 定義したマクロは、「<マクロ名> [,<引数1>[,<引数2>[,……]]」の形式でマクロ展開できる。
- <マクロ定義行>の中で「$(<パラメータn>)」の書式で参照したパラメータは、マクロ展開の際に各々対応する<引数n>に置換される。
- <パラメータn>と、<引数n>の数は合っていなければならない。
- <パラメータn>は、1つのマクロ定義内で互いにユニークな名前にしなければならない。
- 「$(<パラメータn>)」 ⇒ 「<引数n>」への置換は、単なる文字列置換となる。
- 従って、「$(<パラメータn>)」の書式が<マクロ定義行>内のいかなる場所にあっても、置換が発生する。
- マクロ展開(置換)後のアセンブラソースが許容される文法に合致しなければ、エラーとなる。
- 特殊識別子「$(macro)」は、マクロ展開の度にインクリメント(+1)されるシリアル番号の16進数4桁で置換される。
- $(macro)を使って、ローカルアドレスラベルを生成することが出来る。
- <マクロ定義行>内には、自分自身を含むユーザマクロ展開を含むことが出来る。マクロ展開の無限ループを構成しないように使用しなければならない。
- ユーザマクロの展開よりも、文字列マクロ(参考def疑似命令)置換の方が優先される。
- 特殊識別子"macro"や、<パラメータn>の名前を持った文字列マクロがdef疑似命令で宣言されていた場合、そちらが先に置換されてしまうので注意。
- <マクロ定義行>内では、文字列("〜")中も含めて、全て小文字に変換される。
- 例)マクロ定義
-
macro polling_flag ioreg,ioflg
ldwi r7,$(ioreg)
pf_poll_$(macro):
ldw r0,[r7]
andi r0,$(ioflg)
beq pf_poll_$(macro)
endm
- 例)マクロ展開
-
polling_flag uartctl,uart_ravl
↓ 以下の様にマクロ展開される。
-
ldwi r7,uartctl
pf_poll_0001:
ldw r0,[r7]
andi r0,uart_ravl
beq pf_poll_0001
- polling_flagの2回目の展開では、$(macro)="0002"となるので、アドレスラベル「pf_poll_0001」と重複しない。
- 例)ネイティブ命令の置換
- macro命令を使うと、Moscoviumのネイティブ命令でさえ、置換することができる。
-
macro jalw rn
jall $(rn)
endm
- 上のユーザマクロは、Nihoniumでロングワードスタックを使うため、jalw命令をjall命令に置き換えるために使用できる。
- もし、部分的に置換せず、jalw命令のまま、残したい命令があった場合、「\jalw r7」の様に、先頭にバックスラッシュ(\)を追加すると、ユーザマクロ置換を抑止することができる。
改訂履歴