O.k., so you're suggesting to mark the start of a bank switch and to skip the sound update in the rare cases when NMI actually entered while the bank switch was done.This might be a solution.

Although, personally, I guess I'll just put the sound update inside the if NmiCanBeProcessed condition instead of out of it. Then I don't need to save any kind of status at all and can be sure that MMC1 writes are never interrupted by other MMC1 writes.My game is supposed to be mostly lag-free anyway, so if it does lag for a short moment, then I don't care if the sound lags as well.

But how do you avoid the lagging of music? If I simply set a counter in every NMI for every intended music call, this only means that a game logic lag will skip a certain amount of sound, but it will still lag.

Even Pokémon lags during blank-screen transitions, with the music skipping ahead to catch up to the tempo once the transition ends. This is better than what earlier Game Boy games like Tetris did, which was just to let music fall behind.

DRW wrote:

For example, let's take an extreme example: Let's say my game logic lags for five seconds in a certain situation.

If you can profile what function or combination thereof is eating 9 million cycles, call audio_update_if_needed() every so often during this task. The idea is that you try to call it at least once every 20,000 cycles (less than a frame), so that even if you mis-estimate and there ends up a 60,000 cycle (2 frame) gap, the player is unlikely to notice.

DRW wrote:

Unless I clutter all my code with nothing but music calls, but then I have the problem that music is already updated

In this case, audio_update_if_needed() will check the variable, see that nothing needs to be done, and do nothing. In C, it'd look like this:

So, if no interrupt ever switches a bank or writes to any other MMC1 register, can I be sure that an NMI that triggers in the middle of the bank switch function doesn't corrupt the bank switch status?

Correct.

DRW wrote:

What means are there in the MMC1 mapper to protect the battery data? How can I disable battery support and only enable it during writes?

In theory, there are two ways to disable the WRAM. On MMC1B and later, writing to $E000 (PRG bank) with bit 4 true causes the MMC1 not to raise WRAM +CE2 when WRAM is accessed. And on the SNROM board only, the mapper's CHR A16 output is connected to WRAM /CE1, which means writing to $A000 (CHR bank) with bit 4 true causes the MMC1 to hold /CE1 high. But in practice, if the MMC1 is itself losing power, it may lose the power to drive these signals. I'd need someone with a scope to confirm this for sure.

I chose the following now, which is based on one of the suggestions from this thread:

Whenever the bank is switched, I set a flag.Since there's only one bank switch in interrupts, the sound update in NMI, I check the flag before doing the sound update.In the rare case where the NMI triggered in the middle of a bank switch, I skip the sound update and accept a sound lag of one frame (and don't try to catch up).But if the NMI triggers during the game logic, but outside a bank switch, the music is continued normally.

This allows me to keep the bank switches simple, without that the whole "if it was interrupted, start the function again" stuff.

Another thing:About the question "What happens when the NMI triggers while we're right in the middle of setting a sound effect?":

I don't know whether FamiTone can handle such a situation. But this question is moot anyway. Because we can also have the situation where two sound effects are played simultaneously in the same frame.

If the NMI triggers right between those two calls, we have an inconsistent sound status where one sound effect is already sent to the sound library and played, but another one from the same frame isn't.

That's why I will buffer all music and sound IDs in an array. And only in the end will I update all of them right after another.And for this case, I will set the same flag as the one that I use for bank switches, so that the sound update doesn't start until all sound effects have been set.

I need to know one more thing:

Can MMC1 register writes to one register confuse the status of another register?I.e., do I also have to set a "don't switch to the sound bank" flag when I switch the mirroring?

Does disabling the WRAM mean that the whole 8 KB of battery-backed RAM are instantly deleted?Because in this case, I'd rather not do this because it would delete all save states.

Or does it only mean that access to WRAM is impossible as long as it's disabled, so that powering off the console cannot produce any faulty writes to WRAM?In this case, this might be useful, to enable it only when we write to it (or read from it at the start of the game), and then disable it again to protect it from corruption.

Can MMC1 register writes to one register confuse the status of another register?I.e., do I also have to set a "don't switch to the sound bank" flag when I switch the mirroring?

Absolutely. There's only one shift register in the MMC1, and only the last write determine which MMC1 register is actually written to. See the wiki for more info about this.

Quote:

Now the question is: Should I do this?

It's all up to you.

Quote:

Does disabling the WRAM mean that the whole 8 KB of battery-backed RAM are instantly deleted?

Of course not, it just makes WRAM inaccessible/open bus, but the data is still there intact (and that no matter whether the WRAM is battery backed or not).

Quote:

Or does it only mean that access to WRAM is impossible as long as it's disabled, so that powering off the console cannot produce any faulty writes to WRAM?In this case, this might be useful, to enable it only when we write to it (or read from it at the start of the game), and then disable it again to protect it from corruption.

Exactly, I think that was the purpose of those disable bits in the 1st place. In practice, I suspect commercial games hardly ever used them, because most games with battery-backed WRAM also use the chip as extra general-purpose SRAM which is not related to saving games, and as such it's used all the time and isn't disabled. It should check some commercial games with FCEUX in order to see how they handle this.

tokumaru wrote:

Doesn't writing to $2000 mid-frame cause those glitchy scanlines that are common in SMB1? As far as I recall, the consensus was that we just shouldn't do it.

I don't think it's a major problem. I don't use MMC1 in my engine but also write to $2000 to disable NMI when initializing a sound effect pointer, so that the sound engine does never try to play a sound effect with a partially updated address (which can have almost catastrophic consequences).

Well, I happen to find that glitch pretty annoying. I always noticed it as a kid when playing SMB at other peoples' houses and always wondered what that was, until someone here in the forums discovered the reason. I would never intentionally put glitches in my games if there were other options.

Quote:

I don't use MMC1 in my engine but also write to $2000 to disable NMI when initializing a sound effect pointer, so that the sound engine does never try to play a sound effect with a partially updated address (which can have almost catastrophic consequences).

Like I said before, you could simply put sound effect requests in a queue instead, and only process those requests in the NMI, right before calling the playback code.

Exactly, I think that was the purpose of those disable bits in the 1st place. In practice, I suspect commercial games hardly ever used them, because most games with battery-backed WRAM also use the chip as extra general-purpose SRAM which is not related to saving games, and as such it's used all the time and isn't disabled.

I don't think I will need it as general RAM since the regular 2 KB are more than enough for me. (In fact, apart from larger arrays, I try to put all variables of my game into zeropage.)

So, if I disable and enable the WRAM access depending on the situation, is disabling it really an actual, "physical" protection from accidental random writes?

I.e. does disabling the WRAM mean that you don't have to do this whole "hold the Reset button when turning off the system" as long as you don't switch off the console in the middle of saving?

Provided that the program keeps RAM writing disabled, and provided that the mapper can guarantee that disabling will continue even as the mapper is powering down, the user shouldn't have to hold Reset. But it may take an oscilloscope to prove that the mapper can guarantee that disabling will continue even as the mapper is powering down, as I imagine that in some situations, loss of power can cause the mapper to inadvertently generate enable signals.

In the rare case where the NMI triggered in the middle of a bank switch, I skip the sound update and accept a sound lag of one frame (and don't try to catch up).But if the NMI triggers during the game logic, but outside a bank switch, the music is continued normally.

It may be a rare case overall, but the distribution of stuff like this tends to be clustered.

Successive frames often do very similar stuff. The timing could easily be close enough from frame to frame to trigger this "rare" case 100 frames in a row, or continually until you move, etc.

The failure tends to look more like "the music hangs in this one room if I'm wearing the blue armour", a lot less subtle than just hanging for 1 frame at a time on rare occasions.

Same deal with tepples "count lag and catch up" suggestion, 1 frame of doubled music update probably doesn't sound that unusual, but doing it continually will. (And if you're not careful to cap it, you can get a runaway increase in workload as the extra updates cause even more lag on the next frame, cascading out of control.)

Solutions like that can be useful, but don't think of "rare" cases as being surrounded by a safety net of common cases. They come in bunches!

I don't think I will need it as general RAM since the regular 2 KB are more than enough for me. (In fact, apart from larger arrays, I try to put all variables of my game into zeropage.)

In that case, using 80's economic logic, it makes almost no sense to use WRAM and battery, as it would make your game much more expensive than passwords. Heck, many mass-produced games which even used WRAM still used passwords instead of battery (Metroid, Kid Icarus) or nothing at all (SMB3) in order to be cheaper. Today it's entirely different, but I assume you're using 80's economic logic here, like I myself like to do (i.e. use only common mappers).

Quote:

I would never intentionally put glitches in my games if there were other options.

Well I never noticed glitches but if they ever become noticeable I'll probably change the approach and avoid writing to $2000 in dis-synchronization with the PPU. For me it has yet to cause any problems. Perhaps this is an NTSC-only and earlier revisions of PPU only thing, like the controller reading DMC glitch ?

Quote:

Same deal with tepples "count lag and catch up" suggestion, 1 frame of doubled music update probably doesn't sound that unusual, but doing it continually will. (And if you're not careful to cap it, you can get a runaway increase in workload as the extra updates cause even more lag on the next frame, cascading out of control.)

You don't have to catch up in the next NMI, you can catch up after the MMC1 switch is finished and it discovers it was interrupted by NMI.

Provided that the program keeps RAM writing disabled, and provided that the mapper can guarantee that disabling will continue even as the mapper is powering down, the user shouldn't have to hold Reset.

Does "The Legend of Zelda" or "Final Fantasy" use that enable/disable feature anywhere?

rainwarrior wrote:

It may be a rare case overall, but the distribution of stuff like this tends to be clustered.

Well, the first thing that has to happen: The game has to lag at all. And of course, I'll try to avoid this as much as possible.

And even then, the ifs and elses that have to be gone through will be different in every frame. (When I enable intensity bits in PPUMASK to measure the time my code needs to run, the colored layer over the screen always jumps up and down.)And bank switch and music update is a small piece of code in a huge ocean of code.

The last thing that is usually done in every frame is updating the sprites array ($0200) according to the meta sprites. In this case, we switch to the meta sprite bank once in the beginning. And then we iterate through all in-game characters to read their current meta sprite address.If the game lags, it will probably lag in the middle of sprite updates where there's no further bank switch.

So, I would say that consecutive NMI hits during the same bank switch are very, very unlikely.

Bregalad wrote:

In that case, using 80's economic logic, it makes almost no sense to use WRAM and battery, as it would make your game much more expensive than passwords.

Yeah, I know. That's why I intended my game to be UNROM.But my graphics artist absolutely hated the idea of passwords in a story-driven "Zelda"-like top down fantasy action adventure. So, to make her happy, I switched over to MMC1.

With the added bonus that I can now make her draw some huge character artworks for the game because with twice the memory, we will probably have enough room for this kind of excessive stuff.And we don't have to be so cheap on in-game dialogs.

Oh yes, and since I like to hold code in the fixed bank (so the additional memory is good for game data, but the room for actual code is still the same), I got back 550 bytes by removing the "update the graphics row by row during vertical scrolling" feature since I can switch the mirroring, so vertical scrolling works just as easy as horizontal scrolling.

Does "The Legend of Zelda" even need the WRAM excessively? I mean, the game itself with its screen-by-screen logic surely gets along fine with the regular RAM. And as far as savestates are concerned: You need to save all the collected items, all burnt trees, all bombed walls. And what else? That should be pretty much it. I assume each savestate should need less than 100 bytes. So, isn't WRAM and a battery also a total waste here, but they still used it?

Wouldn't battery backed CHR-RAM be an option here? You can put a battery in any CHR-RAM board to preserve the contents of the CHR-RAM chip, and "steal" a few tiles for the save data (8 tiles will give you 128 bytes). It's a little weird but really easy and cheap to implement.

I don't think so. Apparently only one unlicensed game did it (RacerMate Challenge II), but it's a thing, and it's supported by the NES 2.0 format. I figured you wouldn't be interested since this wasn't a common practice, but thought I'd mention it anyway.

Using CHR space for things other than tiles isn't so rare though. SMB and a bunch of CNROM games have data stored where tiles would normally be, so I guess developers weren't opposed to sacrificing a few tiles.

Programming tricks like that are alright for me if it ever becomes necessary. But if the hardware wasn't used commonly back then, I will not create my game in this way.

Even though my cartridges will be built from all-new parts, I only do games that could be easily reproduces with donor cartridges of widely available games.

UNROM with 128 KB is fine since there are countless games like that.

UNROM with 256 KB would be out of the question or at least I would do this only very, very reluctantly. How many copies of "Paperboy 2" or "Best of the Best - Championship Karate" exist out there? 20? 30?

UNROM 512 would be totally disqualified since it didn't exist until it was manuafactured for homebrews.

MMC1 with 256 KB is already acceptable because of "Final Fantasy" alone, a hugely successful game, but I assume there are more games with this mapper and this ROM size.

Who is online

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot post attachments in this forum