Classic Computer Magazine Archive ANTIC VOL. 3, NO. 2 / JUNE 1984

Color Finetuner

By Stephen Malinowski

This article presents an assembly-language program, with a Basic loader, which lets you change the contents of the color registers - even when a program is running. The BASIC version requires BASIC, and the program requires 16K. To use with XL machines, run the Translator program first.

Color Finetuner is a program that gives you direct control of the Atari's nine color registers, even when other programs are running. You can also use it to change GPRIOR, the register that selects the GTIA mode.

How To Install Color Finetuner

The simplest way to install this utility is to enter and RUN the program listing at the end of this article. The program is installed on Page Six (starting at decimal location 1536); it causes the deferred vertical-blank (VB) vector to point to the routine.

If you need to use Page Six for your own purposes, add the lines in Listing 2. Modify line 100 to correspond to the graphics mode you'll be using in your own program. As a result, Color Finetuner will place the routine in high memory, just below the display list used by your application. It will also set HIMEM to protect the routine from BASIC. If you change graphics modes, however, the routine will no longer be protected, and it may be overwritten.

For Advanced Programmers

Color Finetuner also can be used along with your own vertical-blank-interrupt routines. If your routines use only the immediate vector, the program can be used as is. If, however, your routines use the deferred vector or replace the OS VBI service routine entirely, the end of your routine should perform a jump to ORIGIN, as calculated in line 210. (You shouldn't jump to INSTAL, which is used only by the BASIC USR function.) Color Finetuner concludes with a jump to XITVBV

How To Use The Routine

Once Color Finetuner is installed, type Listing 3 and RUN it. The program draws lines in Graphics 10 using all nine color registers (including the background), but you won't see some of the lines at first.

To change any color register, first select the register by pressing the corresponding number key:

                 DECIMAL    HEX
0         PCOLRO    704      2CO
1         PCOLRL    705      2Cl
2         PCOLR2    706      2C2
3         PCOLR3    707      2C3
4         COLORO    708      2C4
5         COLOR1    709      2C5
6         COLOR2    710      2C6 (background
                                  color in GR. 0)
7         COLOR3    711      2C7
8         COLOR4    712      2C8 (border color
                                  in GR. 0)
9         GPRIOR    623      26F
Then use the three console keys to increase or decrease the contents of the register:

OPTION - increases the contents.
SELECT - Fast speed (hold with [START] or [OPTION]).
START - Decreases the contents.

You don't have to hold down the number key. Once you've selected a register, it will be affected by the console keys until you select another register.

Disassembly Of Color Finetuner

This section contains an assembly-language listing of the Color Finetuner routine. The listing is in Atari Assembler Editor syntax and is complete, but line numbers have been deleted for editorial purposes. If you wish to type in the assembly-language program, use the command NUM to provide line numbers.

OS And Hardware Locations Used By Color Finetuner

*=$0600       ; Sets origin to Page Six.
CONSOL=$DOLF    ; Contains the composite output of the
                  console keys.  The following three masks
                  are used to isolate the bit that corresponds
                  with the key:
REVMSK=$OL      ; Mask for [OPTION] key.
FSTMSK=$02      ; Mask for [SELECT] key.
FWDMSK=$04      ; Mask for [START] key.
RTCLK3=$14      ; The byte of the real-time clock, which
                  is incremented every sixtieth of a second
                  (or one jiffy).
KBCODE=$D209    ; The hardware register that contains the
                  raw data for the last key pressed.  It is con-
                  verted to ATASCII form by the table
ATASCI=$FEFE    ; The table used to convert raw keyboard
                  data into ATASCII form.
RANGE=$0A       ; This number, together with TOOHI, is
                  used to convert ATASCII numbers to their
                  actual numerical values, and to check for
                  out-of-range values.
TOOHI=$C6       ; See RANGE.
PRIOR=$DOLB     ; This register controls several aspects
                  of the display.  See De Re Atari (Atari Program
                  Exchange, 1981) for further information.
GPRIOR=$26F     ; The OS shadow for PRIOR.  Its contents
                  are written to PRIOR every sixtieth
                  of a second.
COLPMO=$DO12    ; The first hardware color register.
PCOLRO=$2CO     ; The shadow register for COLPMO.
SETVBV=$E45C	; An OS routine used to set the vectors that
                  are used as access points to the VB service
XITVBV=$E462    ; The last part of the OS VB service
                  routine.  It restores the 6502's registers and
                  returns the processor to whatever it was
                  doing at the time the interrupt occurred.

The Color Finetuner Routine

Every sixtieth of a second, the ANTIC chip generates an interrupt that stops the main activities of the 6502 chip and directs it to the OS vertical-blank service routine. Most of this routine is in ROM, and is not alterable by the user. However, two vectors, or "signposts," are stored in RAM. Color Finetuner (CF) causes one of these vectors to "tie into" the service routine.

The Operating System (OS) has a routine that changes these vectors. The first part of CF calls this routine:

INSTAL  LDA  #$7          7 equals deferred vector.
        LDX #CHECK1/$10   high byte of the main
                          routine location.
        LDY #CHECK1&$FF   low byte of the main
                          routine location.
        JSR SETVBV        sets the vertical-blank
        PLA               pops the stack.
        RTS               returns to BASIC.
Once INSTAL is called from BASIC (with a USR call), the service routine includes CF as part of its "housekeeping" routine every sixtieth of a second.

The first part of the main routine performs a series of checks to determine if CF should change a register. CHECK1 checks for a pressed console key:

CHECK1  LDA  CONSOL     gets console-key-register
        CMP  #$7        is a key pressed?
        BPL  EXIT       no? then exits.
        TAY             yes.? then saves CONSOL
                        value and continues.
CHECK2 controls the speed of the changes. It does this by examining the real-time clock (lowest byte at $14) and checking to see if [SELECT] has been pressed for fast color changes. At fast speed, the registers change every two cycles (one cycle = one sixtieth of a second); the normal speed changes them every sixteen cycles.

CHECK2  LDA  RTCLK3     gets the clock's fastest
        TAX             and saves it.
        AND #$l         is it odd or even?
        BNE EXIT        odd? then exits.
        TYA             even? then gets CONSOL
                        contents again.
        AND #FSTMSK     is fast button pressed?
        BEQ CHECK3      yes? then checks keyboard
        TXA             no? then checks clock
                        byte again.
        AND #$F         is it a multiple of
                        (decimal) 16?
        BNE             no? then exits.
CHECK3 determines if a valid keyboard key has been pressed (0 through 9 only). Since KBCODE contains the raw keyboard code, not ATASCII code, we need to convert the raw code using the ATASCI table.

CHECK3  LDX  KBCODE     gets-the last key pressed.
        LDA  ATASCI,X   looks it up in the table.
        CLC             gets ready to add.
        ADC  #TOOHI     is it high enough to be a
                        decimal digit?
        BCS  EXIT       yes? then exits.
        ADC  #RANGE     is it too low?
        BCC  EXIT       yes? then exits.
        TAX             just right? saves the
                        converted digit.
Now we're ready to change the color registers. There are actually two registers involved: the hardware register and its shadow register. If we were to write only to the hardware register, the change would last just a sixtieth of a second, because the OS copies the shadow registers to the hardware registers as part of the VB service routine.

Normally, it would be feasible to change only the shadow registers, and let the OS copy the color data to the hardware registers. However, since CF may be used in situations in which that part of the service routine is bypassed, we must write the color data to both locations.

PRIOR, the priority register, immediately follows the last hardware color register, so it can be treated as a tenth register. Its shadow GPRIOR does not immediately follow the color shadow registers, however, so it must be handled separately.

FORWRD TYA           gets CONSOL contents
       AND #FWDMSK   is the FORWARD button
       BNE REVERSE   no? then checks reverse.
       TXA           yes? gets keyboard digit.
       CMP #$9       is it equal to 9 (i.e.,
       BNE FCOLOR    no? then it must be a col-
                     or register.
       INC GPRIOR    yes? then increments
       LDA GPRIOR    gets the incremented
       BCS HARD      and writes it to hardware
FCOLOR INC PCOLRO,X  increments the color
       LDA PCOLORO,X gets incremented value
       BCC.HARD      and writes it to hardware
REVRSE TYA           gets CONSOL contents
       AND #REVMSK   is REVERSE button
       BNE EXIT      no? then exits.
       TXA           yes? then gets keyboard
       CMP #$9       is it equal to 9 (i.e.,
       BNE RCOLOR    no? then it must be a
                     color register.
       DEC GPRIOR    yes? then decrements
       LDA GPRIOR    gets decremented value,
       BCS HARD      and writes to hardware
RCOLOR DEC PCOLRO,X  decrements color register,
       LDA PCOLRO,X  and writes it to hardware
HARD   STA COLPMO,X  writes new value to
                     hardware register.
EXIT   JMP XITVBV    exits through vertical-
                     blank vector.
Stephen Malinowski is a free-lance musician and composer who lives in the San Francisco Bay Area. He is currently using his Atari to develop a music-animation machine that will provide visual counterparts to musical sounds.

Listing 1

97 REM * ANTIC MAGAZINE         *
100 INSTAL=1536
200 ? "Takes a couple of seconds to in
220 F0R X=0 T0 107
240 NEXT X
1000 DATA 169,7,162,6,160,11
1010 DATA 32,92,228,104,96,173
1020 DATA 31,208,201,7,16,87
1030 DATA 168,165,20,170,41,1
1040 DATA 208,79,152,41,2,240
1050 DATA 5,138,41,15,208,69
1060 DATA 174,9,210,189,254,254
1070 DATA 24,105,198,176,58,105
1080 DATA 10,144,54,170,152,41
1090 DATA 4,208,21,138,201,9
1100 DATA 208,8,238,111,2,173
1110 DATA 111,2,176,32,254,192
1120 DATA 2,189,192,2,144,24
1130 DATA 152,41,1,208,22,138
1140 DATA 201,9,208,8,206,111
1150 DATA 2,173,111,2,176,6
1160 DATA 222,192,2,189,192,2
1170 DATA 157,18,208,76,98,228

Listing 2

110 HIMEM=PEEK(741)+256*PEEK(742)
130 HI=INT(INSTAL/256)
140 LO=INSTAL-(HI*256)
160 POKE 741,LO:POKE 742,HI
250 HI=INT(ORIGIN/256)
260 LO=ORIGIN-(HI*256)

Listing 3

20 FOR X=l TO 32 STEP 4
30 COLOR (X-1)/4+1
40 PL0T X,0
50 DRAWTO X,190
60 PLOT X+1,0
70 DRAWTO X+1,190
95 GOTO 95
Listing 1: FINETUN1.BAS Download

Listing 2: FINETUN2.BAS Download

Listing 3: FINETUN3.BAS Download