Coding my game Cross Chase also for the NES in C (CC65)

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

Moderator: Moderators

Post Reply
Fabrizio Caruso
Posts: 5
Joined: Thu Nov 09, 2017 3:36 am

Coding my game Cross Chase also for the NES in C (CC65)

Post by Fabrizio Caruso »

I am trying to make a decent NES version of my "universal" 8-bit game Cross Chase (for all 8-bit systems).
Project page: https://github.com/Fabrizio-Caruso/CROSS-CHASE
Video of the current ugly NES version: https://www.youtube.com/watch?v=HK54rtE ... e=youtu.be

The current version is just using tiles and I am getting weird results if I don't disable the screen before modifing some color attributes. This is expected but I am not able to disable and re-enable the screen without losing the tile definitions.

I am using the current default nes.cfg linker file but I am linking my own file with the .byte defitions for the CHARS segment. If I disable and then enable the screen.
How come when I disable the screen, set some attributes and then enable it, all the tile data is lost?
"
PPU.control = 0;
PPU.mask = 0;
(set some color attributes here)
PPU.vram.address = 0;
PPU.vram.address = 0;
PPU.scroll = 0;
PPU.scroll = 0;
PPU.control = 0x90;
PPU.mask = 0x1e;
"

What am I doing wrong?

Fabrizio
User avatar
koitsu
Posts: 4203
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Coding my game Cross Chase also for the NES in C (CC65)

Post by koitsu »

Might have to do with what has been discussed a few times in recent days:

viewtopic.php?p=223803#p223803 (but see thread entirely)

Use of C makes this more difficult to debug. You'll need to actually look at the assembly to see what's going on. The instructions and their order matter greatly.

You may need to set the scroll ($2005) to zero twice as the **last** piece of code. Try that first.

However, because you're playing with $2000 (PPU.control), you may need to read from $2002 (PPU.status) to get things to work. See https://wiki.nesdev.com/w/index.php/PPU_scrolling -- warning: VERY COMPLICATED TOPIC/WIKI PAGE. You've been warned.

Basically, whenever tinkering with $2000 (PPU.control), $2005 (PPU.scroll), or $2006 (PPU.vram_address), you may need to "reset" some values of those registers before the end of NMI for things to draw correctly. Sometimes reading $2002 (not sure what this is called in the struct; PPU.status maybe?) is required as well. Experts here can probably explain it to you better.

Use of C makes this more difficult to debug. You'll need to actually look at the assembly to see what's going on.
User avatar
rainwarrior
Posts: 8062
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Coding my game Cross Chase also for the NES in C (CC65)

Post by rainwarrior »

"Losing the tile definitions" doesn't describe a familiar problem. Could you share a ROM exhibitng the problem? That would be a lot easier to diagnose.
User avatar
koitsu
Posts: 4203
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Coding my game Cross Chase also for the NES in C (CC65)

Post by koitsu »

I took the interpretation, given the code provided, to indicate that visually things on-screen get munged. There may be a slightly language barrier.
Fabrizio Caruso
Posts: 5
Joined: Thu Nov 09, 2017 3:36 am

Re: Coding my game Cross Chase also for the NES in C (CC65)

Post by Fabrizio Caruso »

Thanks for your support!
Sorry, I am a NES noob...
I am coding my game als for the NES but I am distracted by the other systems.
My game is insanely cross-platform...

In the end, Shiru found my issue: I was switching to the wrong page:
PPU.control = 0x80;
PPU.mask = 0x1e;
fixes the issue (0x90 was wrong in my case).

The problem was with PPU.control = 0x90, all the tile data appeared as restored to their default (CC65 default) values.

My next step is to use sprites instead of tiles for animation.
I need to understand how to do this through OAM DMA or by direct writes into PPU memory (is it safe?).
I also need to wait for a vertical blank.
How do I wait for a vblank in C?

The current (ugly) NES version is available at:
https://github.com/Fabrizio-Caruso/CROS ... nes_fx.nes

The source code of the NES screen initialization is at:
https://github.com/Fabrizio-Caruso/CROS ... graphics.c
User avatar
slembcke
Posts: 172
Joined: Fri Nov 24, 2017 2:40 pm
Location: Minnesota

Re: Coding my game Cross Chase also for the NES in C (CC65)

Post by slembcke »

Fabrizio Caruso wrote:I need to understand how to do this through OAM DMA or by direct writes into PPU memory (is it safe?).
I also need to wait for a vertical blank.
How do I wait for a vblank in C?
I seem to remember reading on the wiki that it's possible to write directly to OAM memory on the PPU, but not recommended since it turns of DRAM refreshing or something. The warning was that if leave rendering turned off for too long your OAM values will decay and become corrupted.

CC65 provides a waitvsync() function, but it's not recommended to use it for fine timing. The NES has a hardware bug where the vblank flag will fail to read if written on the same cycle (or something like that). I used it initially in my first project, and the framerate stuttered until I moved to a "proper" NMI. It looks like you've used cc65 enough to know that writing an interrupt handler in C is not very practical. Just too much C state to save and restore.
User avatar
dougeff
Posts: 2875
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: Coding my game Cross Chase also for the NES in C (CC65)

Post by dougeff »

Yes. The OAM is extremely volatile, and needs to be written to every frame, and should be done with OAM DMA, during v-blank. (set up a 256 byte buffer that is aligned to a xx00 address)

And v-blank should be set up with the NMI system that is generated at the start of v-blank (if the NMI bit is turned on with PPU control register 2000)

You could either write an automatic OAM DMA transfer to occur within the NMI code, or you could have a counter which the NMI increments, and have your main code wait for the counter to change, then do the OAM DMA manually.

Have you read Shiru's neslib code? That might be helpful.
nesdoug.com -- blog/tutorial on programming for the NES
Post Reply