Handling Writing to ROM or out of range addresses

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Handling Writing to ROM or out of range addresses
by on (#222022)
I'm not sure if it is a bug with some logic with my emulator or if games actually edit ROM or access out of range address, expecting some behavior which is not implemented.

When running Super Mario Bros, I see that the code tries to edit the pattern tables. When running Ice Climber, I see it trying to access a VRAM address greater than 0x4000. Both occur when writing to 0x2007 and both cause my emulator to crash.
This is how I handle a write to 0x2007:
Code:
mem.setVRAM8(this->currentVramAddr++, this->DATA);
this->currentVramAddr += ((this->CTRL >> 2) & 0x1) * 31; // Ads extra 31 if bit 2 is set

Is this supposed to happen in those games or is something wrong with my implementation? My CPU passes all the tests from nestest and instr_test-v5. My PPU passes all of blargg's tests (blargg_ppu_tests_2005.09.15b) except for vbl_clear_time if I allow the code to edit CHR.

Another interesting thing to note is that everything works perfectly fine in Release mode in Visual Studio. Both Super Mario Bros and Ice Climber seem to work mostly fine, except for some sprites being all black, but I'm pretty sure that it is unrelated to this issue.
Re: Handling Writing to ROM or out of range addresses
by on (#222023)
I believe the PPU uses 14 bit addresses, so going past $4000 wraps around to $0000.

Writing to cartridge memory depends on the mapper. With NROM it's a nop.

BTW an emulator should never crash from bad user programs. One needs to handle every address.
Re: Handling Writing to ROM or out of range addresses
by on (#222032)
Quote:
BTW an emulator should never crash from bad user programs. One needs to handle every address.

Yeah, you're right. I made it overflow after reaching 0x4000 and made writing to ROM a nop.

I also figured out why it was working in Release, but not Debug. It was because I didn't initialize the PPU registers, and they got set to values that caused an NMI on the first cycle, stopping the CPU from running initialization code and messing everything up. I simply initialized them to 0 and made the changes you suggested and it worked! Thanks for the help!

However, on the scrolling page on the wiki, it says that the VRAM address is 15 bits long. Is that talking about a different address?
Re: Handling Writing to ROM or out of range addresses
by on (#222041)
Bits 14-12 of the VRAM address have a different meaning between rendering on the one hand and video memory access through $2007 on the other. During rendering, bits 14-12 represent fine Y scroll, which is reflected as PA2-0 of pattern table fetches. During video memory access through $2007, bit 14 is ignored, and bits 13-12 represent actual PA13-12.
Re: Handling Writing to ROM or out of range addresses
by on (#222048)
ace314159 wrote:
I also figured out why it was working in Release, but not Debug. It was because I didn't initialize the PPU registers, and they got set to values that caused an NMI on the first cycle, stopping the CPU from running initialization code and messing everything up. I simply initialized them to 0 and made the changes you suggested and it worked! Thanks for the help!

Read closely (not all are zero), and also understand the difference between power-on (power cycle) and reset:
https://wiki.nesdev.com/w/index.php/PPU_power_up_state

Similar applies to CPU:
https://wiki.nesdev.com/w/index.php/CPU_power_up_state
Re: Handling Writing to ROM or out of range addresses
by on (#222052)
I've added a small note to the Wiki. Would this have helped understanding?
https://wiki.nesdev.com/w/index.php?title=PPU_scrolling&diff=prev&oldid=15253
Re: Handling Writing to ROM or out of range addresses
by on (#222122)
tepples wrote:
Bits 14-12 of the VRAM address have a different meaning between rendering on the one hand and video memory access through $2007 on the other. During rendering, bits 14-12 represent fine Y scroll, which is reflected as PA2-0 of pattern table fetches. During video memory access through $2007, bit 14 is ignored, and bits 13-12 represent actual PA13-12.

Thank you! This clears everything up!

koitsu wrote:
Read closely (not all are zero), and also understand the difference between power-on (power cycle) and reset:
https://wiki.nesdev.com/w/index.php/PPU_power_up_state

Similar applies to CPU:
https://wiki.nesdev.com/w/index.php/CPU_power_up_state


So if I'm understanding this right, on a power cycle, I set everything but 0x2002 to 0 and set 0x2002 to 0xA0. What I don't understand is the diference between a power cycle and reset. I couldn't find an explanation on the page or through a Google search. Is a reset just a way to change the ROM without resetting all of the registers, and on a physical device without turning it on and off?

rainwarrior wrote:
I've added a small note to the Wiki. Would this have helped understanding?
https://wiki.nesdev.com/w/index.php?tit ... ldid=15253

This would have definitely helped!
Re: Handling Writing to ROM or out of range addresses
by on (#222123)
ace314159 wrote:
What I don't understand is the diference between a power cycle and reset. I couldn't find an explanation on the page or through a Google search. Is a reset just a way to change the ROM without resetting all of the registers, and on a physical device without turning it on and off?

The NES and famicom have two separate buttons: POWER and RESET.

The power switch removes power from the system and turns it off. The reset button doesn't turn anything off, it just restarts the software from the beginning.

A lot of stuff that was happening, most contents of RAM, etc. is preserved across a reset that is not preserved when you power off. Some games will behave differently for a reset than for powering off and on, though I think most games will be the same either way.
Re: Handling Writing to ROM or out of range addresses
by on (#222124)
So you can't change the game or cartridge when you hit RESET? It's just to restart the current game?
Re: Handling Writing to ROM or out of range addresses
by on (#222126)
You can yank a cartridge out of your NES while it's on, if you want, but that's not really something I've ever seen emulated. You can also do that while holding reset, I suppose?

If you pull a cartridge out of the machine while it's powered on, the system will more or less just crash. You can stick a new game in without powering it off, but to get it to run you will need to press reset (or power off and on).

There's some obscure possibilities involved with this, but emulators can usually do the same thing in a more convenient way with game genie codes or other methods.
Re: Handling Writing to ROM or out of range addresses
by on (#222132)
That's definitely out of the scope of my emulator, but I understand what a power cycle and reset does now. Thanks for the help!
Re: Handling Writing to ROM or out of range addresses
by on (#222133)
ace314159 wrote:
So if I'm understanding this right, on a power cycle, I set everything but 0x2002 to 0 and set 0x2002 to 0xA0.

Don't miss the part about the PPU RAM contents, specifically the nametable regions. "Mostly" in this case can probably be interpreted as, for emulation purposes, "fill completely with".
Re: Handling Writing to ROM or out of range addresses
by on (#222136)
I'll make sure to remember that.

Looking at it again, I noticed that for OAM and CHR RAM it mentions a "pattern". What does this mean?
Re: Handling Writing to ROM or out of range addresses
by on (#222137)
ace314159 wrote:
Looking at it again, I noticed that for OAM and CHR RAM it mentions a "pattern". What does this mean?

Hmm, that seems misleading. We probably shouldn't suggest that there is some specific pattern these boot with.

They are unreliable. You can implement it as powering on all 0, all FF, all random, doesn't really matter.

There are usually some pattern tendencies to any particular RAM's power on, but it will vary a bit from time to time your turn it on.
Re: Handling Writing to ROM or out of range addresses
by on (#222142)
I've replaced most of the "pattern" stuff in the article with "unspecified values".
Re: Handling Writing to ROM or out of range addresses
by on (#222493)
rainwarrior wrote:
ace314159 wrote:
What I don't understand is the diference between a power cycle and reset. I couldn't find an explanation on the page or through a Google search. Is a reset just a way to change the ROM without resetting all of the registers, and on a physical device without turning it on and off?

The NES and famicom have two separate buttons: POWER and RESET.

The power switch removes power from the system and turns it off. The reset button doesn't turn anything off, it just restarts the software from the beginning.

There's a minor additional difference in Famicom vs NES in regard to reset behavior: On NES reset affects both CPU and PPU (CPU is reinitialized, starting the restarting the software; PPU is reinitialized), on Famicom reset only affects the CPU. So, on Famicom, for example, if PPU rendering was enabled before reset was pushed, it will stay enabled after reset is released. (However, most games will disable rendering as one of the very first things they do. This is the reason why most games start with something like LDA #0 / STA $2000 / STA $2001.) All in all, it doesn't matter much for emulation, unless you strive to emulate every configuration perfectly.