smora015 wrote:
I'm probably not putting in the right breakpoints somewhere. At what point should I be checking for the program to populate the Name Table with the intro screen?
The subject has now changed from "how do I implement the PPU in my emulator" to "how do I use FCEUX's debugger to look at Super Mario Brothers". *confused look* :P
To answer the latter question: this is fairly easy -- you set up breakpoints on writes to PPU address ranges. Pay attention to the Add Breakpoint dialog and you'll see there's an Address range at the top, and a radio button that lets you pick PPU Mem. That's what you want.
You'll be inclined to look for writes to, say, PPU addresses $2000-23FF which correlate with the
first nametable. But due to how mirroring is configured, and depending on how the game is programmed or what their intentions are, and some of the scroll settings, they might actually be writing to $2400-27FF, or $2800-2BFF, or $2C00-2FFF.
So you may want to just block on addresses $2000-2FFF.
The next thing you're probably going to think is "okay great!", go off and do it, then (probably, I'm speculating) drops to the debugger and does a ton of $2007 writes and a bunch of other complex things. You'll go through the loop a ton of times, and eventually it'll finish... except the screen doesn't contain the title screen you expect. Instead it just shows nothing.
This is because you're thinking the very first time the game starts + first time it starts writing to nametables, it's going to draw a title screen. Don't think that / don't assume that. It's very possible the game is zeroing out parts of the unused nametables (and possibly the active one -- i.e. blanking the screen), or setting up something else first. So really you end up having to step through a few situations until you find what you want. That is simply the art of debugging/reverse-engineering. It's a huge time sink.
Furthermore, many/most games have a "common writing routine" that they JSR to do a bunch of PPU writes, based on some values they write dynamically into zero page first. So what you end up having to do there is figure out what's written to those zero page addresses, then figure out where within the preceding code that was done and break on that (as a ROM execution breakpoint), often by examining the stack (because of the JSR, or multiple JSRs). Again: the art of debugging/reverse-engineering.
So what can you do to help narrow down the conditionals so you get something accurate, rather than spend 90 hours sitting around in loops + clicking buttons + praying? Gotta use your brain a little bit, along with knowing FCEUX's debugger:
The Super Mario Brothers title screen has some text that reads "(C)1985 NINTENDO" on it. It's pretty likely that if we could break on when it writes the copyright symbol (tile) to the screen, that we'd have a "general" idea of where the routine might be.
I'll focus on the ROM titled
Super Mario Bros. (JU) [!].nes (you have to give this because there are a billion ROMs floating around and not all are the same/have the same addresses. SMB is the worst of the bunch, there must be a hundred+ ROMs of this damn thing).
Load it up in FCEUX and when the title screen is drawn, hit Pause (on your keyboard) and the emulation will pause.
Now go to Debug / Name Table Viewer. You'll see the title screen in the upper left nametable ($2000-23FF) as well as in the lower left nametable ($2800-2BFF). This is what I was talking about, re: mirroring. At this point we don't know if the game is writing to PPU memory in the $2000-23FF region or the $2800-2BFF region. But here's what we do know:
If you move your mouse over the copyright symbol/tile, you'll see the debugger say Tile: $CF. Okay, so we know the copyright symbol tile is tile $CF -- which means in turn we know that that's a byte we could "key off of" when doing a breakpoint on a PPU write. But $CF just a value; that same tile value could be used at any other time but with different CHR data (potentially), so we can't just go off of that.
The other thing we know is
where on the screen it writes $CF: again moving your mouse over the copyright symbol, in the upper left nametable you'll see it's at PPU address $21ED, and in the lower left it's at $29ED (makes perfect sense given the game's mirroring).
Now we know what we can add 2 breakpoints on: a write to PPU address $21ED, and another breakpoint with a write to $29ED. But hold on.
You would also think you could use a conditional value of
#CF -- not $CF or #$CF (the syntax here matters greatly because of how FCEUX's debugger works. Read the documentation under Help / Debugger, specifically the stuff under Conditional Breakpoints. The syntax is very very sensitive and it's easy to mess up.) But guess what: nope -- it doesn't work. Feature/bug in the debugger. Nothing we can do about it.
So what, are we just gonna blindly break on every time something writes to $21ED or $29ED? Sure, that's possible... or we could make an assumption -- the assumption that the $CF tile value is in the accumulator (hoping it's not in X or Y when writing to $2007). So we add a conditional of
A == #CF (again note syntax)
I'll save you some time and a breakpoint: the title screen code writes to the $21xx range, not $29xx. (I already took the time to look)
So we add a breakpoint when PPU memory is written to at address $21ED, with the conditional of the accumulator containing the value $CF. Crossing fingers. Press Pause (to resume emulation), then choose NES / Reset. (BTW, doing a NES / Reset while the debugger has tripped a breakpoint won't work -- you need to go into the debugger and click Run for it to resume. Just the way it works. It's easy to forget this when doing NES / Reset.)
Bam -- we get our first breakpoint hit:
Code:
00:8EB6:B0 01 BCS $8EB9
00:8EB8:C8 INY
00:8EB9:B1 00 LDA ($00),Y @ $03E5 = #$CF
>00:8EBB:8D 07 20 STA $2007 = #$FF
00:8EBE:CA DEX
00:8EBF:D0 F5 BNE $8EB6
But is this the right one? The emulator just shows kind of a black line on the blue background. Easy enough: go into Debug / Name Table Viewer again and take a look at the "crosshair" (this is basically where the PPU internally is pointing to, raster-wise, if you were to write to it). Hmm, that's at the exact location the copyright tile would be at... so let's click Run and see what happens.
Imagine that -- the title screen is drawn and the game picks up where it left off. Okay, so now you have some information: the code being used to draw the title screen is within that $8EB9 area of ROM.
If you look closely however, you'll see what it's doing: it's doing an indirect indexed read from the 16-bit address stored at ZP locations $00 and $01, which FCEUX is nice enough to inform you is address $03E5 -- that's in normal RAM. So we can safely assume the game pre-populates a part of RAM with the nametable contents (or maybe just some of the contents, i.e. a little bit at a time -- we don't know)
If we look down a little ways more, we can see that this is certainly just a generic drawing routine used for things, because the rest of the code has:
Code:
00:8EC1:38 SEC
00:8EC2:98 TYA
00:8EC3:65 00 ADC $0000 = #$00
00:8EC5:85 00 STA $0000 = #$00
00:8EC7:A9 00 LDA #$00
00:8EC9:65 01 ADC $0001 = #$4F
00:8ECB:85 01 STA $0001 = #$4F
00:8ECD:A9 3F LDA #$3F
00:8ECF:8D 06 20 STA $2006 = #$00
00:8ED2:A9 00 LDA #$00
00:8ED4:8D 06 20 STA $2006 = #$00
00:8ED7:8D 06 20 STA $2006 = #$00
00:8EDA:8D 06 20 STA $2006 = #$00
00:8EDD:AE 02 20 LDX $2002 = #$50
00:8EE0:A0 00 LDY #$00
00:8EE2:B1 00 LDA ($00),Y @ $4F03 = #$FF
00:8EE4:D0 AC BNE $8E92
00:8EE6:8D 05 20 STA $2005 = #$00
00:8EE9:8D 05 20 STA $2005 = #$00
00:8EEC:60 RTS -----------------------------------------
Last line being the most important one. Okay, so we know this is a routine that almost certainly JSR'd into, and that's confirmed by another fact: when the breakpoint hits, the stack contains the following values:
Code:
C5,80,A5,57,80
For whatever reason the stack dump in FCEUX is backwards compared to what I'd expect -- I'd expect most recent stack values to be shown on the right, i.e. appended to that list, but it's the other way around. Most recent values are on the left, e.g. the values $C5 and $80.
That sure looks like a ROM address, does it not? So given that information, we can safely assume immediately preceding $80C5 is where it does a JSR to somewhere around/near where our breakpoint. So in the debugger, we go looking around $80C5 or so:
Code:
00:80BE:BD 6D 80 LDA $806D,X @ $807B = #$8D
00:80C1:85 01 STA $0001 = #$03
00:80C3:20 DD 8E JSR $8EDD
00:80C6:A0 00 LDY #$00
00:80C8:AE 73 07 LDX $0773 = #$05
And there we have it -- JSR $8EDD. That's pretty close to where the breakpoint broke. The "drawing routine" is fairly large, so if you look closely you'll see it actually branches backwards (with BNE) into where our breakpoint was or thereabouts:
Code:
00:8EDD:AE 02 20 LDX $2002 = #$10
00:8EE0:A0 00 LDY #$00
00:8EE2:B1 00 LDA ($00),Y @ $03E5 = #$CF
00:8EE4:D0 AC BNE $8E92
Anyway, you get the idea now, and I've spent the past 60 minutes typing this up, so I think that's really enough time to dedicate to this particular task. You can dig around yourself and figure out the rest given the above methodology, I think. (I swear I should bill people for my time... :P Haha)
Back to emulation: if you want my advice: do not focus on Super Mario Brothers as your first game to get emulated. Focus on games like Mario Brothers (the original, not Super), Pinball, or Donkey Kong. SMB is kind of a pain in the ass. When you get the others working, then try to accomplish doing SMB. (For example, I'll be surprised if your 6502 emulation core is actually correct -- people keep getting ADC/SBC wrong, or having weird quirky flag behaviour problems that cause weird things to happen, like a ball shooting off diagonally somewhere and it's all because of a single bug in a single opcode). Start simple -- SMB is not simple. :)
Edit: Fixed 1995 typo (should be 1985); thanks Quietust!