Dynamite Batman (SFX).nsf

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

User avatar
zeroone
Posts: 939
Joined: Mon Dec 29, 2014 1:46 pm
Location: New York, NY
Contact:

Dynamite Batman (SFX).nsf

Post by zeroone »

Check out the NSF file attached to this thread. Nestopia 1.46 and NSFPlay 2.3 are not able to play most of it. However, Mesen is able to do it. Here's some info on the file:

From Nestopia:

Code: Select all

File:           Dynamite Batman (SFX).nsf
Directory:      C:\emulators\nes_roms2\NSF\NSF\
Name:           Dynamite Batman
Artist:         Kodaka Naoki, Hara Nobuyuki
Copyright:      1991 Sunsoft C: Seya Shinichi
Region:         NTSC/PAL
Songs:          56
Starting Song:  1
Extra Chips:    No
Bank Switching: No
Load Address:   0x8000
Init Address:   0x9700
Play Address:   0x8009
From Mesen:

Code: Select all

Loading rom: Dynamite Batman (SFX).nsf
File CRC32: 0x5B470F02
[NSF] Region: NTSC & PAL
[NSF] Play speed (NTSC): 60.099766 Hz
[NSF] Play speed (PAL): 122.070313 Hz
[NSF] Title: Dynamite Batman
[NSF] Artist: Kodaka Naoki, Hara Nobuyuki
[NSF] Copyright: 1991 Sunsoft C: Seya Shinichi
[NSF] Ripper: 
[NSF] Load Address: 0x8000
[NSF] Init Address: 0x9700
[NSF] Play Address: 0x8009
[NSF] Sound Chips: <none>
[NSF] ROM size: 48 KB
It's not a banked NSF file, per the NSF spec. But, the data is 48K, suggesting that it is banked.

What logic does Mesen use to load this file?

Edit: FCEUX 2.2.2 is able to play it and it reports it as bank-switched:

Code: Select all

 Name:       Dynamite Batman
 Artist:     Kodaka Naoki, Hara Nobuyuki
 Copyright:  1991 Sunsoft C: Seya Shinichi

 Bank-switched.
 Load address:  $8000
 Init address:  $9700
 Play address:  $8009
 NTSC
 Starting song:  1 / 56
Something is missing from the wiki.
Attachments
Dynamite Batman (SFX).nsf
(45.98 KiB) Downloaded 145 times
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Dynamite Batman (SFX).nsf

Post by lidnariq »

Malformed NSFs and over-compliant NSF players.

All 0s for the "initial bank" settings is supposed to indicate an NSF with no bankswitching, disabling the bankswitching registers but seeding them with a flat 32 KiB space. But if the NSF player fails to disable the bankswitching registers (since, after all, the NSF is supposed to not write to them), then it's as though the game just had "\0\1\2\3\4\5\6\7" in those bytes in the header instead.
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Dynamite Batman (SFX).nsf

Post by Quietust »

lidnariq wrote:Malformed NSFs and over-compliant NSF players.

All 0s for the "initial bank" settings is supposed to indicate an NSF with no bankswitching, disabling the bankswitching registers but seeding them with a flat 32 KiB space. But if the NSF player fails to disable the bankswitching registers (since, after all, the NSF is supposed to not write to them), then it's as though the game just had "\0\1\2\3\4\5\6\7" in those bytes in the header instead.
Nintendulator appears to fall under this category, though it's mainly to simplify emulation since all of the "NSF player" logic (clearing RAM, initializing banks, setting the PLAY timer frequency, etc.) is implemented in 6502 assembly using a tiny ROM (at $3F00-$3FFF) and some I/O registers (at $3E00-$3E13), so the NSF file loader just translates banks \0\0\0\0\0\0\0\0 to \0\1\2\3\4\5\6\7.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Dynamite Batman (SFX).nsf

Post by rainwarrior »

Yeah, I had been considering making that restriction an option in NSFPlay.

I don't think I've ever encountered an NSF that relied on bankswitching not working (that in itself is probably "non compliant"), but I've encountered many that make the opposite mistake.
User avatar
zeroone
Posts: 939
Joined: Mon Dec 29, 2014 1:46 pm
Location: New York, NY
Contact:

Re: Dynamite Batman (SFX).nsf

Post by zeroone »

rainwarrior wrote:Yeah, I had been considering making that restriction an option in NSFPlay.

I don't think I've ever encountered an NSF that relied on bankswitching not working (that in itself is probably "non compliant"), but I've encountered many that make the opposite mistake.
Can you elaborate on that kind of file? Have an example?
Sour
Posts: 891
Joined: Sun Feb 07, 2016 6:16 pm

Re: Dynamite Batman (SFX).nsf

Post by Sour »

Mesen's NSF player is pretty much based on Nintendulator's code (it uses the same assembly code & registers), since it seemed like the cleanest/simplest implementation I could find out of the emulators I checked as a reference.

This particular NSF file expects bankswitching to work, as far as I can tell (the NSF's code writes to the bankswitching registers before playback starts).
So the NSF file itself is incorrect, and should be set to 01234567 in the header, instead of all 0s.

Since Nintendulator/FCEUX/Mesen all allow bankswitching despite the header specifying that there is none, the NSF works.
Nestopia likely disables bankswitching completely and can't play the file.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Dynamite Batman (SFX).nsf

Post by rainwarrior »

zeroone wrote:
rainwarrior wrote:Yeah, I had been considering making that restriction an option in NSFPlay.

I don't think I've ever encountered an NSF that relied on bankswitching not working (that in itself is probably "non compliant"), but I've encountered many that make the opposite mistake.
Can you elaborate on that kind of file? Have an example?
The one you started this thread with is an example.
User avatar
zeroone
Posts: 939
Joined: Mon Dec 29, 2014 1:46 pm
Location: New York, NY
Contact:

Re: Dynamite Batman (SFX).nsf

Post by zeroone »

From the wiki:
If any of the bytes from $070 to $077 in the file header are nonzero then bank switching is used. In this case, take the logical AND of the load address with $0FFF, and the result specifies the number of bytes of padding at the start of the ROM image.
The application of the logical AND is dependent on the nonzero check. Is there a more general way to express this? I am still confused how the file is getting loaded and initialized in this case.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Dynamite Batman (SFX).nsf

Post by rainwarrior »

The idea is that when you're bankswitching, you're not loading the NSF file directly into the NES' 32k address space ($8000-FFFF), you're building a <= 1024k ROM image ($00000-$FFFFF), and then banking 4k pages from that into the NES' address space.

So, in the case of banking, the high nibble of the LOAD address becomes irrelevant, since it's directly controlled by the bankswitching itself. The remaining bits were put to use for padding the bottom of the ROM image (useful for reducing file size slightly when ripping).

Mostly it's important for small rips where the music code and the music data aren't contiguous. e.g. imagine if you found ~2k of music data at $9350, and then ~1k of music code at $F035. Without banking, you'd LOAD $9350, and then have a large amount of padding in your file between that and the music code at $F035. With banking, you can just make bank 0 for $9000 (with LOAD $350) and then bank 1 for $F000, specify 0 0 0 0 0 0 0 1 as the starting bank set, and now the space in between those two regions doesn't have to appear in the file.

(If you need examples, two random ones I could find are Dream Master (1992-09-22)(Birthday)(Namco).nsf, and Dusty Diamond's All-Star Softball [Softball Tengoku] (1989-10-27)(Tose)(Tonkin House).nsf. It's a fairly common thing, though, there's probably some more famous examples if you want to dig around.)

A lot of rippers don't bother trying to save space like that. I think a lot of people wouldn't find it important anymore. Anyhow, it's used by many rips and it's been in the spec forever, so if you want to support NSF you need to support it.
User avatar
zeroone
Posts: 939
Joined: Mon Dec 29, 2014 1:46 pm
Location: New York, NY
Contact:

Re: Dynamite Batman (SFX).nsf

Post by zeroone »

@rainwarrior Thanks for the detailed explanation and the example files. That makes a lot of sense. It helped a lot.
User avatar
zeroone
Posts: 939
Joined: Mon Dec 29, 2014 1:46 pm
Location: New York, NY
Contact:

Re: Dynamite Batman (SFX).nsf

Post by zeroone »

rainwarrior wrote:So, in the case of banking, the high nibble of the LOAD address becomes irrelevant, since it's directly controlled by the bankswitching itself. The remaining bits were put to use for padding the bottom of the ROM image (useful for reducing file size slightly when ripping).
If the load address is $9000, couldn't that be interpreted as leave the first 4K bank empty and populate the rest? In other words, instead of address AND $0FFF, how about address - $8000 (assuming all the loaded data is packed into a contiguous array starting at that offset)?

On a side note, the wiki mentions that load addresses between $6000 and $8000 may be present for FDS NSF files, which would require some additional code to handle that case.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Dynamite Batman (SFX).nsf

Post by rainwarrior »

zeroone wrote:If the load address is $9000, couldn't that be interpreted as leave the first 4K bank empty and populate the rest?
No, there's no "interpretation". The value in the high nibble of LOAD when bankswitching must be ignored. This is specified, and it's been this way for 15 years. Rippers do put values in this nibble sometimes, but it is not valid to make use of it in any functional way.
zeroone wrote:In other words, instead of address AND $0FFF, how about address - $8000 (assuming all the loaded data is packed into a contiguous array starting at that offset)?
No. The address space of the ROM is separate from the address space of the NES. The ROM starts at 0. When not bankswitching you could consider it that way, if your ROM is mapped to $8000 (likely implementation). When bankswitching, the mapping is controlled explicitly by the bankswitching.
zeroone wrote:On a side note, the wiki mentions that load addresses between $6000 and $8000 may be present for FDS NSF files, which would require some additional code to handle that case.
When not bankswitching the FDS may allow load addresses down to $6000. FDS has 32k of RAM from $6000 to $DFFF. For the same reason, an FDS NSF is not allowed to load data above $DFFF (that is BIOS ROM), and if bankswitching the $E000/$F000 banks are remapped to $6000/$7000.
User avatar
zeroone
Posts: 939
Joined: Mon Dec 29, 2014 1:46 pm
Location: New York, NY
Contact:

Re: Dynamite Batman (SFX).nsf

Post by zeroone »

rainwarrior wrote:No, there's no "interpretation". The value in the high nibble of LOAD when bankswitching must be ignored. This is specified, and it's been this way for 15 years. Rippers do put values in this nibble sometimes, but it is not valid to make use of it in any functional way.
I was proposing part of a mechanism to handle malformed NSFs since checking the initial bank values for all zeros apparently does not guarantee a fixed bank. Earlier in this thread, it was mentioned that a fixed 32K bank could be simulated by setting the bank values sequentially from 0 to 7. But, the load address also needs to be taken into account to make that work. That is why I suggested subtracting $8000.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Dynamite Batman (SFX).nsf

Post by rainwarrior »

If the bank bytes are 0 0 0 0 0 0 0 0, you should load it as if not bankswitched.

Whether or not you want the banking registers to work in non-bankswitched mode is kind of up to you. It's generally harmless to do so, because a non-bankswitching NSF should not attempt to write the banking registers. In this case, yes, you would start by mapping banks 0-7 into their respective positions, and after that it runs the same whether it's supposed to be bankswitched or not, and in that implementation "non bankswitched" NSFs can still bankswitch (even though the header said not to).

So basically, yes, it would be LOAD-$8000 because the header is telling you it's not bankswitched, and you're going to automatically map your ROM to $8000 in that case.

I don't think of it as much of a mechanism to deal with malformed NSFs, as a consequence of a fairly natural way to implement it. I'm pretty sure hardware players like the PowerPak and TNS would do it that way too. The bank bytes just specify how to use LOAD and how to set up the initial banks (i.e. 0 1 2 3 4 5 6 7 if you see 0 0 0 0 0 0 0 0), and the runtime implementation doesn't care after that point.

I believe NSFPlay implements it this way too, but it intentionally disables the bankswitching registers to reject malformed NSFs. (I should make it an option, though.)
User avatar
Zepper
Formerly Fx3
Posts: 3262
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Re: Dynamite Batman (SFX).nsf

Post by Zepper »

Well, RockNES doesn't play the file. Here's the RAW info from my emulator.

Code: Select all

Filename....: Dynamite Batman (SFX).nsf
Format......: NSF
STRING RAW..: NESM
VERSION.....: 1
SONGS.......: 56
SONG START..: 1
LOAD ADDRESS: 8000h
INIT ADDRESS: 9700h
PLAY ADDRESS: 8009h
GAME TITLE..: Dynamite Batman
ARTIST......: Kodaka Naoki, Hara Nobuyuki
COPYRIGHT...: 1991 Sunsoft C: Seya Shinichi
NTSC TICKS..: 411Ah
BANKSWITCH..: 00 00 00 00 00 00 00 00 
PAL TICKS...: 2000h
BYTE CTRL0..: 4eh
BYTE CTRL1..: 0h
CRC32.......: $1E9CC24E


File size: 49168 bytes.
Post Reply