C NES programming: tutorials, guides, anything's welcome

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

Petruza wrote:I'm writing a small library for cc65 to ease the NES dev, who knows, maybe you can write a game in c with decent fps.
It really depends on the type of the game. If you mean a platformer with fast scrolling and many active entities, you probably can't do it in C. A simpler game with a static camera and a controlled number of entities can probably be done in C if a proper library in ASM is available.
Petruza wrote:where can I get Tetramino?
About Tetramino, check tepples' profile for a link to his page.
User avatar
Petruza
Posts: 311
Joined: Mon Dec 22, 2008 10:45 pm
Location: Argentina

Post by Petruza »

Hi, I wrote this test program, which will be a metronome.

It makes a beep every 3rd of a second.
I'm relying on vertical retrace being 60hz because it's NTSC, as I don't know any other way to measure time in the NES. ( do you? )
It works fine in emulators, but it hangs my PMP after some beeps.
Am I doing something wrong or is just my PMP that is buggy?
It runs most of commercial games very well, although others crash.

PS: I figuerd out how to make sounds somewhat randomly, but it works.

Code: Select all

#include <nes.h>
#define addr(_addr)		(*(unsigned char*) (_addr))
void main()
{
	unsigned char a = 0;
	addr(0x4015) = 1; // init sound
	addr(0x4001) = 0;
	while(1)
	{
		waitvblank();
		++a;
		if( a == 20 )
		{
			a = 0;
			addr(0x4003) = 2; // make a beep
		}
	}
}
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

I think you should initialize registers $4000 and $4002. $4002 holds the 8 least significant bits of the pitch value, and $4000 determines whether or not it sweeps up, the volume, etc. I don't actually know much about hardware volume decay, because I do volume decay manually to have more control over it. I would just advise against assuming $4000 or $4002 have any value, so just initialize them.

Also, it looks like your code is waiting for Vblank in an infinite loop. It would be best to put the code that's executed once every frame in the NMI routine, which is fired up every Vblank.
User avatar
Memblers
Site Admin
Posts: 3901
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers »

We'd have to see the ROM or assembly. But if your PMP crashes with some games, that doesn't sound very promising.
User avatar
Petruza
Posts: 311
Joined: Mon Dec 22, 2008 10:45 pm
Location: Argentina

Post by Petruza »

Celius: I don't know how to use the NMI routine, can it be accessed in c?
Or is it like a callback or something only feasible in asm?

Memblers: It's strange, but I added a clrscr() and cprintf() calls, and now it doesn't crash. :shock:
User avatar
kyuusaku
Posts: 1665
Joined: Mon Sep 27, 2004 2:13 pm

Post by kyuusaku »

NMI should be a function in the NES library.
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

The NMI is an interrupt fired every Vblank, and the starting address of the NMI is located at $FFFA (I think) in the fixed bank. If you're doing just an NROM 16 or 32k PRG game, the address for the NMI will be located just at $FFFA. So if bit 7 of $2000 is set, the NMI will be fired every Vblank. Otherwise if bit 7 of $2000 is 0 then it won't fire.

I don't know how you set that up in C though. Just set it up so $FFFA/$FFFB of the fixed bank holds the address of the start of the NMI routine. Then make sure you end the NMI routine with RTI. Though I don't know how you say "RTI" in C, unless you can just type "RTI".

I think you should be able to access it in C. I don't see why you wouldn't be able to. If you can't, then you're missing one of the most (if not the most) essential things in programming the NES.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Celius wrote:Then make sure you end the NMI routine with RTI. Though I don't know how you say "RTI" in C, unless you can just type "RTI".
In some dialects of C, you can add a keyword before the definition of a function to get it to generate different calling conventions. For example, a compiler might generate RTI instead of RTS at the end of a function declared this way:

Code: Select all

__interrupt__ void isr() {
  /* blah */
}
I don't know whether CC65 implements anything like this, but it does have inline assembly as one of its extensions.

Still, I'd recommend writing your ISRs in assembly language. NMI in particular only has to increment a variable and then return.
Post Reply