Files in BASIC I - Loading and Saving files and high scores

I never owned a Commodore computer and therefore I will be the first to admit that file management on C64 always seemed confusing to me. I am slowly trying to figure it out as my projects require more and more interactions with external files. Even in BASIC programs we need to occasionally load external assets and even save game state or high scores.

In addition to that the Emulator is pretty much work in progress and there seem to be some features in it that don’t quite work yet. Emulator does override some standard behavior in order to be able to access the host file system but only to some limited functionality makes it even a little bit more confusing.

So my goal is to tackle very basic functionality and as Emulator evolves I will update this tutorial. Of course when the physical system reaches our desks I will review and update this post even more thoroughly.

What File system

First of all Emulator runs on a host system which can be either Windows, Linux or Mac which are all officially supported and several other platforms that were built by members of our community.

It is very important to remember that we can run an emulator with or without a mounted SD card image, however this affects a large part of functionality that is at our disposal. It is expected that when the actual hardware ships it will come with an SD card reader which will be used as primary storage. For that reason the emulator comes with SD card image support which provides full functionality.

Unfortunately the current version of Emulator does not allow the same functionality for the host file system, meaning that we can only test and use some features when we start Emulator with SD card image mounted. Current version R.38 also does not support reading both the host file system and SD Card image at the same time.

Empty SD Card Image can be download from official Commander X16 Repository:

https://github.com/commanderx16/x16-emulator/blob/master/sdcard.img.zip

I am using Windows and I prefer to use VHD format because it allows me to mount and use on Windows 10 directly without any 3rd party tools. Detailed instructions on how to create were written by user TomXP411:

https://www.commanderx16.com/forum/index.php?/topic/996-how-to-create-an-sd-card-image/

To start Emulator with a mounted SD Drive you need to use -sdcard option, of course depending on whatever you name the SD image card and where on your system you save it.

X16emu -sdcard D:\TestDrive.vhd

Or

X16emu -sdcard sdcard.img

I personally like to adjust the size and look of the screen so I start Emulator in several ways depending on what I am doing:

X16emu -scale 3 -quality nearest -debug
X16emu -scale 3 -quality nearest -echo
X16emu -scale 3 -quality nearest -debug -sdcard D:\TestDrive.vhd
X16emu -scale 3 -quality nearest -echo -sdcard D:\TestDrive.vhd

Typically I use -debug option when working on Assembly programs and -echo when working on BASIC programs.

Loading and Saving programs

Let’s start with the part that should be fairly straightforward. Loading and saving BASIC programs.

The good news is that this functionality works on both host file systems and SD cards.

LOAD ”PROGRAMNAME”
SAVE “PROGRAMNAME”

These two commands load and save BASIC programs to the current drive. Note that Emulator assumes current drive to be 8 and therefore above commands are the same as typing

LOAD ”PROGRAMNAME”,8
SAVE “PROGRAMNAME”,8

We will see later why this is important to remember. But what does the 8 mean? It is the result of the Commodore heritage, because Commodore line of home computers used device numbers to determine on which device the command should operate on. It is not clear at this time which of these devices will be available on Commander X16 and if they will stay the same but at the time of writing this post the default disk drive on Commodore 64 would have Device number 8 and that is mapped to either host files system if Emulator is started with SD card or SD Card if sdcard option was used.

I hope that in the future Emulator will be able to use both e.g. 8 for host file system and 9 for SD drive.

Loading and Saving BASIC programs as text

BASIC programs are tokenized immediately after each line of BASIC code is finished by pressing Enter command. This means that in memory BASIC commands only use one byte which is a significant saving in space and also during running the program the commands don’t need to be parsed again.

For example, the command “PRINT” uses 5 characters and would use 5 bytes and a BASIC interpreter would need to read them all and scan all the BASIC commands to determine which one it is and that would slow down BASIC programs to the crawl. Instead the PRINT command is stored as 159 or $99 in hex so the interpreter knows right away that the next characters that follow need to be printed to screen.

That causes a problem that we can’t open BASIC programs with standard text editors on the host system, write and change programs and test them in the Emulator. Ideally we would have an option with the SAVE and LOAD commands to save and load text versions of BASIC programs however that does not exist but there is a workaround.

If we start the Emulator with -echo options everything that is displayed in the Emulator using standard commands like PRINT will be copied to the terminal from which we started the Emulator. So if we write a BASIC program in the Emulator and list it out to the screen using command LIST the complete listing will be printed into the terminal/command window as text. From there we can easily copy it and paste it into our favorite text editor.

After we are done writing or editing it on a host system or even copying the source code from this and other articles and Github repositories we can simply copy the text and paste it directly into Emulator. On Windows we can use Ctrl C and Ctrl V shortcuts.

Loading assets and other data

We already established that BASIC, being interpreted language is not the fastest. So whenever we need to move large amounts of data it will show its weakness. Even reading a few hundred bytes in DATA statements will take a long time and create uncomfortable delays.

On the other hand Commander X16 has very powerful graphics with many colors, layers, sprites, even high resolution bitmap graphics in many color modes and 16K of video memory. Then there are other types of data like short assembly subroutines that can help increase the speed of mostly BASIC programs or add features that are very hard or impossible to do in BASIC like playing music in the background etc.

How do we solve these two seemingly incompatible situations?

One possibility would be to use Assembly language but loading files in Assembly is not trivial and is not something even an intermediate coder can do easily.

The easiest way to do it is to load game assets directly into memory using LOAD and VLOAD commands. The names already hint at what the difference is. Load is used to load files to CPU memory and VLOAD to load files directly in Video Memory or VRAM.

Before we try some examples we have to understand that files that will be loaded need to have two extra bytes at the beginning. Those two bytes are reserved for starting addresses of memory where the file will be loaded. Of course we can override them but Commander X16 expects these two bytes regardless if they are used or not.

Another important note to make is that when the Emulator is started directly from the host file system and receives the Load command from either BASIC or Assembly it directly injects the loaded file into Commander X16 memory which is pretty much instantaneous. That is not the case when using an SD card and in the future on an actual system so loading time still has to be taken into consideration.

Loading to Video Memory (VRAM)

Now that we know how the files have to be structured with two extra bytes at the beginning we can load them directly into VRAM using the following command:

VLOAD “FILENAME”,Drive,Bank,Memory Address

  • Drive has to be 8 for the host file system or SD card depending on how the Emulator was started.
  • Because VRAM is 128K bytes in size we have to choose if our data will go into first 64K (Bank 0) or second 64K (Bank1).
  • Memory Address is the starting address with the chosen bank.

In concrete example to load new font to VRAM starting at address $06000 we would use:

VLOAD”LIGHTFONT.BIN”,8,0,$6000

To load tile sheet to address $12000 following command can be used:

VLOAD”TILESHEET.BIN”,8,1,$2000

As far as I was able to test (without analyzing Emulator source code) VLOAD in Emulator R38 always ignores the address in the first two bytes of file but they still have to be present. In fact if you try to use VLOAD command with less than four parameters it will complain with SYNTAX ERROR. So at this time (Emulator R38) we always have to define where in VRAM to load data.

Loading to CPU Memory

LOAD command is similar to VLOAD just different that it operates in CPU RAM and it comes with its own set of quirks and incompatibilities at this version of Emulator.

Typical files that we would load to CPU memory would be music and to a certain extent level data for games however that comes with a potentially slow reading of data from memory into some kind of BASIC data structure like arrays which is not much faster than reading from DATA statements.

Another very important type of files that we would load into CPU memory are machine code routines and libraries like my Simplest Sounds Effect Library and Music Player Library for BASIC programs. Syntax is similar to the VLOAD command:

LOAD”FILENAME”,Drive,Secondary,Memory Address

  • Drive again has to be 8 for default drive either on host system or SD drive
  • Secondary number does not have any effect so I just put 0 or 1
  • Memory address is starting address to where we want to load our file

The above syntax works on both host file systems as well as SD drive, however I noticed one difference in behavior.

If the starting address is written in the file Emulator loads it to that address only when loading from SD drive but not from Host file system. So for loading from the SD card we don’t need to include any other parameters than just filename. Of course for compatibility purposes it is recommended to always include memory address, which btw. Also makes source code more understandable.

So to load Simplest Sound Effect Library we can use

LOAD”EFFECTS.PRG”

When loading from SD Card, but it is recommended to always use:

LOAD”EFFECTS.PRG”,8,0,$0400

Reading and Writing to files

It is time to switch gears a little, it is time to start programming and accessing files directly from BASIC. We will not go very deep for now but will create a rudimentary set of functions so our BASIC games will be able to load and save High scores. The same technique can be used to save the status of the game etc.

It is important to remember that this functionality at the time of writing this (Emulator R.38) only works with SD Card attached and not on Host file system which is a bit of a pain but I expect that this will be remedied in the future releases of the Emulator and of course on the actual system we will be dealing with SD cards as main storage only anyway.

Checking for Drive availability

Because file access is not guaranteed it is good practice to check first and then enable or disable certain functionality programmatically so the program doesn’t crash. We can check that by opening and closing the drive channel 8:

10 OPEN 1,8,2:CLOSE 1
20 IF ST=0 THEN PRINT "DRIVE IS PRESENT!"
30 IF ST<>0 THEN PRINT "DRIVE IS NOT PRESENT!"

First line returns zero in system variable ST if the Drive opening and Closing was successful or some non zero error value if it was not.

ST stands for STATUS - remember Commander X16 BASIC only distinguishes two characters in variable names so ST and STATUS is exactly the same and is also a reason why we can’t use custom variables START for example.

Reading from file

Reading from a file is very straight forward after we understand all the parameters. We first have to open the file using command OPEN and then read using command INPUT#

OPEN Logical file number, Device, Secondary number, “Filename,Type,Mode”

It looks pretty complicated but it is really not, let’s first check what parameters mean.

  • Logical file number - is a number that will identify the “handle” to this file after it is opened for consequent reads or writes.
  • Device number is now already familiar number 8 for the default drive
  • Secondary number still does not have special meaning for our purposes
  • Filename is in parenthesis and contains more than just a name:
    • File name itself
    • File type. Several different file types are possible but we can just use type P which stands for Program but is commonly used for data files too
    • Mode determines if the file will be opened for Reading or Writing so it can have value R or W

Let’s look at example:

10 OPEN 1,8,2,"HIGHSCORES.TXT,P,R"

Logical file number is 1 wo we will use handle 1 for all consequent operations of the file. We open it from the default drive 8. Number 2 doesn’t have special meaning for our purposes here. File name is HIGHSCORES.TXT and is of type Program and will be opened for Reading.

To read from the file the command to use is INPUT#

20 INPUT#1,A$

The first parameter 1 is of course reference to handle 1 for the file we opened above and the second one is directing it to read a string from the file and store it to variable A$.

We can use system variable ST (STATUS) again to check if reading was successful. If everything was OK then ST will be 0 after the read.

Any other value represents some error. One of the most important ones is 64 which means that the end of the file was reached so we can use it to control the flow of our program if the number of reads can be variable.

At the end it is important to close the file using

30 CLOSE 1

Writing to File

Writing to file is very similar and is also done by opening the file, performing writes and then closing the file like this:

10 OPEN 1,8,2,"@:HIGHSCORES.TXT,P,W"
20 PRINT#1,A$
30 CLOSE 1

As most of the code above is exactly the same as for reading let’s just highlight one obvious change. We see the “@:” in the beginning of the File name. That symbol tells the BASIC interpreter and in turn to the Kernal that we want to rewrite the file if the file with the same name already exists. Without that the opening would fail.

High Score Demo

Let’s put all of the above in a short demo that will allow us to initialize, load and save 10 high scores. I also included a simple function for adding new scores to the sorted array.

And a short video of the demo in action. Again, remember this only works if the Emulator was started with an SD card attached.




Comments

Popular posts from this blog

Commander X16 Premium Keyboard

Hello VERA (BASIC vs C vs Assembly)

Direct VERA Access