4 ms·
I still remember a hack that I figured out on the Commodore 128 to speed up the 80 column display. I'm not aware of any program that actually made use of it (pr
by pflanze 13y ago
I still remember a hack that I figured out on the Commodore 128 to speed up the 80 column display. I'm not aware of any program that actually made use of it (probably because the C128 and its 80 column display did not have a big enough user base to make it worthwhile to develop programs that needed speedy output).
The C128 had two separate video chips/ports, a C64 compatible chip showing a 40x25 character (320x200 pixel) display, and the "VDC"[1] showing 80x25 characters (640x200, or with interlacing, 640x400 or more), which was output on a separate connector. The VDC had a hideous way to change the display: it had its own video RAM, which the CPU couldn't access directly, instead the video chip had two internal registers (low and high byte) to store the address you wanted to access, and another register to read or write the value at that address. But that wasn't enough, the CPU couldn't access those VDC registers directly either, there was a second indirection on top: the CPU could only access two 2nd-level registers, one in which to store the number of the 'real' register you wanted to access, then you had to poll until the VDC would indicate that it's ready to receive the new value, and you would save the new value for the hidden register in the other 2nd level register. (There's assemply on [1] describing that 2nd level.) Those two registers were the only way of interaction between the CPU and the 80 column display.
[1] http://en.wikipedia.org/wiki/MOS_Technology_VDC http://en.wikipedia.org/wiki/MOS_Technology_VDC
This was extremely slow. Not only because of the amount of instructions, but the VDC would often be slow to issue the readyness flag, thus the CPU would be wasting cycles in a tight loop waiting for the OK.
Now my discovery was that the VDC didn't always react slowly, it had times when the readyness bit would be set on the next CPU cycle. Unsurprisingly, the quick reaction times were during the vertical blanking period (when the ray would travel to the top of the screen, and nothing was displayed). During that time, there wasn't even a need to poll for the VDC's readyness, you could simply feed values to the 2nd level interface as fast as the CPU would allow, without any verification. Thus if you would do your updates to the screen during the vertical screen blank, you would achieve a lot more (more than a magnitude faster, IIRC), and the "impossibly slow" video would actually come into a speed range that might have made it interesting for some kinds of video games. Still too slow to do any real-time hires graphics, and the VDC didn't have any sprites, but it had powerful character based features and quite much internal RAM, plus blitting capabilities, so with enough creativity you might have been able to get away by changing the bitmaps representing selected characters to imitate sprites. And you could run the CPU in its 2 Mhz mode all the time (unlike when using the 40 column video, where you would have to turn it down to 1 Mhz to not interfere with the video chip accessing RAM in parallel, at least during that chip's non-screenblank periods.) My code probably looked something like:
lda #$12 ; VDC Address High Byte register
sta $d600 ; write to control register
lda #$10 ; address hi byte
sta $d601 ; store
ldx #$13 ; VDC Address Low Byte register
ldy #$00 ; address lo byte
loop
cycles
stx $d600 ; select address low byte register 4
sty $d601 ; update address low byte 4
lda #$1f ; VDC Data Register 3 ?
sta $d600 4
lda base,y ; load value from CPU RAM 4 ?
sta $d601 ; store in VDC RAM 4
iny 2
bne loop ; or do some loop unrolling 3 ?
..
(28 cycles per byte, at 2 Mhz, => about 300-400 bytes per frame. Although the C128 could remap the zero page, too (to any page?), and definitely relocate the stack to any page, thus there are a couple ways to optimize this. (Hm, was there also a mode that had the VDC auto-increment the address pointer? Thus pushing data to $d601 repeatedly would be all that was needed? I can't remember.))
How would you time your screen updates to the vertical blanking period? There was no way for the VDC to deliver interrupts. It did however have a register that returned the vertical ray position. Also, the C128 had a separate IC holding timers. Thus IIRC I wrote code to reprogram the timer on every frame with updated timing calculations, so that I got an interrupt right when the VDC would enter the vertical blanking area.
As I said, I'm not aware of any production level program that used this; perhaps some did, but at least the behaviour was not documented in the manuals I had.
The VDC felt even more like a waste after I discovered this. The only use I had for it was using some text editor. I wasn't up to writing big programs at the time, either.
PS. sorry if that was a bit long.
- transitionality 13y agoThis is the kind of genius I come to this site for. Thank you.