Tatara

Chapter 32
A binary for MSX-BASIC’s BLOAD

MSX-BASIC can load a file of machine code with BLOAD and run it. This chapter builds BINARY, the example in A:\TATARA\EXAMPLES\BINARY, which makes such a file, runs it from BASIC, and then looks at where in BASIC’s memory a machine-code file can safely go.

32.1 The example

BINARY is one source, BEEP.AS, and its BUILD.BAT. The program prints a line, sounds the MSX’s buzzer and returns to BASIC. It is not a .COM program: MSX-DOS is not there when BASIC runs it, so it prints through the MSX’s BIOS, the routines in the MSX’s ROM. TANREN writes it with a BLOAD header (section 26.4), which makes it a .BIN file.

32.2 The source

; BEEP.AS - a machine-code file for MSX BASIC. 
; 
; BLOAD"BEEP.BIN",R loads this and runs it. The seven bytes BASIC 
; reads first - FEh, the first address, the LAST address, and the 
; address to call - are written by TANREN when /B is given, and 
; nothing else makes a file a .BIN. 
; 
; ASEG and ORG: the code is at a fixed address and the linker moves 
; nothing. It has to be, because BASIC loads it where the header says 
; and does not relocate anything. 
; 
; There is no MSX-DOS here, so the printing is the BIOS. 
 
                include bios.inc        ; CHPUT, BEEP, and every other 
                                        ;   MAIN ROM entry 
                include ascii.inc       ; CHR_CR and CHR_LF 
 
                aseg 
                org     8000h           ; above BASIC in a 64 KB machine 
 
start:          ld      hl,msg 
loop:           ld      a,(hl) 
                or      a 
                jr      z,done 
                push    hl 
                call    CHPUT 
                pop     hl 
                inc     hl 
                jr      loop 
done:           call    BEEP 
                ret                     ; back to BASIC, which is waiting 
 
msg:            db      "Loaded by BLOAD, run from BASIC.",CHR_CR,CHR_LF,0 
 
                end     start           ; the address the header carries
 

32.3 Building it

rem BUILD.BAT - EXAMPLE: BINARY 
rem 
rem A .BIN for MSX BASIC instead of a .COM for MSX-DOS. Two things 
rem make the difference: 
rem 
rem   ASEG and ORG   the code is at a fixed address, not relocatable 
rem   TANREN /B      the seven-byte BLOAD header goes in front of it 
rem 
rem The address BASIC calls is the one on the END line of the source. 
rem Without /B the same link writes the bytes and no header, which is 
rem what a ROM needs - see the ROM example. 
rem 
rem To run it, from BASIC:  BLOAD then the file name in quotes, ,R 
 
rem The headers are in A:\TATARA\INCLUDE and are not copied here. 
rem TATARA is rule 3 of the include search - see the DIRS example. 
rem CHANGE THE PATH BELOW if you put the tree somewhere else. 
 
set TATARA=a:\tatara\include 
 
echo === Assembling 
tatara /q beep.as beep.tro 
 
echo === Linking, with a BLOAD header 
tanren /q /b /o:beep.bin beep.tro 
 
echo === Done. BEEP.BIN is 7 bytes of header and the rest is code. 
 
set TATARA=
 
A:\TATARA\EXAMPLES\BINARY>build 
=== Assembling 
=== Linking, with a BLOAD header 
=== Done. BEEP.BIN is 7 bytes of header and the rest is code.
 

Without /Q, TANREN’s summary shows what it wrote:

A:\TATARA\EXAMPLES\BINARY>tanren /b /o:beep.bin beep.tro 
... 
1 modules, 6 records, ends at EOF. 
Wrote BEEP.BIN, 8000-8035 (54 bytes), BLOAD header, entry 8000.
 

The program is 54 bytes, and the file 61. Its first seven bytes are the header:

FE  00 80  35 80  00 80
 

FE, then the first address, 8000h, the last, 8035h, and the address to call, 8000h, each with its low byte first. The program follows: 21 13 80, ld hl,msg, with the message at 8013h.

32.4 Running it from BASIC

In MSX-BASIC, from the example’s directory, BLOAD with ,R loads the file and calls its start:

Ok 
BLOAD"BEEP.BIN",R 
Loaded by BLOAD, run from BASIC. 
Ok
 

The buzzer sounds after the line, and RET returns to BASIC, which prints Ok.

32.5 Where the file can go

While BASIC runs, the addresses below 8000h hold its ROM and the BIOS, so a file for BLOAD has to go in the RAM above them. But BASIC uses that RAM too: the BASIC program in memory starts just above 8000h, and its variables follow it. The example worked above because no program was in memory. With one, the same file overwrites it:

list 
10 PRINT "hello" 
Ok 
bload"beep.bin",r 
Loaded by BLOAD, run from BASIC. 
Ok 
list 
46974 INSTRMAXTRON 
25697 ed by BLOAD, run from BASIC.501WAIT_VPOKE=^KILLL<0MERGEeMAXO<>41933;+;(3:( 
...
 

The machine code still ran and printed its line, but the BASIC program is gone: LIST shows BASIC reading the machine code as if it were a program, and then the machine stops responding.

CLEAR keeps BASIC away from the memory a file needs. CLEAR 200,&HC000 gives BASIC 200 bytes for its strings and, more to the point here, tells it to use no memory from C000h upwards. A file at C000h is then out of BASIC’s way, as figure 32.1 shows.

PIC

Figure 32.1: MSX-BASIC’s memory, with the file at 8000h and at C000h.

BEEPC.AS is BEEP.AS with its ORG changed:

                aseg 
                org     0C000h          ; above the CLEAR address
 
Ok 
clear 200,&hc000 
Ok 
bload"beepc.bin",r 
Loaded by BLOAD, run from BASIC. 
Ok
 

Give the CLEAR before the first BLOAD, and before the BASIC program is typed or loaded: CLEAR also clears the variables. A BASIC program that uses machine code usually starts with the CLEAR line and then BLOADs its files. The more machine code there is, the lower the address given to CLEAR has to be, and the less memory is left for BASIC.

32.6 Things to try

The files below are not part of the example: make them in its directory, with TATARA set as in BUILD.BAT.

32.6.1 Let TANREN place the code

A module does not have to use ASEG and ORG. BEEPR.AS is the same program in the default code segment, and TANREN places it with /P: (section 24.3):

; BEEPR.AS - the same code, relocatable: TANREN /P: places it. 
                include bios.inc 
                include ascii.inc 
                cseg 
start:          ld      hl,msg 
loop:           ld      a,(hl) 
                or      a 
                jr      z,done 
                push    hl 
                call    CHPUT 
                pop     hl 
                inc     hl 
                jr      loop 
done:           call    BEEP 
                ret 
msg:            db      "Relocated by TANREN /P:.",CHR_CR,CHR_LF,0 
                end     start
                                                                    

                                                                    
 
A:\TATARA\EXAMPLES\BINARY>tatara /q beepr.as beepr.tro 
A:\TATARA\EXAMPLES\BINARY>tanren /b /p:c000 /o:beepr.bin beepr.tro 
... 
Wrote BEEPR.BIN, C000-C02D (46 bytes), BLOAD header, entry C000.
 

The same source can then be linked for any address, and a program of several modules can be placed as a whole.

32.6.2 Call it with USR

Without ,R, BLOAD only loads the file. DEFUSR names the address of a machine-code routine, and USR calls it:

Ok 
clear 200,&hc000 
Ok 
bload"beepr.bin" 
Ok 
defusr=&hc000 
Ok 
a=usr(0) 
Relocated by TANREN /P:. 
Ok
 

The routine can then be called as often as the program needs, without loading it again.

32.6.3 Leave out /B

Linked without /B, the file has the same 54 bytes and no header:

A:\TATARA\EXAMPLES\BINARY>tanren /o:beepraw.bin beep.tro 
... 
Wrote BEEPRAW.BIN, 8000-8035 (54 bytes), entry 8000.
 

BLOAD refuses it, because it does not start with FE:

Ok 
bload"beepraw.bin",r 
Bad file mode 
Ok