VRC7 NSF to NES via Vegaplay

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
VRC7 NSF to NES via Vegaplay
by on (#126401)
Hi All,
I'm trying to find a way to build an .NES from a FT VRC7.NSF. I've run across a hack to Vegaplay by Grapeshot but I need some advice.
viewtopic.php?f=3&t=9102&p=96897#p96897
I have a simple test FT 0.4.3 song that uses VRC7 and 2A03, no bank switching, less then 10K. I export to .NSF (FT doesn't export exp chip to .NES). Using Nestopia the NSF plays fine.
I follow the the procedure for Vegaplay, getting the Load, Init and Play addys. Edit the vegaplay.asm, strip the header out of the .NSF file and compile. The resultant .NES NROM plays the 2A03 fine. Now I change the iNES header to Mapper 85 and Nestopia chokes on it; blank screen, no sound but no error message. Also tried Nintendulator with the same result. The two Header bytes @ offset 06 and 07, from $00 $00 to $50 $50.
When I load up one of Grapeshot's VRC7 vegaplay NES', it plays fine. The post I ran across was 1 1/2 yrs old and seems he was using FT < ver 0.3.8 so I tried the build with FT 0.4.0 but this didn't help. Do you think I need to revert to an even earlier ver? but I need HW VRC7 compatibility which was fixed as of 0.3.8.
Any ideas what went wrong? Am I missing a setting in FT?
Yogi
EDIT fixed title :)
Re: VRC7 NST to NES via Vegaplay
by on (#126402)
How big is the resulting .nes file? Not sure how the emu will handle files smaller than 32KB. You'll want to ensure that all code ends up in the fixed bank of prg rom $E000-FFFF (8KB). If it's already 32KB, but required data is outside of $E000-FFFF the emu probably isn't starting up with the banks initialized as you need them to be. You'll have to initialize the VRC7 prg bank select registers to ensure that all necessary data/code ends up in the correct banks.
Re: VRC7 NST to NES via Vegaplay
by on (#126403)
infiniteneslives wrote:
How big is the resulting .nes file? Not sure how the emu will handle files smaller than 32KB. You'll want to ensure that all code ends up in the fixed bank of prg rom $E000-FFFF (8KB). If it's already 32KB, but required data is outside of $E000-FFFF the emu probably isn't starting up with the banks initialized as you need them to be. You'll have to initialize the VRC7 prg bank select registers to ensure that all necessary data/code ends up in the correct banks.

Vegaplay builds a 41K NES, and like I said the NSF data is <10K in the PRG space. The weird thing is: only changing the mapper bytes in the header fouls it up. With no NSF bank switching going on it shouldn't make a difference, at least in my mind :)
Don't know if I'm fighting a EMU problem or a FT issue.
I'll add an edit to vegaplay for the banking regs; but the older Grapeshot NES didn't seem to need that?!? He did have a modded vegaplay.asm for MMC5 that did this, so may be that's the problem.
Yogi
Re: VRC7 NST to NES via Vegaplay
by on (#126405)
All the mappers with expansion audio require initializing their banking registers, while a plain 2A03 song won't. (Well, won't unless it's too large for an unbanked NSF)
Re: VRC7 NST to NES via Vegaplay
by on (#126407)
lidnariq wrote:
All the mappers with expansion audio require initializing their banking registers, while a plain 2A03 song won't. (Well, won't unless it's too large for an unbanked NSF)

What is causing me the most confusion is the fact that the grapeshot VRC7 NES plays.
I think this is Grapeshot's youtube vid
http://www.youtube.com/watch?v=DQtR5sbADt8
He described only changing the Mapper bytes in the iNES header.
Yogi
EDIT- Here is one of Grapshot's .NES, one has the mapper set to 0, the other has it set to 85. Song 4 Has both 2A03 and VRC7 notes. Not much of a test, as I started with the VRC and downgraded to NROM.
Attachment:
vegaplay.zip [11.92 KiB]
Downloaded 125 times

So IDK
Re: VRC7 NST to NES via Vegaplay
by on (#126409)
There are only two possible explanations for that video.

A: All of the code and data is inside the fixed bank; there is no need to initialize the mapper because the fixed bank is already initialized at power-on.

B: It only works on FCEUX, because FCEUX happened to map things the way the ROM was expecting. It will crash in most other emulators because the mapper is not initialized.

Your ROM does not work because you aren't initializing the mapper.
Re: VRC7 NST to NES via Vegaplay
by on (#126411)
OK, there's two problems here. First of all, Famitracker 0.4 doesn't export all NSFs with a load address of 0x8000, instead it puts the load address somewhere in the 2nd or 3rd 8k. I'm not sure why this was changed, but it leads to the second issue, which is that FCEUX maps the VRC6 banks differently than Nestopia or Nintendulator do at startup, but all 3 map the first and last banks in the same place, it's the second and third that are different.

So the result is: a NSF made by Famitracker 0.38 and compiled by Vegaplay with only the mapper bytes changed will work properly in all 3 emulators if it's less than 8k, but if it's larger it only works in FCEUX (So my previous NES files only worked coincidentally.) A NSF made by Famitracker 0.4 series then compiled by Vegaplay will only work in FCEUX, regardless of size. I'm going to write some init code for the mapper to fix this, but it'll take me a bit to test it.

Also, does anyone know if the actual initial values for the VRC7 have been tested by anyone? It isn't listed on the wiki.
Re: VRC7 NST to NES via Vegaplay
by on (#126412)
Nestopia initializes VRC7 on powerup as:
Code:
if (hard)
    prg.SwapBanks<SIZE_8K,0x0000>(0U,0U,0U,~0U);
Or, translated, bank 0 for the first three 8KiB slots and fixed to the last bank for the uppermost one.

But note that it doesn't reset this on reboot.

So, in any case, a VRC7 NES file that only uses the first and last 8KiB will work right in Nestopia. (and presumably on hardware).

FCEUX (2.2.1) doesn't intentionally initialize anything at all. On powerup, the preg array isn't initialized in code, so it instead falls back to the bit where global variables are initialized to 0. It sure looks to me like it should be the same as Nestopia...
Re: VRC7 NST to NES via Vegaplay
by on (#126414)
Here's what you need to add to your vegaplay.asm file to make things consistent on all emulators.

Code:
SetVRC7:
   LDX #$00;set up VRC7 banks to work consistently
   STX $8000
   STX $A000
   INX
   STX $8010
   STX $A010
   INX
   STX $9000
   STX $B000
   INX
   STX $B010
   INX
   STX $C000
   INX
   STX $C010
   INX
   STX $D000
   INX
   STX $D010


Add it right after the "BNE ClearMemory" line, and your ROM should work in all emulators and the real hardware.

Nintendulator sets bank 0 to the second bank in the ROM, bank 1 to the first, and bank 2 to the second to last bank, for some reason.
Re: VRC7 NST to NES via Vegaplay
by on (#126415)
@ Grapeshot Thank you very much for weighing in here. You cleared up much of my confusion. I did see that FT 4.0 was loading to $A64A but did not know it was causing the issue.
Thank you for the vegaplay patch, very cool of you.
Yogi
Re: VRC7 NST to NES via Vegaplay
by on (#126416)
I guess I should finally make a new version of that Vegaplay special chip package, even if I don't really need it anymore since I implemented NSF support in my own emulator.
Re: VRC7 NST to NES via Vegaplay
by on (#126417)
Grapeshot wrote:
I guess I should finally make a new version of that Vegaplay special chip package, even if I don't really need it anymore since I implemented NSF support in my own emulator.

That would be cool.
Just re built my test ROM, works great. Thank you again!
A Plus for the insight on setting the VRC7 mapper, the wiki was a not clear for me.
Yogi
Re: VRC7 NST to NES via Vegaplay
by on (#126429)
Something that may make this easier:

FamiTracker has an ASM export option in the NSF export dialog. You can use this in combination with the FamiTracker NSF driver source to rebuild your music at whatever address you need. (You can also make any necessary modifications for banking, etc. this way.)
Re: VRC7 NST to NES via Vegaplay
by on (#126430)
rainwarrior wrote:
Something that may make this easier:

FamiTracker has an ASM export option in the NSF export dialog. You can use this in combination with the FamiTracker NSF driver source to rebuild your music at whatever address you need. (You can also make any necessary modifications for banking, etc. this way.)

Grapeshot's register patch fixed the immediate problem I think.
But can you point me to any relevant docs on the asm export. I exported and read through the code but I will need many more passes over the code to understand it well enough to use it ATM. :)
What would you say is a viable location for the player code? vegaplay loads it's self into the top 2K of the PRG rom which isn't too bad but there is no guarantee that a NSF wouldn't be mapped into that space. It would result in an unplayable NFS?
I was going through Loopy's PowerPak NSF source a bit and it loads low, somewhere around $40?? Which is safe but complicates mapping.
I guess I'm wondering what a reasonable ROM size would be for the basic Play/driver and where to put it. Looking at the vegaplay code, Load and Init aren't very big and the Play is a simple call to the nsf play address driven by the NMI. So the bare bones seem very slight. I'm just a bad judge; don't know what I don't know.
Yogi
Re: VRC7 NST to NES via Vegaplay
by on (#126432)
The FamiTracker driver is about 5.5k of data, as I recall. You can locate it anywhere you like if you build it from source. If you need to bankswitch DPCM, you probably want to keep it out of $C000-DFFF, but other than that there's no good or bad place for it; just depends on your other needs. The ASM or BIN export is just a block of music data, separate from the driver. It can also be located anywhere you like.

The only documentation for it is included with the driver source itself, though I did write this guide a long time ago: http://famitracker.com/forum/posts.php?page=1&id=3681
Re: VRC7 NST to NES via Vegaplay
by on (#126435)
rainwarrior wrote:
The FamiTracker driver is about 5.5k of data, as I recall. You can locate it anywhere you like if you build it from source. If you need to bankswitch DPCM, you probably want to keep it out of $C000-DFFF, but other than that there's no good or bad place for it; just depends on your other needs. The ASM or BIN export is just a block of music data, separate from the driver. It can also be located anywhere you like.

Good to know this. So the asm export is just the song data source and together with the FT driver source you can compile the core of an nsf, with freedom to arrange it as needed. To conform to the nsf spec this should be within the PRG ROM space or banked into it?
OK, sorry I've confuse things. The FT driver is the song player within the nsf, right? I was trying to refer to the kernel/wrapper (the nsf player?) that calls the FT driver/song player routine. This is tripping me up a lot, because the nsf has a driver and you need a player to call that driver @ 60Hz or the songs freq. right. I'm really not getting the terminality correct.
But back to a point, as I understand, the nsf player should allow the whole of the PRG 32K for banking of the nsf rip. So does the nsf player code need to be located outside of the PRG 32K space or do most nsf songs stay clear of the top most 1 or 2K?

Quote:
The only documentation for it is included with the driver source itself, though I did write this guide a long time ago: http://famitracker.com/forum/posts.php?page=1&id=3681

Thanks much, more for my reading list :)
Yogi
Re: VRC7 NST to NES via Vegaplay
by on (#126437)
If you assemble the FT driver at $E000-$F7FF and the NSF player at $F800-$FFFF, everything should fit. Then you can bankswitch songs into $8000-$BFFF and samples into $C000-$DFFF.
Re: VRC7 NST to NES via Vegaplay
by on (#126443)
tepples wrote:
If you assemble the FT driver at $E000-$F7FF and the NSF player at $F800-$FFFF, everything should fit. Then you can bankswitch songs into $8000-$BFFF and samples into $C000-$DFFF.

Thanks tepples. The more I think about the export asm/bin the better it sounds. Thinking of a build tool to target a large Flash with a work flow:
Compose in FT. Export song asm. Multi asm' sorted into a 'album'. Then processed into a standard player template and compiled into a bin to be uploaded. Far more organized and less stressful for users.
This is enticing, will need to research this more.
Yogi
Re: VRC7 NSF to NES via Vegaplay
by on (#126804)
EDIT- Yea I figured it out!! The fixed 8K bank at the end of the Bin did the trick. :)

OK so vegaplay has been in my lab for a couple weeks and I have mutated it a bit. But I'm at a stumbling block.
I have things setup like so:
iNES Header
Code:
   
   .BASE $7ff0
   .DB "NES", $1a
   .DB $04             ; size of PRG ROM in 16kb units
   .DB $00            ; size of CHR ROM in 8kb units
   .DB #%01010000      ; mapper 85
   .DB #%01010000      ; mapper 85
;   .DB #%00000000      ; NROM
;   .DB #%00000000      ; NROM      
   .DB $02            ; PRG Ram
   .DB video         ; NTSC or PAL Timming
   .DB $00
   .DB $00
   .DB $00
   .DB $00
   .DB $00
   .DB $00

Then my CHR setup:
Code:
   
       .BASE $8000         ; PRG build starts here
RAM_CHR:               ; CHR ROM into PRG
   .incbin "geo.chr"         ; default Vega Play background

;       ----------------------------------------------------
Load_RAM_CHR:      ;
     src = 0            ; ZP Pointer
   lda #<RAM_CHR   ;
   sta src
   lda #>RAM_CHR   ; Hi byte of RAM_CHR lable val
   sta src+1
 
   ldy #0             ; starting index into the first page
   sty PPUMASK        ; turn off rendering just in case
   sty PPUADDR        ; load the destination address into the PPU
   sty PPUADDR
   ldx #32            ; number of 256-byte pages to copy
loop:
   lda (src),y        ; copy one byte
   sta PPUDATA
   iny
   bne loop        ; repeat until we finish the page
   inc src+1        ; go to the next page
   dex
   bne loop        ; repeat until we've copied enough pages
   rts

The NSF data loads @ $A64A, the NSF header load address
The Reset and NMI code continues @ $FA00. This works fine with no bank switching in a 32K bin. Just init the VRC7 PRG regs with $00 - $02

If I move the above CHR code to @$10000 in a 64K bin with a .BASE $8000 and try to bank it in over the NSF data only during Reset by writing $04-$06 to the VRC7 PRG registers @ $8000, $8100 and $9000, NO GO. So I don't have my Bin organized correct, right?

What order should I use:
1. The fixed 8K bank ( .BASE $E000 .PAD $10000) as the first block in the bin, follower by bank 0, bank 1 .....to the end of 64K?
2. Or the fixed reset bank at the end of the 64K bin?
3. Of like I've been trying Banks $00-$02, then the fixed 8K, then bank $03 and above?

Here is my banking code:
Code:
   LDX #$03   ; bank in $03-$05 Load CHR Ram
   STX $8000   ; Reset the 3 PRG banks
   INX
   STX $8010
   INX
   STX $9000
   JSR Load_RAM_CHR      ; Load 8K CHR into CHR Ram 
   JSR DrawScreen          ; draw initial nametable
   JSR InitSprites
   LDX #$00     
   STX $8000   ; Reset the 3 PRG banks to default
   INX
   STX $8010
   INX
   STX $9000

Thanks for any help,
Yogi