This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

High level SMB Disassembly on RHDN

High level SMB Disassembly on RHDN
by on (#107340)
The RHDN release seems to not have a good upload...

As in: It is corrupt.

Movax12, Can you please solve it?

EDIT: The person actually posted a corrupted link posing as a ZIP file using the WikiSend File Shareing site, He should find a better place to upload things like this!
Re: High level SMB Disassembly - Corrupted Released
by on (#107349)
I'm sure it will be resolved soon.
Re: High level SMB Disassembly - Corrupted Released
by on (#107361)
This is fixed, Hamtaro126. Please see http://www.romhacking.net/documents/635/


Edit: Maybe we could change the title of this thread? Maybe: High level SMB Disassembly - Released
Re: High level SMB Disassembly - Corrupted Released
by on (#107454)
Here, I made some FCEUX debugging symbols with this, for people who would like to inspect it with FCEUX.

(It also works on a regular SMB ROM, you don't need to go compiling Movax12's.)
Re: High level SMB Disassembly - Corrupted Released
by on (#108945)
Hey. The really interesting code!
I want to ask questions.
When I change the source code (make mistakes), then build, wait, and nothing happens.
In the folder "obj" appears Fail "smbdishl.o". No more files do not.
What a way to debug?
Re: High level SMB Disassembly - Corrupted Released
by on (#108949)
I don't think I understand the problem. Could you try to explain more?

If you are getting an assembly error, please check the line referenced in the error output.
Example: There is something wrong at line 188:

src\smbdishl.s(188): Error: Unexpected trailing garbage characters
Re: High level SMB Disassembly - Corrupted Released
by on (#108952)
The problem with ca65's error messages for programs that use lots of macros is that "Unexpected trailing garbage characters" shows up on the line where the macro is called even if the error is inside the macro.
Re: High level SMB Disassembly - Corrupted Released
by on (#108955)
tepples wrote:
The problem with ca65's error messages for programs that use lots of macros is that "Unexpected trailing garbage characters" shows up on the line where the macro is called even if the error is inside the macro.

This was fixed (kind of) a long time ago, but I'm not sure if the change has made it in to the release version yet. In some situations what you described will still occur, but it's pretty rare.
Re: High level SMB Disassembly - Corrupted Released
by on (#108958)
tepples wrote:
The problem with ca65's error messages for programs that use lots of macros is that "Unexpected trailing garbage characters" shows up on the line where the macro is called even if the error is inside the macro.


There was the opposite problem for some time with the snapshot releases: It would only show the error line inside the macro and not where it was called from at all. This was fixed: The error messages are pretty verbose/helpful now.
Re: High level SMB Disassembly on RHDN
by on (#108991)
Now I'm running CMD and see a error message.

Code:
ld65.exe: Warning: src\nes.cfg(9): Memory area overflow in 'ROM', segment 'CODE' (1 bytes)
ld65.exe: Error: src\nes.cfg(9): Start adress too low in 'ROM', segment 'VECTORS'
Re: High level SMB Disassembly on RHDN
by on (#109008)
Unfortunately there is no room left in the ROM. If you want to add code you're going to have to figure out what you can remove or a way to add banks.
Re: High level SMB Disassembly on RHDN
by on (#109011)
Movax12 wrote:
Unfortunately there is no room left in the ROM. If you want to add code you're going to have to figure out what you can remove or a way to add banks.


If I add a bank, then the new code will work with your code?

What is better to remove the code inside?

Another question. Which program is better to edit the code?
Re: High level SMB Disassembly on RHDN
by on (#120418)
Can anyone explain how to add a bank?

(Good idea to port Mario for easy programming language. I do not understand how the assembler, too many unclear statements.)
Re: High level SMB Disassembly on RHDN
by on (#120423)
There's been a lot of discussion about this in the past, but I'll give you the 10,000-foot view as a starting point. Also, I'd like to mention that this is an excellent first hack to get your feet wet with NES development! Don't dismiss it as too complex!

First, understand what a memory mapper is and what it does. The wiki doesn't really have a high-level overview, so I'll start with that.

The NES's memory goes something like this:
$0000 - $07FF RAM
$0800 - $7FFF Registers and etc.
$8000 - $FFFF Game code and data

That gives you 2KB of RAM and 32KB of game code and data to work with, of which SMB uses just about all of it. Using only the NES, there is no way to access more game code or data.

A memory mapper allows a game to access game code and data beyond the 32KB limit by means of "bank switching". For instance, if we have a game with 128KB of code and data, we could think of it as 4 separate 32KB "banks", and we could call them banks 0 through 3. By means of bank switching, we can select which of the four banks are visible to the NES in the address space $8000 - $FFFF at any given time.

One way to approach extending SMB into multiple banks is to use the fairly simple BNROM mapper, which provides 4 separate 32KB banks for code and data, but uses RAM for the character patterns.

The strategy is to embed all character data (8KB) into the first bank, along with the code to load that data into character RAM, and the rest of the code to initialize the system. The other three banks will contain copies of the original 32KB SMB code and data bank with your code modifications, consuming level data to make up the extra room. Finally you split the level data into separate banks and change the level load routine to bank switch prior to passing the data pointer back.

There are other approaches that have been used in the past, and many more to come I'm sure.
Re: High level SMB Disassembly on RHDN
by on (#120424)
I wonder if I'd face any repercussions making a NESICIDE project out of this? Source code is OK but CHR is not?
Re: High level SMB Disassembly on RHDN
by on (#120428)
Source code that compiles into the CHR?

If you think source code that compiles into an exact copy of the binary is legit, then surely a bunch of .byte statements that compiles into the CHR portion is legit :)
Re: High level SMB Disassembly on RHDN
by on (#120432)
Thanks. Nice to know about mappers.
I think the problem is complicated. To do need an experienced assembler programmer, not a novice.

(I learned that there are hacked emulators for big roms. More than FFFF. Do not know how they work with the memory. Maybe it's more simple)
Re: High level SMB Disassembly on RHDN
by on (#120434)
Some emulators support a 512 byte "trainer" ROM, which has been used to provide rom hacks in the past. I don't have much info on this however.
Re: High level SMB Disassembly on RHDN
by on (#120436)
If the bit is set, it loads 512 bytes into RAM mapped from $7000 to $71FF. In the file, it's placed before PRG.

In practice, it's almost always used for mapper hacks for pirates.

It'd be easier, if you find emulators that support it, to use NROM-368.
Re: High level SMB Disassembly on RHDN
by on (#120438)
Uyeah, I forgot about that whole thing :) Good news is that mapper is also expressible in hardware as well.
Re: High level SMB Disassembly on RHDN
by on (#129813)
A good idea to port this code into the source code of the emulator.
This will reduce compile time and give other possibilities.
Re: High level SMB Disassembly on RHDN
by on (#129815)
I'm having trouble understanding what you mean.
Re: High level SMB Disassembly on RHDN
by on (#129824)
Movax12 wrote:
I'm having trouble understanding what you mean.

Maybe it will be clearer.
Code:
    if (PC == 0x8000) {
         
    } else if (PC == 0xB689 ) {   
          _FireballObjCore();
         
    } else if (PC == 0xECDE+0 || PC == 0xECED ) {   //FireBar
          _DrawFireball();

      } else {
        pb = 0;
        final int instr = r.read(PC++);
       ...


I wrote it in code emulator HalfNES (Java.)
Looks like assembler.
Here is another example.
Code:
public  void _DrawExplosion_Fireball() {

        ldy( Alt_SprDataOffset + X );                   
        lda( Fireball_State + X );                       
        inc( Fireball_State + X );                       
        lsrA();                                               
       if ((A &= 0b00000111) < 3) {
          _DrawExplosion_Fireworks(); return;
       }
           r.wram[ Fireball_State + X ] = 0; PC = 0xED65+1; rts();
}

Perhaps this section and topic only real hardware NES. Then I'm sorry.
Re: High level SMB Disassembly on RHDN
by on (#129825)
Yes, something like that could work.
I made sure the SMB disassembly matches the original ROM exactly when built to help ensure there are no mistakes. The high-level look of the code could be improved with more macros, etc (I could have done a better job to begin with). From there you could probably convert the code to C (or whatever) without too much difficulty and run by emulating the NES hardware without the CPU.

Maybe take a look at this, it may help with this idea: http://andrewkelley.me/post/jamulator.html
Re: High level SMB Disassembly on RHDN
by on (#129829)
Graphics are probably also available elsewhere, so you can take the two thing from two places and combine them to make a Mario game. You do not need to include the graphics with the game code, since that is not the purpose of this game code; the purpose is to see how it is working.
Re: High level SMB Disassembly on RHDN
by on (#133433)
teremochek wrote:
Movax12 wrote:
Unfortunately there is no room left in the ROM. If you want to add code you're going to have to figure out what you can remove or a way to add banks.


If I add a bank, then the new code will work with your code?

What is better to remove the code inside?

Another question. Which program is better to edit the code?


Or you can do what I did when I added SMB2J stuff to my SMB1 for FDS: Remove residual code. Here are some places that code can be removed, also some other ways to save space; if you follow my advice, you'll get roughly 250 free bytes (note that not everything labeled in the disassembly as 'residual' are really residual; the ones I listed are proven residual):

Code:
;In "PrintVictoryMessages:", remove these
cmp #$09                 
bcs IncMsgCounter

;In "Palette1_MTiles:" remove these
.db $24, $2f, $24, $3d ;flag ball (residual object)

;In "WaterPipe:" remove this:
ldy AreaObjectLength,x

;In "ScrollScreen:" remove this
sta ScrollIntervalTimer

;In "FlagpoleSlide:" remove these
cmp #FlagpoleFlagObject
bne NoFPObj

;In "NoFPObj:" remove this
inc GameEngineSubroutine

;In "UseMiscS" remove this
sty JumpCoinMiscOffset

;In "MovePlatformUp:" remove these
cpy #$29
lda #$09

;In "CheckEndofBuffer" remove all these
iny
lda (EnemyData),y
and #%00111111
cmp #$2e
beq CheckRightBounds

;In "SetupGFB" remove this
jsr GetFirebarPosition

;In "BPGet:" remove these
lda FlyCCBPriority,y
sta Enemy_SprAttrib,x

;In "DrawFlameLoop:" remove this
sta Sprite_Y_Position+12,y

;In "FirebarSpin:" remove
ldy #$18

;In "SpinCounterClockwise:" remove
ldy #$08

;In "RightPlatform:" remove
sta $00

;Remove "ResidualXSpdData:" completely

;In "CheckToAnimateEnemy:" remove this
iny

;In "DrawBrickChunks:" remove
lda #$75

;In "PowerUpGrabFreqData:" remove these at the end
.db $22, $1c, $14

;In "FindAreaMusicHeader:" remove this
sty MusicOffset_Square2

;Remove "ResidualHeaderData:" completely


Code:
;Did you know you could get 16 free bytes from changing lda BrickShatterEnvData,y in "ContinueBrickShatter:" to "lda BowserFlameEnvData,y"? They both make the same SFX but now you have 16 free bytes where the data used to be!


Optimize the following routine to get another 32 bytes:
Code:
;This is the original routine
SetPlatformTilenum:
        ldx ObjectOffset   
        iny                 
        jsr DumpSixSpr         
        lda #$02           
        iny                       
        jsr DumpSixSpr           
        inx                         
        jsr GetXOffscreenBits   
        dex
        ldy Enemy_SprDataOffset,x
        asl                       
        pha                   
        bcc SChk2
        lda #$f8                   
        sta Sprite_Y_Position,y
SChk2:  pla                     
        asl                     
        pha                   
        bcc SChk3
        lda #$f8                 
        sta Sprite_Y_Position+4,y
SChk3:  pla                     
        asl               
        pha                 
        bcc SChk4
        lda #$f8                   
        sta Sprite_Y_Position+8,y
SChk4:  pla           
        asl                   
        pha                   
        bcc SChk5
        lda #$f8                 
        sta Sprite_Y_Position+12,y
SChk5:  pla                       
        asl                 
        pha                 
        bcc SChk6
        lda #$f8             
        sta Sprite_Y_Position+16,y
SChk6:  pla                 
        asl                 
        bcc SLChk                 
        lda #$f8
        sta Sprite_Y_Position+20,y
SLChk:  lda Enemy_OffscreenBits   
        asl                       
        bcc ExDLPl
        jsr MoveSixSpritesOffscreen
ExDLPl: rts

;okay, now change it to this:

SetPlatformTilenum:
        ldx ObjectOffset     
        iny                     
        jsr DumpSixSpr           
        lda #$02                   
        iny                       
        jsr DumpSixSpr           
        inx                         
        jsr GetXOffscreenBits     
        dex
        ldy Enemy_SprDataOffset,x   
        ldx #$06
SChk:   asl                       
        bcc SChkNx
        pha                         
        lda #$f8                   
        sta Sprite_Y_Position,y
        pla                       
SChkNx: iny
        iny
        iny
        iny
        dex
        bne SChk
        ldx ObjectOffset
        tya
        sec
        sbc #$18
        tay
        lda Enemy_OffscreenBits   
        asl                       
        bcc ExDLPl
        jsr MoveSixSpritesOffscreen
ExDLPl: rts


There are many more ways to clear up free space. This next method will get you about 150 free bytes:

SMB1 was very wasteful with level data. For example look at this:
Image

^The above leftmost brick can be made to a horizontal brick length 4 and the rightmost brick can be removed (see below). This can be done with various objects in ALL levels/rooms to save space while functioning the same.

Image


The above trick can also be done with enemies while function the same, too. See below.

Before:
Image

After:
Image

Notice that I changed it from a 'Little Goomba' to a '2 Little Goomba (V=10).

With the above, counting every possible level, you get around 150 free bytes this way. I hope this was helpful instead of having to convert this from NROM to MMC3 and extra routines. 200 or so free bytes is a lot of free space to make many routines.

EDIT: Here is another code that can be optimized.
Code:
;Original code

CheckPlayerVertical:
       lda Player_OffscreenBits
       cmp #$f0                 
       bcs ExCPV
       ldy Player_Y_HighPos   
       dey                     
       bne ExCPV
       lda Player_Y_Position
       cmp #$d0   
ExCPV: rts

;Optimized code
CheckPlayerVertical:
       lda Player_OffscreenBits 
       and #$f0                 
       clc
       beq ExCPV             
       sec                       
ExCPV: rts

;you've saved 7 bytes


EDIT2: Also, remove anything labeled as "free space" etc. They will always be bytes of $FF. They are scattered throughout the file and will add up to another 20 or so free bytes.

EDIT3: Make sure that the assembled binary file is no GREATER or LESS than 32,768 bytes. Whenever you add or minus code, you need to pad it or else there will be trouble. I can tell you are new to this. My advice is use something like Notepad++ that tells you the line numbers for when the assembler shoots out a "value out of range" or a line with an error or what not.

EDIT4: Here's one more that's easy to miss. The underwater level has a room pointer to World 3 that's never used. (Room pointers always take 3 bytes). So removing it will give you three more. I just mentioned this because this one was hard to find. But the other wasteful ones are easy.
Re: High level SMB Disassembly on RHDN
by on (#133434)
Do these removals of residual code preserve sync of tool-assisted speedruns?

If you're not worried about TAS sync for warpless runs, another big one is to remove the flying fish code and replace it with the simpler code in the PAL version.

Might you be interested in reviewing the code from one of my NES projects to find space optimization opportunities?
Re: High level SMB Disassembly on RHDN
by on (#133435)
Shoot. I forgot these routines where you can save space. In total, another 33 bytes right here (I took advantage of these in my SMB1 hacks to load the beta tiles I found):

Code:
;In "VRAM_AddrTable:", remove
.dw UnusedAttribData

;and
.dw BowserPaletteData

;You can also remove the 8 bytes from the "BowserPaletteData" data and just change the palette to $1A using FCEUX PPU viewer.

;you can also remove these; remember to update where the immediate values are loaded for certain objects like trees (only takes a few minutes):
 .db $45, $47, $45, $47 ;breakable brick (not used)
 .db $24, $47, $24, $47 ;half brick (not used)

;remove this completely
DoNothing:
      lda #$ff       ;this is residual code, this value is
      sta $06c9      ;not used anywhere in the program
      rts

;In "ProcHammerObj:" remove
sta $01

;In "SwimCCXMoveData:" remove
.db $04, $04

;In "ShufAmtLoop:" remove
jsr DoNothing


EDIT: I thought of another way to get another 24 free bytes. But the above is more than enough to even add SRAM, Upside-Down pipes, Wind. etc. So if you need more free space, I can give you what I have in mind plus I can probably find more. Let me know.
Re: High level SMB Disassembly on RHDN
by on (#133436)
tepples wrote:
Might you be interested in reviewing the code from one of my NES projects to find space optimization opportunities?


If it's a Mario or Pokemon game, sure. Those are the only things I'm interested in hacking. It must be in either 6502 or Z80.
Re: High level SMB Disassembly on RHDN
by on (#133438)
teremochek wrote:
Can anyone explain how to add a bank?

(Good idea to port Mario for easy programming language. I do not understand how the assembler, too many unclear statements.)



If you choose to make this MMC3 rather than my optimizations (keeping it NROM), might I suggest using infidelity's MMC3 conversion of this? It even comes with the bankswitch routine within the included .docx. Use the routine he included with it to preform bankswitching. Add it to the .asm file. (Just google "acmlm board infidelity MMC3 SMB1")

His notes include everything needed to know about bankswitching.
Re: High level SMB Disassembly on RHDN
by on (#135740)
Thanks for the interesting information.