Relearning MSX #24: Calling MSX-C functions from assembler
Posted by Javi Lavandeira in How-to, MSX, Retro, Technology | September 09, 2015We saw in the previous post how to run assembler routines from MSX-C. I’m sure you’re about to ask whether it’s possible to do the opposite: Is it possible to write programs in assembler and use the functions from the MSX-C Standard Library or the MSX-C Library disk?
I’m glad you asked. Yes, it’s possible, and it’s actually very easy to do.
Here’s how.
Calling MSX-C library functions from assembler programs
The rules that we saw for how MSX-C passes parameters to assembler functions also apply to MSX-C’s own library functions. This means that we can leave arguments in the CPU registers or in the stack as appropriate and call the function just like that.
As always, let’s see an example:
The program above prints two sentences on the screen using MSX-C functions printf() and puts():
- The first sentence is the same as doing printf(“It’s a beautiful %s!\n”, “morning”) in MSX-C.
- The second one is exactly the same as doing puts(“And now it’s night again.\n”).
In the first case we pass the pointers to the strings on the stack and the number of arguments in register HL. This is because printf() is a function that takes a variable number of arguments. Note that we push the arguments on the stack in reverse order, so when the printf() code retrieves them they will be in the right order.
It’s important to remember to restore the stack after the function returns. In this case we passed two 16-bit values via the stack, so we POP twice after the call to printf() returns. This restores the stack pointer to the same state it was before we passed the parameters.
We print the second sentence using puts(). This function always takes a single 16-bit argument, so we pass it in register HL. Note that in this particular case we use JP to call the function instead of CALL because this code is at the end of our program. When puts() has done its work it will run its own RET instruction and correctly end the program.
Note also the two lines at the beginning of the assembler code: the symbols printf and puts are declared as external, so the M80 assembler won’t return an error.
After assembling we’ll have to link the code of our program with the appropriate functions from the MSX-C Standard Library. The following script (AS.BAT) does both the assembling and linking:
This will generate the program EXAMPLE.COM. The file size should be about 2 kilobytes. This is because this program contains not just the assembler code above, but also all the code required by MSX-C’s printf() and puts().
Run it to confirm that it works:
Summary
We’ve seen how to call MSX-C functions from assembler. This will be useful when we want to take advantage of C’s powerful string format functions without having to implement them in our program.
In the next post…
In these last few posts we have taken a detour into assembler and how to mix it with MSX-C. In the next post we’ll retake learning about MSX-C programming just where we left it in issue #18, Structure of an MSX-C program. From now on we’re going to be jumping back and forth between MSX-C and assembler.
I’ve never programmed in assembly, but I find this highly interesting. You say that “It’s important to remember to restore the stack after the function returns.”
Why is this important? Is this because MSX-DOS requires it?
Also, what will happen if the stack is full when we push something on it?
Nah, this is because function should return to where it was called, so stack must be preserved. The stack is the place where return addresses are being stored among some other temporary data and variables.