Beamhacking: Blanking

By now I've pretty much laid out all that one needs to create high resolution TRS-80 Model 3 graphics. However, one important topic has only been mentioned in passing. A little thing I refer to as blanking or what happens when the both the video circuitry and the Z-80 wish to access video memory at the same time. Blanking will definitely be an issue for any serious beam synced program. It is not always a bad thing.

Before talking about what to do or not do about it, let me back up a little. Why does blanking happen at all? The Z-80 and the video want to access video memory at the same time, so what? A fair question. It all comes down to having only one path (or bus) to video memory which the two must share. The path can only be used by one thing at a time. Thus something must be done when both the Z-80 and video need it. The Model 3 offers the programmer two ways to resolve the conflict.

One way is to behave like the Model 1 and let the Z-80 win — it gets to read (or write) the video memory. The video itself? Well, it's not like it was asking after the data for no reason. In fact it's nanoseconds away from drawing that data on screen. There is no time to try again so rather than draw random data the TRS-80 designers decided to have the video processor draw black for the next 8 dots. I think of this mode as "blanking on" and it is enabled by turning off bit 5 of port 236. The current settings of other bits on port 236 can be read from port 255. Here's a code fragment to turn on blanking.

        in      a,(255)
        and     a,0dfh
        out     (236),a

The other way is to let the video processor win and tell the Z-80 to wait. This works out pretty well as the Z-80 only loses time and not functionality if the data isn't ready for it right away. The BASIC ROM sets up the hardware with blanking off and you can do so by setting bit 5 or port 236.

        in      a,(255)
        or      a,20h
        out     (236),a

Surprisingly, this does not eliminate blanking. You may have noticed this with programs that scrolll a graphics screen rapidly or are otherwise constantly updating the display. A few of the leftmost character columns do not get displayed or flash because the Z-80 has managed to take away video memory access for a few characters. Although the Z-80 has to wait, there's nothing the video circuity can do if the Z-80 is already accessing video memory. In this case the Z-80 has accessed video memory near the end of the horizontal blank interval. That's OK as the video circuitry doesn't need to read the screen at the time. But a Z-80 memory access takes a long time by video standards: at least 3 T-states which is 15 dots. Thus the memory is still busy when the next line starts, the video circuitry is told to wait and blanking results.

Once the video circuitry gets access to video memory and starts drawing a line the Z-80 is locked out until the end of the line. Recall that we used this fact to get in sync with the video beam. However, the video memory does sometimes relinquish control during the visible display area. Characters are 12 lines high but only graphics characters (128 - 191) use all 12 lines. The rest come from a character ROM and only use the top 8 lines, the rest are hard-coded to be black (all zeros). The video circuit lets the Z-80 access memory freely whenever it is drawing the last 4 lines of a non-graphic character. Well, almost freely. There is still a tiny window during the time it takes it to read the memory to determine that there's no need to keep the Z-80 at bay. My emulator doesn't yet support this carry-over blanking, but here's an example captured from a real Model 3.

Notice the horizontal blank carry-over of about 3 characters on the left. Then the video gets control but releases it when the last 4 lines of the B's are being displayed. The blanking continues up until a certain point where the video gets a chance to take over again.

One thing to keep in mind is that video memory conflicts are not about the Z-80 and the video circuitry reading the same memory location. Even if the Z-80 is accessing the top left of the screen and the video ciruitry needs the bottom right there will still be a conflict if they happen at the same time.

Coping with blanking

By and large you'll want to work with blanking turned on. It makes the cycle counting much easier. And it's the only mode fully supported by my emulator. I find developing software with the emulator far easier than using the real hardware. Thus you'll have to somehow deal with the black strips that happen every time you access video memory.

For simple effects you can avoid the problem entirely by doing all the work in the horizontal blank. That's exactly what I did in my various star field demos. With only a couple bytes changing per scan line it can easily be done during the brief horizontal blank.

Otherwise it is a matter of timing and using black backgrounds. Take a look at Doubled Dancing Demon and you'll quickly realize there's no way to have him dance on anything but a black background. There are too many video writes per scan line to hide. Even adding a border around the screen is a difficult proposition.

Learning to love blanking

Blanking is not without its benefits. The black strips it generates can be used to cover up areas of the screen that would otherwise be white. If you run Z-80 code in the screen memory it can even blank out entire scan lines. Or even the whole screen as this program demonstrates.

        org     32000
start:  di
; White-out screen.
        ld      hl,15360
        ld      de,15360+1
        ld      bc,1024-1
        ld      (hl),191
; Wait for a key to be pressed
nokey:  ld      a,(38ffh)
        or      a
        jr      z,nokey
; Turn off video waits
        in      a,(255)
        and     a,0dfh
        out     (236),a
; Load up video blanking program and call it
        ld      hl,(looper)
        ld      (15360),hl
        ld      a,(looper+2)
        ld      (15362),a
; Never returns, but the screen will be black.  Ta-da.
looper: jp      15360
        end     start

The screen will clear all white and wait for you to press a key. It then jumps into a blanking program which steals every memory access from the video circuitry. The screen will go black even though most of the video memory still contains white blocks. Press and hold the orange reset button to see that the screen itself has not changed. Note that if a jr relative jump was used for the on-screen infinite loop the screen would not be completely blanked out.

My Apple ][ bload simulator uses this ability to blank on a per-scanline basis to carve up the display. It is also the key to the 128 x 192 graphics demo. Both marquee lights and blitz use the effect for parts of their display.

Have we now covered every hidden aspect of the TRS-80 Model 3 video display? My heavens, no. There are still mysteries whose depths have not been plumbed.

George Phillips, August 10, 2009, gp2000 -at-