First post, by clb
Heya,
in an earlier thread Why does Commander Keen 4-6 hardware scrolling glitch on ATI (Mach) PCI video cards? we touched a bit on the topic of the SVGA Compatibility option in Keen 4-6 games, and I wrote
[..], when Carmack said in Lex Fridman's interview that Fabien quotes:
John Carmack: "On some of those cards there was a weird compatibility quirk again because nobody thought this was what it was designed to do"
[..] When IBM increased the memory size from CGA to EGA, they had specifically added new registers to control whether the address space should wrap or extend (Register 3D4h/17h bit 5, Address Wrap Select) - they knew all about this type of behavior potentially becoming an issue in the future. My impression is strongly that it was not at all that "nobody thought this was what it was designed to do", but it was "everyone thought this was what it was designed to do". From the selection of SVGA cards that I have, it looks more like the vast majority of early >256KB adapters that shipped got the wraparound right from the first go (and added similar wrap address beyond 256KB mark extension registers), it was only few, e.g. Tseng and S3 in their first Vision cards that dropped the ball here."
First off, let me correct myself. It was not an early S3 Vision card that I had observed to also exhibit this issue, I misremembered which card I had tested. Instead it was an early Miro Video 12PD v1.02 Alliance ProMotion 3210 card that had the issue on addition to the Tsengs (and a later ProMotion 6410 no longer did). I rechecked to be 100% sure, and I'll post actually verified info in a comment below. Thanks to @wbc for asking me to double check so I didn't slip misinfo in. That would have been bad.
Anyhow, I thought it would be interesting to splice this topic from the above thread into this dedicated thread, to try to collect together which different SVGA cards actually do have this "256KB address space doesn't-wrap" bug. It is super well known and documented that Tsengs had this, but beyond that, I had never heard of any other manufacturer having done the same bug (until recently when testing SVGA cards for CRT Terminator Digital VGA Feature Card ISA DV1000 ).
What is this bug about again? Well, in the original EGA and VGA cards, the address space consists of 16-bit addresses containing 32-bit words, for total of 256KB of VRAM. (Although EGA cards could come with as little as 64KB, and the address space would still only wrap at 256KB, leaving up to 192KB "hollow")
Likewise, there is a 16-bit Display Start Address register on the card, that specifies the scanout starting address for the top-left pixel for when the card pushes pixels out to the CRT. If this register is programmed to a too high value, e.g. starting address value 49537 or higher when in 320x200 mode 0Dh or 13h, then the memory address scanout counter (again a 16-bit register) will eventually exceed the 16-bit address space, and naturally as a 16-bit register it will wrap around, since FFFFh+1 == 0000h.
This works out super well together with Intel's segmented memory in real mode, where with far pointers the offset part as a 16-bit register also naturally wraps around in the same manner. One way to think about it is that it effectively lets one pretend that there is a "virtual" address space that is infinitely long, as long as one ever only uses less than 256KB of it contiguously. So one could play with a single offset register in the A000h segment, and keep on scrolling.
This wraparound was super convenient since it allows one do smooth horizontal and vertical scrolling without ever needing to fully repaint the whole display within a single frame. Recall, 8086/286/386s struggled with pixel bandwidth to paint full video frames every frame, which is why many games back in the day were also utilizing "repaint stacks", where on each frame, one would not redraw everything, but instead the changed contents of the previous frame would be erased in the reverse order that they had been drawn in during the previous frame. (sometimes with crazy quadtree, bsp or binning based mechanisms used to detect pairs of overlaps the quickest)
Hardware EGA/VGA scrolling was no black magic, and one of those things that is somewhat simple to reason about and straightforward to program after learning it, but certainly can make one feel smart if independently discovering it. (certainly if being the first to ship a commercial game with it 😀 )
So some manufacturers, when they added more than 256KB of VRAM to their cards, just extended the scanout pixel address register on the card from 16-bits to more, without regarding that it was very useful and utilized functionality to let the address space wrap around. So on those cards, the wrap around would no longer occur, as FFFFh + 1 = 10000h, scanning memory above the 256 KB mark onto the display, while the game would have expected it to go back to address zero, and wrote its pixels starting at A000:0000h.
In Keen 4-6 games, if you run them on an affected card, you will get these types of glitches almost immediately after playing:
Keen 4 on Tseng ET 4000
and to remedy, you'll need to enable the "SVGA Compatibility" option in the menu:
which causes Keen to repaint the whole video memory when necessary to relocate the video starting address.
So, the topic goes: which SVGA cards can we find that have this "address-space-doesn't-wrap-at-256KB" issue?
To test, you can download Keen 4 Shareware from https://keenwiki.shikadi.net/wiki/Keen_4_Versions . Any EGA version will do, but the last v1.4 is recommended.
Or alternatively, you can download SCROLL.EXE test from https://github.com/juj/crt_terminator/blob/ma … /bin/SCROLL.zip , which gives a few different options for testing other types of scrolling synchronization behavior.
If you find a card that is not yet mentioned here, please add info about it.
------------------------
Btw, last note: In Lex Fridman's interview, Carmack had also said:
I took the easy solution of when you finally did run to the edge of the screen I accepted a hitch and just copied the whole screen up.
Even with this Tseng wraparound issue, one does not necessarily need to submit to having to repaint the whole display in a single frame and get a stutter, but the manual wrap can be maintained incrementally as well. This can be achieved conceptually by reserving the topmost 320*200 pixels of VRAM (in reality a few pixels of guardband wider) to be identical to the 320*200 bottommost pixels, which enables one to reset the start address at the 256KB-320*200 address mark back to zero. So when the current starting address is high enough, the fast incremental sprite/background repaint loop can be run twice, once for the current address at high mark, and a second time to the shadowed copy at the low address mark, and never need to hitch.