Tutorial 4 – C Programming in 6502 – Useful Macros


Although I have already written three short tutorials [1][2][3] on 6502 C Programming for NES, it is not yet the time to start something complex. C is a low-level programming language, which is handy to program hardware-related code (such as embedded). The 6502 NES is one of such embedded hardware where there are lots of places you need to directly access the hardware such as RAM, VROM or PROM (Picture/Graphics)

1. No such things as File Access

The NES file is self-contained: all code and data. There will be no file access. The data (resources, images, sound) should be included as part of the NES file. You can include your data as static const array. For instance,

1
2
3
4
5
const char data[] = {0x00, 0x01, 0x02, ..., ...};
 
void main() {
 
}
const char data[] = {0x00, 0x01, 0x02, ..., ...};

void main() {

}

2. Avoid Dynamic Allocation

As 6502 memory is limited (2K RAM), avoid the usage of malloc to create dynamic space. Instead, use static/const arrays (such as above).

1
2
3
4
5
6
7
8
9
10
void main()
{
    char *arr = malloc(3);
    if (arr != 0) {
        cputs("OK"); 
    } else {
        cputs("FAILED");
    }
    for(;;); // loop forever, never ends
}
void main()
{
	char *arr = malloc(3);
	if (arr != 0) {
		cputs("OK"); 
	} else {
		cputs("FAILED");
	}
	for(;;); // loop forever, never ends
}

The above will print FAILED in 6502 C, because malloc has no effect on NES targets.

3. Is 6502 NES programming dead ?

No, of course. We can still find many existence in the emulators of smart phones, portable devices (MP4) and so many more. Many of us are still playing 8-bit 6502 games because it reminds us of happy childhood.

Of course, 6502 C programming is a very good topic for teaching/educational purpose. Yes, 6502 CPU is slow and 8bit only, but it can be used to make wonderful games without problems (e.g. Super Mario 3)

4. Useful Macro to Address Memory

In 6502 NES, we need to directly access memory given a memory location, e.g. read or write to a memory address. In this case, we can define the following macro in C.

1
#define addr(_addr)     (*(unsigned char*) (_addr))
#define addr(_addr)		(*(unsigned char*) (_addr))

The above Macro is for direct memory access. use it both as r-value and l-value. Example: addr(0x0200) = 6; sets memory address $200 to value 6.

5. Bit Shifting

Bit shifting is used quite often. A byte consists of 8 bits.

1
2
3
4
5
6
7
8
9
10
11
12
// Trick to write binary. example: bin(0,0,0,0,1,0,0,1) = bin4(1,0,0,1) = 9
#define  bin(h,g,f,e,d,c,b,a)     (a|b<<1|c<<2|d<<3|e<<4|f<<5|g<<6|h<<7)
#define bin8(h,g,f,e,d,c,b,a)       (a|b<<1|c<<2|d<<3|e<<4|f<<5|g<<6|h<<7)
#define bin7(g,f,e,d,c,b,a)         (a|b<<1|c<<2|d<<3|e<<4|f<<5|g<<6)
#define bin6(f,e,d,c,b,a)               (a|b<<1|c<<2|d<<3|e<<4|f<<5)
#define bin5(e,d,c,b,a)                 (a|b<<1|c<<2|d<<3|e<<4)
#define bin4(d,c,b,a)                       (a|b<<1|c<<2|d<<3)
#define bin3(c,b,a)                         (a|b<<1|c<<2)
#define bin2(b,a)                               (a|b<<1)
 
#define highbyte( value )       ((byte)(value>>8))
#define lowbyte( value )        ((byte)value)
// Trick to write binary. example: bin(0,0,0,0,1,0,0,1) = bin4(1,0,0,1) = 9
#define  bin(h,g,f,e,d,c,b,a)	  (a|b<<1|c<<2|d<<3|e<<4|f<<5|g<<6|h<<7)
#define bin8(h,g,f,e,d,c,b,a)		(a|b<<1|c<<2|d<<3|e<<4|f<<5|g<<6|h<<7)
#define bin7(g,f,e,d,c,b,a)			(a|b<<1|c<<2|d<<3|e<<4|f<<5|g<<6)
#define bin6(f,e,d,c,b,a)				(a|b<<1|c<<2|d<<3|e<<4|f<<5)
#define bin5(e,d,c,b,a)					(a|b<<1|c<<2|d<<3|e<<4)
#define bin4(d,c,b,a)						(a|b<<1|c<<2|d<<3)
#define bin3(c,b,a)							(a|b<<1|c<<2)
#define bin2(b,a)								(a|b<<1)

#define highbyte( value )		((byte)(value>>8))
#define lowbyte( value )		((byte)value)

–EOF (The Ultimate Computing & Technology Blog) —

GD Star Rating
loading...
659 words
Last Post: Tutorial 3 - C Programming in 6502 - Using Assembly
Next Post: Tutorial 5 - C Programming in 6502 - Video RAM

The Permanent URL is: Tutorial 4 – C Programming in 6502 – Useful Macros

Leave a Reply