Tutorial 5 – C Programming in 6502 – Video RAM


Previous four tutorials [1][2][3][4] are preparation for coding games on 6502 platform. Now, it is time to move a bit forward onto the NES hardware programming.

NES Family Computer has a 6502 CPU which frequency is 1.8 MHz (Yes, nothing compare to what we have today, but it was the technology almost more than 20 years ago). There is also an external PPU (Picture Process Unit), which has a resolution of 256*240 pixels (32*30 blocks of 8*8 each).  4 layers of background, maximum 52 colours but only 13 colours per screen.

There is not bitmap in FC. Everything (text, pictures) printed on screen should be mapped to the pattern table (a table that contains the tiles of size 8*8). The Name Table is used to specify the index (which tile) to print to screen.

The Name Table and Pattern Table are stored in the Video RAM which is separate from RAM (accessed by CPU). The RAM is so a precious resource (2K only) that it is impossible to map all the video RAM to it. Therefore, only the registers used by PPU is mapped to RAM. For example, the address register in PPU is mapped to $2006 in RAM and the data register is mapped to $2007 in RAM.

The address pointer in 6502 is 16 bit, which means we need to write TWICE to $2006 locations, first time the high byte of the address and the second time the low byte of the address mapping to PPU. For instance,

1
2
3
4
5
// specify the address is $2100
address(0x2006) = 0x21;
address(0x2006) = 0x01;
// put character 'A' on $2100
address(0x2007) = 65;
// specify the address is $2100
address(0x2006) = 0x21;
address(0x2006) = 0x01;
// put character 'A' on $2100
address(0x2007) = 65;

The Video RAM address from 0x2000 to 0x23BF is the default Name Table 0 which consists of 32*30 tiles.

For example, if we want to write a character ‘A’ to position (16, 14), The corresponding VRAM address is calculated as 0x2000+(14+1)*32+16=0x21f0

The 0x2000 is the starting address of the Name Table 0. The first and the last rows are not displayed, so virtually it is 32*28 tiles. That is where the +1 comes from. 16 is the number of horizontal offset.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "conio.h"
 
typedef unsigned char u8;
#define address(add) (*(u8 *)(add))
 
void main()
{   
    cprintf("visit VRAM");
    address(0x2006) = 0x21;
    address(0x2006) = 0xf0;
    address(0x2007) = 65;
    while(1); 
}
#include "conio.h"

typedef unsigned char u8;
#define address(add) (*(u8 *)(add))

void main()
{	
	cprintf("visit VRAM");
	address(0x2006) = 0x21;
	address(0x2006) = 0xf0;
	address(0x2007) = 65;
	while(1); 
}

This gives the following output, but accessing the VRAM hardware directly.

6502-nes-vram Tutorial 5 - C Programming in 6502 - Video RAM 6502 8 bit c / c++ code compiler interpreter / compiler Nintendo Entertainment System programming languages

The NES rom can be downloaded [here]

With modern emulators (such as Virtual NES), under the Tool->View, we can see some tables.

virtualnes Tutorial 5 - C Programming in 6502 - Video RAM 6502 8 bit c / c++ code compiler interpreter / compiler Nintendo Entertainment System programming languages

The Pattern Table look like this, and we can see the second one is empty (we can make use of this later).

6502-vnes-pattern-view Tutorial 5 - C Programming in 6502 - Video RAM 6502 8 bit c / c++ code compiler interpreter / compiler Nintendo Entertainment System programming languages

The ASCII larger than 127 is the opposite (background colour and foreground color) of the first 127 characters.

There are four Name Tables, but two of them are mirrors.

6502-name-table Tutorial 5 - C Programming in 6502 - Video RAM 6502 8 bit c / c++ code compiler interpreter / compiler Nintendo Entertainment System programming languages

The lower-left Name Table is the mirror of the top-left one and the lower-right Name Table is the mirror of the top-right one.

The Palette Table shows that on NES, there is only limited number of colours.

palette Tutorial 5 - C Programming in 6502 - Video RAM 6502 8 bit c / c++ code compiler interpreter / compiler Nintendo Entertainment System programming languages

And finally, the Memory Viewer will let you see all the values from memory location $0000 to $FFFF (RAM accessed directly by 6502 CPU).

memory Tutorial 5 - C Programming in 6502 - Video RAM 6502 8 bit c / c++ code compiler interpreter / compiler Nintendo Entertainment System programming languages

This is useful since if you know the memory address holding important values (gold, number of lives) in the NES game, you can easily modify it to be able to enjoy unlimited gold or lives.

Useful Functions to Access VRAM

We can use the following two functions to access VRAM, set the text to print and colour.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
typedef unsigned char uint8;
typedef unsigned int uint16;
#define ADDR(add) (*((uint8 *)add))
 
void put_char(uint8 x, uint8 y, uint8 c) 
{
    uint16 adr = 0x2000;
    adr = adr + 0x20 * y + x;
    ADDR(0x2006) = adr >> 8;  // high byte
    ADDR(0x2006) = (uint8)adr;   // low byte
    ADDR(0x2007) = c; 
} 
 
void set_color(uint8 n, uint8 m, uint8 color)
{
    ADDR(0x2006) = 0x3f;  
    ADDR(0x2006) = 0x00 + n * 4 + m;   
    ADDR(0x2007) = color;   
}
typedef unsigned char uint8;
typedef unsigned int uint16;
#define ADDR(add) (*((uint8 *)add))

void put_char(uint8 x, uint8 y, uint8 c) 
{
	uint16 adr = 0x2000;
	adr = adr + 0x20 * y + x;
	ADDR(0x2006) = adr >> 8;  // high byte
	ADDR(0x2006) = (uint8)adr;   // low byte
	ADDR(0x2007) = c; 
} 

void set_color(uint8 n, uint8 m, uint8 color)
{
	ADDR(0x2006) = 0x3f;  
	ADDR(0x2006) = 0x00 + n * 4 + m;   
	ADDR(0x2007) = color;   
}

–EOF (The Ultimate Computing & Technology Blog) —

GD Star Rating
loading...
924 words
Last Post: Tutorial 4 - C Programming in 6502 - Useful Macros
Next Post: Coding Exercise - C++ - Single Number II - Online Judge

The Permanent URL is: Tutorial 5 – C Programming in 6502 – Video RAM

Leave a Reply