Deeper into display lists.
The display list interrupt (DLL) feature of ATARI computers allows you to run brief machine-language program routines during your television's horizontal blank period. The ATARI uses 192 horizontal scans of the electron beam for the playfield each l/60th of a second. The horizontal blank is the period during which the beam is turned off while returning to the left side of the screen to begin the next line.
The computer is much faster than the television, and during the blank period it can use the time to vary colors, modify Player/Missile graphics, or alter the character set graphics. Use of the display list interrupt provides a wide range of opportunity for creative programmers.
In our previous article (ANTIC, June 1983), we demonstrated short machine-language routines that changed up to three colors in the display. The examples that we used employed a single DLI instruction inserted into a display list. But there is no reason why you must be restricted to a single interrupt in a display list since it is possible for each mode line in a display list to contain an interrupt instruction. In this article we explain how to implement several display list interrupts in the same program. First we will focus on making color changes.
Later we will mention other ways to use DLIs. A major problem in the use of multiple DLIs is that there is only one memory location in which to store the starting address of a DLI service routine. When ANTIC encounters a DLI it signals the central processor unit (CPU) to halt its current operations and proceed to a subroutine. The CPU then automatically checks memory locations 512 and 513 to find the lo-byte and hi-byte of the address of the DLI service routine to execute.
Suppose you have two different service routines for the CPU to perform. You might store each routine at a different location in Page Six, but to your dismay there is provision for storing only one starting address.
Of course, there are ways to solve this predicament. The solution you choose will depend upon the specific operation you wish to perform. If your DLI routine will do the same job each time it is executed, but uses different values (for example it changes a single color register several times) then a table and pointer can be used. This is called a "table-driven" DLI service routine. With this method you set up a table of color values in memory and provide a pointer (a particular memory location) that tells the service routine which color in the table to use.
If, on the other hand, each of your DLI routines is going to perform quite different tasks, then the most efficient plan is to make each service routine put the starting address for the next routine into memory locations 512 and 513, thus pre-loading the pointer.
Program 1 demonstrates the use of a color table. This program uses six display list interrupts to change a yellow rectangle into a rectangle with six colors. The program is divided into four sections:
1.Lines 10 through 50 set up the Color table and initialize the pointer.
2.Lines 70 through 100 put six interrupt instructions into the Graphics 7 display list.
3. Lines 120 through 170 create the display.
4. Lines 190 through 230 set up and enable the display list interrupt routine.
The portions of the program that are of most interest to us are the color table, the pointer, and the service routine. These have been placed into Page Six as follows.
(00 = LO BYTE)
(06 = HI BYTE)
THROUGH ------------31 Bytes of Machine Language DLI Service Routine
(30 = LO BYTE)
(06 = HI BYTE)
1567 ---------------THE POINTER
(31 = LOBYTE)
(06 = HI BYTE)
(32 = LO BYTE)
(06 = HI BYTE)
THROUGH------------6 Bytes of the COLOR TABLE
(37 = LO BYTE)
(06 = HI BYTE)
MNEMONIC DECIMAL VALUE----FUNCTION
PHA ................ 72,................ Push accumulator to stack
TXA..................138...............Transfer X-register to accumulator
PHA...................72................Push accumulator to stack
INC POINTER..238,31,6............Increment (add one to value in pointer).
This last instructibn is carried out each time the interrupt is used. We initialized the value here to 31 so that when the first DLI is encountered this instruction will increment the pointer to 32, which is the lo-byte of the first color's address.
LDX POINTER.....174,31,6........Load X-register with the value in pointer.
LDA ADDR,X.......189,0,6.........Load accumulator with the value in address following using the X-register as an index.
When this command is executed, the "0" in 0,6 is added to the value in the X-register to get the lo-byte of the address.
STA WSYNC......141,10,212.....Wait for horizontal blank
STA COLREG.....141,22,208.....Store color into color register.
CPX NUM.............224,37.......compare the value in X-register with 37.
This command subtracts 37 from the value in the X-register. The result is used by the next command.
BNE END.............208,5.................Branch if not equal to zero
If the result of the CPX command is not equal to zero, the program jumps ahead to restore the X-register and the accumulator and return from the interrupt, by-passing the next two instructions:
LDA RESET.........169,31........Load the accumulator with 31.
STA POINTER.....141,31,6...Store the accumulator value into 31,6 to reset the pointer.
These last two commands are executed only when the result of the comparison, CPX, is zero. This occurs when the X-register holds the lo-byte of the last color's address.
The remaining commands restore the registers and exit the routine:
END PLA.................104.......Pull value from stack to accumulator
TAX........................170.......Transfer accumulater to x-register.
RTI .........................64.........Return from interrupt.
Each time a DLI is encbuntered the accumulator and X-register values are saved to the stack. The pointer is incremented and the new value is placed into the X-register. The accumulatbr is then loaded with a color value at an address, the lo-byte of which is the value in the X-register. After this color value has been stored in a color register, the program tests to see if the address used was that of the last color value. If not, the routine ends for that interrupt. If it is the last color, then the pointer is reset before the routine ends.
Most of the assembly-language commands in this program should be familiar to you from our previous article. However, there are some new wrinkles here. Notice that we have used LDA twice. But we used a different decimal code in each case. The decimal code specifies both the operation and the type of addressing mode used. When the decimal code for LDA is 169, the number immediately following is loaded into the accumulator. This is called the immediate mode of addressing. When the decimal code for LDA is 189, the accumulator will use the next two numbers as the address of the byte to be loaded, but only after the contents of the X-register have been added to the lo-byte. The X and Y registers are also known as the X-index register and the Y-index register, so this mode of addressing is called indexed addressing. A third mode of addressing is illustrated by the LDX instruction. If the decimal value of LDX is 174, the two numbers following LDX are the low and high bytes of the address of the value to be loaded into the X-register. This is known as the absolute mode of addressing. Now you can see that 224 is the decimal value for the immediate mode of the CPX instruction since it is comparing the next number, 37,with the value in the X-register.
The INC instruction (decimal value 238) uses absolute addressing since the next two numbers are the address of the number to be incremented. The last new instruction in this program, BNE (branch on result not zero), uses relative addressing. While a program is being run by the CPU, a special register called the program counter holds the address of the next instruction to be executed. When a BNE is acted upon, the program counter is incremented by one and the number following the BNE is added, giving the address of the next instruction. If you look at our program again, you will see that the sixth number after the line BNE END 208,5 is PLA 104 which is the start of the routine to exit the program.
Our second method of implementing multiple interrupts, in which each routine sets the starting address of the following routine, is more flexible than the simple use of a color table. You are not limited to changing a single register, but can change different registers at different places in the display. However, to keep the program that illustrates this technique simple, we have chosen to make two changes in the text color of Graphics 2. We have done this by using two DLI routines. This first changes the text to pink, the second changes it to blue.
Study the listing of Program 2 and note that line 40 puts an interrupt instruction at the third and sixth mode lines; line 60 is the data for the first interrupt routine; line 70 is the data for the second. The data for these routines is stored on Page Six. With a little counting you can see that the first interrupt routine is stored at 1536 (00,06) through 1551 (15,06) and the second at 1552 (16,06) through 1568 (32,06). The basic structure of these two routines is the same. Here is the first one written out in detail:
PHA.........................72 ................ push value in accumulator to stack
LDA COLVAL .......169,92.................load accumulator with 92 (pink)
STA WSYNC..........141,10,212..........wait for horizontal blank
STA COLREG..........141,22,208.........store value in accumulator in the hardware register
LDA LOADDR..........169,16...............load accumulator with lo-byte of the address of the next routine
STA PAGE2............141,00,02............store value in accumulator at 512
PLA...........................104...............load accumulator with value on the stack
RTI............................64................return from interrupt
The second routine differs from the first only in the color value used and the fact that it stores the address of the first service routine back into 512.
We have included Pragram 3 for you to take apart and to improve. We suggest that you write out the assembly-language mnemonics for the two service routines. The first routine is at line 90. The second is at lines 100 through 120. After you run the program and write out the service routines you will realize that we have inverted three of the redefined characters by putting a four into the hardware register 01,212. This is just one of the many things you can do with a DLI. When you run Program 3 you will see the character set being redefined in the printing in the text window. This is one part of the program that you can improve. With DLIs you can use one set of characters in the display part of the screen and a different set in the text window by putting the starting address of the character set you wish to use in CHARBAS - 54281.
The power of DLIs comes from the fact that you can change the nature of the screen display at any mode line on the screen. With Player/Missile graphics you can change player colors, width, and priority. If you consider a player to be a vertical column eight bits wide by 128 bytes high you can use DLIs to divide this strip into sections and position each section at different places horizontally on the screen.
A final idea for experimentation might be to have a DLI at each mode line of the display list and use the service routine to play music while the display is being drawn.
Allan Moose is an associate prrofessor (math/physics) at Southampton College, New York. Marian Lorenz is a special education teacher for handicapped children in Central Islip, New York.