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
- ASEG and ORG put the code in the absolute segment, at 8000h (chapter 10). The file is loaded at the address in its header, and TANREN gives it the address the source names.
- The loop prints the message one character at a time with CHPUT, the BIOS routine that prints the character in A, until it reaches the zero byte at the end. BIOS.INC gives the addresses of CHPUT and BEEP.
- BEEP, another BIOS routine, sounds the buzzer, and RET returns to BASIC.
- The END line names start. TANREN puts it in the header as the address to call (section 26.5).
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.
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