Simple ROM works as expected on FCEUX but not on Mesen

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Simple ROM works as expected on FCEUX but not on Mesen
by on (#224874)
Howdy! :)

I'm trying to teach myself the basics of NES programming, and my first objective was to make a couple of sprites move around.
I got one sprite to display and wrap around the screen, but once I tried to have two sprites on screen Mesen (0.9.6) only displayed a black screen. FCEUX (2.2.3) however still worked as expected.

Looking at OAM on Mesen, it stayed static despite being written to, which doesn't seem quite right, unless I'm missing something.

Image

"Sprite 2 disabled.nes" has the writes to OAM relative to the second sprite commented out and works as expected on both emulators whereas "Sprites test.nes" is the ROM I'm trying to fix.

I'm probably missing something obvious, so, please, be patient with this noob :lol:
Re: Simple ROM works as expected on FCEUX but not on Mesen
by on (#224875)
First problem: You're using ANROM, and its power-up state is not guaranteed. Mesen picks a random bank on boot (unless he's changed that?), and your second bank is almost entirely 0.

Second problem: You basically cannot safely use $2003 and $2004 on the 2C02G that the majority of Famicoms and US NESes had; you more-or-less have to use ($2003 and) $4014.

There are very specific and narrow conditions under which you can use $2003 and $2004, but unless you know you're in a situation where that's true for you, it's best to not try.
Re: Simple ROM works as expected on FCEUX but not on Mesen
by on (#224876)
lidnariq wrote:
First problem: You're using ANROM, and its power-up state is not guaranteed. Mesen picks a random bank on boot (unless he's changed that?), and your second bank is almost entirely 0.

Oh, good to know!
I had wondered what the default behavior was but since these ROMs seemed to always work on the emulators I tested, I just assumed it defaulted to bank 0.
lidnariq wrote:
There are very specific and narrow conditions under which you can use $2003 and $2004, but unless you know you're in a situation where that's true for you, it's best to not try.

I see! Well, guess there's a reason why games generally use OAMDMA :P
Using $2004 didn't seem like the quick and dirty way of updating OAM without reason, then...

Thanks for the fast response! I think that probably answers the questions I had for now :D
Re: Simple ROM works as expected on FCEUX but not on Mesen
by on (#224882)
lidnariq wrote:
Mesen picks a random bank on boot (unless he's changed that?), and your second bank is almost entirely 0.
0.9.6 adds a "Randomize mapper power-on state" option in Emulation->Advanced which randomizes the startup state for most common mappers (this is disabled by default though, but if you're getting a black screen in 0.9.6, it's most likely enabled). For homebrew dev, keeping this option on is recommended, though.
Re: Simple ROM works as expected on FCEUX but not on Mesen
by on (#224884)
Sour wrote:
[...] but if you're getting a black screen in 0.9.6, it's most likely enabled)

That's the thing! I had that option disabled and it defaulted to bank 0 as expected.
Everything seemed to run fine on the CPU side, looking at the debugger, but all writes to OAM seem to be ignored, at least according to the memory viewer.
Re: Simple ROM works as expected on FCEUX but not on Mesen
by on (#224885)
Thecoolestnerdguy wrote:
but all writes to OAM seem to be ignored, at least according to the memory viewer.
Just to explicitly explain this:
On the 2C02G
if OAMADDR is 8 or greater when rendering starts
the eight bytes at (OAMADDR & 0xF8) are copied over the first 8 bytes.
So that's why it worked when you wrote one sprite, but not two.

The klever thing that works is if you only need 1¾ sprites (you can't update the second sprite's X coordinate, because you can safely write 7 values)
Re: Simple ROM works as expected on FCEUX but not on Mesen
by on (#224887)
lidnariq wrote:
So that's why it worked when you wrote one sprite, but not two.

Ah, so, Mesen's the one out of the two that correctly implements it, as you'd expect :P
Thanks for clarifying, it does make a lot more sense to me now :D
Re: Simple ROM works as expected on FCEUX but not on Mesen
by on (#224906)
Thecoolestnerdguy wrote:
I had wondered what the default behavior was but since these ROMs seemed to always work on the emulators I tested, I just assumed it defaulted to bank 0.

The trick is to never expect any "default behavior" with computer hardware. Any register and ram content can be any value at power on, and there's no way to reliably predict it.
The only reliable approach is to only depend on the static banks, and use that to initialize everything else to the states you want as the first thing in your reset vector.

Don't worry about banks on your first test project, though. Just make it NROM :)
Re: Simple ROM works as expected on FCEUX but not on Mesen
by on (#224940)
Sumez wrote:
Don't worry about banks on your first test project, though. Just make it NROM :)

Haha, you've got a point.
Since I plan on using ANROM for future projects tho, I wanted to try to figure out how it works too :)
Sumez wrote:
The only reliable approach is to only depend on the static banks, and use that to initialize everything else to the states you want as the first thing in your reset vector.

Question: since ANROM switches the entire 32KB window at once, I believe the routine that switches banks would have to run from RAM, is that right?
Re: Simple ROM works as expected on FCEUX but not on Mesen
by on (#224942)
Mappers with 32KiB banking can be assembled in a way with a logical fixed bank, by having the exact same data in the same place in every bank.

For example, as part of Memblers's GTROM kit, he has a tool to convert an UNROM game into something compatible with GTROM by dividing it up into 16 KiB banks (01234567) and then recombining them (0717273747576777)
Re: Simple ROM works as expected on FCEUX but not on Mesen
by on (#224943)
It'd have to either run from RAM or be at the same place in all banks.
Re: Simple ROM works as expected on FCEUX but not on Mesen
by on (#224948)
Even if the bankswitch code is in RAM, you need to have a "virtual" fixed bank (i.e. same code in the same place in all banks) for initialization. I personally prefer to have the bankswitch code in this "virtual" fixed bank too.
Re: Simple ROM works as expected on FCEUX but not on Mesen
by on (#224950)
tokumaru wrote:
Even if the bankswitch code is in RAM, you need to have a "virtual" fixed bank (i.e. same code in the same place in all banks) for initialization. I personally prefer to have the bankswitch code in this "virtual" fixed bank too.

I agree this is a good way to do it, and it's what I'd normally do, myself. (I will share some example code sometime soon that demonstrates this. ;))

Though if you wanna get nuts, technically you don't actually need initialization in the same place in all banks. You can have a different RESET vector in each bank if you need it. Even the bankswitch code doesn't have to be at the same place in all banks, whenever you do that store instruction to store the bank, the next instruction will be fetched from the new bank, whatever happens to be at that particular location. Putting the same routine in all banks makes this easy, but you can put the code you intend to run in the new bank right there where it switches. ;) This would probably be bad organization for most situations though.