I have found a technique used by demosceners that relies on accessing the ULA from a I/O port other than $FE.
This technique is used to get full screen (including borders) graphics and animations. The technique works as follows: let's say you have graphics shown on the screen, the regular way, and you want to superimpose a scrolling text that goes from right to left, from the very right edge of the screen to the very left edge, that is, the text is shown sometimes over the border area, sometimes over the paper area.
Usually, controlled changes in the border colour are accomplished by writing to port $FE at a very precise moment, and controlled changes in paper colour by writing a new attribute value to memory.
But having a text that scrolls over border and paper needs a way to do this as fastest as possible, so the code shouldn't have to test if the ULA is painting the border or the paper, so the code switches to writing to port $FE or writing to memory. That's too many wasted cycles.
Instead, this technique allows for changes to the screen regardless of whether border or paper is being scanned.
The trick uses the two screen buffers present on 128K models. The main screen with the graphic, and the shadow screen, which presents a solid colour filling the entire paper area.
The scrolling text is written by writing to an I/O port at very precise times. For that, a port that triggers both the ULA and the paging hardware is used, such as $7FFC. Writing to this port writes to both the ULA and the 128K paging hardware.
The value written to this port is 0001agrb where:
- a is 0 if we want to show the background image or background border, and 1 if we want to show the scrolled text.
- rgb is the RGB code of the colour we want to show on the border: 000 is used for the background border and any other value corresponding to the colour of the scrolled text. For example, for a white text, it would be 111. The shadow screen is filled with this same colour.
To quickly change from background to scrolled text, the value 00011grb is stored in a register, and it is xored to the accumulator.
So, to start drawing the text, 00011grb is written to port $7FFC. If the ULA is scanning the paper area, this causes the shadow screen to be displayed, and a certain RAM bank to be paged in area $C000-$FFFF (which we won't care about). If the ULA is scanning the border area, this causes the border to be of this colour. The shadow screen will be selected as well, but as the ULA is not drawing the paper area, it won't matter.
To stop drawing text and revert to the background image, 00001000 is written to port $7FFC, which causes the regular screen buffer to be displayed (if the ULA is scanning the paper area) and the border to be black (if it is scanning the border area).
This technique can be observed in the small demo Scroll 2017:
