Commodore 64 BASIC Programming Series
Part 1: Introduction to Commodore BASIC
Part 1.5: Installing CBM Prg Studio on Mac/Linux
Part 2: Commodore BASIC Commands GOSUB and FOR Loops
Part 3: If/Then, Game Logic and Cursor Movement
Part 4: The Magic of POKE
Commodore might have built game-changing (heh) video game features in the C64, but their background was firmly in the business market, especially the small business market. Therefore it is hardly surprising that they included rudimentary Disk Operating System commands into the Commodore 64.
For games too, loading data is important. Today we call game data “assets” – things like sprites, level data, music, graphics, and so on. While listing out this data as part of the program in DATA
statements works, it soon becomes cumbersome.
In this article we will look at how we can use these disk and file access features within our Commodore 64 BASIC programs
Commodore 64 File Types
The C64 has these four file types. Really, it is 3 with a variation on Sequential called USR.
We have already been using the PRG
type as that is what our BASIC programs are saved as. PRG files can also be used for data and loaded using the LOAD,8,1
command as the first two bytes set the address in RAM to place the file.
SEQ
, or Sequential files are the simplest type. They must be read from the beginning in order to get to the part you need. Think of them like documents or plain text files.
Unlike SEQ, you can access individual REL
records directly thanks to an index stored on disk (“side-sectors”). REL files are organized as fixed-length records, and records can only be up to a maximum of 254 bytes in size due to the maximum sector size of the disk format.
Back in the day, programs rarely used the USR
file type. They are essentially a SEQ file for our needs.
PRG | Program |
SEQ | Sequential |
REL | Relative / Random-Access |
USR | User |
C64 DOS Commands
Before we can send any file or disk commands, first we must open the appropriate channel:
OPEN 15,8,15
This takes the following three parameters:
- File number – for referencing the file in future commands. In assembly it is referred to as the Logical Address.
- Device number – specific device attached to the computer. By default, the first disk drive is device 8, the second device 9. In assembly this is called the Physical Address.
- Secondary address – the communication channel. This is passed to the device in the range 0 to 14 when reading or writing data, or we use 15 as the “command channel”, which is used to send DOS commands.
Once we have an open channel we can issue commands:
Format:
PRINT#15,"NO:FILENAME,XX"
Rename:
PRINT# 15,"RO:FILE2=FILE1"
Backup:
PRINT#15,"CO:FILE2=O:FILE1"
Delete:
PRINT#15,"SO:FILENAME"
How to use the CMD Command to Save Your Tokenized BASIC Program as an ASCII Text File
Confusingly for many, Commodore BASIC programs are NOT plain text files. They are converted, or “tokenized”, into PRG files. This means you can’t just load one up into your text editor.
What we can do though is output our tokenized BASIC to a Sequential file by redirecting the output using CMD
, and then we can load that newly generated file instead.
OPEN8,8,8,"NEWFILE,S,W":CMD8:LIST
Followed by
PRINT#8:CLOSE8
To display the saved text file we simply load the Seq file:
10 OPEN8,8,8, "NEWFILE,S,R"
20 FORI=0TO1:GET#8,A$: PRINTA$;
30 I=ST:NEXT:CLOSE8:END
Loading Binary Data into C64 Memory
Just as we can load a program into the memory address it was saved to, we can do the same with data. That, of course, means we must have saved the data with a header containing the address that it should be loaded into.

10 REM LOAD DATA
20 IF A=0 THEN PRINT CHR$(147)"START"
30 IF A>0 THEN PRINT "LOAD FILE"A
40 A=A+1:ON A GOTO 50,60,70
50 LOAD "CHARS.BIN",8,1
60 POKE 53272,(PEEK(53272)AND240)+12
70 PRINT “{CLEAR}DONE!"
Strangely, each LOAD
command in BASIC resets the program counter and restarts the program, so we have to keep track of which load we are currently on using a variable, in this case we increment A
.
Finding the Current Drive Number
The drive we are using right now is stored at the memory address 186 so we can PEEK
that to determine which drive number to reference:
CD=PEEK(186)
Some commands do change what is returned by PEEKing 186, but always to a number less than 8, therefore the best approach would be to do:
CD=PEEK(186):IF CD<8 THEN CD=8