This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

VRC6 scanlines and scrolling

VRC6 scanlines and scrolling
by on (#89542)
Okay, so I was making a little parallax scrolling test earlier with MMC3, and that was fine, except today I got a PowerPak to test on my NES, and it turned out the FamiTracker music driver I was using doesn't actually work with MMC3 for some reason.

So... I've ported it to VRC6, except there's one thing I can't figure out. MMC3's IRQ seems to start at a consistent point in the scanline, so I can easily move the actual scroll register write around with NOPs. With VRC6, it doesn't sound like it knows anything about its horizontal position?

Has anybody found a way to deal with this issue? Or... is VRC6's scanline IRQ just not up to the task?

by on (#89543)
Also, I'm kind of curious about the startup PRG banks for VRC6. On emulators $8000 seems to be bank 0, and $C000 seems to be bank 2, but on the PowerPak it seems like $C000 is something else (maybe 0?).

My startup code was in the $C000 range, so I ended up moving it to $8000. I'm just wondering if it's like MMC1 where you want to have a startup stub in every bank, or is it okay to put it in the $8000 bank 0?

by on (#89544)
VRC6 IRQ is a cycle counter, so it should be triggering at the same point in the scanline that you started it at. Could try setting the enable bit at the beginning of NMI so its always the same?

by on (#89545)
I just checked the wiki and it seems that VRC6's IRQs are driven by CPU cycles, unlike the one in the MMC3, which is driven by the PPU. The difference is that since the PPU doesn't do anything during VBlank, the scanline counter isn't clocked, so no matter when in VBlank you setup the IRQ, the counting doesn't start until rendering begins.

The CPU on the other hand never stops, so a CPU-based IRQ counter will count even during VBlank, so if you don't setup the IRQ at the same point every frame the time when the IRQs fire will also fluctuate. Your best bet is probably to setup the IRQ right at the start of your NMI routine, before any branches or decisions that might result in different program flows each time.

by on (#89546)
And $E000-FFFF is the only fixed bank, so the others will be unreliable on boot. Can't necessarily rely on the $8000 bank being bank 0 either.

by on (#89547)
tokumaru, I had the same idea. Now I've had a chance to try it out. It was a huge pain to get the interrupts happening on the same horizontal position; basically I offset the first IRQ setup with NOPs right after vblank, and then in the IRQ I set scroll, and then offset the next IRQ setup with NOPs again. Eventually I was able to get it consistent and in the right place.

I'm actually really impressed by Nintendulator's timing accuracy; it's not 100% but it was REALLY close (off by one NOP from what I get from my NES with PowerPak), and consistent enough that I could figure out what it was going to do based on what I saw in the emulator.

It was a fun experiment, but I don't think I'd want to do it in an actual game.

Also, bunnyboy, thanks for the clarification. I moved my bank setup stub to the last bank.

by on (#89556)
rainwarrior wrote:
I'm actually really impressed by Nintendulator's timing accuracy; it's not 100% but it was REALLY close (off by one NOP from what I get from my NES with PowerPak)

Don't forget that mappers on the PowerPak are emulated, so they aren't necessarily 100% correct either. To be absolute sure you'd have to use an actual VRC6 cart.

by on (#89557)
Or you could start running the cycle counter right after the first PHA of the NMI handler. That'd need a change for PAL NES, but not for Dendy style PAL clones. The maximum variation you'd get in the starting point would be roughly the difference between the shortest instruction (2 cycles) and the longest official instruction (7 cycles), which is slightly less than the expected sprite 0 hit variation (7-12 cycles depending on how you handle a timeout).

by on (#89559)
The VRC IRQs don't support PAL at all. The CPU counter scaler is intended for NTSC.

The primary benefit to the VRC IRQ being CPU based is you can use patterns from both sides of the table for sprites unlike MMC3. Otherwise MMC3 is clearly the better IRQ system being PPU based. MMC5 ofcourse is even better.

by on (#89560)
MottZilla wrote:
The VRC IRQs don't support PAL at all. The CPU counter scaler is intended for NTSC.

What happens when you add 50 lines and then multiply the result by 15/16 before writing it to the mapper? That's an add, four shifts, and a subtract to adapt to PAL. I'll admit that you will lose some precision from the multiplication by 15/16, so be careful if you want multiple splits in one screen.

Quote:
The primary benefit to the VRC IRQ being CPU based is you can use patterns from both sides of the table for sprites unlike MMC3.

I explained one workaround to tokumaru a while back: map one bank to both sides of the pattern table. Write 0, 2, 0, 5, 6, 7 to the CHR bank registers, and sprites and background can share bank 0.

by on (#89564)
Ofcourse you can have a hacky implementation for PAL but it's just not meant for it normally.

And that defeats the point of having extra CHR for sprites if you are using up a bank like that. For example in Gradius II, the game uses sprites from the BG side of the pattern tables which makes MMC3 unsuitable.

by on (#89572)
tokumaru wrote:
Don't forget that mappers on the PowerPak are emulated, so they aren't necessarily 100% correct either. To be absolute sure you'd have to use an actual VRC6 cart.


Yes, this is true, but I'm not about to go -that- far to find out.

In the end I've decided it's not a very viable technique, since it's not very robust across different emulators, and even on the most available "real" hardware (PowerPak) there may be some uncertainty still.

On a related not I'm really curious how Rad Racer works, since it seems to do scanline scrolling with an MMC1 somehow. One of these days I'm going to start tracing its rendering code...

by on (#89575)
rainwarrior wrote:
On a related not I'm really curious how Rad Racer works, since it seems to do scanline scrolling with an MMC1 somehow.

F-1 Race does scanline scrolling with an NROM somehow. I'm thinking sprite 0 trigger and a 113.667 cycle inner loop.

by on (#89581)
Battletoads in level 3 does raster parallax scrolling with AxROM which has no IRQ generation either. Anything is possible with very carefully timed code.

by on (#89582)
The NES can do parallax/raster effects without mapper IRQs, it's just a bit harder and less practical. You need a way to synchronize with the PPU, which can be done with the vertical blank (you can detect the start or end of it in various ways), a sprite 0 hit, a sprite overflow, or even APU IRQs (these are really tricky!), and then some timed code. With these methods you typically waste more CPU time to pull off the effects than if you used a mapper with IRQs though.

by on (#89586)
I never realized Battletoads' Turbo Tunnel level was a raster effect. I'd always assumed it was like the other scrolling effects in the game (careful CHR-RAM tile cycling), since the differently-scrolling portion was tileable anyway. That game has a little bit of everything in it though. One thing I've always wondered... that differently-scrolled part of the background in this level flickers sometimes with punches/kicks. I sometimes consider maybe it's just a bug they left in?

I've done a partial analysis of Rad Racer; I'll create a thread for it once I've got a bit more information on it (I think it's pretty interesting), but it is indeed just carefully timed code for the most part (after a sprite 0 hit at the start of the road).

Edit: after looking at it, the top of the battletoads turbo tunnel screen before the first split appears to be timed code, and the second split to halfway down the screen a sprite 0 hit. A lot of other crazy stuff is going on, like the code that updates PPU data each frame appears to be written to $0700-$0800... dynamically generated code? Very interesting. I'm sure there would be a lot to learn from the Battletoads source code.

by on (#89588)
rainwarrior wrote:
One thing I've always wondered... that differently-scrolled part of the background in this level flickers sometimes with punches/kicks. I sometimes consider maybe it's just a bug they left in?

Punches and kicks in Battletoads freeze the game while they run because they're played through $4011.

by on (#89594)
tepples wrote:
Punches and kicks in Battletoads freeze the game while they run because they're played through $4011.

Graphical glitches for sound effects... that's a horrible trade-off if you ask me!

by on (#89596)
True, but remember they had no mapper IRQs to work with !

Also, it's fun how the status bar stays in place but the other raster effects are disabled during the sound effect. I guess they stop the sound completely between the start of the VBlank and the end of the end of the status bar every frame, which makes the sound effects sound weird/distorted (it doesn't matter that much since it's sound effects).

That also explains why the sound effects plays at a lower rate on the snake level and last level, the status bar is longer because they needed to update more tiles to VRAM every frame.
Quote:
On a related not I'm really curious how Rad Racer works, since it seems to do scanline scrolling with an MMC1 somehow. One of these days I'm going to start tracing its rendering code...

I've analyzed a good part of the game.
Apparently it runs most of the game logic between VBlank and the start of the road part. Then it synchronizes with a sprite zero hit that happens at a variable pixel position but always just one scanline before the start of the road part.
Then there is several lines where the game writes an adress to $2006 every 2 scanlines for the 3d look of the road, in a addition with $2005 writes for the curve of the road. This section also vary in length, but added with the background section, is always a constant.
Then comes the part where there is only $2005 writes for the curve of the road, and finally comes the status bar which of course is fixed.
All those timings depend on the synchronization with the sprite zero hit.

Rad Racer 2 is similar the only difference is that there is no sprite zero hits, and the initial synchronization is done with an IRQ instead. However, the other split points are still synced with timed code from the first IRQ. I don't remember if there was a second IRQ for the status bar but it would be easy to check.

by on (#89598)
Bregalad wrote:
True, but remember they had no mapper IRQs to work with !

Sure, but when designing a game you have to think of all the possibilities, how different aspects of it (specially the ones that involve hardware "tricks") will work with each other. You can't realize that the sound effects screw up the raster effects and just say "fuck it" and ignore this bug. IMO, visual glitches are the worst kind, and should be avoided at all costs.

by on (#89599)
tokumaru wrote:
tepples wrote:
Punches and kicks in Battletoads freeze the game while they run because they're played through $4011.

Graphical glitches for sound effects... that's a horrible trade-off if you ask me!


The area in question is going to be played through in a matter of 30 seconds to 1 minute. The need some point in time for updating the samples. Alot of players probably won't even notice it. I did vaguely remember the background part would change when you hit them but I thought it was intentional. It was only after this was mentioned that I fired it up and observed that part of the background to realize that the mid section wasn't being properly scrolled for that brief moment.

I really don't think it was a big issue. A bigger issue is that Player 2 can't play Clinger Winger and must lose all their lives for Player 1 to get your team to the next level.

by on (#89603)
I always thought it was kinda cool that the background was reacting to the gameplay. Like it was a living brain or something that didn't like it when you were fighting.