Task: Learn about Vertical Blank Interrupts in BASIC for Atari 8-Bit Computers
Needed: Altirra emulator
Time: 30-60 mins
One of the frustrating aspects of programming in BASIC on Atari 8-bit computers is its speed. This particularly true for moving players through memory as part of player-missile graphics. I have previously covered the implementation of player-missile graphics in BASIC by calling assembly language routines for doing fast player movement. The execution of the player movement routines is usually done during the vertical blank when the ANTIC chip is done drawing the screen. The time between when drawing the screen has finished and when the drawing the next screen begins provides some computing cycles to execute machine code. Further, since the screen is drawn 60 times per second, whatever code is executed during the vertical blank happens faster than the eye can see. I describe here the basics of executing assembly code from BASIC during the vertical blank. Implementation is fairly straightforward.
Pages 74-76 of De Re Atari (pages 8-16 to 8-18 in the paper version) provide a good description of how the operating system uses the vertical blank for housekeeping duties and how the process can be interrupted to run some assembly language code. The figure below provides a simplified overview of the vertical blank interrupt (VBI) process.
As shown in the figure above, there are two opportunities to interrupt the VB and run some assembly code. The first is called the immediate interrupt which is limited to just 2000 machine cycles. The second is called the deferred interrupt which has 20,000 cycles. This longer interrupt period is more commonly used and will be the focus of this post. The following are the simple steps to follow to implement a deferred VBI.
First, you need place your assembly code in a memory location to be specified in the VBI code described next. Page 6 (starting at memory location 6*256=1536) of memory is a good place to store this code. The key is to end the code with a jump or JMP to location XITVBL (58466 or 228 high byte and 98 low byte) and an RTS. This sends the OS to the end of the pipeline shown above. Note that the JMP needs to be to SYSVBV (58463 or 228 high byte and 95 low byte) as shown in the figure above for executing an immediate VBI (see below for how to set this up). The simple code shown below (Program) writes the number 9 to memory location 203. The PHA at the beginning pushes the accumulator onto the stack for safe keeping. We return it later using PLA. We need the RTS in this one to get back to BASIC.
Second, you need to initialize the VBI with some simple assembly code that loads the accumulator (LDA) with a 7 indicating a deferred VBI (a 6 is used for an immediate VBI), loads the X register with the high byte of the memory address where the assembly program you want to execute resides (e.g. 6 for page 6 of memory), and loads the Y registers with the low byte of your assembly code to be executed (e.g. 0 for beginning of page 6 of memory). This VBI initialization code is then finished with a jump or JMP to location SETVBV (58460 or 228 high byte and 92 low byte) which reads the registers and sets up the VBI once executed. No RTS is needed here. This is shown in the VBI initialization assembly code below. The PLA is needed when executing from BASIC as I have previously discussed.
That is it! Put your assembly code in memory, execute the VBI initialization code, and let the VB do its job 60 times per second.
Here is the BASIC code which provides a simple example. Line 30 and 40 setup the Graphics 1 screen with a blue background so it looks nice. Line 50 initializes memory location 203 with a 0. Our VBI code will change this to a 9 later so we know it is working. Line 60 initializes the string where we will store the VBI initialization code for execution on line 410. Lines 100 to 140 read our assembly program to be executed during the VBI into memory location 1536 (Page 6). Lines 300 to 230 print the initial value (the 0) stored in location 203. Lines 400 to 450 are the main loop. Line 410 executes out VBI initialization code stored in string VBI$. Lines 420 to 440 read memory location 203 and print the value to the screen. Line 450 created an eternal loop. Lines 500 to 520 hold the decimal values for the assembly code for our program shown the left above. Lines 600 to 620 hold the decimal values for the assembly code for our VBI initialization shown to the right above.
10 REM SIMPLE VERTICAL BLANK INTERRUPT DEMO
20 REM BY JASON H. MOORE, PH.D.
30 GRAPHICS 1+16
40 SETCOLOR 0,0,14:SETCOLOR 4,7,0
50 POKE 203,0
60 DIM VBI$(10)
100 REM *** READ IN PROGRAM CODE AND ***
110 REM *** STORE IN PAGE 6 OF MEMORY ***
120 FOR I=0 TO 9
130 READ DAT:POKE 1536+I,DAT
140 NEXT I
200 REM *** READ IN VBI CODE ***
210 FOR I=1 TO 10
220 READ DAT:VBI$(I)=CHR$(DAT)
230 NEXT I
300 REM *** PRINT MEMORY 203 BEFORE VBI ***
310 POSITION 0,0:PRINT #6;”BEFORE VBI 203=”
320 POSITION 15,0:PRINT #6;X
400 REM *** MAIN VBI LOOP ***
430 POSITION 0,2:PRINT #6;” AFTER VBI 203=”
440 POSITION 15,2:PRINT #6;X
450 GOTO 420
500 REM *** ASSEMBLY CODE FOR PROGRAM ***
510 REM *** PHA,LDA 9,STA 203,PLA,JMP XITVBL,RTS ***
520 DATA 72,169,9,133,203,104,76,98,228,96
600 REM *** ASSEMBLY CODE FOR VBI ***
610 REM *** PLA,LDA 7,LDX 6,LDY 0,JMP SETVBV ***
620 DATA 104,169,7,162,6,160,0,76,92,228
Open Altirra and load BASIC. I used Turbo BASIC XL but any flavor including Atari BASIC will do. You can also load the built-in BASIC from Altirra from the File->Attach special cartridge menu.
Open the BASIC code in your PC text editor or web browser and copy the text to your clipboard. Click on the View tab of Altirra and choose the paste text option from the bottom of the list. Altirra will slowly paste the text into the BASIC command line. It is important to keep focus on the Altirra window or the paste will stop and it will lose some characters.
Also try booting the ATR file in Altirra or on your Atari from your PC using SIO2PC. You can also load the ATR on a FujiNet or similar device and boot from there. You must have a BASIC cartridge loaded. You can load the file from BASIC using LOAD “D:VBIDEMO.BAS” and then type RUN.
I had used VBIs before but this exercise really helped cement my understanding of how they work. You will see many games make use of the VBI for executing assembly programs which would not be practical to execute in BASIC. I hope this post provide a different and perhaps higher level and clearer explanation than some of the book sources out there. A mentioned above, De Re Atari is probably the best source for a more technical description.