comprehensive SMB1 disassembly

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

Post Reply
User avatar
beneficii
Posts: 127
Joined: Tue Jul 12, 2005 4:37 pm

Post by beneficii »

I have a question: Is the SpriteShuffler subroutine the one that deals with the can't have more than 8 sprites on a scanline problem? I'm not sure I entirely understand it.
doppelganger
Posts: 183
Joined: Tue Apr 05, 2005 7:30 pm

Post by doppelganger »

Yes. It effectively shuffles around in memory which sprites get used for enemy, fireball, air bubble, block and misc objects so that one sprite object never stays in either a low or high-numbered sprite set for longer than a frame. The sprite offsets get shuffled every NMI (long, long after the DMA of sprite data to OAM), and all the sprite Y positions in the sprite data (except sprite #0) are moved offscreen by default. The sprite data is written to $0200-$02ff, and only the sprites actually being used are assigned onscreen Y positions. Then the sprite data is used on the next frame upon NMI.

The only sprites that do not get shuffled are the sprites used by the player (right after sprite #0), and sprite #0. I think the reasons are obvious.

I believe the whole thing about lower-numbered sprites overlapping higher-numbered ones is merely symptomatic of the rendering order of the sprite evaluation mid-scanline, and this may play some part in which sprites appear on the screen with the 8 sprites per scanline limitation. My knowledge of the NES PPU is not perfect, however.
Be whatever the situation demands.
User avatar
beneficii
Posts: 127
Joined: Tue Jul 12, 2005 4:37 pm

Post by beneficii »

Hmm, just as a let you know, I am trying to do the same thing you did for SMB2J. With your permission, I'm more or less copy-and-pasting a lot of your disassembly into this one, as I am noticing (especially with regards to direct interaction with the PPU and the joypads) a lot of the code is more or less the same (the UpdateScreen function for example I notice is exactly the same). I'm also stealing your label names for cross-compatibility as the two games are so similar. :p

I hope that's OK.

Now, this game has different "files" on the disk, and when it gets to certain points (World 5, the Princess/World 9, and World A), it loads a new file over on top of some of the old one (because there is not enough room for all of the data). I'm not sure if some of the functions are used multiple times yet (I'm just working on the "SM2MAIN " file for right now), but there are some interesting things. The "JumpEngine" is there, and they've got an interesting function for loading files, which I was spending time working up:

Code: Select all

;starting at MEM address $C0CA

ChkNumFiles:
	tya
	ldy $07F7  ;current loadlist to use
	cmp NumFiles,Y
	rts

VerificationData:
    .byte $01
	.byte $53, $4D, $42, $20 ;"SMB "
	.byte $00, $00, $00, $00, $00

LoadList_Low:
	.byte <LoadList1, <LoadList2, <LoadList3, <LoadList4
	
LoadList_High:
	.byte >LoadList1, >LoadList2, >LoadList3, >LoadList4
	
LoadList1:
    .byte $01, $05, $0F     ;char data, main program (this and worlds 1-4), save
    .byte $FF               ;terminator
    
LoadList2:
	.byte $20               ;program part 2 (worlds 5-8)
    .byte $FF
    
LoadList3:	
	.byte $10, $30, $0F     ;princess char data, data 3 (princess and world 9), save
    .byte $FF
	
LoadList4:
	.byte $40               ;data 4 (worlds a-d)
    .byte $FF
	
NumFiles:
	.byte $03               ;loadlist1
	.byte $01               ;loadlist2
	.byte $03               ;loadlist3 
	.byte $01               ;loadlist4

LoadFiles:
	ldx $07F7               ;current loadlist to use
	lda LoadList_Low,X
	sta LoadList
	lda LoadList_High,X
	sta LoadList+1
	jsr $E1F8      ;FDS_LoadFiles

DiskID:
	.addr VerificationData
LoadList:
	.addr LoadList1      ;rw (this gets written to)
	rts
This is all FDS-specific, but I think I am starting to make progress on it. ^_^
doppelganger
Posts: 183
Joined: Tue Apr 05, 2005 7:30 pm

Post by doppelganger »

Well, good luck with that. I don't really mind if you use smbdis.asm to do smb2j, just as long as you give credit where it's due.

How are you going to organize this? Will it be by the files themselves?
Be whatever the situation demands.
User avatar
beneficii
Posts: 127
Joined: Tue Jul 12, 2005 4:37 pm

Post by beneficii »

doppelganger,

It would seem to make the most sense. Perhaps to avoid copyright issues, I should make people have to get a hold of the CHR data themselves.

Other than that, it seems like it's a pretty long task. ^_^ How long did it take you again? :D

EDIT: Though the RAM addresses are almost completely the same, there are some differences:

Code: Select all

DisplayDigits         = $07d7
TopScoreDisplay       = $07d7
ScoreAndCoinDisplay   = $07dd
PlayerScoreDisplay    = $07dd
GameTimerDisplay      = $07ec
DigitModifier         = $0134

FDS_WaitCycles        = $077b  ; currently waiting for IRQ
CurrentLoadList       = $07f7  ; current files to load
World9Check           = $07fa  ; if set to #$ff, then meets qualifications for world 9
LetterWorld           = $07fb  ; currently in worlds a-d if set
They got rid of the second player's score display and moved the GameTimerDisplay up, and that made room for the current load list and the A-D check.

The UpdateTopScore function was slightly changed due to this:

Code: Select all

UpdateTopScore:
	ldx #$05
	ldy #$05
	sec
GetScoreDiff:
	lda PlayerScoreDisplay,X
	sbc TopScoreDisplay,Y
	dex
	dey
	bpl GetScoreDiff
	bcc NoTopSc
	inx
	iny
CopyScore:
	lda PlayerScoreDisplay,X
	sta TopScoreDisplay,Y
	inx
	iny
	cpy #$06
	bcc CopyScore
NoTopSc:	
	rts
And here are the offsets, with World 9 added:

Code: Select all

WorldAddrOffsets:
	.byte World1Areas-AreaAddrOffsets, World2Areas-AreaAddrOffsets
	.byte World3Areas-AreaAddrOffsets, World4Areas-AreaAddrOffsets
	.byte World5Areas-AreaAddrOffsets, World6Areas-AreaAddrOffsets
	.byte World7Areas-AreaAddrOffsets, World8Areas-AreaAddrOffsets
	.byte World9Areas-AreaAddrOffsets
; see "SM2DATA4" for worlds A-D
	
AreaAddrOffsets:
World1Areas:
	.byte $20, $29, $40, $21, $60
	
World2Areas:
	.byte $22, $23, $24, $61

World3Areas:
	.byte $25, $29, $00, $26, $62

World4Areas:
	.byte $27, $28, $2A, $63

World5Areas:
	.byte $2B, $29, $43, $2C, $64
	
World6Areas:
	.byte $2D, $29, $01, $2E, $65
	
World7Areas:
	.byte $2F, $30, $31, $66
	
World8Areas:
	.byte $32, $35, $36, $67
	
World9Areas:
	.byte $38, $06, $68, $07
doppelganger
Posts: 183
Joined: Tue Apr 05, 2005 7:30 pm

Post by doppelganger »

beneficii wrote:doppelganger,

It would seem to make the most sense. Perhaps to avoid copyright issues, I should make people have to get a hold of the CHR data themselves.

Other than that, it seems like it's a pretty long task. ^_^ How long did it take you again? :D

EDIT: Though the RAM addresses are almost completely the same, there are some differences:

Umm, removed the code here so it wouldn't clog the forum unnecessarily.
Re: the CHR data, that's what I did. But then again, it was all neatly tucked away in a CHR-ROM. You would probably need to make notes on where CHR data was stored depending on how haphazardly it's stored on the disk (or disk image).

Re: how long it took me, I'd say it took me about four months to do the actual reverse-engineering, then a few weeks for the clean-up phase (I tend to work slowly). But what you have to bear in mind is that I did most of the work on SMB on my own (level data format, I had some help with, was able to verify the work others did on it).

It was pretty clever of them to use the extra space where player 2's score would have been for that. Perhaps the data at $0761-$0767 also got used for a different purpose? Perhaps not, but that's something to speculate on. Anyway it looks like your efforts are coming along nicely. :-)
Be whatever the situation demands.
User avatar
loopy
Posts: 403
Joined: Sun Sep 19, 2004 10:52 pm
Location: UT

Post by loopy »

Last edited by loopy on Wed Aug 20, 2008 11:14 am, edited 1 time in total.
User avatar
beneficii
Posts: 127
Joined: Tue Jul 12, 2005 4:37 pm

Post by beneficii »

loopy,

Interesting. One thing I noticed though, is that starting with World 4, the right-side up Pirhana plants did not change to red. In fact only the upside down Pirhana plants did. Did you take it out?

Still, very useful to distinguish between what's code and not. What was your methodology for the conversion?
User avatar
loopy
Posts: 403
Joined: Sun Sep 19, 2004 10:52 pm
Location: UT

Post by loopy »

Last edited by loopy on Wed Aug 20, 2008 11:13 am, edited 1 time in total.
User avatar
beneficii
Posts: 127
Joined: Tue Jul 12, 2005 4:37 pm

Post by beneficii »

doppelganger wrote:
beneficii wrote:doppelganger,

It would seem to make the most sense. Perhaps to avoid copyright issues, I should make people have to get a hold of the CHR data themselves.

Other than that, it seems like it's a pretty long task. ^_^ How long did it take you again? :D

EDIT: Though the RAM addresses are almost completely the same, there are some differences:

Umm, removed the code here so it wouldn't clog the forum unnecessarily.
Re: the CHR data, that's what I did. But then again, it was all neatly tucked away in a CHR-ROM. You would probably need to make notes on where CHR data was stored depending on how haphazardly it's stored on the disk (or disk image).

Re: how long it took me, I'd say it took me about four months to do the actual reverse-engineering, then a few weeks for the clean-up phase (I tend to work slowly). But what you have to bear in mind is that I did most of the work on SMB on my own (level data format, I had some help with, was able to verify the work others did on it).

It was pretty clever of them to use the extra space where player 2's score would have been for that. Perhaps the data at $0761-$0767 also got used for a different purpose? Perhaps not, but that's something to speculate on. Anyway it looks like your efforts are coming along nicely. :-)
Re: CHR data, I've already mapped it out. It wasn't scattered all over the disk: Just stored in two files "SM2CHAR1" and "SM2CHAR2". The first file is from the range $0000-$1fff and is the full file more or less; the second file is just from the range $0760-$079f and contains the data for the Princess, replacing the door to the Princess's room data in the first file.

If you don't mind me using your stuff and loopy doesn't mind me using his stuff as bases for this, then perhaps it could be done a bit quicker. Right now, I'm just going a bit here and a bit there, as I haven't really come up with a good system (and probably won't) for putting this all on. I checked the "bankx" asm files in Loopy's NES implementation and they seem to resemble for each of the files the whole $C000-$DFFF range in the PRG-RAM. Part of this project is tracing out things and seeing how they work, then marking it in a memory map to see how it's done, so I can change it later; another part is reading through doppelganger's SMB1 disassembly and trying to find similar pieces of code in this game. Maybe by June-ish, I will get it done?

Regarding player 2 data, as far as I know, the space (in RAM) from $0761-$0767 is not used in anyway in SMB2J.
User avatar
beneficii
Posts: 127
Joined: Tue Jul 12, 2005 4:37 pm

Post by beneficii »

(Sorry for the double post, for some reason edit button isn't working.)

Here is the code I used to "break apart" and analyze the FDS file so to speak:

http://nesdev.com/bbs/viewtopic.php?t=3203
daniel3843
Posts: 5
Joined: Sun May 14, 2006 10:39 pm

Post by daniel3843 »

after you design the smb2k dissasembly, maybe you can create a recompilation that will work in a cart without any issues (althought i have loopy's smb2j on a cart currently). that way there aren't the red pirhana bugs and stuff like that.

-DanSS
User avatar
beneficii
Posts: 127
Joined: Tue Jul 12, 2005 4:37 pm

Post by beneficii »

daniel,

Daniel Boik I presume? Regarding the red pirhana plant issue, that was the only issue I noticed with the game (aside from the decreased sound quality of the ending theme, but that's because the NES can't support as good sound quality as the FDS), and I think I have a way of fixing it. ^_^
daniel3843
Posts: 5
Joined: Sun May 14, 2006 10:39 pm

Post by daniel3843 »

beneficii wrote:daniel,

Daniel Boik I presume? [...]
nope, not me, but that's okay.

I usually hang out in the nesdev irc channel under DanSS.

I was just curious if you'd be doing a recompile for carts, thats all
User avatar
beneficii
Posts: 127
Joined: Tue Jul 12, 2005 4:37 pm

Post by beneficii »

OK, regardless, I fixed the red piranha plant issue. And sigh, since there seems to be no easy way to upload this to the server, you can get it here. Extract it to a folder and run make.bat:

http://www.geocities.com/beneficii/smb2jsrc.zip

It was a bit to fix, though I only had to change 6000.asm. Basically, the original game would write to the PRG-RAM in a weird way. It wrote to 2 places:

B517

and

9FFE

B517 is part of a table that gets loaded (though the game checks that value specially) and 9FFE is part of the instruction at 9FFD: CMP #$21 (which gets to CMP #$13 when it's time to do the red plants). Basically, I created 2 new variables at $51 and $50: oldb517 and old9ffe (which can be found declared at the top of the 6000.asm file). I just did a whole bunch of redirecting to those 2 variables. It appears that in the normal course of the game $50 and $51 don't really get written to, and I've tested it through, but I could still get surprised. So the purpose is to make it easily modifiable. It needs to be somewhere on the zeropage for space reasons.
Post Reply