Implementing saving with MMC1

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

JonnyManjiro
Posts: 16
Joined: Thu Jan 27, 2022 3:22 am

Implementing saving with MMC1

Post by JonnyManjiro »

I was wondering if there are any tutorials about how to set up a saving system.

Currently, I'm using NESASM3, and my program uses the MMC1 mapper.

I've been setting all my variables in the $6000 to $7FFF range (WRAM), counting up from $6000.

I've also set .inesmir to 2 in the header.

My questions:

1. Am I only suppose to place variables in the 8kb range above, and have other variables (that I want zeroed out upon loading the game) be in the first 2kb starting from $0000, or is okay to have my current configuration?

2. With my current set up, loading the game in an emulator does generate a .sav file, but it doesn't seem to have any noticeable impact when I reload the ROM - is there something else I need to do to specify that I want certain variables saved/loaded?

Any help is much appreciated :)
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Implementing saving with MMC1

Post by tokumaru »

Simply placing your data in the battery-backed RAM is not enough - you have to initialize that memory with meaningful data before you can use it, but you only want to do that when there's no data saved yet (or after it has been erased), otherwise the save would revert to the initial state every time the game started.

In order to detect whether there's data saved, you need to come up with a way to validate the data. Back in the day, the most common method was to use a checksum, which is calculated by adding all the saved bytes together and keeping only the lower 8 or 16 bits. If the calculated checksum matches the saved checksum, the data is valid and you don't need to initialize it. If it doesn't match, there's no saved data or it got corrupted somehow.

A simpler method is to store a signature somewhere in the save memory, and the signature alone will tell you whether the save memory has already been initialized or not. This is not as safe as using a checksum though, because the data can get corrupted (e.g. from hardware quirks or a weak battery) without the program noticing it, and the game won't play right. A checksum or another form of hashing will usually catch unwanted modifications to the data.

Another thing to consider when using checksums (or other forms of hashing) is that you can't turn off or reset the console at any moment without saving an updated checksum, since that would cause the next check to fail. Because of this (and other reasons too), it might actually be a good idea to not have the save data be the "live" version of the game's state, but actually a copy of the game state, done at specific times, such as when a level is completed or when the player explicitly chooses to save. This way you can always keep the save data and its checksum in sync, since they're both updated at the same time, and even have multiple save slots if you want to.

EDIT: As for how to split your variables between the built-in RAM and the save RAM, you're free to do it however you want. You can put things completely unrelated to saving in save RAM, such as level maps, which are fairly big. Everything you have there will of course be saved along with the actual save data, but you can just ignore everything that's not supposed to persist and treat it like "empty" memory.
JonnyManjiro
Posts: 16
Joined: Thu Jan 27, 2022 3:22 am

Re: Implementing saving with MMC1

Post by JonnyManjiro »

Thank you a lot for your detailed reply!

I understand the logic a lot better now, and have gotten some saving to work in practice now :beer:
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Implementing saving with MMC1

Post by sdm »

Note that NESASM3 has no way to set the SRAM battery in NES-Header - you have to do this manually after compiling the code (edit byte 06 NES Header). Without this information, the emulator will treat the rom as such without S-RAM (restarting the rom will not read the. SAV / .SRM file for you)
JonnyManjiro
Posts: 16
Joined: Thu Jan 27, 2022 3:22 am

Re: Implementing saving with MMC1

Post by JonnyManjiro »

sdm wrote: Fri Feb 18, 2022 3:38 am Note that NESASM3 has no way to set the SRAM battery in NES-Header - you have to do this manually after compiling the code (edit byte 06 NES Header). Without this information, the emulator will treat the rom as such without S-RAM (restarting the rom will not read the. SAV / .SRM file for you)
I'll keep this information in mind, but I've been compiling with NESASM3, and I've been able to load the .sav file without issue (the variables I intended to load were loaded fine), and I've never done any post-compiling edits to the header or anything else. Maybe the issue is with specific emulators? I generally use Mesen, and FCEUX SP also worked fine. I'll try some other emu cores on RetroArch and my Everdrive and see if they work on those too.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Implementing saving with MMC1

Post by tokumaru »

The bit that indicates the presence of battery-backed RAM is right next to the mirroring bit in the iNES header, so I guess it's possible that you can (unintuitively enough) control it with .inesmir too. I never tried it myself.

What NESASM lacks, AFAIK, is support for the NES 2.0 format, which allows you to describe the extra RAM in more detail (its size, how much of it is battery-backed, etc.) but games using the standard 8KB don't usually need any of that.
JonnyManjiro
Posts: 16
Joined: Thu Jan 27, 2022 3:22 am

Re: Implementing saving with MMC1

Post by JonnyManjiro »

I see. It's certainly seems like something I should keep on my radar if anything goes wrong in the future though.

For what it's worth, my header looks like this:

.inesprg $10
.ineschr $10
.inesmap $01
.inesmir %10
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Implementing saving with MMC1

Post by sdm »

Good to know if it works.

For me, the biggest, annoying problem of NESASM3 is the inability to include binary .incbin data of a certain size (manually set the start and end of the value of the attached .bin) - asm6 it has or wla-dx. Another problem is the number of banks - it is limited to 128 (128x8 = 1024KB) which can be a problem if someone wants to make a large rom, e.g. the maximum size of MMC5 etc.
JonnyManjiro
Posts: 16
Joined: Thu Jan 27, 2022 3:22 am

Re: Implementing saving with MMC1

Post by JonnyManjiro »

From what I've read on forums and such, there seems to be a lot of people that don't like NESASM3. The only reason I use it is because I got started by using the Nerdy Nights tutorials, so now my project boiler plates are all in NESASM3, making it hard to convince myself to switch over to an alternative, especially when I haven't yet run into anything I wasn't able to accomplish with NESASM3.

I didn't realize the bank limit of NESASM3, but I'm currently not using nearly that many banks. I might try to set up a future project using MMC5 though, 1024 kb sounds like infinity to me 😅
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Implementing saving with MMC1

Post by tokumaru »

JonnyManjiro wrote: Sat Feb 19, 2022 6:17 pmThe only reason I use it is because I got started by using the Nerdy Nights tutorials
That's probably the only reason why NESASM is one of the popular assemblers... One day, someone decided to write the most comprehensive beginner's tutorial for it.
I haven't yet run into anything I wasn't able to accomplish with NESASM3.
And you probably never will. The assembler doesn't really impose any limits on what your programs can do... If you're a good programmer, you can code Super Mario Bros. 4 in NESASM without a problem. However, the assembler you use can affect how smooth the development journey is. If you don't know what the alternatives can offer you, whatever drawbacks NESASM has will appear "normal" to you.
I didn't realize the bank limit of NESASM3
I wasn't aware of that either. It seems that every once in a while we learn a new NESASM "fun fact". This is strange though, considering its origins as a PC Engine assembler.
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Implementing saving with MMC1

Post by sdm »

tokumaru wrote: Sat Feb 19, 2022 6:52 pm I wasn't aware of that either. It seems that every once in a while we learn a new NESASM "fun fact". This is strange though, considering its origins as a PC Engine assembler.
PCEAS (PCEASM) also has a limit of 128 banks of 8KB, it is impossible to make a rom over 1MB. :)
The size of the 8KB banks also comes from PCEAS. This is a disadvantage, but sometimes an advantage, for example, when we use a mapper, for example MMC3, and the size of the banks' window is 8KB, then it is convenient with this size.
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Implementing saving with MMC1

Post by Pokun »

Nothing wrong with Nesasm really, though I personally use Asm6.

NESASM3 is a horribly outdated version of it however, with those weird bugs where it silently dies if your code bleeds over the 8 kB bank border for example.
I would try using Nesasm from the latest still maintained fork of HuC instead as it has tons of fixes and improvements. It technically uses 8 kB banks but allows code to bleed over. Elmer said that he is willing to fix the Nes side of the assembler if anyone finds something not working correctly.
Dig out the "pceas.exe" file from the BIN directory in HuC and rename it to "nesasm.exe" to enable the Nesasm mode.
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Implementing saving with MMC1

Post by sdm »

I checked the latest version of NESASM (v3.23-c266d57 Beta) and I have a error that was not showing up in the earlier v3.11 version I was using.

Code: Select all

NES Assembler (v 3.23-c266d57 Beta, 2018-07-07)

pass 1
pass 2
#[2]   famitone\music.asm
    6  0E:C559                  .dw .samples-4
       Undefined symbol in operand field!
# 1 error(s)
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Implementing saving with MMC1

Post by Pokun »

Maybe the dash is no longer allowed in label names.
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Implementing saving with MMC1

Post by sdm »

I have reported this issue and there is already an update for NESASM - v 3.25-978acaa Beta, 2/22/2022.
https://pcengine.proboards.com/thread/2 ... urce-links
www.dropbox.com/s/4wu35utcrmz6pcx/huc-2 ... 4.zip?dl=1
Post Reply