Writing a NSF player

Discuss NSF files, FamiTracker, MML tools, or anything else related to NES music.

Moderator: Moderators

User avatar
SusiKette
Posts: 103
Joined: Fri Mar 16, 2018 1:52 pm
Location: Finland

Re: Writing a NSF player

Post by SusiKette » Sun Dec 16, 2018 5:30 am

Do NSF players usually run on single thread or do they run on multiple? If they run on one, should the player really take much processing power at all?

lidnariq
Posts: 8782
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Writing a NSF player

Post by lidnariq » Sun Dec 16, 2018 11:00 am

The only computationally intensive thing is resampling the original audio stream at 1.8MHz down to whatever is supported by the sound card, and that only if you synthesize audio that way in the first place.

User avatar
SusiKette
Posts: 103
Joined: Fri Mar 16, 2018 1:52 pm
Location: Finland

Re: Writing a NSF player

Post by SusiKette » Wed Dec 19, 2018 1:31 pm

Unless some error occurred in my emulation code, FamiTracker's NSF files seem to use some illegal opcodes. I have currently set it so that when encountering one, a message is printed to console and the player is halted. The specific opcode is LAX, zpg ($A7). Since I have to implement these, how do the status flags behave on the ones that are usable? Some are mentioned to affect no flags, though. At least for LAX, both A and X will have the same value, so it probably doesn't matter which register you check the flags with, unless the status flags behave differently for some reason

User avatar
rainwarrior
Posts: 7675
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Writing a NSF player

Post by rainwarrior » Wed Dec 19, 2018 2:09 pm

Regular Famitracker does not use illegal opcodes AFAIK, so that could indicate another issue, though I couldn't say whether the 0CC fork uses them.

I think I learned most of what I needed to know about the illegal opcodes from this document, and by inspecting source code of a few emulators:
http://www.oxyron.de/html/opcodes02.html

User avatar
SusiKette
Posts: 103
Joined: Fri Mar 16, 2018 1:52 pm
Location: Finland

Re: Writing a NSF player

Post by SusiKette » Wed Dec 19, 2018 4:11 pm

The original cause of the issue was JMP incrementing PC after it was set to the target value. Next problem seems to be either with JSR or RTS. I'm not sure which one it is though.

Just in case there is some obvious mistake that I just can't see here is how I have implemented the said instructions: https://pastebin.com/GpFKfKQf
I'm not sure how easy it is to read, but I added some comments to hopefully make it a bit easier to understand.

(EDIT: cv. and sr. are references to other files)

tepples
Posts: 21751
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Writing a NSF player

Post by tepples » Wed Dec 19, 2018 4:36 pm

JSR is supposed to add 2 to PC before pushing it, and RTS is supposed to add 1 after pulling PC. Some NSFs rely on this as a means of jumping through a jump table.

User avatar
SusiKette
Posts: 103
Joined: Fri Mar 16, 2018 1:52 pm
Location: Finland

Re: Writing a NSF player

Post by SusiKette » Thu Dec 20, 2018 4:09 am

I did a few tests some time ago before implementing these instructions, but just to be sure:
-JSR pushes the high byte to stack first and then the low byte
-RTS pulls the low byte first and then the high byte

User avatar
SusiKette
Posts: 103
Joined: Fri Mar 16, 2018 1:52 pm
Location: Finland

Re: Writing a NSF player

Post by SusiKette » Fri Jan 11, 2019 4:13 am

I took a look at bankswitching and I don't understand the meaning of the "padding bytes" that you get from load_addr AND #$0FFF. Can someone explain this a bit further?

User avatar
Memblers
Site Admin
Posts: 3770
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: Writing a NSF player

Post by Memblers » Sat Jan 12, 2019 2:16 am

An NSF that doesn't use bankswitching can be loaded directly into NES memory based on the load address, and one that does needs to be loaded as a (potentially larger) ROM that gets mapped into NES memory.

If I understand it correctly (I'll need to implement this myself soon), basically you're building a ROM out of 4kB banks. AND #$0FFF keeps the padding within that 4kB size, those upper 4 bits of the load address are ignored. The NSF load address becomes the beginning load address for your ROM. Like this:

NSF header says load address is $8456 (or $A456, $F456 would all be the same)
[ROM at 0x000000] bank 0
[padding up until 0x000456]
[load NSF data from here on]

Post Reply