Been playing with INL's TNROM board and it rules but I thought I would share an interesting caveat when working with it!
I had recently shared a ROM for people to test on their Powerpaks, etc, when I was having problems with FCEUX emulation (that ended up being a bad version of FCEUX, but that's for another thread). It seemed to work fine on consoles everywhere and when using a good emulator all is well.
I tried the same ROM on an INL TNROM board? Nothing! Before I decided to fret, I loaded up a familiar title to see if it was my ROM. Final Fantasy 3 worked like a dream!
So, I tried making the most basic program I could think of: a simple image appearing on the screen. Still didn't work. This was when I suspected it had something to do with my init code, which is of course the universal start up code, I'm certain most people use, found on the wiki.
I stepped through FF3 using Nintendulator's debugger and soon discovered that even though TNROM's use CHR RAM and not ROM, they had some bank switching code for the RAM as part of the init! Sure enough, once I put this code into my own init, everything was fine. It seems that actual TNROM hardware requires at least a basic set up of the CHR RAM where emulators and even the Powerpak don't! I'm not sure if the Powerpak is doing some kind of emulation inside but don't let it fool you into thinking a TNROM game is working the way it would on a TNROM board!
Now here's the code (for ASM6). This would go wherever you choose to do your mapper setup but BEFORE any PPU code (I prefer to play it safe and let the two frame warmup happen before doing anything):
Then wherever your data goes but still in your hardwired bank:
The table likely has to be different for a different CHR config, but I haven't tested that. So, $00, $01, $02, $03, $05, $07 instead if using the opposide config, etc. After that, everything loads up just as you would want!
I hope this helps anyone doing TNROM development or testing, and if anyone with more technical prowess can elaborate on why this is required on an actual TNROM board but not a Powerpak, I'd love to know!
edit: the first bank write might be redundant, but I am a stickler for making 100% sure things are going to work the way I want
I had recently shared a ROM for people to test on their Powerpaks, etc, when I was having problems with FCEUX emulation (that ended up being a bad version of FCEUX, but that's for another thread). It seemed to work fine on consoles everywhere and when using a good emulator all is well.
I tried the same ROM on an INL TNROM board? Nothing! Before I decided to fret, I loaded up a familiar title to see if it was my ROM. Final Fantasy 3 worked like a dream!
So, I tried making the most basic program I could think of: a simple image appearing on the screen. Still didn't work. This was when I suspected it had something to do with my init code, which is of course the universal start up code, I'm certain most people use, found on the wiki.
I stepped through FF3 using Nintendulator's debugger and soon discovered that even though TNROM's use CHR RAM and not ROM, they had some bank switching code for the RAM as part of the init! Sure enough, once I put this code into my own init, everything was fine. It seems that actual TNROM hardware requires at least a basic set up of the CHR RAM where emulators and even the Powerpak don't! I'm not sure if the Powerpak is doing some kind of emulation inside but don't let it fool you into thinking a TNROM game is working the way it would on a TNROM board!
Now here's the code (for ASM6). This would go wherever you choose to do your mapper setup but BEFORE any PPU code (I prefer to play it safe and let the two frame warmup happen before doing anything):
Code:
; Set up banks
lda #$00
sta BANK_SELECT ; $8000 swappable, $c000 fixed
; Two 2k banks at $1000
; Four 1k banks at $0000
sta BANK_SWITCH
tax ; Init CHR RAM
ChrBankLoop:
stx BANK_SELECT ; $00, $01, $02, $03, $04, $05
lda CHRinitTable,x ; Sets up CHR banks
sta BANK_SWITCH ; $00, $02, $04, $05, $06, $07
inx
cpx #$06
bcc ChrBankLoop
lda #$00
sta BANK_SELECT ; $8000 swappable, $c000 fixed
; Two 2k banks at $1000
; Four 1k banks at $0000
sta BANK_SWITCH
tax ; Init CHR RAM
ChrBankLoop:
stx BANK_SELECT ; $00, $01, $02, $03, $04, $05
lda CHRinitTable,x ; Sets up CHR banks
sta BANK_SWITCH ; $00, $02, $04, $05, $06, $07
inx
cpx #$06
bcc ChrBankLoop
Then wherever your data goes but still in your hardwired bank:
Code:
CHRinitTable:
.db $00, $02, $04, $05, $06, $07
.db $00, $02, $04, $05, $06, $07
The table likely has to be different for a different CHR config, but I haven't tested that. So, $00, $01, $02, $03, $05, $07 instead if using the opposide config, etc. After that, everything loads up just as you would want!
I hope this helps anyone doing TNROM development or testing, and if anyone with more technical prowess can elaborate on why this is required on an actual TNROM board but not a Powerpak, I'd love to know!
edit: the first bank write might be redundant, but I am a stickler for making 100% sure things are going to work the way I want