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

Discussion of hardware and software development for Super NES and Super Famicom.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Post Reply
User avatar
Hamtaro126
Posts: 783
Joined: Thu Jan 19, 2006 5:08 pm

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

Post by Hamtaro126 »

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...
AKA SmilyMZX/AtariHacker.
d4s
Posts: 94
Joined: Mon Jul 14, 2008 4:02 pm

Post by d4s »

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.
User avatar
Hamtaro126
Posts: 783
Joined: Thu Jan 19, 2006 5:08 pm

Post by Hamtaro126 »

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.)
AKA SmilyMZX/AtariHacker.
d4s
Posts: 94
Joined: Mon Jul 14, 2008 4:02 pm

Post by d4s »

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: Select all

/**
* 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: Select all

/**
* 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.
Last edited by d4s on Fri Sep 02, 2011 11:54 am, edited 2 times in total.
User avatar
Hamtaro126
Posts: 783
Joined: Thu Jan 19, 2006 5:08 pm

Post by Hamtaro126 »

Thank you a lot, d4s. This will help me a lot!

And I will give credit when used, if nessicary.
AKA SmilyMZX/AtariHacker.
d4s
Posts: 94
Joined: Mon Jul 14, 2008 4:02 pm

Post by d4s »

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!
Post Reply