Hallo all,
years ago I made first experience in NES emulation. I managed to write an emulator which was capable of emulating simple no-mapper games correctly. Only problem was that SMB always started in the first water world.
Now, for about a week, I'm having my second go on it.
I built a new emulator from scratch, now working my way around all the mistakes I made on my first attempt.
It works really well, and I even got the PPU scrolling working just like it is described in Brad Taylor's PPU document.
All no-mapper games seem to work great.
Except SMB. It still has the same issue, though this time you don't start in first water world, but in a castle. And you are able to swim in there ;D
After starting emulation, the status bar shows "WORLD" 1-1 correctly for 1 frame (or a bit more), but then it immediately switches to someting like P-1. P being any weird symbol.
Still, the game intro is correctly playing in 1-1.
Any ideas what could cause this problem?
Thanks!
Starting in the wrong world is one common symptom of an incorrect ROM dump. Have you checked your ROM with GoodNES?
That's incredible!
Indeed, when I use another rom of SMB, the problem doesn't occur.
Thanks for that hint!
But I still think there must be an issue with my emulator, because
the SMB rom that starts in the wrong world, works very fine with NESticle95. So NESticle95 must do something right, that my emulator doesn't.
Another symptom is, that - in my emulator - the background of world 1-1 is black instead of a light blue.
The Lord wrote:
But I still think there must be an issue with my emulator, because
the SMB rom that starts in the wrong world, works very fine with NESticle95. So NESticle95 must do something right, that my emulator doesn't.
Nesticle is inaccurate. It was good for its time, but it was obsolete as soon as LoopyNES was released. Knowledge of how the NES actually works has advanced since then. It takes
four lines of assembly language for a program to determine whether it is running on an NES or on Nesticle. The boot sequence of
LJ65 incorporates code like the following:
Code:
vwait2:
bit $2002
bpl vwait2
bit $2002
bmi is_running_on_nesticle
If you want to benchmark your emulator against another emulator running the same ROM, benchmark it against Nintendulator and Nestopia. If you want to be
sure, benchmark it against an NES with a PowerPak.
It has entirely to do with whether you are initializing RAM to 00 or FF. If you initialize to 00, the bad dump of SMB1 works, and if you initialize to FF, it starts at 0-1.
Of course, you can always use the Continue feature (A+Start) and start at 1-1 regardless.
Dwedit wrote:
It has entirely to do with whether you are initializing RAM to 00 or FF. If you initialize to 00, the bad dump of SMB1 works, and if you initialize to FF, it starts at 0-1.
Of course, you can always use the Continue feature (A+Start) and start at 1-1 regardless.
Nice. You are completely right. Initializing the RAM to 0 did the trick.
Didn't know the NES clears its RAM.
tepples wrote:
Nesticle is inaccurate.
Yes I though so. My point was, that Nesticle managed to execute SMB right. So that made me conclude that my emulator must have a bug that Nesticle doesn't have. And it had, as Dwedit made me realize.
However, the NES's ram is approximately initialized to FFs in reality, so people trying to speedrun Final Fantasy (which relies on uninitialized memory for the RNG) will fail if memory is cleared to zeroes.
The Lord wrote:
Didn't know the NES clears its RAM.
It doesn't. If a game relies on any RAM it didn't initialize, it's badly programed (except if it's for generating random numbers, like Dwedit mentioned FF does).
Quote:
So that made me conclude that my emulator must have a bug that Nesticle doesn't have.
Why can't Nesticle be the one with the bug? As tepples said, Nesticle is very old and many new things have been discovered about the NES since the last version of it. You should completely disregard what Nesticle does if you are aiming for accuracy, because you are trying to emulate a NES, not Nesticle. The emulators tepples mentioned (Nintendulator and Nestopia) are the most accurate nowadays.
Quote:
And it had, as Dwedit made me realize.
Initializing the RAM to something other than 0 isn't a bug. The contents of RAM on start up shouldn't matter, because no well programmed game will rely on uninitialized RAM.
Don't make your emulator less accurate just to support a crappy hack or a bad dump. The ROM has a bug, not your emulator.
tepples wrote:
If you want to be sure, benchmark it against an NES with a PowerPak.
Actually if you load it from the PowerPak, the RAM will probably be in an entirely pre-determined state by the time your program starts. I wonder if that messes up the Excitebike music variations or something like that.
tokumaru, I know what you mean.
The second SMB rom I tested doesn't depend on initial RAM content at all. It simply always works. And thats all to the good.
Thanks all, I guess that problem is solved for good.
I've been eyeing these posts.. Would it be right to initialize ram to FF, or should it be initialized to random values throughout?
essial wrote:
I've been eyeing these posts.. Would it be right to initialize ram to FF, or should it be initialized to random values throughout?
People who have tested on hardware say that the RAM contains mostly $FFs, but this behaviour isn't constant enough for you to count on it. This is one of those things that change with the phase of the moon and you simply can't replicate exactly. So I guess you can do whatever you want with the RAM, it shouldn't matter.
I don't think it would be anywhere near white-noise style random on the real system (I haven't checked though, but you can see it when you don't clear the nametable memory). FCEU I noticed seems start out with some pattern of eight 00s then eight FFs. kinda helps for checking if people cleared RAM or not in their programs
In my NES programs I do the exact opposite of clearing RAM: I fill it with "random" values myself. I do this to make sure I haven't used any variable without initializing it properly. Of course I have to change the seed a few times to in order to detect if something is wrong with a new piece of logic. It doesn't catch everything, but it helps. I don't plan on leaving the code that randomizes RAM on the release versions though, this is just for debugging.
I always found clearing RAM an evil thing, because although it might save you some specific initializations it will make it easier for you to forget to initialize something. Say you have a routine that happens to work when it reads a zero from RAM. You forgot to clear that variable, but the routine will work because you cleared the whole memory before. So you tested the routine and have considered it works, and you decide to use it in other parts of the program. But if this particular byte happens to be changed by this very routine or by some other code, the other times this routine is called it might not work. That's a very hard bug to find, as you don't even have that routine in mind because you tested it before and it worked fine. This is why I consider clearing RAM evil. I initialize before I use it, always.
Memblers wrote:
I don't think it would be anywhere near white-noise style random on the real system (I haven't checked though, but you can see it when you don't clear the nametable memory). FCEU I noticed seems start out with some pattern of eight 00s then eight FFs. kinda helps for checking if people cleared RAM or not in their programs
I used to just leave the RAM contents alone but then I noticed that uninitialized it was typically CDCDCDCD values which just looked aesthetically wrong to me. So I now set it to zeros.
The CDCD is just the Visual Studio Debugging environment. It initializes memory to this pattern so developers recognize uninitialized memory.
If you start your emulator outside Visual Studio, the CD pattern won't be there, but the memory will truly be uninitialized.
The Lord wrote:
The CDCD is just the Visual Studio Debugging environment. It initializes memory to this pattern so developers recognize uninitialized memory.
If you start your emulator outside Visual Studio, the CD pattern won't be there, but the memory will truly be uninitialized.
Actually it WILL be zeroed on Release builds. But of course one should never count on that...
Only if started inside the Visual Studio environment.
I just tested it.
Code:
unsigned int *d;
unsigned int res;
d = new unsigned int[5];
for (int i = 0; i < 5; i++)
{
res = d[i];
printf("0x%08x\n", res);
}
Debug build:
0xcdcdcdcd
0xcdcdcdcd
0xcdcdcdcd
0xcdcdcdcd
0xcdcdcdcd
Release build:
0xbaadf00d
0xbaadf00d
0xbaadf00d
0xbaadf00d
0xbaadf00d
Release build outside Visual Studio:
0x003442b0
0x00340178
0x00000000
0x00000000
0x00000000
Off topic: Any ideas, why I can't see the content of Code blocks? I'm using IE 8.0.
What kind of "Code blocks"? I assume you don't mean
Code::Blocks or
"blocks" (closures) in the Objective-C language. If you mean phpBB's [code] element, that shows up just fine for me in IE 8.0.6001.18702 on Windows XP Professional. But then I use Firefox for most browsing.
To emulate an NES accurately, you need to emulate its RAM chips, and that means filling RAM and VRAM with mostly $FF. If a bad dump doesn't run on an NES, it shouldn't run on your emulator.
I mean the bbcode "code"-Element.
It just shows me the empty borders, but not the code that's written in it.
Whatever, I'll figure it out some day.
I still can copy the block and paste it into Notepad to read it.
I don't think initializing the RAM to anything will make any difference. If you have a rom that depends on initial RAM content, it may work sometimes, sometimes it may not. And this both on the NES and on the emulator. Of course I might try to emulate the initial content of NES RAM (mostly $FF as you say), but I would never get it accurate, because on the NES it won't ever be the same twice anyway. So I just might leave it unitialized as it is.
The Lord wrote:
Only if started inside the Visual Studio environment.
I just tested it.
Seems like they've changed it recently. Could also be operating system related. I tried it in MSVC10 and yeah it seems like it's never cleared to 0 now. In Debug builds it's always 0xCDCDCDCD. In Release builds if run inside the MSVC debugger it's 0xBAADF00D, otherwise (if run inside MSVC without debugger with CTRL+F5 or outside MSVC) it's uninitialized.
I'm glad to see they changed that as I've seen quite a lot of people complaining about how their software only works in Release mode and blaming MSVC. But enough off-topic =)