Tutorial 2 – C Programming in 6502


In the last tutorial, I have shown you how to create a ‘Hello World’ program for 6502 CPU (it works perfectly in NES emulator).  Now, in this tutorial, I will show you some basic functions that we can use to play around with the NES console.

1. ASCII Table

The ASCII table is slightly different from what we have today. The code from 0 to 127 is the same in 6502, but from 128 to 255, it is the opposite in terms of background and foreground colour. For example, the following C code in 6502 will put all the ASCII characters one by one.

1
2
3
4
5
6
7
8
9
10
11
#include "conio.h"
 
void main()
{
    unsigned int i;
    for (i = 1; i < 256; i ++) {
        cprintf("%c", (char)i);
    }
 
    for(;;); // loop forever, never ends
}
#include "conio.h"

void main()
{
	unsigned int i;
	for (i = 1; i < 256; i ++) {
		cprintf("%c", (char)i);
	}

	for(;;); // loop forever, never ends
}

6502-ascii Tutorial 2 - C Programming in 6502 6502 8 bit c / c++ code compiler implementation interpreter / compiler Nintendo Entertainment System programming languages windows

2. Header Files and Functions

After you install C compiler for 6502, you will find lots of header files (*.h) in the Program include folder, however, not all of them are for 6502 NES platform. That is why you have -t switch in the command line to specify the targeted platform.

The <nes.h> provides some constant color/key values and most importantly, it provides the function waitvblank() that will wait for screen to complete a refresh (we can use this to make delay function).

1
2
void __fastcall__ waitvblank (void);
/* Wait for the vertical blanking */
void __fastcall__ waitvblank (void);
/* Wait for the vertical blanking */

The <conio.h> provides functions related to screen and text printing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
void clrscr (void);
/* Clear the whole screen and put the cursor into the top left corner */
 
unsigned char kbhit (void);
/* Return true if there's a key waiting, return false if not */
 
void __fastcall__ gotox (unsigned char x);
/* Set the cursor to the specified X position, leave the Y position untouched */
 
void __fastcall__ gotoy (unsigned char y);
/* Set the cursor to the specified Y position, leave the X position untouched */
 
void __fastcall__ gotoxy (unsigned char x, unsigned char y);
/* Set the cursor to the specified position */
 
unsigned char wherex (void);
/* Return the X position of the cursor */
 
unsigned char wherey (void);
/* Return the Y position of the cursor */
 
void __fastcall__ cputc (char c);
/* Output one character at the current cursor position */
 
void __fastcall__ cputcxy (unsigned char x, unsigned char y, char c);
/* Same as "gotoxy (x, y); cputc (c);" */
 
void __fastcall__ cputs (const char* s);
/* Output a NUL-terminated string at the current cursor position */
 
void __fastcall__ cputsxy (unsigned char x, unsigned char y, const char* s);
/* Same as "gotoxy (x, y); puts (s);" */
 
int cprintf (const char* format, ...);
/* Like printf(), but uses direct screen output */
 
int __fastcall__ vcprintf (const char* format, va_list ap);
/* Like vprintf(), but uses direct screen output */
 
char cgetc (void);
/* Return a character from the keyboard. If there is no character available,
 * the function waits until the user does press a key. If cursor is set to
 * 1 (see below), a blinking cursor is displayed while waiting.
 */
 
int cscanf (const char* format, ...);
/* Like scanf(), but uses direct keyboard input */
 
#if defined(_textcolor)
#  define textcolor(x)          _textcolor(x)
#endif
#if defined(_bgcolor)
#  define bgcolor(x)            _bgcolor(x)
#endif
#if defined(_bordercolor)
#  define bordercolor(x)        _bordercolor(x)
#endif
void clrscr (void);
/* Clear the whole screen and put the cursor into the top left corner */

unsigned char kbhit (void);
/* Return true if there's a key waiting, return false if not */

void __fastcall__ gotox (unsigned char x);
/* Set the cursor to the specified X position, leave the Y position untouched */

void __fastcall__ gotoy (unsigned char y);
/* Set the cursor to the specified Y position, leave the X position untouched */

void __fastcall__ gotoxy (unsigned char x, unsigned char y);
/* Set the cursor to the specified position */

unsigned char wherex (void);
/* Return the X position of the cursor */

unsigned char wherey (void);
/* Return the Y position of the cursor */

void __fastcall__ cputc (char c);
/* Output one character at the current cursor position */

void __fastcall__ cputcxy (unsigned char x, unsigned char y, char c);
/* Same as "gotoxy (x, y); cputc (c);" */

void __fastcall__ cputs (const char* s);
/* Output a NUL-terminated string at the current cursor position */

void __fastcall__ cputsxy (unsigned char x, unsigned char y, const char* s);
/* Same as "gotoxy (x, y); puts (s);" */

int cprintf (const char* format, ...);
/* Like printf(), but uses direct screen output */

int __fastcall__ vcprintf (const char* format, va_list ap);
/* Like vprintf(), but uses direct screen output */

char cgetc (void);
/* Return a character from the keyboard. If there is no character available,
 * the function waits until the user does press a key. If cursor is set to
 * 1 (see below), a blinking cursor is displayed while waiting.
 */

int cscanf (const char* format, ...);
/* Like scanf(), but uses direct keyboard input */

#if defined(_textcolor)
#  define textcolor(x)          _textcolor(x)
#endif
#if defined(_bgcolor)
#  define bgcolor(x)            _bgcolor(x)
#endif
#if defined(_bordercolor)
#  define bordercolor(x)        _bordercolor(x)
#endif

3. Example

Now we are going to use some function from above header files to a simple demo.

The delay function can be accomplished by using waitvblank() 

1
2
3
4
5
6
7
8
#include "nes.h"
 
void delay(int i)
{
   while(i--){
      waitvblank();
   }
}
#include "nes.h"

void delay(int i)
{
   while(i--){
      waitvblank();
   }
}

And we are going to do a demo that prints a few lines of text, scroll the text in the up direction at a time interval.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include "conio.h"
#include "nes.h"
#include "stdio.h"
 
void delay(int i) 
{
    while(i--){
        waitvblank();  
    }
}
 
void main() { 
    unsigned char wx, wy;
    char oy, i, j, k;
    /* use const to save memory */
    const char s[][24] = {"http://HelloACM.com", "I love NES!\0", " Do you love NES?\0", "Yes!\0"}; 
    screensize(&wx, &wy); // get screen size (width and height)
    bgcolor(COLOR_BLUE);
    textcolor(COLOR_WHITE);
    clrscr(); // clean the screen
    i = wy - 4;
    oy = i;
    for (;;) {
        delay(50); // 50ms
        for (j = 0; j < 4; j ++) { // clean previous text
            gotoxy(0, oy + j);      
            for (k = 0; k < wx; k ++) {
                cputc(32); // print a whitespace
            }
        }
        if (--i < 1) {
            i = wy - 4;
        }
        for (j = 0; j < 4; j ++) {
            gotoxy(0, i + j);       
            cputs(s[j]);
        }
        oy = i;
    }
}
#include "conio.h"
#include "nes.h"
#include "stdio.h"

void delay(int i) 
{
	while(i--){
		waitvblank();  
	}
}

void main() { 
	unsigned char wx, wy;
	char oy, i, j, k;
	/* use const to save memory */
	const char s[][24] = {"http://HelloACM.com", "I love NES!\0", " Do you love NES?\0", "Yes!\0"}; 
	screensize(&wx, &wy); // get screen size (width and height)
	bgcolor(COLOR_BLUE);
	textcolor(COLOR_WHITE);
	clrscr(); // clean the screen
	i = wy - 4;
	oy = i;
	for (;;) {
		delay(50); // 50ms
		for (j = 0; j < 4; j ++) { // clean previous text
			gotoxy(0, oy + j); 		
			for (k = 0; k < wx; k ++) {
				cputc(32); // print a whitespace
			}
		}
		if (--i < 1) {
			i = wy - 4;
		}
		for (j = 0; j < 4; j ++) {
			gotoxy(0, i + j); 		
			cputs(s[j]);
		}
		oy = i;
	}
}

The macro bgcolor and textcolor are global settings, i.e. you cannot use this for particular piece of text. It will be changed for all text and the entire screen.

We print white space i.e. cputc(32) to clear previous text given previous text position. It should be noted that we should always try to minimal the variables because the memory is very limited resources in NES 6502.

The above source code compiled into a 6502 NES file, loaded into the NES emulator and we have a scrollable text.

6502-scroll-text Tutorial 2 - C Programming in 6502 6502 8 bit c / c++ code compiler implementation interpreter / compiler Nintendo Entertainment System programming languages windows

The sample NES file can be downloaded at locally.

–EOF (The Ultimate Computing & Technology Blog) —

GD Star Rating
loading...
937 words
Last Post: Tutorial 1 - C Programming for 6502 (8 bit) CPU
Next Post: Tutorial 3 - C Programming in 6502 - Using Assembly

The Permanent URL is: Tutorial 2 – C Programming in 6502

One Response

  1. sugar

Leave a Reply