Page 1 of 2

NES C programming

Posted: Mon Oct 26, 2009 4:28 am
by Doogie
Alright, so I've done a bit of searching for this, and I've come to the conclusion that no libraries for the NES C compiler have been made.

Compiler can be found here: http://www.cc65.org/

So I'm going to take it upon myself to build my own libraries that will allow:
* Joypad Input
* Sprite Drawing
* Pallette Loading

and much more.

The only problem is, I am not fluent in NES asm and am just beginning, so I will be following the basic NES asm tutorials here: http://patater.com/gbaguy/nesasm.htm

Here is a little bit of test code you folks can try out at home, I've already made the keyboard input part.

Code: Select all

#include <conio.h>
#include <peekpoke.h>
#include <6502.h>

typedef struct joypad
{
	unsigned char a;
	unsigned char b;
	unsigned char select;
	unsigned char start;
	unsigned char up;
	unsigned char down;
	unsigned char left;
	unsigned char right;
} joypad;

void keyprocess(joypad* joy1)
{
	// Reset the Pad
	asm("lda #$01");
	asm("sta $4016");
	asm("lda #$00");
	asm("sta $4016");

	// Read Keys
	joy1->a = PEEK(16406) & 1;
	joy1->b = PEEK(16406) & 1;
	joy1->select = PEEK(16406) & 1;
	joy1->start = PEEK(16406) & 1;
	joy1->up = PEEK(16406) & 1;
	joy1->down = PEEK(16406) & 1;
	joy1->left = PEEK(16406) & 1;
	joy1->right = PEEK(16406) & 1;
}

joypad joy;

void main (void)
{
	clrscr();
	cprintf("hello world");
	while(1)
	{
		clrscr();
                gotoxy(0,0);
		keyprocess(&joy);
		if (joy.a)
		{
			cprintf("win");
		}
		else
		{
			cprintf("fail");
		}
	}
}
Oh and here is the batch file I use to compile (assuming the C file is named test.c):

Code: Select all

SET CC65_INC=\nesC\include
SET CC65_LIB=\nesC\lib
SET PATH=\nesC\bin

cc65.exe -t nes test.c
ca65.exe -t nes test.s
ld65.exe -t nes test.o nes.lib -o test.nes 
pause

Posted: Mon Oct 26, 2009 5:09 am
by Rid
Hi,

It's seems that gbaguy's tutorial is not really good. Some event think that it really sucks.

Anyway, there are other good tutorials, and so far I've been reading them, I can recommend you bunnyboy's one.

Posted: Mon Oct 26, 2009 7:48 am
by UncleSporky
Yeah, just wanted to echo what Rid said above. Bunnyboy's Nerdy Nights are very good for newbies! Check them out.

Posted: Wed Oct 28, 2009 4:36 am
by Doogie
Yeah thanks guys, I'll refer to bunny boys from now on.

Also I've successfully made palette loading and a little app which converts a file to raw c code.

Posted: Wed Oct 28, 2009 10:27 am
by GradualGames
Didn't petruza make a C library for NES development?

Posted: Thu Oct 29, 2009 1:04 am
by Doogie
Ahh, thanks, this will help me develop my library. (His uses pure C code, but mine will use ASM as much as possible to keep it more effecient and optimized)

EDIT: Don't forget about learning experiences :D

EDIT2: Oh guys, I've hit a bit of a roadblock. I was wondering if anyone could give me pointers on compiling a new NES.lib file, as the current one isn't flexible enough to allow NMI vector handling in C and etc.

Posted: Fri Oct 30, 2009 6:40 am
by Doogie
Oh guys, I've hit a bit of a roadblock. I was wondering if anyone could give me pointers on compiling a new NES.lib file, as the current one isn't flexible enough to allow NMI vector handling in C and etc.

Posted: Fri Oct 30, 2009 7:59 am
by Banshaku
I don't think many people in this forum uses CC65 in C for making libraries so maybe you will not be able to get your answer here. Most people uses CA65 directly, me included.

I'm sure there must be some help on their forum (CC65) for making libraries.

Posted: Fri Oct 30, 2009 12:47 pm
by Memblers
You may want to check out the CC65 mailing list, I haven't looked at it in a very long time but I recall it was very active, and Uz (who wrote/maintains CC65) is really helpful.

Posted: Sat Oct 31, 2009 7:12 am
by Doogie
Alright, I've managed to compile a more dynamic library (without cprint as well, since there is no point in having those functions)

I believe there is a problem with how I'm handling sprites, so I just wanted to check with you guys.

Code: Select all

;
; File generated by cc65 v 2.13.0
;
	.fopt		compiler,"cc65 v 2.13.0"
	.setcpu		"6502"
	.smart		on
	.autoimport	on
	.case		on
	.debuginfo	off
	.importzp	sp, sreg, regsave, regbank, tmp1, ptr1, ptr2
	.macpack	longbranch
	.export		_tile

.segment	"RODATA"

_tile:
	.byte	$03
	.byte	$0F
	.byte	$1F
	.byte	$1F
	.byte	$1C
        <... The rest of the bytes that make up the sprites/tiles... >
So thats how my file looks, and in the C code it uses lowbyte and highbyte of the address to copy it into the DMA. This is done during the NMI loop.

Posted: Sat Oct 31, 2009 9:05 am
by Memblers
I have to admit it scares me a little bit that every person who's worked on NES libraries for CC65 hasn't done any development with NES before, heheh. It's just that most people who write their first asm program ends up finding out about a lot of little quirks and optimal order of operations they didn't know about at first.

I'm little experienced with C, and tried once to fix Groepaz's NES libraries, and had no luck with it really. I suspect a lot of the forum users are the same, better with asm and not as knowledgeable with using C libraries. But don't let that discourage you, I think it'd be great to have a usable mixed C/asm dev environment.
So thats how my file looks, and in the C code it uses lowbyte and highbyte of the address to copy it into the DMA. This is done during the NMI loop.
By the DMA you mean the page in RAM that will be DMA'd? You definitely won't want to use the $2004 register, it's too slow. If you're copying it from ROM (RODATA segment), it won't be too useful to copy that every frame. You could copy it once during an initialization, then modify it in RAM to move the sprites.

Also when it gets to more advanced projects, many projects will call for working with animated objects that are made up of multiple sprites. Here's the routine I use, though I'm not sure how easy it is to decypher - http://www.parodius.com/~memblers/nes/animate.asm
It builds the sprites, and depending on the data tables, will handle their animation as well. I believe they are moved by just manually moving the first sprite of the animation. This provides no "OAM cycling" however, they are in fixed positions in RAM, so there's trouble if there are more than 8 sprites on a line.

Posted: Sun Nov 01, 2009 1:10 am
by Doogie

Code: Select all

// NES_LoadSprite_real(address of the tileset)
void NES_LoadSprite_real(unsigned short tileset)
{
	// Load Params
	++tileset; // fix address
	cTemp = lowbyte(tileset);
	cTemp2 = highbyte(tileset);
	// Set up DMA range
	asm("lda %v",cTemp); // lowbyte
	asm("sta $2003");
	asm("lda %v",cTemp2); // highbyte
	asm("sta $4014");

}
This is the current code for 'loading' the sprite. basically the text '%v' means it will use the value of the variable used afterwards. in the first case, cTemp (aka the lowbyte of the tilesets address)

Is this fine, as is?

Posted: Sun Nov 01, 2009 7:25 am
by tepples
No.

The DMA always starts at highbyte(tileset)<<8. If lowbyte(tileset) != 0, then this code will not do what you want.

Posted: Sun Nov 01, 2009 7:44 am
by Doogie
So basically if the address where the tile data is stored at, ends up not being 0 for the lowbyte, it won't load?

Posted: Tue Nov 03, 2009 3:54 am
by Doogie
Alright guys, I think I know for sure whats wrong with my code. How do I tell the NES (In asm) to store a value at an address that is held in a variable.

Psuedo Code example:

Code: Select all

lda #01
ldx #$0100
mga
My hypothetical asm code 'mga' would store the value of the Accumulator at the address of the X register.