Page flipping is possible in high resolution graphics modes on the Color Computer 3 but there are a couple of caveats. First, the type of drawing and how much drawing your perform will certainly affect performance due to how the BASIC interpreter works. The second problem you may face is that it requires 512k since BASIC uses 32k when the ROM is copied into RAM and patched, 32k for BASIC programs, and 32k for housekeeping and extra data like HGET and HPUT buffers which leaves only 32k for a single 320x192 16 color screen.
In order to achieve page flipping you will need to manage the active and display pages yourself as there are no facilities provided by BASIC to do this. There only one region of memory that you will need to access in order to accomplish this - the MMU.
The memory you need to access contains the memory mapped MMU registers located from $FFA0
to $FFAF
. The Color Computer 3 divides this region into two logical MMU regions colloquially known as Task 0 ($FFA0
to $FFA7
) and Task 1 ($FFA8
to $FFAF
). Note that only one Task can be active at a time. Each register in a MMU task maps in an 8k block of memory with the first MMU register of a Task block controlling memory from $0000
to $1FFF
all the way to the last register of the Task controlling $E000
to $FFFF
.
This is important because the implementation of BASIC in the Color Computer 3 uses Task 0 to map in the memory for BASIC programs and the ROM (which is copied to RAM on startup). It uses Task 1 to map in the graphics screen in order to perform drawing. This is where we will be working in order to achieve page flipping.
When BASIC switches from Task 0 to Task 1 to perform rendering it expects the frame buffer to be mapped into memory from $2000
to $9FFF
. It does this by initializing 4 registers in MMU Task 1 from $FFA9
to $FFAC
. This initialization is performed in a few places such as BASIC's HSCREEN
command so it is important to be mindful of using commands like this when drawing.
To achieve page flipping we simply change the MMU registers in Task 1 to use the region of memory we want for our frame buffer, perform all drawing, then set the video offset registers at $FF9D
and $FF9E
to display our frame buffer.
For our example we are going to use the first 64K of the 512K memory and create two routines in BASIC to map in each of the frame buffers for drawing. To map in the first page we POKE
values 0
, 1
, 2
, and 3
into the Task 1 registers from $FFA9
to $FFAC
respectively.
100 REM MAP IN PAGE 0 FOR DRAWING
101 POKE&HFFA9,0
102 POKE&HFFAA,1
103 POKE&HFFAB,2
104 POKE&HFFAC,3
105 RETURN
This will map in physical memory $00000
to $07FFF
for drawing by BASIC. To map in the second frame buffer we do the same thing but with values 4
, 5
, 6
, and 7
.
110 REM MAP IN PAGE 1 FOR DRAWING
111 POKE&HFFA9,4
112 POKE&HFFAA,5
113 POKE&HFFAB,6
114 POKE&HFFAC,7
115 RETURN
This will map in physical memory $08000
to $0FFFF
for drawing by BASIC. Now we need to be able to display each page and for that we POKE
in specific values into the high byte of the video offset register at $FF9D
. Keep in mind that the video offset register is 16 bits ($FF9D
and $FF9E
) and allows you to view all 512k of memory at 8 byte intervals. This means that to convert the physical address to the values that needs to be POKE
d into the registers you just divide the address by 8. So for frame buffer 0 the value will be $0000
and for frame buffer 1 the value will be $1000
. Since the least significant byte of each value of $00
we don't need to do anything with the register at $FF9E
.
200 REM DISPLAY PAGE 0
201 POKE&HFF9D,0:RETURN
210 REM DISPLAY PAGE 1
211 POKE&HFF9D,&H10:RETURN
Now to put this all together we'll create a simple program to enable the 320x192 16 color video mode and animate a line being drawn at an angle using HCLS
and HLINE
along with our page flipping code.
0 POKE65497,0:HSCREEN2
1 FOR I=0 TO 319:PAGE=I AND 1
2 IF PAGE <> 0 THEN GOSUB 100 ELSE GOSUB 110
3 HCLS:HLINE(I,0)-(319-I,191),PSET
4 IF PAGE <> 0 THEN GOSUB 201 ELSE GOSUB 211
5 NEXT I:GOTO1
100 REM MAP IN PAGE 0 FOR DRAWING
101 POKE&HFFA9,0
102 POKE&HFFAA,1
103 POKE&HFFAB,2
104 POKE&HFFAC,3
105 RETURN
110 REM MAP IN PAGE 1 FOR DRAWING
111 POKE&HFFA9,4
112 POKE&HFFAA,5
113 POKE&HFFAB,6
114 POKE&HFFAC,7
115 RETURN
200 REM DISPLAY PAGE 0
201 POKE&HFF9D,0:Return
210 REM DISPLAY PAGE 1
211 POKE&HFF9D,&H10:RETURN
This is of course very slow since we are erasing the entire screen (32k) on each flip. On the plus side you don't actually see the screen being erased and redrawn each frame, just the end result. Keep in mind that there is no way to sync with the vertical refresh from BASIC, even with peeks and pokes, so if you end up needing that you may have to drop to assembly language.