Skip to main content

C64: Create a PRG file with a simple machine-language program

Getting back to machine-language, we will take the program from a previous post, assemble it by hand, and create a PRG file that can be run on a C64 emulator. 

The program is a very simple one that changes the background and border color to black:

LDA #00
STA $D020
STA $D021
RTS

If we look up the opcodes by hand or use an assembler, we can see that the machine language code for this program is the following byte sequence:

A9 00 8D 20 D0 8D 21 D0 60

One way to run this program, at least on a Commodore 64 emulator, is to create a PRG file with it. Another way would be to create a disk image (D64). But the PRG format is much simpler, so we go with it, for now. A PRG file consists of a 2-byte header followed by the binary contents of the program to load into memory. The header specifies the memory address for the binary code to be loaded in the C64 memory space. So we could start with the bytes 00 C0 (the 6502 is a little-endian CPU) and load the code to address $C000; then we should execute a SYS instruction calling this code. 

However, in general we want to distribute programs to users, and users in general want to just do LOAD and then RUN. The RUN instruction will execute the BASIC program at $0801, which is the designated space in RAM for BASIC programs. We could put the program in this space, together with a small BASIC program just to run our machine language code. Another advantage of doing this is that we can use the more than 38kb of RAM in the space for BASIC programs, instead of just 4kb reserved for machine language code at $C000. 

The BASIC program to load the machine language code is just a single SYS instruction pointing to where the code is placed. This address could be just after the BASIC program (a single SYS instruction). This is the standard "BASIC autoloader" used by C64 programs. The machine language code will be placed 15 bytes after the BASIC code, so at $0801 = 2049 + 15 = 2064. This means the BASIC program is the following:

10 SYS 2064

We have to investigate how this line of BASIC code is encoded in memory. It's simple though: there's a linked list of lines where each line starts with a pointer to the next line, followed by the line number and the contents of the line. Standard BASIC instructions (like SYS) are represented by bytecodes, but the operands of instructions are represented as strings (even when the operand is numeric, like the address after SYS). So the loader program would be encoded as the following byte sequence:

0C 08 0A 00 9E 20 32 30 36 34 00 00 00

The first two bytes are the pointer to the next line of BASIC, which will be at $080C. then comes the line number which is 10 ($000A). $9E is the byte code for the SYS instruction, and then the operand is represented as a string, beginning with a space and then the characters for 2064. after that, the first 00 byte is a line terminator, while the next two 00 bytes represent the pointer to the next line of BASIC code, in this case a null pointer indicating the end of the linked list, that is, the end of the program.

So this is the entire contents of our PRG file: the file header (two bytes $01 $08, placing our program at $0801, the address for the BASIC program that will be executed when the user issues a RUN command), followed by the BASIC loader program (10 SYS 2064), followed by our machine language code.

We could easily create a binary file with these bytes by hand using a hex-editor, or write a small program to build this file. This is a Racket program that does that. Loading the generated PRG file in a C64 emulator or C64Mini/C64Maxi and running it, we can see the background and border becoming black.

This very simple program provides the template for creating bigger and better programs that will be run on the machine. 

Comments

Popular posts from this blog

First assembly program on the C64... in BASIC

There are many books, tutorials etc dedicated to teaching C64 programming, many of them start by teaching BASIC. I had an MSX as a kid so I'm pretty familiar with this flavor of BASIC (Microsoft BASIC). On the other hand, most assembly programming tutorials begin with number systems, binary numbers and other pretty basic stuff for someone who's already familiar with assembly programming in other platforms.  What I wanted was to create the smallest programs in assembly that could run on the machine and show some effect. After looking around for a bit I've found this one: lda #$00 sta $d020 sta $d021 rts This sets the contents of the accumulator to 0 and then store this zero at memory locations 0xD020 and 0xD021. These two memory locations control the color of the screen background (0xD021) and the border (0xD020). As expected, setting them to zero will make the whole screen black (except for the text). Now the next step is how to run this program. The id...

C64: Playing with video memory in text mode

 As it happens with older computers, with the C64 the programmer had complete control over the machine and could write directly to any part of memory, perform I/O and so on. Video memory was mapped to the CPU address space and so could be read and written directly as well.  For the C64, the relevant memory addresses are 0x0400 for characters and 0xD800 for colors. The byte at 0x0400 determines the character that appears at the top left corner at the screen, while the byte at 0xD800 determines the color of this character. The following bytes store the next characters in order going from left to right, and top to bottom. So, to find the address of screen position (x, y) for column x and row y, you have to calculate 40*y+x. Multiplication can be slow in these old CPUs, but we can fill the memory sequentially and, en passant, see the complete character set of the computer (it does not follow ASCII).  So here's a small BASIC program to manipulate video memory using POKEs. We c...