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.