Tatara

Chapter 26
Output formats

TANREN writes one output file for each link. This chapter describes what is in that file, the kinds of file it can be, and how to link a program for each of them: a .COM program for MSX-DOS, an image for some other address, a file for MSX-BASIC’s BLOAD, and a ROM image. It ends with how large a program can be.

26.1 What TANREN writes

The output file holds the program’s memory from the first byte that has content to the last, and nothing else (section 24.1.1). The file does not say at which address it goes, except in the header that /B adds: whatever loads the file has to know.

Table 26.1 lists the four kinds of file, and how each one is made. Only .COM is TANREN’s default; for the others, the output file is named with /O:, or gets .bin with /B.

Kind

How to link it

Loaded by

At

.COM

as it is: tanren main sub

MSX-DOS, when its name is typed

0100h

Raw image

/P:, and /O: for its name

another program

the /P: address

.BIN

/B, and /P:

MSX-BASIC’s BLOAD

the address in its header

ROM image

ASEG, and ORG 4000h or 8000h in the source, and /O: for its name

the MSX, from a cartridge

4000h or 8000h, where the MSX looks for the header

Table 26.1: The kinds of output file.

26.2 A .COM program

A .COM program is what TANREN makes without any option. MSX-DOS loads it at 0100h and starts it there, so it must be linked for 0100h, which is where TANREN starts the code (chapter 24):

A:\>tanren main sub 
... 
2 modules, 16 records, ends at EOF. 
Wrote MAIN.COM, 0100-0125 (38 bytes), entry 0100.
 

Do not use /P: for a .COM program. The file would still be loaded at 0100h, and every address in it would be wrong.

26.3 A raw image for another address

With /P:, TANREN links the program for another address. The file is the same kind of file, the bytes and nothing else, but it only works at that address, and something other than MSX-DOS has to load it there: another program, for example, that reads the file into memory and calls it.

This module prints a line with CHPUT, the routine of the MSX’s BIOS that prints a character (BIOS.INC), so that it works without 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
 

Linked for C000h, it is 34 bytes:

A:\>tanren /p:c000 hellob /o:hellor.bin 
... 
1 modules, 8 records, ends at EOF. 
Wrote HELLOR.BIN, C000-C021 (34 bytes), entry C000.
 

The file starts with 21 0E C0, ld hl,msg: the message is at C00Eh, after the fourteen bytes of code.

26.4 A file for BLOAD: /B

MSX-BASIC loads a machine-code file with BLOAD. The file must start with a seven-byte BLOAD header that says where it goes, and /B makes TANREN write one. With /B, the output file gets .bin when it is not named with /O::

A:\>tanren /b /p:c000 hellob 
... 
1 modules, 8 records, ends at EOF. 
Wrote HELLOB.BIN, C000-C021 (34 bytes), BLOAD header, entry C000.
 

The summary line gives the addresses and the size of the program, as always. The file on the disk is 41 bytes, seven more, because of the header. Figure 26.1 shows the header of HELLOB.BIN:

Each address is two bytes, the low byte first, as the Z80 keeps them. After the header come the same 34 bytes as in HELLOR.BIN.

PIC

Figure 26.1: The BLOAD header of HELLOB.BIN, and the three addresses it holds.

In MSX-BASIC, BLOAD with ,R loads the file and calls its start address, and the program returns to BASIC with RET:

Ok 
bload"hellob.bin",r 
Hello from BLOAD. 
Ok
 

While MSX-BASIC runs, the addresses below 8000h hold its ROM, and the RAM starts at 8000h, so a .BIN file has to be linked for an address in that RAM, where it does not overwrite what BASIC is using. A .BIN linked for 0100h cannot be loaded at all. Chapter 32 is a complete example.

26.5 The entry address

The entry address is the address named on an END line (section 12.6). When more than one module names one, the first in command-line order counts, and the others are ignored. E1.AS and E2.AS each name one:

; 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.
 

With E1 first, the entry is e1start, at C000h; with E2 first, it is e2start, at C001h.

When no module names one, the summary line has no 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).
 

A BLOAD header always has an entry address, so with /B TANREN uses the first address of the program, and the summary line says so:

A:\>tanren /b /p:c000 noend 
... 
Wrote NOEND.BIN, C000-C002 (3 bytes), BLOAD header, entry C000.
 

The entry address is used only in the BLOAD header. MSX-DOS always starts a .COM program at 0100h (section 21.1), and a raw image is usually entered at its first address too. Without /B, TANREN therefore warns when the entry address is anything else, and still writes the file:

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.
 

The warning is printed even with /Q. With /B there is none, as E21.BIN above shows: the header tells BLOAD where to start.

26.6 A ROM image

A ROM cartridge of 16 KB sits at 4000h to 7FFFh, and starts with a header that the MSX looks for when it starts. ROM.AS, in EXAMPLES\ROM, is a complete one (its first lines, a comment, are shortened here):

; 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
                                                                    

                                                                    
 

The code is in the absolute segment, at the addresses written in the source (section 24.5), so no /P: is needed:

A:\>tanren rom /o:rom.rom 
... 
1 modules, 6 records, ends at EOF. 
Wrote ROM.ROM, 4000-7FFF (16384 bytes).
 

A cartridge image has to be the full 16,384 bytes, and the last two lines make it so: TANREN writes everything from the first byte with content to the last, and a single byte at 7FFFh makes the gap before it part of the file, as zeros. Without those two lines, the same program makes a file of 77 bytes:

A:\>tanren romshort /o:romshort.rom 
... 
Wrote ROMSHORT.ROM, 4000-404C (77 bytes).
 

A DS at the end would not do it, because the memory a DS reserves after the last byte of content is not written to the file (section 24.1.1). Chapter 33 describes the cartridge in full.

26.7 How large a program can be

TANREN builds the program in the memory mapper, not in the memory that MSX-DOS gives to programs, and writes it to the file from there. A program can therefore use the whole address space, from 0100h to FFFFh, including the addresses where TANREN itself is running. This module has a byte at 0100h and another more than 60 KB above it:

; 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).
 

A large program needs enough free mapper memory for its image, as well as for TANREN’s tables, whose size depends on the program: how many modules, segments and names it has. When the mapper runs out, TANREN stops with ERROR: out of mapper memory.

A .COM program still has to fit in the memory MSX-DOS gives it when it runs, which ends well below FFFFh. TANREN does not check this: the limit depends on the MSX and on MSX-DOS, not on the linker.

26.8 When there is nothing to write

A program whose modules hold only DS has no byte with content, and TANREN writes no file:

; 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.
 

This is not an error, but no output file is made, and one of the same name from an earlier link is left as it was.

26.9 Messages

Table 26.2 lists the messages about the output file. ERROR: the linked image would run past FFFFh. is described in chapter 24.

Message

Meaning

ERROR: cannot create NAME

The output file cannot be made, for example because its directory does not exist, as with /o:nodir\x.com. The name is shown in capitals.

ERROR: cannot write the output file - the disk may be full.

The file was made, but writing to it failed.

ERROR: out of mapper memory.

The memory mapper has no room left for the program’s image or for TANREN’s tables.

WARNING: NAME is entered at XXXX, not at YYYY.

Not an error: the file, written without /B, will be entered at its first address, XXXX, but the END address is YYYY.

Nothing to write: no module has any content.

Not an error: no module has a byte with content, and no file is made.

Table 26.2: Messages about the output file.