May 5, 2019 - by Paul Bosselaar
I somehow get the feeling every now and then that more people want to know how to program things for old computers. Since I still have a working MSX and still sometimes program for it, let’s see if I can create some tutorials.
The MSX has a Z80 processor on board. So you need a Z80 assembler if you want to program in assembly. You can use an assembler on the MSX like Wbass-2 or Compass, or you can use a PC or Mac for cross-development and use something like Sjasm or Glass. For now I wont be covering how to use an assembler. Instead I’ll focus on assembly and the MSX bios at first.
The MSX Bios? What is that? BIOS stand for Basic Input Output System and this consists of routines which can do things for you so you do not have to program everything yourself. The Bios is also the program that boots the MSX, show’s the MSX logo and starts MSX Basic or MSX DOS.
When booting from a cartridge or when in basic, the BIOS is in the first part of the MSX’s memory: from 0000 to 4000. The routines in the BIOS are document in different books (e.g. the MSX red book) and online, for example at the MSX Assembly Page. Looking at that list, there are quite a few routines there!
When code is executed from MSX Basic or from a ROM, you can directly call those routines.
If you look at the routines, you’ll find the routine called “BEEP” at address 00C0. This routines simply clears the text screen. In assembly code you’ll use that as follows:
CALL $C0
Note that Now that wasn’t to hard was it?
To create an actual program which the msx can run from Basic, the program needs something called a header. This header contains the information the MSX needs to correctly load and execute the program. This header is simply a set of numbers. Most assemblers can simply create those numbers with db (define byte) or dw (define word, e.g. 2 bytes)
; This is a comment and is skipped by the assembler
db $FE ; magic number
dw Begin ; begin address of the program
dw End - 1 ; end address of the program
dw Execute ; program execution address (for ,R option)
You said a header consist of numbers, but “$FE” and “Begin” are not numbers. And subtracting 1 from the word “End”, are you nuts?
Well, no I’m not. $FE is an actual number. Not in a normal (decimal) notation, but in hexadecimal notation (as is the address of the BEEP routine). Those texts are labels in the program. When assembling, the assembler will replace those labels with the actual adresses in your program. So to create an actual .bin file which will produce a beep and can be BLOADed from Basic, we need the following program:
db $FE ; magic number
dw Begin ; begin address of the program
dw End - 1 ; end address of the program
dw Execute ; program execution address (for ,R option)
org $C000 ; The program start at C000h in the MSX's RAM
Begin:
Execute:
CALL $C0 ; Call the BEEP bios routine
ret
End:
So the first line is the so called magic number. When the MSX sees that the first byte is this magic number, it will assumbe it is a file which can be BLOAD’ed and run. The second line is where the program should be loaded in memory and together with End the MSX knows how many bytes should be loaded into memory.
The fourth line dw Execute
determines the memory address where the MSX should start executing the code. In this case this is the same address as where the program is located.
The next line is new. The “org” instruction lets the assembler know how to calculate at which addresses labels should be. The assembler has an address counter. That address count is set to a specific value with the “org” instruction. When the assembler encounters an instruction it will increase the address counter with the same number of bytes that the instruction takes. In this case both the labels “Begin” and “Execute” will contain C000. The label END will afcource be a bit higher since the address counter will be increaded after the CALL en RET instructions.
The CALL instruction will simple jump to the bios routine BEEP. Since we use a CALL and the BEEP routine (as most BIOS routines) ends with RET (short for RETurn) the BEEP routine will jump back to our program. Our program contains a RET as well and should return to Basic. If we forget the RET in our program, the MSX would simply try to execute whatever is in memory right after our program. This usually results in garbage or een MSX that hangs.
So, this was our first real assembly program. Which topic should be next? Let me know at https://twitter.com/PaulBosselaar