Emulating Super Mario Bros. *solved*

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
HLorenzi
Posts: 23
Joined: Thu Jun 28, 2012 9:10 pm
Location: São Paulo, Brazil

Emulating Super Mario Bros. *solved*

Post by HLorenzi » Thu Jun 28, 2012 10:30 pm

[edit] After running Nestest and comparing it to my emulator's output (I had to write a small program, since they're so extensive), I could figure out wrong behaviors, and now Super Mario Bros runs flawlessy! Thank you guys for your patience! :P

I am writing a (kinda) didactic NES emulator. I've already finished the CPU and most of the PPU, but I am in doubt over some things. I am trying to run Super Mario Bros, which I know is difficult, but I can already play the whole game (and even hear basic sounds and music!). I wish to know:

1. How does it fill up the palettes? It seems to be writing to the $3300-$331F PPU area, but I thought that address mirrored down to $2300-$231F (and ended up changing on-screen tiles). Making it mirror to $3F00-$3F1F works, but I'm not sure if that's correct.

2. How does the nametable select (lowest bits written to port $2000) work? Does it affect writing to/reading from nametables, or does it just affects how PPU renders things? I get to see question blocks from the next screen on the title screen.

I tested my emulator with tutorial games (like ones that teach scrolling), and they worked perfectly, including palettes, so I don't know what's wrong. :D :D :D
Last edited by HLorenzi on Fri Jun 29, 2012 11:02 pm, edited 1 time in total.

3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames » Thu Jun 28, 2012 10:52 pm

The palette is 3F00 and up. And the nametable select bits work as basically think of the screen as a bit map where nametable to the right is +256 horizontally and to the bottom of the main one is +240 vertically and the last is both. If you treat it like that it'll work basically, but you'll need to start emulating the V, T, and X registers in the document below to get an accurate PPU.

http://wiki.nesdev.com/w/index.php/The_ ... _scrolling

same document, source:

http://home.comcast.net/~olimar/NES/skinny.txt

HLorenzi
Posts: 23
Joined: Thu Jun 28, 2012 9:10 pm
Location: São Paulo, Brazil

Post by HLorenzi » Thu Jun 28, 2012 10:56 pm

3gengames wrote:The palette is 3F00 and up. And the nametable select bits work as basically think of the screen as a bit map where nametable to the right is +256 horizontally and to the bottom of the main one is +240 vertically and the last is both. If you treat it like that it'll work basically, but you'll need to start emulating the V, T, and X registers in the document below to get a accurate PPU.

http://wiki.nesdev.com/w/index.php/The_ ... _scrolling

same document, source:

http://home.comcast.net/~olimar/NES/skinny.txt
Thanks, but I've already implemented the V, T and X registers. The scroll works fine, it's just that blocks from other screens get drawn on the current one. It seems that lots of PPU addresses used by Super Mario Bros are getting screwed up.

3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames » Thu Jun 28, 2012 11:02 pm

You have to remember the mirroring, there's only RAM for 2 nametables usually so you either do mirroring like:

Code: Select all

AA
BB
or

Code: Select all

AB
AB
unless they have 2KB VRAM on cart, or some other weird mirroring. If you mirror wrong they will seem like they're all going to the first nametable. Use NESTOPIA and change a SMB ROM to the other mirroring and play it and see if it's the same as your problem, if so, you know what it is.

User avatar
tokumaru
Posts: 11991
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Emulating Super Mario Bros.

Post by tokumaru » Fri Jun 29, 2012 6:06 am

HLorenzi wrote:How does it fill up the palettes? It seems to be writing to the $3300-$331F PPU area
SMB is known for writing the palettes to mirror addresses.
How does the nametable select (lowest bits written to port $2000) work?
The name table selected through these bits is the one where rendering will start from.
Does it affect writing to/reading from nametables, or does it just affects how PPU renders things?
The 2 lowest bits of $2000 only affect rendering, but the mirroring (which in the case of SMB is hardwired) affects how the name tables are distributed in the addressing space, for both reading (which includes rendering) and writing.
I get to see question blocks from the next screen on the title screen.
SMB uses vertical mirroring, meaning that the two name tables are arranged side by side, so when it renders the first screen it has a full screen to the right of it that it can preload with blocks that will show up when the screen scrolls.

If you use the wrong mirroring and arrange the two name tables vertically, the one to the right of the first screen will be a mirror of the first one, so things that aren't supposed to be displayed yet will overwrite tiles in the first screen.

HLorenzi
Posts: 23
Joined: Thu Jun 28, 2012 9:10 pm
Location: São Paulo, Brazil

Post by HLorenzi » Fri Jun 29, 2012 8:37 am

Thanks, I found the problem (it was something else! The PPU register V was still being copied from register T even when sprites and background were off). Now it scrolls and draws the background correctly... But there's still something wrong. Attribute tables seem off (just blocks on even rows and columns get colored right - maybe it's just my fault on the render section), and when Mario destroys a block, it updates the tile on the top of the screen, rather than on the block's position.

Does Super Mario Bros. uses the V register while drawing the screen (i.e. non-V-blank) to update tiles?

Also, firebars aren't drawing correctly (they're just ONE fireball in the middle of blocks). Is there something special to them, or is it just me that haven't implemented full emulation?

tepples
Posts: 22278
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples » Fri Jun 29, 2012 8:49 am

Are you sure you don't have any CPU bugs? Does it get through nestest with the same instructions executed in the same order as the log from Nintendulator?

HLorenzi
Posts: 23
Joined: Thu Jun 28, 2012 9:10 pm
Location: São Paulo, Brazil

Post by HLorenzi » Fri Jun 29, 2012 8:51 am

tepples wrote:Are you sure you don't have any CPU bugs? Does it get through nestest with the same instructions executed in the same order as the log from Nintendulator?
I tried NEStress, and it passed the tests. I'm going to try nestest, then.

[edit] OK, so something is really wrong :lol:, because it doesn't even show the little asterisk cursor! I get to see all the text, though. But I can't move nor run any tests. What should I do? Commercial games are working, what does Nestest do differently?

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch » Fri Jun 29, 2012 9:40 am

Yeah, smells like a CPU bug.
What should I do?
Run nestest in automated mode (I think this is done by changing the reset vector to $C000 instead of $C003). Dump a trace log, and compare it with a known good run. I believe there's a "good" log on the wiki right next to the download for nestest.
Commercial games are working
No they're not. You just mentioned like 4 or 5 problems SMB was having.

HLorenzi
Posts: 23
Joined: Thu Jun 28, 2012 9:10 pm
Location: São Paulo, Brazil

Post by HLorenzi » Fri Jun 29, 2012 9:43 am

Disch wrote:Yeah, smells like a CPU bug.
What should I do?
Run nestest in automated mode (I think this is done by changing the reset vector to $C000 instead of $C003). Dump a trace log, and compare it with a known good run. I believe there's a "good" log on the wiki right next to the download for nestest.
Commercial games are working
No they're not. You just mentioned like 4 or 5 problems SMB was having.
OK, thanks! I'm gonna look into it. But other games do work, like Excitebike and Balloon Fight.
Last edited by HLorenzi on Fri Jun 29, 2012 10:41 am, edited 2 times in total.

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch » Fri Jun 29, 2012 9:46 am

If there's a bug in your CPU behavior, it will only be noticable in games which rely on that behavior. For example, if you aren't setting the N flag properly on LDY, lots of games will probably run just fine -- until you try to run a game that actually reads the N flag after an LDY.

Maybe Balloon Fight / Excitebike just don't rely on whatever behavior is broken, so they are unaffected by it.

HLorenzi
Posts: 23
Joined: Thu Jun 28, 2012 9:10 pm
Location: São Paulo, Brazil

Post by HLorenzi » Fri Jun 29, 2012 10:41 am

Well, the trace logs are identical (apart from really small clock cycle differences). I checked the beginning and then a few random spots to check whether they matched, and they did. Could there still be little bugs? I could create something to automatically read both logs and tell me what's different, since it's so long. Is that necessary?

So maybe I'm screweing up the PPU ports? It's strange, because the level gets drawn correctly, it's just the attributes and blocks updating that go wrong.

Post Reply