X680x0 SC62015 クロスアセンブラ SCASM v1.29 小笠原博之(COR.) ●最初に このプログラムは、パソコン上において SHARP のポケコン PC-E500/1490U などの マシン語プログラムをクロス開発するために作成されたものです。もちろん同じ CPU を使用している電子手帳や ZAURUS でも使えます。これらポケコンの CPU、SC62015 のプログラムを組む場合に、パソコン上でソースの作成とアセンブル作業を行い、 RS232C を介して転送し実行させることができます。 初めて公開したのは工学社の I/O 誌で、その後バージョンアップして同じ工学社 の X68K DISK本、そして今回クロスコンパイラにともなう修正となりました。このド キュメントは、当時 I/O 上で発表するための原稿として書かれたものをベースに修 正したものです。 ●特徴 マクロ定義、条件アセンブル等の機能に加え、構造化ブロックローカルブロックと いった高級言語のようなシンボル管理能力を持ちます。そのため、アセンブラ上で高 レベルなプログラミングが可能です。 強制プレバイト指定や、マルチパス方式によるさまざまな最適化など、SC62015 に よるプログラミングを考慮した、独自のアイデアを取り入れています。 ●使い方 ◎アセンブル方法 エディタもしくはクロスコンパイラ等を使用し、ソースリストを「〜.ss」のファ イル名で作成します。コマンドラインで A> scasm ファイル名 ~~~~~~~~~~~~~~~~~~ とタイプ(下線部)するとアセンブルを開始します。ファイル名の拡張子を省略した場 合は「.ss」とみなします。出力されるプログラムの拡張子は「.sx」になります。出 力されたファイルには、余計な情報は一切付きません。もしマシン語ファイルのヘッ ダをつけたい場合は、-h オプションを指定しておいて下さい。 ◎起動時のスイッチ 引数を取らないスイッチの場合連続して「-qauh」のように指定することができます。 -o <ファイル名> オブジェクトの出力ファイル名を指定します。スイッチのすぐ後ろ にファイル名を書いて下さい。このスイッチを指定しない場合は、 〜.sx のファイルに出力します。 -p アセンブルリストを出力します。出力するファイルは 〜.sp となり ます。アセンブルリストの左端にある番号はソースリストの行番号 にそのまま対応するようになっています。1行が2行以上に分られ た場合は、同じ番号が続くことになります。 -i インクルードファイルの内容もアセンブル・リストに出力します。 行番号は、各ファイル毎にカウントします。 -j マクロ展開の内容もアセンブル・リストに出力します。 -f アセンブルリストの行番号の後にファイル名も書き出します。 -s シンボルファイルを出力します。ファイルの拡張子は「〜.sl」に なります。 -g -g スイッチがあるとき、ローカルラベルもシンボルファイルへ出 力します。 -q アセンブル時にさまざまな最適化を行い、より効率のよいコードを 出力します。 -a -q に加えてさらに強い最適化を行います。(-q がなければ無効) -v アセンブル時に、パス数、ローカルブロック及びシンボルの状態を 随時表示します。 -h 出力バイナリの先頭に 16byte のファイルヘッダを出力します。 -m ハッシュテーブルの大きさを指定します。デフォルトでは3000です。 -w ワーニングメッセージを出さないように指定します。 -r <ファイルパス> インクルードファイルを読み込むディレクトリを指定します。無指 定の場合は環境編数 sc_include で指定したディレクトリ、それも 未定義ならばカレントになります。このディレクトリ指定があると カレントディレクトリは検索しません。カレントから読み込ませた い場合は「include ./file」のように、ソース中でカレントを明示 的に指定して下さい。 -u 未定義シンボルのパスキャンセルを行います。このオプションをつ けた時は必ず -q オプションもつけて下さい。-q オプションがな いとエラーが大量に出ます。 -b 指定パス数強制実行します。ただし -e 指定もある場合はそれ以上 は実行しません。 -e 最大パスカウント数を実行します。デフォルト -e24 で、この回数 をパス数が越えるとエラーになります。 ◎エラー レベル1のエラーでは、パスが終わるかエラー数が増えるまでアセンブルを続行し ます。レベル2のエラーでは、発生時にアセンブルを中止します。 ●ソースリストの記述方法 ◎行の構成 ;コメント行 ラベル コマンド/ニモニック オペランド ;コメント ラベル: コマンド/ニモニック オペランド 行の 1文字目から始まる文字列はラベルとみなします。この場合、ラベル名の後ろ にコロンは無くても構いません。1 文字目から文字列が始まっていない場合は、最後 にコロンが付いているものはラベル、それ以外はニモニックやマクロなどのシンボル 名として扱います。 セミコロン「;」以後行末まではコメントとして扱われます。セミコロンは行のどこ にあっても構いません。行頭にある場合のみ「#」と「*」もコメントとみなします。 ラベル、ニモニック、オペランドは、それぞれスペースかタブで区切ります。全角 のスペースは使えません。オペランドとオペランドは、カンマで区切ります。 ニモニック、レジスタ名、システムラベル等の予約語は、大文字小文字のどちらで 記述しても構いません。ただしラベルやマクロ名は大文字と小文字を区別します。 ◎ラベル ラベル名には、アルファベット、数字、「@?_」の記号が使えます。ただし1文字目 が数字だったり、予約語と同じものであってはいけません。ラベル名は最大26文字ま で判別可能ですが、ローカル情報等が付加されるので、必ず20字以内で用いるように して下さい。 ローカルブロックの外で宣言したラベルをグローバル・ラベルといいます。これは ソースリスト中のどこからでも参照できます。ローカルブロック内で宣言したラベル はローカル・ラベルとなり、宣言したブロック内でしか参照できません。 -u オプションのパスキャンセル機能を使用する時は、'?' で始まるラベル名は使 わない方がいいでしょう。 ◎強制PREバイト指定 内RAMアドレスの前に「#」を付けると、どんな PRE バイトが指定してあっても、 内RAMアドレッシングが強制的に絶対指定「(n)」になります。例えば PREバイトとし て「(BP+m),(BP+n)」が指定されていても、 mv (#$ec),(0) と書けば、PREバイトは「(m),(BP+n)」であると勝手に解釈してくれますす。実際に 書き込まれるPREバイトは、次の優先順位に従っています。 強制プレバイト指定「#」 > PREコマンド > DEFPRE 通常は特にPREコマンドを用いなくても、この強制PREバイトだけで用が足りるはず です。例えば、DEFPREを0に設定して、普段はPREバイトを省略する様にしておきます。 当然、プログラムの先頭でBPにワークエリアのアドレスを代入しておくのを忘れない ように。こうしておいて、キー入力等で内RAMアクセスで特に絶対指定が必要な場合に のみその部分に「#」を書くのです。サンプルプログラムで使っているので参考にして 下さい。 ※内RAMの記述に関しては、PREバイトが (BP+PX) の場合でも (0) の様に、括弧の中 に必ず数値を書いて下さい。その数値は動作に影響を与えません。 ◎拡張ニモニック 記述できるニモニックは SC62015 純正のものです。その他に次のものが拡張され ています。 addb r,r 出力コード$46 addw r,r 出力コード$44 addp r,r 出力コード$45 subb r,r 出力コード$4e subw r,r 出力コード$4c subp r,r 出力コード$4d pushu (n) mv [--u],(n) popu (n) mv (n),[u++] pushs r mv [--s],r pops r mv r,[s++] pushs (n) mv [--s],(n) pops (n) mv (n),[s++] ◎疑似命令 ※ 説明中[〜]で囲まれたものは省略できることを意味します。 (1)ローカルブロックの宣言 ・begin ・end この begin と end で囲んだエリアをローカルブロックといいます。ローカルブロッ クは宣言したラベルの有効範囲を制限するためにあります。つまり、この中で宣言し たラベルはそのブロック内でのみ有効となります。CASL でいう、START/END のこと ですが、こちらはネスティングも可能になっています。ローカルブロックの中でさら にローカルブロックを形成することができます。(最大256段) [ 例 1] 有効範囲 begin ---------------------------------------------- lab1                  | begin ------------------------------ エリアA lab2:            |     lab1/5 が begin --- エリアC   エリアB    参照可能 lab3:  | lab1/2/3/5 lab1/2/5   | end  --- が参照できる が参照できる |              | | begin --- エリアD     | | lab4:     | lab1/2/4/5    | | end  --- が参照できる   | | lab5:   global           | | end ------------------------------- | begin ------- エリアE          | lab6:    | lab1/5/6          | end ------- が参照できる        | end ---------------------------------------------- [ 例 2] サブルーチン宣言 sub1 begin pushu a loop: mv a,[x++] : jrnz loop popu a ret end 例2のように、サブルーチンを組む場合に必ずローカルブロックになるよう宣言し ておくと、再利用するときもラベルがぶつからなくて便利です。 (2)構造化ブロックの宣言 ・{ ・} ローカルブロックとは全く別に、「{」と「}」で囲むことにより構造化ブロックと いうものを形成できます。この構造化ブロック内では特別に、システムラベル break と continue が使えます。ラベルの代わりにこの break を使った場合ブロックの最後 の位置、つまり「}」のアドレスを示します。また同様に continue を用いると、「{」 のアドレスを指します。  この構造化ブロックは、256段までネスティングさせることが可能で、使用するラベ ル数を大幅に減らすことができます。 尚、この構造化ブロックはラベルのスコープに制限を与えるものではありません。 [ 例 ] aバイトのメモリ転送 { cmp a,0 jrz break ; ここでの break は L-B のアドレスを示す { ; L-A mv il,[x++] mv [y++],il dec a jrnz continue ; この continue は L-A のアドレスを示す } } ; L-B (3) 定数の割り付け ・equ 式 直前に宣言したラベルに定数を割り当てます。 [ 例 ] __START equ $30000 (4) グローバルラベルの宣言 ・global 直前に宣言したラベルをグローバルラベルにします。 (注意:この命令は思った通りに動作しないことが多いので注意) (5) アセンブル制御コマンド ・ if 式 ・ elseif 式 ・ else ・ endif アセンブルを制御します。if は式が 0 以外のとき else, elseif, end までの領 域をアセンブルします。0 のときその領域を無視し、代わりに else 以降、endif ま での、領域をアセンブルします。elseif の場合、そこでさらに条件を指定できます。 elseif, else の部分は省略可能です。if 〜 の中に、さらに if 〜 を指定するこ とができます。このとき256段までのネスティングが可能です。 if/elseif の後には「式」の他に特別に次の書き方もできます。 if 文字列 == 文字列 (等しい) if 文字列 != 文字列 (等しくない) この場合数値ではなく文字列として比較を行います。そのため「8==$8」は等しくな いとみなします。数値として比較したい場合は「<8.eq.$8>」と書いて下さい。比較 する文字列を「"」や「'」で囲むことができます。この書き方をすると、比較文字列 に「=」や「!」等の記号も使えるようになります。ただし「"」「'」は比較文字列に 含まれません。 [ 例 ] if \1 == \2 if < mcount .eq. 100 > if "\1" != "=" if @DEFprint (6) デフォルトのプレバイト指定 ・ defpre 式 デフォルトの PRE バイトを指定します。内 RAM を用いる命令の前で PRE を指定し なかった場合は、この DEFPRE で設定したものを PRE バイトとして書き込みます。式 の値は $21 〜 $27 か、$30 〜$37 です。式に 0 を指定した場合は、PRE バイトは省 略するものとみなし書き込みません。ただし、強制 PRE バイト指定がある場合はこの 限りではありません。尚、DEFPRE デフォルト値は 0 (すなわち省略)です。 (7) プレバイト指定 ・pre 式 内 RAM を使う命令の前で用い、PRE バイトを指定します。0 を指定すると、PRE バ イトを省略します。この疑似命令を書かなかった場合は、DEFPRE で指定した値が用い られます。PRE バイトを必要としない命令の前で用いた場合は警告を表示し、PRE バ イトの書き込みはしません。 (8) アドレス設定 ・org 式 出力するプログラムを割り付けるアドレスを指定します。この命令を実行しなかっ た場合は 0 番地から割り付けます。 (9) データの展開、1バイト単位 ・db 式[,式 …] メモリに式の値を1バイト書き込みます。256以上の値を指定した場合は、上位ビッ トを無視します。式に‘〜’や“〜”で文字列を指定した場合、そのままメモリ上に 文字列として割り付けます。「'」と「"」は同様の働きをします。文字列に「"」を含 む時は '〜'、「'」を含む時は "〜" を使って下さい。 (10) データの展開、2バイト単位 ・dw 式[,式 …] メモリに式の値を2バイト書き込みます。下位、上位の順になります。65536以上の 値を指定した場合、上位ビットを無視します。式に '〜' や "〜" で文字列を指定し た場合、1文字が2バイトに展開されてメモリに割り付ます。 (11) データの展開、3バイト単位 ・dp 式[,式 …] メモリに式の値を3バイト書き込みます。下位から上位の順になります。式に '〜' や "〜" で文字列を指定した場合、1文字が3バイトに展開されてメモリに割り付けま す。 (12) 作業領域確保 ・ds 式1 [,式2] 式で示したバイト数だけ領域を確保します。領域を式2の値で埋めます。式2を省略 した時は0になります。 (13) 行番号指定 ・line 式 行番号を指定します。以後、この行番号を基準にして行をカウントし、アセンブル リストやエラーメッセージ等で使います。 (14) ファイル名指定 ・file ファイル名 ファイル名を指定します。以後、アセンブルリストやエラーメッセージ等で表示さ れる時このファイル名を用います。 (15) マクロ定義 ・macro ・endm macro から endm までをマクロとして定義します。macro の直前に名前が必要で、 以後その名前をコマンドとしてソース中に記述することができます。マクロ名自身も ローカルブロックの制約を受けます。あるローカルブロック中で定義したマクロは、 そのブロック内でのみ有効になります。 マクロには引数を渡すことができます。マクロ名の後にカンマかスペースで区切っ て書き、マクロ定義中にある「\n」が対応する引数に置き換えられます。nは引数の番 号です。左から順に 1, 2, 3 ... 9, a, b, ... f となります。0 は呼び出したマク ロ名を指します。引数が無い所の「\n」は NULL になります。 この引数の展開は単なる行内文字列の置換なので、引数でニモニックを渡したり、 引数でラベル宣言をすることまで可能です。その他「\Ln」はそれぞれの引数の文字 数に、「\#」は渡された引数の個数になります。 尚、マクロ中で「\」という記号そのものを使いたい場合は「\\」のように記述して 下さい。 マクロ中で別のマクロを呼ぶことも可能で、これは自分自身でも構いません。アセ ンブル制御命令と組み合わせれば再帰構造が記述できて、ほとんど言語に近い感覚で マクロ・プログラミングができます。ただし、ネストをあまり深くするとスタックオー バーの可能性もあり、メモリもやたら喰うので注意が必要です。 どのコマンドもマクロ定義の中に記述できますが、マクロ定義の中でさらにマクロ を定義することはできません。 [ 例 1] b レジスタ用の mv 命令を定義する例 mvb macro ex a,b mv a,\1 ex a,b endm [ 例 2] 引数が 10 なら dec a、それ以外なら inc a を展開する cset macro if \1 == 10 dec a else inc a endif endm [ 例 3] IOCS 呼び出し、2番目の引数は省略可能 IOCS macro if \L2 != 0 ; 省略チェック mvw (#$d6),\2 ; cx endif mv il,\1 callf $fffe8 endm [ 例 4] 永久ループマクロ forever macro { endm end_forever macro jp continue } endm (16) マクロ展開中止コマンド ・exit exit はマクロ展開を強制的に終了させるコマンドです。必ずアセンブル制御コマン ドと組み合わせて使います。 [ 例 ] errchk macro if \1 == ba exit ;もし引数が ba だったらこれ以後のマクロ展開を行わない endif : : endm (17) ファイルの挿入 ・include ファイル名 ソースファイルに別のファイルを挿入します。挿入されたファイルの中でさらに include コマンドを使うことができます。システムのスタックを越えない範囲でネス ティング可能です。 スイッチ「-p」があるとき、「-i」も付けるとこの挿入ファイルの内容もアセンブ ルリストに出力します。行番号はファイル毎にカウントしますが、挿入ファイルの中 でさらに include していたりすると非常にわかりにくくなるので、その場合はスイッ チ「-f」も付けて下さい。行番号と一緒にファイル名も書き出すようになります。 インクルードファイルは、-r または環境変数 sc_include で指定したディレクト リからのみ検索を行います。もしどちらも未定義ならカレントから読み込みます。 インクルードパスが定義されていても、ファイル中「include ./ファイル名」のよう に相対パスで記述した場合は、インクルードパスを参照せず、そのディレクトリで検 索を行います。 (18) メッセージの表示 ・@message 表示文字列 メッセージを表示します。文字列はそのまま書いても構いませんが、「"」や「'」 で囲むこともできます。 (19) 値の表示 ・@print 式 式の値を表示します。16進数と10進数の両方で表示されます。後方で宣言したラベ ルの場合、1パス目では0を返します。 (20) エラー発生 ・@warning エラーメッセージ ・@error エラーメッセージ ・@abort エラーメッセージ エラーを発生させます。レベルによって3種類のコマンドがあります。 @warning : メッセージの表示のみでアセンブルは続行します。 @error : 1pass が終了するか、よりレベルの他いエラーが発生する、もしくはエ ラーカウンタがオーバーするまでアセンブルを続行します。 @abort : 即座にアセンブルを終了させます。 これらのコマンドは、自分で定義したマクロ中でエラーチェックを行うなどして、 独自にエラーを発生させたい場合に使います。エラー時により詳しい情報を表示させ るためには @message や @print と組み合わせて使って下さい。 [ 例 ] constdiv macro if < \# .eq. 0 > @error 引数がありません。 exit endif : : endm (21) ラベル値の再割り付け ・set ラベル = 式 ラベルの内容を書き換えます。同一 pass 内でラベルの値を変更する場合に用いま す。書式上の「=」は特に無くても構いません。ラベルは必ず一度宣言したものでな ければなりません。予め equ 等で宣言しておいて下さい。このコマンドを使うこと によって、ラベルを変数として使用できます。 [ 例 ] scvar1 equ 100 set scvar1 = 20 (22) シンボル削除 ・unset シンボル シンボルを削除します。ラベルに限らず、定義されているものはなんでも、ニモニッ クでも、マクロ名でも削除することができます。削除されたものは新しく宣言できる ので、ニモニックを削除して同じ名前でマクロを定義することも可能です。 [ 例 ] retf コマンドを実行する度、キャリーを消す。 unset retf retf macro rc db $07 endm RETF macro retf endm (23) BSS関連命令 オブジェクトに出力せずに、メモリ領域の確保のみを行います。通常の命令のロケー ションカウンタとは別にカウンタを持っているため、通常の命令中にラベルや宣言を 記述しても、アセンブル時には分離して出力されます。 ・bss_ds 式 ワークメモリを式byteだけ確保し、直前のラベルにそのアドレスを代入します。 ・bss_org 式 bss_ds のワークメモリを確保するアドレスを定義します。 bss_org 命令がない場合、ワークメモリは全テキストメモリを展開したその後ろか ら確保されます。初期化の不用なワークメモリの確保に使います。 [ 例 ] mv x,work_buf work_buf: bss_ds 256 _loop: mv a,[y++] mv [x++],a dec i jrnz _loop ret ワークメモリを確保している。命令中に宣言を書いても、アセンブル時は分 離され、全部の命令を展開したあと(上記の例の場合は ret のあと)に確保 する。確保したメモリはオブジェクトには出力されない。 ◎式の構成 式と書いた所には、次の 1) 〜 16) を書くことができます。内部では、32ビット 符号付の整数演算を行っています。 1) 10進定数 整数です。負数のときは「<-定数>」のように記述して下さい。 2) 16進定数 「$」で始まる16進数定数です。 3) 2進定数 「%」で始まる2進数定数です。 4) 文字定数 '文字〜', "文字〜" 文字のコードを値とします。文字を複数書いた場合、1番右側の文 字が下位バイトになります。ただし、db, dw, dp では特別扱いに なります。「'」と「"」の区別はとくにありません。文字に「'」を 含むときは "〜"、それ以外は '〜'、のように、使い分けて下さい。 5) ラベル名 ラベルの値を持ちます。 6) システムラベル 以下のラベルはシステム内部で特別扱いされます。 break :構造化ブロックの終わりのアドレス値を持ちます。 continue:構造化ブロックの先頭アドレス値を持ちます。 location:現在のロケーションアドレス値を持ちます。 @DEF〜 :@DEFシンボル名、とした時そのシンボル名が定義されてい るかどうかを返します。未定義なら 0、そうでなければ 0 以外の値を取ります。(@DEFは必ず大文字) [例] @DEFprint (print が定義されていれば 1) @defpre :コマンドDEFPREで指定した値を持ちます。 @switch :システムスイッチの内容。上位ワードには現在のパス数 が入ります。下位ワードの内容は次の通りです。 bit0 シンボルファイルを出力する bit1 アセンブルリストを出力する bit2 ワーニングメッセージのoff bit3 最適化を行う bit4 アセンブル禁止 bit5 アセンブル経過を表示する bit6 グローバルラベルのみシンボル出力 bit7 挿入ファイルのリスト展開 bit8 前の命令にpre指定があった bit9 得た値はレジスタ番号である bit10 最終パスである bit11 マクロ展開中 bit12 ファイル名も同時にリスト出力 bit13 マクロのアセンブルリスト展開 @verion : scasm のバージョンが返ります。 7) !式 式のビットパターンを反転した値を取ります。 8) *B式 式の下位ワードだけを取り出し、その上位バイトと下位バイトを逆 にした値を返します。 9) *W式 式の上位ワードと下位ワードを逆にした値を返します。 10) *L式 下位バイトのみ取り出します。 11) *M式 下から2バイト目の取り出しです 12) *H式 下から3バイト目の取り出しです 14) *D式 下位ワードを取り出します。 15) *P式 下位3バイトを取り出します。 16) 演算 < 〜 > 計算式も「<」と「>」で囲むことにより記述することができます。 演算子は次の物が使えます。ただし、計算に優先順位はありません。 左から計算します。どうしても優先順位を付けたい場合は、その部 分をさらに「<>」で囲って下さい。 演算子、記述は大文字小文字どちらでも構いません。  + 加算  - 減算  * 乗算  / 除算  % 余り  & AND  | OR  ^ XOR  .eq. 等しい、条件が成り立てば1、不成立なら0,以下同様  .ne. 等しくない  .lt. 小さい  .le. 小さいまたは等しい  .gt. 大きい  .ge. 大きいまたは等しい .shl. 左シフト .shr. 右シフト [ 例 ] db 100, if ●最適化 起動時にスイッチ「-q」を付けるとアセンブルするときに最適化を行うようになり ます。ただし、この場合パスが最低でも3回以上行われるためアセンブル速度は遅く なります。最適化を行わない場合は2パスのみです。最適化は次の3つです。 1) 絶対番地ジャンプ(jp)で飛先が256バイト以内のとき、等価な相対番地ジャンプ (jr)に置き換えます。プログラム速度、プログラムサイズ、共に効果があります。 よって、普段はジャンプ命令は全部 jp で書いてさえ置けば、アセンブラが常に 適切なジャンプ命令に置き換えてくれます。 2)「mv i,n」の i レジスタへの定数代入で、n の値が $00〜$ff の範囲に収まると き「mv il,n」に置き換えます。 3) [r+n] や [(m)+n] 等、インデックスつきアドレッシングで、インデックス n の 値が 0 の場合は [r] や [(m)] に置き換えます。[x+OFFSET] 等、インデックス 値をラベルで指定してもむだコードが生成されませんので便利です。なお、この 最適化は -q の他に -a スイッチがなければ行われません。 4) jr/jp での飛び先が無意味な場合、その命令を削除します。この最適化も -q と -a スイッチがなければ行われません。無意味な飛び先とは、その命令直後への ジャンプ、もしくはその命令そのものへのジャンプです。 [無意味なジャンプの例] jr point ;<= ジャンプ命令の次の番地へのジャンプは無意味 point: jpc point ;<= 自分自身への条件分岐も無意味 例えば、次のようなプログラムがあったとします。途中を if 0 でコメントアウ トした場合、-qa つきでアセンブルすると (A) の命令が不要なので除去されます。 popu x popu y add x,y jp _sub ; ← (A) if 0 call _put endif _sub: sub y,x ret このように、scasm は最適化が強力です。普段は常に -qa オプションをつけたま まにして、ジャンプ命令はすべて jp で記述することをお勧めします。 ●未定義シンボルのパスキャンセル -u オプションがある場合、各パスにおける未定義シンボルの参照をキャンセルし、 次のパスへまわすことができます。この時、未定義で参照されたシンボル名の先頭に '?' を追加したシンボルを定義します。24回のパスを越えてもすべての未定義シンボ ルが解消されなかった場合はエラーになります。 この機能の有効な使い方は次のようになります。まず各サブルーチンを、 if @DEF?_sub _sub: endif のように if @DEF を使い、サブルーチン名に '?' をつけた名前によって展開を分岐 するようにします。上記例では "?_sub" というシンボルが定義されていなければ、 if〜endif 間のコードは展開されません。 -u がある場合、未定義シンボルとして _sub がアクセスされると「?_sub」が定義 されるので、次のパスからは if が有効になってサブルーチン _sub が展開されると いうわけです。 このように、汎用のサブルーチンを if @DEF? で囲んでおけば、call などでアク セスしたルーチンのみ展開することができ、たいへん便利でかつ強力な機能です。 ただしこの処理を行う場合は、未定義シンボルをアクセスすると次のパスにその解 消をまわし、また有効になったブロックによって未定義シンボルが次々に発生するこ とがあります。よってパス数は最適化に加えてさらに増加し、アセンブルコードの展 開は非常に遅くなります。(7〜8パスはまわるようになる) またこの機能を使う場合はパルチパスが必須なので、必ず -q オプションも指定し ておかなければなりません。 この未定義シンボルのパスキャンセル機能を使って内部にローカルブロックを構成 する場合は注意が必要です。たとえば次のような場合 if @DEF?_den _den: begin 〜 end endif begin〜end 間のブロックは、未定義シンボル _den がアクセスされてはじめて出現 します。よって前のパスでカウントしたローカルブロックのナンバーと合わずに、不 要なラベル定義が発生してしまうことになります。特に実害はありませんが、むやみ にパス数を増加させてしまうことになるので、これを防ぐには次のように else で空 のローカルブロック begin, end を入れておくようにして下さい。 if @DEF?_den _den: begin 〜 end else begin ;この空ブロックを追加しておく end endif また if @DEF? 〜 endif 内部は、第1パスを通ることがありません。そのため2パス 以降であってもラベルの内容値が決定していないことがあります。このとき相対ジャ ンプ命令があると飛び先が遠すぎてエラーになるので、ジャンプ命令は必ず jp で記 述するようにして下さい。-u オプション使用時は -q も必須なので、jp での記述は 常に適切な jr に置換されます。 ●シンボルファイル スイッチ「-s」を付けてアセンブルすると、ファイル名の拡張子を「.sl」に置き 換えたシンボルファイルを出力します。これは内部で使われたラベルのラベル名、割 り当てられた内容を、equ 形式で出力するものです。グローバルラベル以外はコメン トにしてあるので、分割アセンブルを行う場合にそのまま用いることができます。 同時に「-g」スイッチを付けると、グローバルラベルのみ出力します。 ●アセンブル・リスト スイッチ「-p」を付けてアセンブルすると、ファイル名の拡張子を「.sp」に置き 換えたファイルにアセンブルリストを出力します。このファイルはアセンブルした結 果をソースに追加したものです。 ●ネスティング ローカルブロック、構造化ブロック、アセンブル制御コマンドはそれぞれ独自にス タックを持っていて独立してネスト構造を形成できます。それぞれが各々256段まで ネスト可能になっています。ネストの最大数は scasm.h にて変更可能です。また、 種類が異なればブロックが交差していても構いません。 どのスタックも256段もあれば特にチェックする必要もないだろうという考えからス タックオーバーの検出はしていません。 ●予約語 ニモニック名、システムラベル名、コマンド名、レジスタ名等は予約語であって、 これと同じ名前をラベルやマクロ名として用いることはできません。予約語は大文字 小文字を同一扱いにするので、大文字であろうと、小文字であろうと、混在していよ うが、使うことはできません。定義できても、参照時にエラーになる場合があるため 注意して下さい。レジスタ名として予約語に含まれているものは、以下の通りです。 a, il, ba, i, x, y, u, s, b, bp, px, py, m, f, imr ●サンプルプログラム 作者が過去に発表したプログラムのアセンブルソースです。 mus.ss は、PJ90年7月号で発表した「拡張PLAY」コマンドの元になったソースリス トです。BASIC のコマンドに組み込んでいませんが、内容はほとんど同じ物で、リロ ケータブルになっています。 このプログラムを組んだ当時はまだマクロ定義やブロック構造が無かったので使っ ていませんが、強制プレバイトは使用しています。 vtrans.ss は少々古いですが、PJ88年12月号で発表した V-RAM 転送ルーチンをこ のアセンブラの書式で書いてみました。構造化ブロックのおがげで余計なラベルがあ りません。使用している定数定義もローカルブロックの中にあるので、どのルーチン に組み込んでもラベル名がぶつかる心配がないのです。 ●最後に 力まかせに仕上げたプログラムで、汎用性、拡張性、に欠けると思います。とにか く、強制プレバイト指定、構造化ブロック、マクロ定義、最適化は非常に便利で強力 な機能ですので、一度使ってみて下さい。 同時に皆さんもこのクロスアセンブラを使用して、ポケコンや ZAURUS の様々なプ ログラムを開発して下さい。 ●参考文献 1)「PC-1480U*PC-E500活用研究」,工学社 2)「アセンブラマニュアル」,SHARP XC ver1.01 付属 3)「X68000環境ハンドブック」,工学社 -- 小笠原博之 oga@dgw.yz.yamagata-u.ac.jp DenDenNET: DEN0006 COR.