Skip to main content

Volatile

I spent about 2 hours last night pounding my head in a wall trying to figure out the solution to a new bug that I ran into: Anguna's save game function was no longer working.

In the GBA, the most common save method is to just write to a magical area of ram that happens to be battery-backed, so it retains its values. So when I save, I write the game state to that area, including a checksum.  On loading, I read the checksum to see if there's a valid game state in ram (as opposed to un-initialized garbage), and if it's valid, load it.

So last night, I was writing the data, but then when I read it back out, the checksums didn't match!

So I started debugging. I logged the first few bytes writing to save, and logged them again as I read them...everything looked right. So the first few bytes were working. I tried again with the last few bytes -- they matched also. Weird.

So I dumped ALL the data to a log upon saving and loading. And Lo And Behold, they matched, and it worked correctly.  Uh oh.

I removed the debugging, and it broke again.

This is normally an unhappy position to be, although this time it quickly led me to the solution. There were no actual side effects of my logging code (other than the logging itself), so clearly the compiler was optimizing something differently.

Then I checked to make sure that the save ram was marked as volatile. Nope. Oops.


In C, you can mark variables/memory/etc as volatile, which means that its value can be read or written outside of your current program. This lets the compiler know NOT to optimize away read/writes to it.

For example, in the gba, to get the state of the controller inputs, you read a particular memory location. If you don't mark it as volatile, the compiler will notice that you are reading it every frame, but never writing to it, and might optimize away your other reads. Which is not what you want.

In this case, I'm not sure exactly WHAT the compiler was thinking in optimizing away my reads/writes to the save data, but marking it as volatile did the trick. And I guess the compiler's optimization strategies have changed since I last worked on Anguna, as I never had it marked volatile before. Oh well.


Comments

sverx said…
volatile? There must be some mistake.
I never had to declare variables in SRAM as 'volatile', because in fact they aren't (unless you've got an Interrupt Service Routine changing them too!)
The real mess with SRAM and C, it's that this memory can be written ONLY using 8-bit writes and the C compiler will instead try to optimize the writes using 16-bit and 32-bit writes, which can FAIL (not write anything or even mix up data!)
Nathan Tolbert said…
Yeah, that makes sense. I dunno -- maybe it does have to do with the compiler trying to optimize it into 16 or 32-bit writes. (despite me casting the data to a 8-bit value and looping through writing it 8 bits as a time). I wonder if marking it volatile tricked the compiler into not over-optimizing that.
sverx said…
I also tried casting data to 8-bit and making a loop... but no dice.
So I finally choose to use a 'shadow-copy' in regular RAM and write two small custom ARM ASM routine to move data from and to SRAM.
Also, no$debug can detect if you're writing to SRAM using illegal opcodes.
Nathan Tolbert said…
Yeah, casting to 8-bit and making a loop used to work, back in 2008 :)

Ah well, I guess that probably explains it. (Alternatively, I probably could have gone the really cheesy way and left some of my debugging code in there!)

Popular posts from this blog

Retrospex 32 Review

RetrospexInternational recently sent me a couple units of their new handheld device, the Retrospex 32, a new dedicated GameboyAdvance emulator handheld.  To make the unit playable out of the box, they pre-loaded a handful of homebrew games, including Anguna, which is why they were kind enough to send me 2 of the units to play with.  I was pretty excited to get my hands on the device and try it (I loved my old GBA micro with a good flash cart!), and see Anguna running on it. So here's my thoughts after playing with it.



Their website lists the Retrospex 32 for £59.99, which is around $100 USD. It seems like it's marketed toward people into retro-gaming (which makes sense for a dedicated GBA emulator device). At that price, with that target market, and such a limited set of functionality (why not make it a multi-machine emulator, and emulate all the old consoles?), it would hopefully do a really good job of it.

The short version of my review: it doesn't. It has one job (emula…

Making the game fun

The real trick for Spacey McRacey (as I'm calling it now) is going to be making it fun.  And that's what I'm rather unsure about at this point.

I have a game design that basically works. The technical issues are mostly sorted out, I just need to get a few more implemented before I can seriously play test it.

But fun? It's hard to know if it's actually going to be any fun to play.  With a 4-player party-style game, it's seems like it might be hard to hit that fine line where everyone is close and competing, where everything feels exciting and tense, as opposed to tedious and boring.  And despite envisioning my game as fun, it might just be boring to play.

Some of that comes down to tweaking it. Tweaking the speeds, difficulties, etc, will make a difference. (If it's too easy to shoot people from behind, then it will be nearly impossible to hold a lead for very long, which could ruin it and make it no fun. If it's too hard to kill the guy in front, it wil…

Killer Queen

So at PRGE, I played an arcade game that just left me amazed.  Killer Queen.

It's a 10-player game. You have 2 cabinets linked together, and 5 players huddled on each one. Each one is a team of 5 people, working together to play a simple one-screen 2d platformer.  But what made it work was the high quality game design.

First, the game is relatively simple, yet there is a lot going on at once.  One player plays the queen, the most important and powerful character on the team. The others start as workers, but can become warriors who can fly around and attack in a very joust-like flappy contest of height.  The real trick is that there are three completely different ways to win: either collect a bunch of berries and bring them back to your base, or ride a REALLY SLOW snail across the screen (while other people try to kill you, and you hope your team protects you), or kill the enemy queen 3 times.  There's some other things going on as well (using berries to upgrade, capturing upgr…