Skip to main content
Dansbo TechBlog

Adding BASIC command to Commander X16 kernal

Developing for the Commander X16 kernal can be a daunting task. It is a large project and a lot of the existing code comes from the original CBM BASIC and is largely uncommented.

But it is not impossible to get to a point where you only need to focus on what is needed to get your task completed. As the very first thing, you should fork the x16communit/x16-rom project and create a working branch. There is plenty of documentation on how to do that.

Once you have your own repository and you have cloned it to your local computer, you can get startet. Before doing anything else, ensure that you actually have the tools to build the kerneal. It should be as simple as entering the x16-rom directory and typing make

If you are unable to get the ROM to build by typing make, seek help on the forum and discord to get your development environment set up correctly. There is no reason to continue from here if you are not even able to build the kernal without any modifications.

Now that you have a working development environment, we can continue. Since the BASIC ROM bank is almost full, it is recommended to add your code to the BANNEX ROM bank.

Start by creating a new file in the bannex directory. Usually you will want to call the file something along the lines of the BASIC command name you want to add. Ensure that the file has a .s ending, not .asm or anything else.

In your file, you can use include files from the inc directory and you can import functions you need to create you own function. Take a look at some of the other files in the bannex directory to see how people have done before you.

When you have written your function you need to export it to let the rest of the kernal know that it exists. One thing is to add the .export command to you newly created file, but a lot of other stuff needs to be done before you can actually use it as a command in BASIC.

First, you need to add your new file in the Makefile under BANNEX_SOURCES to ensure that it is actually build together with the rest of the kernal.

Next, we need to tell BASIC that a new command exists. This is done in two places. basic/tokens.s where you add your assembler procedure name under statements or functions. See the existing list to figure out which one you need to do. Usually it is a function if you are returning a value.

You also need to add the name of the BASIC command to basic/token2.s. Again you need to ensure that you place your BASIC command name correctly depending on if it is a statement or a function. You will see that the existing BASIC command names are written a bit strange. Ex. VPEEK is written like this:

.byt "VPEE", 'K' + $80

The trick is that bit 7 of the last letter must be set, hence the addition of $80

Now we have created our assembler function in bannex and we have told basic that there is a new command. Next we need to ensure that BASIC ROM bank knows how to get to your function in the BANNEX ROM bank.

In basic/x16additions.s you add a label with the name you have used for your assembler function and make it call your assembler function in the bannex bank. For the TDATA function, it looks like this:

tdata:
	bannex_call bannex_tdata
	rts

In bannex/main.s you import your assembler function and add it to the jumptable, when you look at the file, it should be fairly obvious what you need to do.

You also need to add your function with bannex_ prepended to inc/bannex.inc. Again it should be fairly obvious what you need to do.

That is it. You should now be able to build the kernal.

make clean
make

When you load your new ROM on hardware or in the emulator, you should now have a brand new BASIC statement or function.

Final thing to do is to create a pull request against the official kernal so that others can benefit from your hard work. To ease the work of the kernal maintainers, you should be sure to describe the purpose of your change and what impact it may have on the rest of the kernal.

In summary, this is what you need to do:

  • Create your source file in bannex directory, ensure it ends with .s
  • Be sure to export you assembler function name
  • Add your new source file to the Makefile under BANNEX_SOURCES
  • Add the assembler function name to basic/tokens.s
  • Add the new BASIC command to basic/token2.s
  • Add your assembler function name to basic/x16additions.s and call you function in BANNEX
  • Add your assembler function to the jumptable in bannex/main.s
  • Add your assembler function prepended with bannex_ to inc/bannex.inc
  • Create pull request against offical Commander X16 ROM

Symbols from BASIC bank

If you find that you need functions from BASIC bank and they are not available to .import, you need to make them available your self.

This is done in the Makefile under.

# Bank C : BASIC Annex

Here are 3 lines that uses a findsymbols script to find symbols/functions in other banks. The first line is for BASIC symbols that live on zeropage, they can be exported to BANNEX bank directly. Second line is BASIC symbols that do not live on zeropage. These need a bit more work. To begin with, you just add the BASIC symbol/function that you need to the second line.

Symbols/functions that are added to the second line will be prepended with basic_

In bannex/basic_far.s you can .import the basic_ symbol name and .export the name without basic_, but be sure to actually add it as a far jump to the BASIC bank.

myfunc:
	jsr bajsrfar
	.word basic_myfunc
	.byte BANK_BASIC
	rts

After this, you should be able to .import the symbol into your code.

If you have any questions or comments, feel free to contact me here, on https://cx16forum.com or the Commander X16 discord server.