第26章
出力形式
TANRENは、1回のリンクで1つの出力ファイルを書き出します。この章では、そのファイルに何が入るか、ファイルの種類、そしてそれぞれの種類に合わせてプログラムをリンクする方法を説明します。MSX-DOS用の.COMのプログラム、ほかのアドレス用のイメージ、MSX-BASICのBLOAD用のファイル、ROMイメージの4つです。最後に、プログラムの大きさの限度について説明します。
26.1 TANRENが書き出すもの
出力ファイルには、プログラムのメモリのうち、内容のある最初のバイトから最後のバイトまでが入り、それ以外には何も入りません(24.1.1節)。/Bが付けるヘッダーを除いて、ファイルには、どのアドレスに置くものかは書かれていません。ファイルを読み込む側が、それを知っている必要があります。
表26.1に、4種類のファイルと、それぞれの作り方を示します。TANRENが標準で作るのは.COMだけです。ほかの種類では、出力ファイルの名前を/O:で指定するか、/Bで.binが付くようにします。
26.2 .COMのプログラム
オプションを何も付けないと、TANRENは.COMのプログラムを作ります。MSX-DOSはこれを0100hに読み込んでそこから実行するので、0100h用にリンクされている必要があり、TANRENはそこからコードを置きます(24章)。
A:\>tanren main sub ... 2 modules, 16 records, ends at EOF. Wrote MAIN.COM, 0100-0125 (38 bytes), entry 0100.
.COMのプログラムには/P:を使わないでください。ファイルはやはり0100hに読み込まれ、中のアドレスがすべて合わなくなります。
26.3 ほかのアドレス用のイメージ
/P:を付けると、TANRENはプログラムをほかのアドレス用にリンクします。ファイルの種類は同じで、中身はバイトだけですが、そのアドレスでしか動かず、MSX-DOS以外の何かがそこに読み込む必要があります。たとえば、ファイルをメモリに読み込んで呼び出す、ほかのプログラムです。
次のモジュールは、MSXのBIOSの1文字を表示するルーチンCHPUT (BIOS.INC)で1行を表示するので、MSX-DOSなしで動きます。
; HELLOB.AS - prints a line with the BIOS, for BLOAD from BASIC. include bios.inc include ascii.inc cseg start: ld hl,msg loop: ld a,(hl) or a ret z push hl call CHPUT pop hl inc hl jr loop dseg msg: db 'Hello from BLOAD.',CHR_CR,CHR_LF,0 end start
C000h用にリンクすると、34バイトになります。
A:\>tanren /p:c000 hellob /o:hellor.bin ... 1 modules, 8 records, ends at EOF. Wrote HELLOR.BIN, C000-C021 (34 bytes), entry C000.
ファイルは21 0E C0、つまりld hl,msgで始まります。メッセージは、14バイトのコードのあとのC00Ehにあります。
26.4 BLOAD用のファイル: /B
MSX-BASICは、マシン語のファイルをBLOADで読み込みます。そのファイルは、どこに置くかを示す7バイトのBLOADヘッダーで始まっている必要があり、/Bを付けるとTANRENがそれを書きます。/Bを付けると、/O:で名前を指定しないとき、出力ファイルには.binが付きます。
A:\>tanren /b /p:c000 hellob ... 1 modules, 8 records, ends at EOF. Wrote HELLOB.BIN, C000-C021 (34 bytes), BLOAD header, entry C000.
要約行には、いつもと同じく、プログラムのアドレスと大きさが表示されます。ディスク上のファイルはヘッダーの分だけ7バイト多い41バイトです。HELLOB.BINのヘッダーを図26.1に示します。
- マシン語のファイルであることを示すFE
- プログラムの最初のアドレス、C000h
- プログラムの最後のバイトのアドレス、C021h(その次のアドレスではありません)
- プログラムを始めるアドレス、つまりエントリー・アドレス、C000h (26.5節)
アドレスはどれも2バイトで、Z80と同じく下位バイトが先です。ヘッダーのあとには、HELLOR.BINと同じ34バイトが続きます。
MSX-BASICで,Rを付けてBLOADすると、ファイルを読み込んで開始アドレスを呼び出し、プログラムはRETでBASICに戻ります。
Ok bload"hellob.bin",r Hello from BLOAD. Ok
MSX-BASICが動いている間は、8000hより下のアドレスにはBASICのROMがあり、RAMは8000hから始まります。そのため、.BINのファイルは、その RAMの中の、BASICが使っているものを上書きしないアドレス用にリンクする必要があります。0100h用にリンクした.BINは、まったく読み込めません。完全な例は32章にあります。
26.5 エントリー・アドレス
エントリー・アドレスは、ENDの行に書いたアドレスです(12.6節)。複数のモジュールがそれを書いているときは、コマンド・ラインの順で最初のものが使われ、ほかは無視されます。E1.ASとE2.ASは、どちらも書いています。
; E1.AS - its END names e1start. cseg e1start: nop ret end e1start
; E2.AS - its END names e2start, which is not its first byte. cseg nop e2start: ret end e2start
A:\>tanren /b /p:c000 e1 e2 /o:e12.bin ... Wrote E12.BIN, C000-C003 (4 bytes), BLOAD header, entry C000. A:\>tanren /b /p:c000 e2 e1 /o:e21.bin ... Wrote E21.BIN, C000-C003 (4 bytes), BLOAD header, entry C001.
E1を先にするとエントリーはe1startのC000h、E2を先にするとe2startのC001hになります。
どのモジュールも書いていなければ、要約行にentryは表示されません。
; NOEND.AS - no address on its END line. cseg ld a,1 ret end
A:\>tanren noend ... Wrote NOEND.COM, 0100-0102 (3 bytes).
BLOADヘッダーには必ずエントリー・アドレスがあるので、/Bを付けると、TANRENはプログラムの最初のアドレスを使い、要約行にもそれが表示されます。
A:\>tanren /b /p:c000 noend ... Wrote NOEND.BIN, C000-C002 (3 bytes), BLOAD header, entry C000.
エントリー・アドレスが使われるのは、BLOADヘッダーの中だけです。MSX-DOSは、.COMのプログラムをいつも0100hから実行し(21.1節)、そのままのイメージもふつうは最初のアドレスから実行されます。そのため、/Bなしでは、エントリー・アドレスがそれ以外のとき、TANRENは警告を出し、ファイルはそのまま書き出します。
A:\>tanren e2 e1 /o:e21raw.bin ... WARNING: E21RAW.BIN is entered at 0100, not at 0101. 2 modules, 12 records, ends at EOF. Wrote E21RAW.BIN, 0100-0103 (4 bytes), entry 0101.
この警告は/Qを付けても表示されます。上のE21.BINのように、/Bを付けると警告は出ません。ヘッダーがBLOADに開始アドレスを伝えるからです。
26.6 ROMイメージ
16 KBのROMカートリッジは4000hから7FFFhにあり、MSXが起動するときに探すヘッダーで始まります。EXAMPLES\ROMのROM.ASは、その完全な例です(最初の数行のコメントは、ここでは短くしています)。
; ROM.AS - a 16 KB cartridge. include bios.inc ; INITXT, CHPUT, and the rest aseg org 4000h db "AB" ; a cartridge, says the BIOS dw init ; INIT: called at once dw 0 ; STATEMENT: no CALL statements dw 0 ; DEVICE: no device dw 0 ; TEXT: no BASIC program in here dw 0,0,0 ; reserved, and zero init: call INITXT ; a text screen, from nothing ld hl,msg ini.lp: ld a,(hl) or a jr z,ini.end push hl call CHPUT pop hl inc hl jr ini.lp ini.end: jr ini.end ; a cartridge has nowhere to go msg: db "Assembled by Tatara. Linked by TANREN.",13,10,0 org 7fffh ; the last byte of the 16 KB... db 0 ; ...so that the file is all of it end
コードはアブソリュート・セグメントにあり、ソースに書いたアドレスに置かれるので(24.5節)、/P:は要りません。
A:\>tanren rom /o:rom.rom ... 1 modules, 6 records, ends at EOF. Wrote ROM.ROM, 4000-7FFF (16384 bytes).
カートリッジのイメージは16,384バイトちょうどでなければならず、最後の 2行がそれを実現しています。TANRENは内容のある最初のバイトから最後のバイトまでを書き出すので、7FFFhに1バイト置くと、その前の空いた部分が 0としてファイルに入ります。この2行がないと、同じプログラムが77バイトのファイルになります。
A:\>tanren romshort /o:romshort.rom ... Wrote ROMSHORT.ROM, 4000-404C (77 bytes).
最後にDSを置いても、そうはなりません。内容のある最後のバイトのあとにDSが確保したメモリは、ファイルに書き出されないからです(24.1.1節)。カートリッジについては33章でくわしく説明します。
26.7 プログラムの大きさの限度
TANRENは、MSX-DOSがプログラムに与えるメモリではなく、メモリ・マッパーの中でプログラムを組み立て、そこからファイルに書き出します。そのため、プログラムは、TANREN自身が動いているアドレスも含めて、0100hからFFFFhまでのアドレス空間全体を使えます。次のモジュールは、0100hに1バイト、それより 60 KB以上上にもう1バイトを置いています。
; BIG.AS - one byte at the start and one near the top of memory. cseg db 1 ds 0EF00h db 2 end
A:\>tanren big ... 1 modules, 6 records, ends at EOF. Wrote BIG.COM, 0100-F001 (61186 bytes).
大きなプログラムには、そのイメージのための、そしてTANRENの表のための空いたメモリ・マッパーが十分に必要です。表の大きさは、モジュール、セグメント、名前の数など、プログラムによって変わります。メモリ・マッパーが足りなくなると、TANRENはERROR: out of mapper memory.と表示して止まります。
.COMのプログラムは、実行するときに、MSX-DOSが与えるメモリに収まらなければなりません。そのメモリはFFFFhよりかなり下で終わります。この限度はMSXとMSX-DOSによって決まり、リンカーによるものではないので、TANRENはこれを確認しません。
26.8 書き出すものがないとき
モジュールにDSしかないプログラムには、内容のあるバイトがないので、TANRENはファイルを書き出しません。
; EMPTY.AS - only DS: nothing to write. dseg buffer: ds 100 end
A:\>tanren empty ... 1 modules, 4 records, ends at EOF. Nothing to write: no module has any content.
これはエラーではありませんが、出力ファイルは作られず、以前のリンクで作った同じ名前のファイルは、そのまま残ります。
26.9 メッセージ
出力ファイルに関するメッセージを表26.2に示します。ERROR: the linked image would run past FFFFh.については24章で説明しています。