Skip to main content

ADVANCED  RASTER INTERRUPT PROGRAMMING - OR:  HOW DO I  GET  MORE 
THAN 16 COLORS AT ONCE
 by Udo from TEX

The problem:  To get more than 16 colors at once on the screen at 
once,  you  must change the color palette somewhere somewhere  in 
the screen.  This can be done with Xbios function 6  (setpalette) 
because  this waits for the electron beam to prevent  flickering. 
The  operating  systems waits for the  Vertical  Blank  Interrupt 
before the palette is set.  For example,  we'd have to change the 
color  palette in the middle of the screen to be able to  use  16 
other  colors in the lower half of the screen.  And,  of  course, 
we'd have to put the previous color palette after the VBL so that 
the upper half of the screen uses the first 16 colors  again.  So 
that  the screensplitting is done with each setup of  the  screen 
(50  or  60  times per second) without  the  main  program  being 
harassed with it,  we have to use Interrupt techniques. The Atari 
has  three possibilities therefore:  The Level 2  Interrupt,  the 
Level 4 Interrupt and the Level 6 Interrupt.

All three methods have in common that Level 4 is used to set  the 
upper  color palette and to initialise the data for  the  further 
interrupt procedure.
Installation of a Level 4 interrupt:
     instal4:
     move.l $70,old4+2   ;mark old vector
     move.l #new4,$70    ;set new vector
     rts
This routine has to be executed in supervisor mode (e.g.  by  use 
of Xbios 38, Supexec).

The new Level 4 routine:
     new4:
     ;here are the seperate initialise routine
     old4:
     jmp $000000     ;after old4+2 comes the old interruptvector,
                      so that the interruptroutines from the OS
                      are still being executed

All program examples were written for the SEKA assembler, and can 
be re-written for use with other assemblers without much  trouble 
(a ';' denotes a comment).
Raster Interrupts with Level 2:
This interrupt is usually disabled through interruptmask $0300 of 
the Processor Status Register (sr),  because it is caused by  the 
electron beam going back to the beginning of a line (15625  times 
per  second).  When the interrupt is cleared,  is halts the  main 
program  (the biggest disadvantage of this  method).  For  raster 
programming,  one  installs  a Level 2 routine,  that  makes  the 
variegated screen together with the Level 4 routine:

     instal:             ;should again be executed from
                         ;supervisor mode
     move.l $70,old4+2
     move.l #new4,$70
     move.l $68,old2
     move.l #new2,$68
     rts
     
     wert = 50
     old2: dc.l 0
     zeile: dc.w 0
     pal_o: blk.w 16,0
     pal_u: blk.w 16,0
     new4:
     movem.l d0-d7/a0-a1,-(sp)
     move.w #wert,zeile       ;set in which line the palette
                              ;should be switched
     move.l #pal_o,a0         ;upper palette
     move.l #$ff8240,a1       ;palette register
     movem.l (a0),d0-d7       ;load colors in registers
     movem.l d0-d7,(a1)       ;set colors
     movem.l (sp)+,d0-d7/a0-a1
     old4:
     jmp  $00000

     new2:
     move.l d0,-(sp)
     move.w zeile,d0
     subq.w #1,d0             ;decrease counter
     move.w d0,zeile
     bne    no2               ;not yet zero, then nothing

     movem.l d1-d7/a0-a1,-(sp)
     move.l  #pal_u,a0        ;palette below
     move.l  #$ff8240,a1      ;palette registers
     movem.l (a0),d0-d7       ;load colors in registers
     movem.l d0-d7,(a1)       ;set colors
     movem.l (sp)+,d1-d7/a0-a1

     no2:
     move.l  (sp)+,d0
     rte

To switch off the interrupt,  you have to put back the old values 
of the vectors back to $68 and $70.
The disadvantage of this method is that both the level 6 and  the 
level  2 interrupt have priority above the level 2 interrupt  and 
thus  can block it or even interrupt it.  This causes the  colors 
not to be switched on the same lines all the times, which creates 
a  flickering  effect  (just like in  the  "Gauntlet"  text  when 
there's  no  titles  music  to be  heard).  When  you  block  the 
interrupt level 6,  you cannot use the mouse or the keyboard, and 
you can't even perform disk operations!

Raster Interrupts with Level 4:
Because  you  can  create  stable  raster  interrupts  with  this 
technique that,  however,  take up such a lot of time so that the 
main  program almost stops completely (and the level 6  interrupt 
has  to  be blocker as well),  I would just like to  mention  the 
possibility  of this method but not explaining it in more  detail 
(I have discovered this possibility in the 42-Crew demo):
After  the  switch-off  of the level 6  interrupt,  the  level  4 
routine is modified in such a way that it reads memory  locations 
$ff8205/6/7  after  being  called.  In  these  locations,  it  is 
possible  to  read  the current position  of  the  Video  Address 
Pointers  (the  address that the video chip momentarily  uses  to 
fetch its screen data from).  It now waits until a certain  value 
is reached. Is it the first value of a line, it is reached at the 
end of the preceding line and the colors can be changed while the 
electron beam is going back to the beginning of the next line. If 
the colors in line 180 should be changed, the program has to wait 
until  this  line is reached,  which takes 90% of  the  available 
time!

Raster Interrupts with Level 6:
The Level 6 Interrupt is controlled by a peripheral chip that can 
recognise  16  different  interrupts  and  gives  these  to   the 
processor as a Level 6 interrupt. In the Atari, the following are 
used: RS232, Keyboard, Centronics busy, monochrome monitor detect 
and  Timer  C (one of 4 timers).  Timer B can  now  count  screen 
lines,  where  the difference with the Level 2 interrupt lies  in 
the  fact  that  only  the screen  lines  are  counted  that  are 
displayed and not the number of times the electron beam goes back 
to the beginning of a line!  Because of this fact, one cannot use 
stable rasters in the border (in our "Super-Neo-Demo-Show"  there 
is no lower border for the video chip).
But now for practical proceedings; the installations of the Timer 
B:
     instal6:
     move.l #new6,$120   ;interruptvektor
     or.b   #1,$fffa07   ;enable Timer B
     or.b   #1,$fffa13
     move.l $70,old4+2   ;divert level 4
     move.l #new4,$70
     move.b #0,$fffa1b   ;Timer B stop
     rts
If this routine was called from supervisor mode,  than the 'new6' 
routine waits for the first call.  This is reached when the level 
4 interrupt sets a counter value and thus starts Timer B. Timer B 
then  decreases  that value by one each time an end of  a  screen 
line is reached,  until zero is reached.  When that  happens,  an 
interrupt is executed (if you change the palette only once,  this 
will happen 50 or 60 times per second instead of 15625 times  for 
the level 2 interrupt).
The new level 4 routine:
     new4:
     movem.l d0-d7/a0-a1,-(sp)
     move.b  #0,$fffa1b       ;Timer stop
     move.b  #wert,$fffa21    ;Counter value
     move.b  #8,$fffa1b       ;Timer start
     move.l  #pal_o,a0        ;Upper palette
     move.l  #$ff8240,a1
     movem.l (a0),d0-d7
     movem.l d0-d7,(a1)       ;Set colors
     movem.l (sp)+,d0-d7/a0-a1
     old4:
     jmp     $000000

And the Timer B routine:
     new6:
     movem.l d0/d3-d7/a0-a6,-(sp)
     move.w  #$fa21,a4        ;Takes $fffa21 -> a4
     clr.b   -6(a4)           ;Timer B stop
     move.b  #240,(a4)        ;Pseudo value (see remark 1)
     move.b  #8,-(a4)         ;Timer B start
     move.l  #pal_u,a6        ;Pointer on color palette
     movem.l 2(a6),d4-d7/a0-a2     ;Load colors in registers
     move.w  #$8240,a5
     move.w  30(a6),d3
     move.b  (a4),d0          ;Trick 1! (See remark 2)
     wait:
     cmp.b   (a4),d0
     beq     wait
     movem.l d4-d7/a0-a2,2(a5)     ;Trick 2! (See remark 2)
     move.w  d3,30(a5)
     move.w  (a6),(a5)
     movem.l (sp)+,d0/d3-d7/a0-a6
     bclr    #0,$fffa0f       ;Clear interrupt again
     rte

Remark  1:  In this example,  the color palette is to be  changed 
only once.  That's why a value is written to the counter register 
that is never reached (maximum 200).
Remark  2:  So that really nothing start flickering,  the  colors 
have  to be set in the border and during the time needed for  the 
electron beam to get back to a beginning of a line. The interrupt 
is executed at the beginning of the right border,  but as soon as 
the  processor reaches the actual command to set the  colors  the 
electron  beam  is already too far  to  prevent  flickering.  The 
colors  have  to be set at the beginning of the border -  and  as 
fast as possible (Trick 2 - the movem.l is the fastest).  Trick 1 
reads  the Timer B counter and waits until it changes - in  other 
words,  it waits until the end of a line is reached.  Because  it 
now still waits until the next line, this way is only suitable to 
change the color palette at every second line.

Problematical aspects:
The  MFP  interrupts  are reported to the processor  as  level  6 
interrupts and are not mutually interrupted!
If  system interrupts are still installed,  this can cause  quite 
some problems. To prevent this, there are three possibilities:

1)  One  tolerates  the  flickering and  does  nothing  about  it 
    (absolutely out of the question in our Demos!)
2)  One switches off the hazardous interrupts (like we did in our
    TEX DEMOS 1-3)
3)  One   programs  the interrupts in such a way  that  they  can 
    interrupt  themselves (be careful!) (This is what we  did  in 
    our Super-Neo-Demo-Show)

Remark for 2):  Hazardous are Timer C, that is simply turned off. 
When doing that,  the keyboard repeat as well as the  possibility 
to load with GEMDOS are blocked.  Because keyboard checks through 
GEMDOS are still possible,  the program can still react, turn off 
the  raster  interrupts and turn on the  other  interrupts  again 
before going on with the actual program.

Add  thereto  the  complete  sample  program,  that  rescues  the 
starting values in 'hblon',  sets the raster interrupts and  then 
waits for a key to be pressed.  After pressing 'ESC',  the raster 
interrupt  is switched off and the starting values are set  back. 
The diatance values specify the distances between the current and 
the  previous  raster interrupt.  A number of  additional  raster 
interrupts can be inserted as long as you make sure the  distance 
values are not larger than 199.  Of course, enough color palettes 
have to be present.

Remark to 3):  To create the possibility to load,  it is possible 
to give priority to an interrupt by software. To give priority to 
the  raster interrupt,  for example,  you have to take care  that 
Timer  C can be interrupted.  This can be done the following  way 
(initialising of the other interrupt routines has to be done like 
I explained earlier):

     newtimc:           ;New Timer C routine
     tst.w    flagtc    ;test Timer C flag
     bne      noirq
     move.w   #1,flagtc ;Set flag to prevent second call
     move.w   #$2500,sr
     bclr     #5,$fffa11 ;Clear ISR bit to enable level 6
     move.l   #hier,-(sp) ;To operating system after 'hier:'
     move.w   sr,-(sp)
     jmp      $000000   ;This is where the old Timer C vector
                        ;has to go
     hier:              ;From the OS from here on
     clr.w    flagtc    ;Clear flag
     noirq:
     bclr     #5,$fffa11 ;Interrupt End
     rte

With  this method,  flickering can be  prevented.  The  Operating 
System doesn't like this,  however,  and takes revenge with a lot 
of read errors (depending on computer,  drive and disk,  this can 
vary between 15% and 60%).  This is why our "Super-Neo-Demo-Show" 
keeps on reading until 32128 bytes were able to be read.  Because 
this is not always possible,  I would advise the second method to 
prevent  flickering (Quote:  " luckily there are only few  raster 
interrupts  to manage in  our  game....  movem.l..  swap..  rte.. 
aaarghh...")!

P.S.:  Because  GEM  really  doesn't like  it  when  many  raster 
interrupts  are  present  on  the  screen  (because  of   reasons 
unknown),  the program crashed when moving the mouse. Help: Start 
the  program  as a .TOS file or send a command  to  the  keyboard 
processor ($12 = Turn off the mouse).  Who knows exactly why .PRG 
files crash,  should please write to us on the address  mentioned 
below:

For  questions  and support you can also contact us  through  the 
following address:

               -TEX-
               Postfach 1322
               D-6702 Bad Dürkheim 1
               West Germany

Have fun while trying the routines!

                                   Udo (TEX)

Disclaimer
The text of the articles is identical to the originals like they appeared in old ST NEWS issues. Please take into consideration that the author(s) was (were) a lot younger and less responsible back then. So bad jokes, bad English, youthful arrogance, insults, bravura, over-crediting and tastelessness should be taken with at least a grain of salt. Any contact and/or payment information, as well as deadlines/release dates of any kind should be regarded as outdated. Due to the fact that these pages are not actually contained in an Atari executable here, references to scroll texts, featured demo screens and hidden articles may also be irrelevant.