The Future of VSP Scrolling on the C64
NOTE: In its original form, this article first appeared in my abortive Newsletter in June 2021.
From time to time I have considered deploying DMA delay scrolling aka VSP scrolling (Variable Screen Placement or Variable Screen Positioning) as a CPU time-saver on Commodore 64 games, having accidentally triggered it on a few occasions tinkering with FLD (Flexible Line Distance) while developing the vertical parallax effect for Parallaxian.
(Incidentally, the rumour is that someone experimenting with FLD many moons ago is what led to the discovery of VSP).
As most people of a technical inclination within the C64 scene will already know, VSP is used in Mayhem in Monsterland, Creatures and, allegedly, Phobia for the full-screen, full-colour scrolling; in the case of Mayhem, it is particularly beneficial when the game scrolls at its maximum speed (i.e. when Mayhem is tearing around the landscape at supercharged speed).
Combined with Linecrunch, it is reported that VSP also forms part of the AGSP scrolling (Any Given Screen Position) used in the Fred's Back series of platformers.
For the uninitiated, VSP capitalises on an unintended quirk in the "moody diva" register that is $D011 which, under the right cycle-precise conditions, inadvertently allows the screen RAM to be shunted by an arbitrary amount in the x-direction, thus synthesising a much-desired full-lateral-width hardware scroll capability on the C64.
There is one small problem, though.
On a tiny minority of machines - that is, on some real hardware, with original MOS components - VSP crashes the system and might hypothetically, in extremis, even brick the hardware.
From what I can discern, anecdotal evidence seems to suggest C64Cs are the most prone to the VSP crash vulnerability and, despite some crumbs of statistical data giving rise to the hope that C128s were immune to it, sadly even some of them have been reported as occasionally succumbing to it.
Cue the First in-depth Forensic Deconstruction of VSP
For years (decades), the innermost workings of the VSP bug remained an elusive mystery to the C64 scene until a savvy Swede decided to probe deeper into the problem.
Linus Akesson (“LFT”) has reported on this in his seminal Safe VSP article, concluding that the crash consists of the VIC chip briefly triggering a system-wide de facto speed wobble consisting of a “metastability condition in the DRAM” caused by a combination of physical, electronic charge issues unique to any given piece of VSP-vulnerable hardware and potentially originating anywhere across the whole spectrum of components from the power supply unit right up to manufactured-in “parasitic resistance” on the motherboard, with even the version of the VIC chip itself entering the fray as a contributing factor.
In other words, the VSP crash vulnerability, in those few machines exhibiting it, is a quirk that arises out of a confluence of disparate influences and is, to my knowledge at least, the only well known 8-bit example of what physicists would describe as a complex system output.
Unfortunately, though, that output renders VSP - and games that use it - a crashing risk to vulnerable hardware, which has led to it having latterly become something of a pariah effect in coding circles.
After all, who wants to be the game developer or demo coder who finally administers the coup de grâce to some hobbyist's old hardware, however improbable that may be?
Or so goes the argument.
First, a Crude Fix: “Safe VSP” via RAM Gaps
LFT did, however, provide a glimmer of hope with his “Safe VSP” hack, in which memory locations ending in certain numbers (e.g. 7), which he describes as “fragile”, can be skipped
and data arranged or, alternatively, restored on-the-fly to preserve its integrity, and he has provided a
Safe VSP demo that works on that basis.
Note that this crude fix doesn't prevent the vulnerability from arising in the first instance; it merely avoids executing code anywhere across the "collateral damage" within the RAM.
But is this kind of workaround of practical value outside the realm of scene demos?
That is to say, could it be worked into a game?
Personally, I would imagine trying to refactor the codebase - before we even think about graphics - to include NOP-based firebreaks against the metastability corruption effect would very obviously be a logistical nightmare prior to 99.9% of the game's development having been completed... and that's before even considering the performance hit the non-scrolling code in the game would take with byte-skipping at every location ending in 7 and F.
And of course, it would scupper any possibility of using certain coding expedients, such as this kind of thing:
|LDA $DD06||; (3 bytes)|
|EOR #%00000111||; (2 bytes)|
|STA CORRECTOR+1||; (3 bytes)|
|CORRECTOR||BPL *+2||; (2 bytes)|
|CMP #$C9||; (2 bytes)|
|CMP #$C9||; (2 bytes)|
|BIT $EA24||; (3 bytes)|
That's a section of self-modifying code used for timer interrupt stabilisation and its final 4 instructions traverse 9 contiguous bytes; the problem with the “NOP-gap fix” in this scenario becomes clear when it is understood that we have to ensure the branch instruction BPL lands somewhere in the 7 contiguous bytes of RAM that follow it.
So where could we place the NOPs (assuming a #$*7 - #$*F gap schema)?
The last optimal location would be just before the BPL instruction, but then the next one would have to come 8 bytes later, slap-bang in the midst of the BIT instruction's absolute address, meaning... we would be unable to use that kind of code within LFT's “Safe VSP” fix methodology.
Secondly, let's look at the figures involved.
One page of RAM has 16 locations ending in 7 and another 16 ending in F, requiring 32 NOPs per page, resulting in 32 x 4 = 128 NOPs (i.e. 256 dead-weight CPU cycles = approx 4 raster lines) per 1K of executable code.
That's 12.5% of your code consisting of NOP instructions, just to make VSP safe on vulnerable hardware, so on a game that has, say, 32K of executable code, 4K of that code does nothing but prevent fallout from the VSP vulnerability.
For that amount of RAM, you could gain 64 sprite definitions instead if you weren't using it to make VSP safe!
Then there is the actual dirty work of inserting NOP every 8 bytes... that's like the coding equivalent of a horror movie for anything more lengthy than a proof-of-concept tech demo.
Finally, there is the graphical corruption side of the coin, which is another major hassle and one which might require some judicious redesign of important in-game elements; where things could get the most prickly might be raster time concerns in the case of streaming in fresh gfx data to restore corrupted bytes.
But why go to all that trouble?
Remember, the whole point of VSP is to save CPU time (and do away with huge swathes of speedcode in RAM), but if more CPU time and RAM space are consumed by making it safe, it's very raison d'etre vanishes.
Next, a Refined Fix: “VSP Lab”
Interestingly, a short time after releasing his Safe VSP demo, LFT - in a further moment of characteristic ingenuity - proposed another way to deal with VSP that didn't involve cumbersome
firebreaks in the RAM.
That was based around the idea of finding a way to positively influence the timing of the writes to y-scroll in $D011 using “VSP channels”, an esoteric concept described in detail in a lengthy forum exchange on CSDB and backed with a special utility called VSP Lab that tested real C64 hardware to determine where its VSP vulernabilities - where they exist at all - actually lie.
(Inexplicably and inexcusably, the utility was supplied with zero documentation).
LFT was so enthused by this discovery that he proposed using it to patch games and demos that used VSP, although to date I am only aware of such a patch for Mayhem In Monsterland.
But it doesn't circumvent the issue of the the VSP crash vulnerability being a function of time expired from machine switch-on, or more, accurately, a function of the internal operating temperature of the VIC chip plus other components.
To me, that means no automated VSP vulnerability detection routine makes much sense, as it might declare the machine safe or unsafe depending on other external factors, such as the ambient temperature of the room the crash-prone computer is located in, the relative humidity of the air and who knows, the spin of the earth at that latitude!
I know I'm not the only coder who thinks it may be thus and so it has to be viewed with a healthy dose of caution; remember, this vulnerability is the outworking of a complex system (in the physicist's sense of that term), so for that I think there is no truly one-size-fits-all coding remedy.
And sadly, it seems LFT is no longer interested in the matter from what I can observe; nevertheless, his work on the subject is invaluable and if nothing else, reveals the problem in its fullness (as well as LFT's genius).
Best Practice for VSP
So where does that leave VSP for games, going forward?
And for that matter, what does it mean for legacy era games that used it?
For one thing, I believe the negativity and drama surrounding the technique needs to be reined in, as it's unmerited and disproportionate to the issue, “exhibit A” being bumbershoot's well-written but overly alarmist article.
Sure, the VSP crash is a nasty side effect on those very, very few machines vulnerable to it but here are some
- It's as much a wonky hardware issue as a game on tape not loading is, yet there is no clamour to stop using tapes to load games.
- If we're being consistent, the VSP issue renders Creatures, Mayhem, Fred's Back, along with many demos, “dangerous software”, yet nobody in their right mind would call for those titles to be consigned to the dustbin of C64 history.
- As LFT pointed out, the crash is not merely a VSP side effect and can, under some circumstances, be triggered by a badly timed write to $D011's y-scroll, so do we pedantically insist on patching / binning all affected vertically scrolling software too?
- Most of all, it's an outlier side effect, affecting a tiny minority of machines; the onus, therefore, in the absence of Commodore Business Machine's present day existence and accountability, is on the owner of the hardware to either buy an invulnerable machine or seek an after-market hardware fix for what is, one may reasonably argue, a hardware flaw in the affected old machines.
But let's say you're unconvinced by my rationale and have bought into the melodrama surrounding the “forbidden technique”... what then?
Well, it seems that these are your options:
- Deploy VSP but have a “graceful degradation” fallback version for affected machines and / or new tech such as the Mega65*, which can't run VSP.
- Reserve VSP exclusively for digital releases for use on emulators.
- Bin VSP totally and run with other efficient scrolling expedients such as Staggered Screen Scroll “SSS” (limitations: 1. only works at lower scroll speeds, 2. requires staggered gfx design) or unrolled scroll with “fast colour scroll” where the design allows it (as described in my Wild Wood Deconstructed article), or double line crunch scroll.
- Be utterly pedantic and never alter y-scroll under any circumstances, lest you trigger “the bug” on 0.1% of machines!!!!!!
- Accept that your game is going to be very limited / lame, and use the easiest, bloatiest, CPU-hogging spaghetti code you can come up with to scroll your screens.
- Forget about scrolling altogether and design flip-screen games.
* = The MEGA65 documentation on VSP scroll states:
“However, some advanced VIC-II graphics tricks, such as Variable Screen Position (VSP) are highly unlikely to work correctly, due to the uncertainty in timing of the memory write cycles of instructions. However, in most cases such problems can be easily solved by using the advanced features of the MEGA65’s VIC-IV video controller. For example, VSP is unnecessary on the MEGA65, because you can set the screen RAM address to any location in memory”.
You might, if you could justify the effort, make a third version of the game that avails of the MEGA65's stated screen RAM shifting feature.
And while you're at it, you could avail of its myriad of colours, etc., until your game is no longer recognisable as a C64 game at all, but if we go down that route, we may as well start coding for PC and consoles!