NES to SNES - JML/JSL/Bankswitching - Myth Help/Assistance!

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
NES to SNES - JML/JSL/Bankswitching - Myth Help/Assistance!
by on (#83265)
Yes, It is another wierd-arse question, but in order to use banks for SNES, we need to use long jumps,

We need to figure out a myth concerning conversions, at least with some compare routines, using the rom and extra SNES RAM for the bankswitch emulation.

Games like Hebereke and SMB2 have bankswitching, I just turned the banks into 32k (16k combined with Fixed Bank).

In short: Can/Did anyone solve this big myth?

EDIT: Tables are also what I am talking about, Can't always do it without a way to find the bank switching tables.

Hebereke uses some sort of them. But I do not know...

by on (#83270)
The way you stated your question is vague and I don't really get what the myth you're talking about might be.

Here's how I understand it:
You want to port NES games to the SNES and you have a problem rewriting the PRG-ROM bankswitching parts to work on the SNES.

I started to port a NES game myself a while ago (just to check out how much work would be involved), and found that the hardest/most tedious parts were getting a 100% accurate disassembly (which i consider imperative) and rewriting PPU register accesses.
The game I worked on used 8kb CHR-RAM, which spared me the trouble of CHR-bankswitching, which (depending on the game) could obviously implicate heavy rewrites.

Didn't have a single problem rewriting the bankswitching code to use long jumps instead.
Please elaborate on what exactly is causing you trouble.
Code examples would help.

by on (#83275)
d4s wrote:
The way you stated your question is vague and I don't really get what the myth you're talking about might be.

Here's how I understand it:
You want to port NES games to the SNES and you have a problem rewriting the PRG-ROM bankswitching parts to work on the SNES.

I started to port a NES game myself a while ago (just to check out how much work would be involved), and found that the hardest/most tedious parts were getting a 100% accurate disassembly (which i consider imperative) and rewriting PPU register accesses.
The game I worked on used 8kb CHR-RAM, which spared me the trouble of CHR-bankswitching, which (depending on the game) could obviously implicate heavy rewrites.

Didn't have a single problem rewriting the bankswitching code to use long jumps instead.
Please elaborate on what exactly is causing you trouble.
Code examples would help.


I changed my mind... I was going to do SMB2, But appearently it's not that good to do it!

I guess I'll create a new SMBDIS package (Easier).

Since no CA65 SNES code for GFX and other stuff exists, I had to try to create a new NES Emulation method. (Sound is at least MSU1 Only for now.)

I already know how to disable sprite 0 for it, as the SNES PPU cannot use it.

the SMB Disassembly is by Doppleganger and can be found in RomHacking.Net.

EDIT: If you have the code for your NES Port, Can you please share? (Without the actual game code, of course.)

by on (#83425)
Hamtaro126 wrote:
EDIT: If you have the code for your NES Port, Can you please share? (Without the actual game code, of course.)


Yeah, in case this ever yields something presentable, I'll release the full sourcecode.

Regarding the topic of bankswitching and long jumps:
IMHO, the only correct way to do this is to replace all instances of bankswitching with native long jumps, i.e. remove all traces of the bankswitching interface.
This requires quite some effort, mainly because you'd not only have to modify all callers, but all callees aswell.


If, for some reason, you'd want to take the route of least possible modification,
preserving the bankswitching interface, possibly using static patches even (which probably would be a gigantic nightmare to maintain), the following would be one possible way to do that.
It's far from pretty though:

original nes bankswitching code, AOROM game:
Code:
/**
* switch bank, jump to subroutine
*
* @param a   return bank with mirror flag
* @param x   (target routine number + 1) * 3
* @param y   target bank with mirror flag
*/
Lbl_00_ffcd:
   ora #$00
   sta $2d
   lda $13
   pha
   stx $13
   lda.w AOROM_BANK_PPU_MIRROR_2000,y
   sta.w AOROM_BANK_PPU_MIRROR_2000,y
   jsr Lbl_00_8000
   ldy $2d
   pla
   sta $13
   lda.w AOROM_BANK_PPU_MIRROR_2000,y
   sta.w AOROM_BANK_PPU_MIRROR_2000,y
   rts


/**
* bank LUT (avoids bus conflict on bank select), also with/out ppu mirroring flag
*/
AOROM_BANK_PPU_MIRROR_2000:
   .byte $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$0f

AOROM_BANK_PPU_MIRROR_2400:
   .byte $10,$11,$12,$13,$14,$15,$16,$17


/**
* trampoline bank 0
*/
Lbl_00_8000:
   jmp ($0013)

/**
* jump table bank 0
*/
Lbl_00_8003:
   jmp Lbl_00_e7b2

Lbl_00_8006:
   jmp Lbl_00_8326

etc.


/**
* trampoline bank 1
*/
Lbl_01_8000:
   jmp ($0013)

/**
* jump table bank 1
*/
Lbl_01_8003:
   jmp Lbl_01_80a2

Lbl_01_8006:
   jmp Lbl_01_8719

etc.


/**
* sample routine, bank 1
*/
Lbl_01_8719:
   lda #$17
   sta $b3
   lda #$d0
   sta $b4
   lda #$86
   sta $95
   lda $b5
   ror a
   ror a
   ror a
   and #$c0
   tay
   ldx #$60

Lbl_01_872f:
   lda.w Lbl_01_8619,y
   sta $0100,x
   iny
   inx
   cpx #$a0
   bne Lbl_01_872f
   rts




relevant routines modified to use long jumps instead while preserving interface (minus ppu mirror flags, which would probably best be handled in the graphics subsystem instead):
Code:
/**
* jump to subroutine, long (no ppu mirror flag handling here)
*
* @param x   (target routine number + 1) * 3
* @param y   target bank
*/
Lbl_00_ffcd:

   ;save previous jump target for whatever reason
   php
   pei ($13)

   ;prepare pointer to target bank
   rep #$30
   lda #Lbl_00_8000
   sta $13
   sep #$20
   tya
   sta $15

   ;execute jump
   jsl longJump

   ;restore previous jump target
   rep #$30
   pla
   sta $13
   plp
   rts

longJump:
  jml [$13]


/**
* trampoline bank 0
*/
Lbl_00_8000:
   dex
   dex
   jsr (Lbl_00_8003,x)
   rtl

/**
* jump table bank 0
*/

Lbl_00_8003:
   jmp Lbl_00_e7b2

Lbl_00_8006:
   jmp Lbl_00_8326

etc.


/**
* trampoline bank 1
*/
Lbl_01_8000:
   dex
   dex
   jsr (Lbl_01_8003,x)
   rtl

/**
* jump table bank 1
*/
Lbl_01_8003:
   jmp Lbl_01_80a2

Lbl_01_8006:
   jmp Lbl_01_8719

etc.


To be honest, I don't think this example is terribly useful, because these modifications highly depend on the games actual implementation, but maybe it will give you some ideas.
As already hinted at earlier, I'm not actually using the above code snippet, because it feels hackish and not very maintainable to me.

by on (#83435)
Thank you a lot, d4s. This will help me a lot!

And I will give credit when used, if nessicary.

by on (#83491)
Hamtaro126 wrote:
And I will give credit when used, if nessicary.


Don't mention it, it's nothing.
But please report back when you're making progress, I'm curious!