The first exercise in any coding tutorial is invariably printing ‘Hello World!’ to the screen, this gives us a basis for the structure of the language and shows us something on screen.
I’m not going to sugarcoat coding for the NES can be difficult and in order to get this basic message onscreen, we will need to learn how the NES hardware works as well as how the keychain operates. On the positive side of this, after you have completed and understood this process the learning becomes easier.
Using C as a Language
The best place to start is probably by looking at how to create this in C, C programming is easier than looking at Assembly and its important that we get the basic understanding of the NES down.
I am using Visual Studio Code as my IDE and creating a new C file which I call simply hello_world.c
Step 1: Definitions
The first thing you will notice about this code is the list of #define statements which all begin with PPU_. These are aliases to specific memory addresses that are mapped to 8 bit registers in the PPU – The Picture Processing Unit. This generates the video signal sent to the TV and exposes them to the CPU. These registers allow us to communicate with the PPU and tell it what we want to appear on the screen.
After this we have our definitions for Color values – these are used to define palettes. The PPU is capable of a limited set of pre-defined colors which can be combined in palettes and then assigned to sprites. Each color can then be represented in a single byte, hence the term “8-bit graphics“.
Step 2: Setting up the Data
Next we are going to be defining a few variables, first there are a few things to explain. The #pragma bss-name is a pragma provided by cc65, this is as we mentioned before, the C compiler we are using to target the 6502 CPU in the NES. What this Pragma does is allow us to specify where in memory we want variables to be defined. We will get to where we define these memory areas in a bit, but first lets talk about how memory is laid out in the NES.
The NES CPU has 2KiB of internal RAM, this is split into eight 256-byte pages, with each address represented as a two -byte (16 bit) Word. The first page is called the Zero Page, as all the addresses begin with 0x00. The 6502 instruction set has particular instructions for dealing with Zero page memory addressing that take into account the implicit zero byte. These run a little faster than the same instructions performed on memory on other pages.
We want to take advantage of the zero page for variables that are used most often in our code. One of the most used elements in a C program is a loop counter.
Loop counters are often used and we want to take advantage of the extra speed in using Zero Page memory. Using a register would be even more ideal, however the CPU only has three of those and we want to make those available to the compiler.
Next we define the rest of the data to be used in the program, this is the text that we wish to display and the palette.
Palette data has to be in a very specific format. This is expected by the PPU. Aside from a universal colour (here we use black) we can define up to four different background palettes, each with three colours. Here we only need black and white.
Each 16px x 16px area of the background will be associated with a background palette and can make use of its three colours in addition to the background colour. As we are creating a very simple background and not using any sprites, we’re only worried about a single background palette.
Step 3: Defining our Main Function
Now that we have all the data set up, let’s move onto our main function. If you have coded in C before you will know that this is the starting location of our program.
One thing that might surprise C developers is the lack of args (arguments) in the main function. This is because we are running directly on the hardware, there’s no OS / Shell to pass in arguments and we do not need to return anything.
The first thing we do is send the palette data to the PPU. To understand what is going on here, you need to know that neither the CPU or the PPU have direct access to each other’s memory. When writing to the PPU, we first tell it where in its memory we want to read or write data from.
This is done by writing to the Upper followed by the lower byte of the target address to the PPU_ADDRESS Register. The palette data is to be stored in the addresses 0x3f00 through to 0x3f1f. This is in the PPU RAM.
We write the data one byte at a time to the PPU_DATA register, each read or write to this register increments the PPU_Address by one.
Step 4: Background Tiles
Now that the Palette information is copied over to the PPU, let’s move onto the background tiles which make up our “Hello World!” greeting.
Here we are writing to an address which is designated for Nametable 0. A nametable is a 1KiB chunk of memory that represents the background. There are four such nametables which are addressable by the PPU and we can switch between them by using a flag in PPU_CTRL.
You can read more about Nametables here.
Before turning rendering on, we need to tell the PPU which pixel of the nametable should be at the top-left corner of the screen. This is done by writing the horizontal offset followed by the vertical offset to the PPU_SCROLL register. We want to start at the beginning of the nametable so we set both to Zero.
Now it’s time to tell the PPU to start rendering. First, we’ll write the byte
ox80 to PPU_CTRL.
The last thing that we have to fo is set the PPU_MASK.
We’re setting a value of 0x1e, which tells the PPU to render all backgrounds and sprites and to render them in color.
Our work being done, we command the CPU to spin forever
After we create our Appropriate files (how to do this was shown in our first lesson) When we run this on our emulator we get:
A note on Character Sets
In this tutorial I have not shown how to create character sets, instead I have provided some of my own for you to use. Please insure that these are included in your project bfore you compile. You can find them here.