rNES - a NES library for cc65 - version 0.1 released

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

User avatar
Petruza
Posts: 311
Joined: Mon Dec 22, 2008 10:45 pm
Location: Argentina

rNES - a NES library for cc65 - version 0.1 released

Post by Petruza » Sun Feb 01, 2009 7:30 pm

Well, here's the quick and dirty first release of rNES, a library for NES apps and games development, written in C for cc65.

Hope some newbie can benefit from this

Contributions, criticism and ideas are welcome!

http://tachdaun.com.ar/rnes/rNES-0.1.zip

Image

Image
Last edited by Petruza on Sat Apr 04, 2009 4:37 pm, edited 1 time in total.

User avatar
Banshaku
Posts: 2393
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Post by Banshaku » Sun Feb 01, 2009 9:23 pm

It's good to see some effort done for the C version of CC65. It may help some developers that doesn't have any knowledge about assembler to be able to do some tinkering on the nes.

Good work!

User avatar
Bregalad
Posts: 7951
Joined: Fri Nov 12, 2004 2:49 pm
Location: Chexbres, VD, Switzerland

Post by Bregalad » Mon Feb 02, 2009 3:01 am

Looks promising. However you should learn some assembly. Also I'd have to go to GBA dev seeing how they do games in C, and maybe try to do similar libraries for the NES, so that they are suitable for game use.
Useless, lumbering half-wits don't scare us.

User avatar
Zepper
Formerly Fx3
Posts: 3218
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper » Mon Feb 02, 2009 5:22 am

- My emu displays wrong colors:
Image

- Any help?

User avatar
Petruza
Posts: 311
Joined: Mon Dec 22, 2008 10:45 pm
Location: Argentina

Post by Petruza » Mon Feb 02, 2009 5:51 am

Fx3 wrote:- My emu displays wrong colors:
Image
:(
Letters' colors are right. The earth seems to have a problem.
What emulator and version is it?

Fx3 wrote:Image
OH! now that I see your screenshot, your emulator shows the first and last rows of tiles...
And I can see now what I supposed, as I zero-out page 2 ( $0200 ) to write it to OAM, then all sprites use tile 0, which is one pixel, used for sprite 0 hit, and all are at 0,1.

I should make them all off-screen.

Thanks for the double feedback :D
Last edited by Petruza on Mon Feb 02, 2009 5:58 am, edited 1 time in total.

User avatar
Petruza
Posts: 311
Joined: Mon Dec 22, 2008 10:45 pm
Location: Argentina

Post by Petruza » Mon Feb 02, 2009 5:59 am

Banshaku wrote:It's good to see some effort done for the C version of CC65...Good work!
Thanks!
Bregalad wrote:Looks promising. However you should learn some assembly. Also I'd have to go to GBA dev seeing how they do games in C, and maybe try to do similar libraries for the NES, so that they are suitable for game use.
Thanks! Good advice, I'll give it a look

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

Post by tokumaru » Mon Feb 02, 2009 1:55 pm

Petruza wrote:What emulator and version is it?
He is the author of RockNES, so he probably meant the lastest version.
OH! now that I see your screenshot, your emulator shows the first and last rows of tiles...
You should configure your emulator like this when developing too. Not being able to see many scanlines can easily make you miss errors, like in this case.
I should make them all off-screen.
Yeah, that's the correct way to hide unused sprites. For better performance, you don't even have to clear the whole page, simply setting the Y coordinates to $F0 or more will hide them, you don't even have to touch the other bytes, so don't waste precious CPU time with that.

User avatar
Petruza
Posts: 311
Joined: Mon Dec 22, 2008 10:45 pm
Location: Argentina

Post by Petruza » Mon Feb 02, 2009 3:25 pm

tokumaru wrote:He is the author of RockNES, so he probably meant the lastest version.
Oh, that was he meant by "My" emu. =D
tokumaru wrote:Yeah, that's the correct way to hide unused sprites. For better performance, you don't even have to clear the whole page, simply setting the Y coordinates to $F0 or more will hide them, you don't even have to touch the other bytes, so don't waste precious CPU time with that.
Very true.
it's worth a void rNES_offscreen_sprites( byte page ); which puts every 4th byte to $F0 in the given page

User avatar
Zepper
Formerly Fx3
Posts: 3218
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper » Mon Feb 02, 2009 6:15 pm

- Probably a bug in my emulator (RockNES), I still need to trace the code. Well, it works on Nintendulator and Nestopia, but not on FCEUX.

EDIT: hmm, it's buggy from beta 8, works fine on beta <= 7... Interesting.

User avatar
Petruza
Posts: 311
Joined: Mon Dec 22, 2008 10:45 pm
Location: Argentina

Post by Petruza » Mon Feb 02, 2009 7:54 pm

Fx3 wrote:- Probably a bug in my emulator (RockNES), I still need to trace the code. Well, it works on Nintendulator and Nestopia, but not on FCEUX.
Yes, it's strange, my progs run perfectly on FCEUXD but not at all on FCEUX.
Fx3 wrote: EDIT: hmm, it's buggy from beta 8, works fine on beta <= 7... Interesting.
Well, it has to be something with the background pallete. And one pallete only, because the two other palletes are just like the other emus.

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg » Tue Feb 03, 2009 6:13 am

Some things that I noticed:

- rNES_get_joy: both controllers are strobed by $4016; $4017 controls the APU. Also, you could accept the joypad selector as an enumeration, for better type-safety. But it makes more sense to me to select it as an index, 0 or 1.

- rNES_waitvblank() should read rNES_PPU_status once before the loop, in case you're already in vblank. Without this clearing, if you were already in vblank right near the end, rNES_waitvblank() wouldn't delay and your code might run outside it unexpectedly. Also, there's no reason to make this a macro, as efficiency isn't an issue for a routine that waits for something in a loop.

- The macro addr should cast its result to a volatile unsigned char*, to ensure that none of the accesses are optimized out.

- times2: does cc65 really not optimize n*2 to n+n, n*4 to n<<2, etc.?

- In C, "void rNES_init();" declares a function that can accept any arguments. Better to make it "void rNES_init( void );"

- Why do many of the files have lots of newlines at the end?

- For your bin macro, you could use this instead, which is easier to use and does checking:

Code: Select all

/* Compile error if a has too many bits or any are not 0 or 1.
Always evaluates to 0. */
#define BIN8_VALID_(a)  (0 * sizeof (char [(01##a & 0111111111) == 01##a]))

#define BIN8_(n)        ((n       & 0x01) |\
                         (n >>  2 & 0x02) |\
                         (n >>  4 & 0x04) |\
                         (n >>  6 & 0x08) |\
                         (n >>  8 & 0x10) |\
                         (n >> 10 & 0x20) |\
                         (n >> 12 & 0x40) |\
                         (n >> 14 & 0x80))

#define BIN8(a)         (BIN8_( 0##a ) + BIN8_VALID_( a ))
Examples: BIN8(10000000) = 0x80. BIN8(100) = 7, BIN8(100000000) is error (too many bits), BIN8(200) is error (invalid bit).

User avatar
Petruza
Posts: 311
Joined: Mon Dec 22, 2008 10:45 pm
Location: Argentina

Post by Petruza » Tue Feb 03, 2009 8:18 am

blargg wrote:Some things that I noticed:
- rNES_get_joy: both controllers are strobed by $4016; $4017 controls the APU. Also, you could accept the joypad selector as an enumeration, for better type-safety. But it makes more sense to me to select it as an index, 0 or 1.
ooops, never actually tested 2nd controller
- rNES_waitvblank() should read rNES_PPU_status once before the loop, in case you're already in vblank. Without this clearing, if you were already in vblank right near the end, rNES_waitvblank() wouldn't delay and your code might run outside it unexpectedly. Also, there's no reason to make this a macro, as efficiency isn't an issue for a routine that waits for something in a loop.
Sorry, I don't get it. "near the end" of what?
- times2: does cc65 really not optimize n*2 to n+n, n*4 to n<<2, etc.?
Don't have any idea. I'll check.
- In C, "void rNES_init();" declares a function that can accept any arguments. Better to make it "void rNES_init( void );"
Never heard of that, do you mean the empty parenthesis mean the function can accept any number and type of arguments??
- Why do many of the files have lots of newlines at the end?
:D I have a problem with coding at the bottom of the screen, so I put them to make the last written line in the middle of the screen. Anf forgot to take them out.
- For your bin macro, you could use this instead, which is easier to use and does checking:

Code: Select all

/* Compile error if a has too many bits or any are not 0 or 1.
Always evaluates to 0. */
#define BIN8_VALID_(a)  (0 * sizeof (char [(01##a & 0111111111) == 01##a]))

#define BIN8_(n)        ((n       & 0x01) |\
                         (n >>  2 & 0x02) |\
                         (n >>  4 & 0x04) |\
                         (n >>  6 & 0x08) |\
                         (n >>  8 & 0x10) |\
                         (n >> 10 & 0x20) |\
                         (n >> 12 & 0x40) |\
                         (n >> 14 & 0x80))

#define BIN8(a)         (BIN8_( 0##a ) + BIN8_VALID_( a ))
Examples: BIN8(10000000) = 0x80. BIN8(100) = 7, BIN8(100000000) is error (too many bits), BIN8(200) is error (invalid bit).
Wow that was twisted.

Thanks for all the contributions, I'll stack'em in my to do bucket. :P

User avatar
Zepper
Formerly Fx3
Posts: 3218
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper » Tue Feb 03, 2009 9:41 am

- I still don't know what's broken here. From what blargg said, probably nothing :), but I can confirm it's not the palette (2007 r/w), since both dumps (of 3F00-1F) have identical data. It's quite difficult to "undo" changes.

- Since I have no other game/demo with this problem, I suspect it's not with RockNES after all...

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch » Tue Feb 03, 2009 9:47 am

blargg wrote: - In C, "void rNES_init();" declares a function that can accept any arguments. Better to make it "void rNES_init( void );"
Is this a C89 thing? I always thought empty parenthesis meant no aruments, and an elipsis was any number of arguments. But maybe that was just C++ (and C99?).

I suppose putting (void) couldn't hurt. Better safe than sorry.

User avatar
Petruza
Posts: 311
Joined: Mon Dec 22, 2008 10:45 pm
Location: Argentina

Post by Petruza » Tue Feb 03, 2009 11:42 am

Disch wrote:I always thought empty parenthesis meant no aruments, and an elipsis was any number of arguments.
Me too.

Post Reply