15

The Apple II hi-res screen sits on 8KB of memory, so it should be possible to erase it quickly. The Applesoft HGR command is slow enough that the "Venetian blind" erasure is clearly visible. Clearing the screen to a color with CALL 62454 feels even slower. Why is this?

23

If you look at the screen clear code in the Applesoft BASIC ROM, you'll find this:

f3f6    lda $e6        ;put base address of current hi-res page
        sta $1b        ; into $1a/1b (will be $2000 or $4000)
        ldy #$00
        sty $1a
f3fe    lda $1c        ;get color value
        sta ($1a),y    ;store it in frame buffer
        jsr $f47e      ;update color value
        iny            ;advance, looping...
        bne $f3fe
        inc $1b
        lda $1b
        and #$1f
        bne $f3fe      ;...until we get to $4000/$6000
        rts

f47e    asl            ;lose the hi bit, now $00/$fe for black/white,
        cmp #$c0       ; or $54/$aa for green/purple/orange/blue
        bpl $f489      ;branch if black or white
        lda $1c
        eor #$7f       ;invert color bits for odd/even
        sta $1c
f489    rts

This is a ROM routine, so size is at a premium, and self-modifying code is not allowed. It's optimized for space, not speed.

The most significant impact of this optimization choice is the code at $f47e, which tests the color value and potentially updates it for every byte. This code is necessary because of the rather strange hi-res graphics layout, which (among other oddities) represents an odd number of pixels with each byte. So while a solid black line is 00 00 00 00 ..., a solid green line is 2a 55 2a 55 .... The high bit doesn't change, hence the exclusive-OR with $7f. (The code at $f47e is shared with other routines, e.g. the line-drawing code, that must update the color when moving across the screen.)

The total time required to erase the screen to black is 271,121 cycles. Clearing to green would require 328,465 cycles.

The fastest possible screen clear would write a byte to 7680 addresses -- it's not 8192 because we don't need to overwrite the "screen holes". On a 6502, that requires 4 cycles per byte, or about 30720 cycles. The code to do that would fill about half of available RAM on an Apple II though.

A 192-byte unrolled loop can do it in about 39480 cycles. That's ~5x the code, for ~8x the speed.

While these approaches are faster, they still have the "Venetian blind" look. While that's something of an Apple II hallmark, not everyone wants that, and it may not be possible to simply show page 2 while you're erasing page 1. In a mere 127 bytes, for ~41,300 cycles you can erase the screen from right to left, using a clever function written by John Brooks.

  • As an addendum -- the screen holes are not only not used for pixel data, but they aren't just unused, either. Memory was at such a premium back then that these bytes sitting there unused was unthinkable. So they're used to store working data for the I/O cards and the ROM. – Eric Shepherd May 4 '16 at 3:09
  • @EricShepherd: I think that's only the holes in the page 1 text screen. AFAIK nothing in the ROM, DOS, or ProDOS relies on the hi-res holes. – fadden May 4 '16 at 5:30
  • Yeah, only page 1 text screen screen holes are used. And the //c uses some in the aux page 1 text screen too! Here's a decent list. – Nick Westgate May 5 '16 at 9:29
  • Gah! Yes, my brain went sideways and started thinking text mode. Sorry :) – Eric Shepherd May 9 '16 at 21:18
  • I wonder if anyone considered processing even and odd bytes separately [using the same loop, with $1A equal to 1 on the first pass and 0 on the second]? That would reduce the cost per byte to 6+2+2+3=13--a pretty major speed-up. – supercat May 9 '16 at 22:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.