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
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:
My hypothetical asm code 'mga' would store the value of the Accumulator at the address of the X register.