Atari Graphics and Arcade Game Design
Home
Mapping the Atari
Atari Graphics and Arcade Game Design
Old Hackers Newsletter

Chapter 2
Display Lists

We introduced you briefly in chapter I to a graphics microprocessor called ANTIC that is capable of displaying any of fourteen graphics modes. Since any screen actually consists of a collection or vertical stack of these individual graphics modes, ANTIC looks to a program called the display list to determine in which graphics mode it should display the screen data. The fact that there is something resembling a graphics display instruction set makes the computer extremely flexible. It becomes possible to display any collection of graphics modes from data in screen memory that can be stored virtually anywhere within the computer's RAM memory. This flexibility allows the user to mix graphics modes and even scroll the screen in any direction by altering the portion of screen memory displayed.

ANTIC, like most true microprocessors, has an instruction set that is used to write the display list program. The display list specifies three things: where the screen data is located, what display modes to use to interpret the screen data, and what special display options, if any, to implement.

Antic Instruction Set

ANTIC has a simple instruction set with only four basic instruction types. -there are map mode instructions, character mode instructions, blank line instructions, and jump instructions. Map mode instructions instruct ANTIC to display a mode line as colored pixels, while character mode instructions tell ANTIC to display a mode line with character data either from its internal ROM or from your own custom designed set. Blank line instructions instruct ANTIC to display a number of horizontal scan lines with solid background color. Like GOTO statements in BASIC, jump instructions change the value in ANTIC's program counter so that it looks for its next opcode somewhere else.

Special Options or Modifiers

ANTIC also has a number of special options or modifiers to its map and character mode instructions. These are specified by setting one of four high bits in the instruction set. These options are load memory scan (LMS), display list interrupt (DLI), vertical scroll, and horizontal scroll.

The load memory scan option is the most frequently used option for it occurs at least once in every display list. It specifies where the screen data is stored in memory. Technically, only one of these instructions is actually needed in any series of display modes because screen memory is usually continuous. However, if memory isn't continuous, either within a particular display mode or at the boundry between different modes, an LMS instruction is needed each time a new section of memory is used. Another instance where an additional LMS instruction is required, is in ANTIC modes E and F (GRAPHICS 8) where continuous screen memory crosses a 4K boundary. The load memory scan option is invoked by adding a decimal 64 ($40) to the map or character in the mode instruction. This is equivalent to setting the sixth bit in the instruction. LMS instructions are three bytes long. The first byte is the opcode specifying the mode and the last two bytes contain the address of screen memory in low byte, high byte order.

The other three modifiers are sometimes used by Assembly language programmers to achieve special effects. Setting bit 7 or adding 128 to the opcode enables a display list interrupt. Execution of this instruction causes ANTIC to force the 6502 to generate an interrupt. The interrupt service routine will be at the address pointed to in memory locations 512,513 decimal ($200, 201). Display list interrupts are often used to change the colors in the color registers over part of a screen or to change between character sets midway down the screen. We will discuss these uses in detail in chapter 6 and 4, respectively.

Horizontal scrolling can be set up by adding 16 to the opcode or setting bit 4. Likewise, you enable vertical scrolling by adding 32 to the opcode or by setting bit five. These modifiers allow you to fine scroll the screen in either direction. Naturally if you are planning to scroll through memory by changing the start of screen memory, you will need to combine your scroll modifier with a load memory scan modifier. This technique will be shown in more detail in chapter 7.

(figure)


Note:
1) Display List Interrupts can be enabled by adding 128 decimal, $80 Hex to above values
2) Since it is impractical to do horizontal scrolling without a LMS instruction values are not referenced.

Blanking Instructions

The blanking instructions generate a certain number of blank scan lines in the color and luminance of the background or border color. From I to 8 blank scan lines can be generated by these opcodes. They are primarily used to correct the overscan on a television set.

Jump Instructions

There are two jump instructions. The first (JMP) tells ANTIC to continue looking for instructions at a different address. It is equivalent to a GOTO in the display list. It is a three byte instruction with the address in low byte, high byte order following the opcode. Its only function is to provide a solution to the display list's inability to cross a I K boundary. If for any reason your display list must cross a 1K boundary, then it must use a JMP instruction. Otherwise, don't worry about this instruction.

The second jump instruction (JVB)-Jump and wait for Vertical Blank-is used in every display list. It is a three byte instruction; the address in low byte, high byte order follows the opcode. JVB tells ANTIC to jump to the start of the display list and wait for a new screen refresh to begin. Surprisingly, this address doesn't have to be accurate, because the OS keeps track of the top of the display list and passes it to ANTIC during the vertical blank. However, you should try to maintain the real address because if you use any SIO functions such as the disk drive or the printer, ANTIC won't be updated properly and the jump will be to the address that you specify in the instruction.

ANTIC INSTRUCTION SET
Instruction       Comment
Decimal  Hex                                  
  0      0        1 Blank Line
 16     10        2 Blank Lines
 32     20        3 Blank Lines
 48     30        4 Blank Lines
 64     40        5 Blank Lines
 80     50        6 Blank Lines
 96     60        7 Blank Lines
112     70        8 Blank Lines
  1      1        Jump to Location
 65     41        Jump & Wait for VBlank

Typical Graphics 0 Display List

Let us look at the display list for a typical Graphics #0 screen, the standard text mode. If you look at the chart below, you will see that this is ANTIC mode 2. It is a character mode with forty bytes per line. Each row is eight scan lines high, and there are twenty-four rows of characters. To produce an entire screen of text, twenty-four mode lines of ANTIC mode 2 will be required.

In BASIC the display list is setup automatically in memory just below screen memory. The memory pointers to the top of the display list are shadowed at locations 560, 561 decimal in low byte, high byte order. Thus:

DLIST = PEEK(560)+256*PEEK(561)

It is possible to look at the display list if, we write a short program to print the entire list to either the screen or a line printer. Display lists are easy to view if there are at least four lines of text 0; but viewing display lists for full screen graphics modes, and especially custom graphics modes, can be a problem without a printer. The reason is that you must PEEK the values in the display list while you are in the appropriate mode, and not when you return to text mode 0. A method to avoid the problem is to store the PEEKed display list elsewhere in memory and print it after you return to the text mode. A safe spot depending on circumstance might be 256 or more bytes below the desired display list.

The following program will print the display list for GRAPHICS 0 to the screen.

10 GRAPHICS 0
20 DLIST=PEEK(560)+256*PEEK(561)
30 FOR I=0 TO 40
40 PRINT PEEK(DLIST+I);" ";
50 NEXT I
60 GOTO 60

If you choose to print the list to the line printer then change line 40 to;

40 LPRINT PEEK(DLIST+I)

It is quite useless to attempt to get an 80-column printer to print the display list across several rows instead of in a vertical column. Putting in a semi-colon at the end of the print line does little more than place two values on one line and this becomes confusing. The fault lies in the Operating System's printer driver.

The 32 byte long display list appears as follows for a 40K or larger computer with BASIC present;

	112	Blank 8 scan lines to provide for overscan
	112
	112
	66	\Display ANTIC mode 2 (BASIC 0) 64+2
	64	|Screen memory starts at
	156	/64+156*256 =40000
	2	\Display ANTIC mode 2 for second mode line
	2	|
	2	|
	2	|
	2	|
	2	|
	2	|
	2	|
	2	|22 more ANTIC mode 2 modes
	2	|
	2	|
	2	|
	2	|
	2	|
	2	|
	2	|
	2	|
	2	|
	2	|
	2	|
	2	|
	2	|
	2	/
	65	\JVB-Jump and wait for Vertical Blank
	32	|to display list address which starts
	156	/at 32+256*156=39968

The first thing you notice is that every display list begins with three "blank 8 lines" instructions. This is to defeat the television's overscan by starting the display twenty-four scan lines down. The next instruction is a load memory scan (LMS). The ANTIC mode number is added to 64. The next two bytes are the low, high byte address to the beginning of display memory. Since the LMS instruction counts as the first display mode, only twenty-three more display ANTIC mode 2 instructions are needed. Finally there is a JVB instruction that resets the program counter to the top of the display list at location 39968.

The display list for a 16K machine is similar. The differences are in the locations of the top of the display list and the start of screen memory. The start of screen memory is at 15424 decimal. The low byte after the LMS instruction is 64 and the high byte is 60. The top of display list is at 15392 decimal. The low byte after the JVB instruction is 32 and the high byte is 60.

Mixing Graphics Modes

You are not always stuck with a homogenous stack of display modes. After all, splitting text and graphics is mixing modes. It is very easy to mix display modes just by changing a single display mode instruction in the display list. For example, we could change the twelfth row of GRAPHICS 0 text in the program below to a GRAPHICS I elongated text mode (ANTIC 6) characters by changing the 12th display instruction in the display list.

20 GRAPHICS 0
30 DLIST=PEEK(560)+PEEK(561)*256
40 FOR I=1 TO 24
50 PRINT "LINE";I;" THIS ROW HAS FORTY CHARACTERS";:IF I<24 THEN ?
60 NEXT I
1000 GOTO 1000
If we count down the display list starting with the Oth byte, a POKE DLIST+ 16,6 would change the text characters to GRAPHICS I characters. Do this by adding; 70 POKE DLIST + 16,6. The trouble is that everything below our new mode line is offset by half a row or twenty bytes. To understand why this occurs you need to understand what happens when ANTIC receives instructions to display a particular mode.

When ANTIC gets an instruction to display a particular graphics or character mode it automatically goes to display memory and gets the precise number of bytes of data necessary to display that mode line. When it sees an ANTIC 2 (GRAPHICS 0) display mode it retrieves forty bytes and interprets them in the proper display mode. When it sees another ANTIC 2 display mode it retrieves the next forty bytes in sequence from display memory. If instead it sees an ANTIC 6 (GRAPHICS 1) display mode, it only retrieves twenty bytes. Upon encountering the next ANTIC 2 display mode ANTIC retrieves another forty bytes. The trouble is that each of our print statements start at intervals of exactly forty bytes from the beginning of screen memory. When ANTIC only retrieved twenty bytes, it displayed only half of our printed line. The next ANTIC 2 display mode retrieves memory beginning with the last half of our line of text and displays it on the next line. Each of the ANTIC mode 2 lines on subsequent lines are also off by twenty bytes. You could correct this by adding another ANTIC 6 mode instruction immediately below the first one. Add line 80 POKE DLIST+17,6 to the program. The text for the twelfth row is now split between the two display lines of elongated text. Since we retrieved forty bytes less memory in producing the screen, the last row in memory isn't displayed.

You can experiment by changing any display instruction to any desired mode. If you try substituting BASIC GRAPHICS 2 (ANTIC 7) characters for those same two lines by POKEing a 7 instead;

70 POKE DLIST+16,7
80 POKE DLIST+17,7
the bottom of the display gets pushed downward, partially off screen.

What has happened is that we are now displaying more than 192 scan lines, 208 lines to be exact. While this isn't a major problem, it is possible to confuse the television screen's timing and the picture may begin to roll. As a rule of thumb, you shouldn't have more than 192 scan lines in your display. Displaying fewer scan lines will cause no problems. In fact it will decrease the 6502 execution time by reducing the number of cycles stolen by ANTIC to display the screen data.

Moving The Text Window

In BASIC, whenever you specify mixed text in any graphics mode, the four lines of text are automatically placed at the bottom of the screen. This is rarely the best location for it. It is often preferable when designing games to put your scoring information at the top. The text window is easy to move if you rewrite the display list.

If you look at a GRAPHICS 3 display list you will obtain the following values. The display list on the left is the one BASIC defaults to, and the one on the right is the display list we need to have four lines of text at the top and a GRAPHICS 3 screen below.

112 Blank 8 lines               112 Blank 8 lines
112                             112 to provide for overscan
112                             112
 72 \LMS display ANTIC 8         66 \LMS display ANTIC 2 (GR.0)
112 |Screen memory starts at     96 |Text memory starts at
158 /112+(158*256)                  |
  8 Display ANTIC 2 (GR.0)      159 /96+(159*256)
  8                               2
  8                               2
  8                              72 \LMS display ANTIC 8 (GR. 3)
  8                             112 |Screen memory starts at
  8                             158 /112+(158*256)
  8                               8
  8                               8
  8                               8
  8                               8
  8                               8
  8                               8
  8                               8
  8                               8
  8                               8
  8                               8
  8                               8
  8                               8
 66 \LMS display ANTIC 2          8
 96 |Text memory starts at        8
159 /96+(159*256)                 8
  2 Display ANTIC 2               8
  2                               8
  2                               8
 65 \JVB                         65 \JVB
 78 |Address to top of DLST       78 |Address to top of DLST
158 /78+(158*256)                158 /78+(158*256)
There are two ways to modify the display list. The first method changes only the groups of bytes that need to be modified. If the change is simple, you need rewrite only a fraction of an entire display list. In this example we are only shifting sections of the display list in order to change the position of the text window, so we can move blocks of display list data around if we are careful not to overwrite data. The diagram shows the sequence of the three moves. The actual move is accomplished in three short FOR-NEXT loops. The three data bytes at DLIST+3, 4, and 5 are read and POKEd into locations DLIST+9, 10, and 11. The other two moves are similar.

Download DLIDEMO1.BAS (Saved BASIC)
Download / View DLIDEMO1.LST (Listed BASIC)

(figure)

BASIC doesn't even notice the change. It keeps internal pointers to the locations of both text memory and screen memory. Since we didn't change these values text is printed correctly to the text area, and graphics are plotted correctly on the shifted screen. You might observe that when we set the colors for plotting in GRAPHICS 3, we affected the background of the text window. This is because SETCOLOR 2 affects the text background. We avoided plotting with SETCOLOR I because this register affects the luminance of the letters. We won't have any problem if we set this color register as long as we keep in mind that the luminance must be 6 or greater for readablity.

The second method and sometimes the easier method when rewriting the display list is to put the new list in data statements. Then it is only a matter of reading the list and POKEing the values into memory starting at the top of the old display list. Since the screen does act funny during the change, ANTIC can be temporarily disabled by writing a zero into SDMCTL at location 559 (32217). After the list has been POKEd into position, you turn ANTIC back on with a POKE 559,34. If you did it right, the screen will appear exactly as you set it up. If for some strange reason you decide to move the display list, remember to tell the operating system by POKEing the address to the top of the list in locations 560 and 561 ($230,231), low and high bytes respectively.

Download DLIDEMO2.BAS (Saved BASIC)
Download / View DLIDEMO2.LST (Listed BASIC)

(figure)

Custom Display List For Mixing Graphics Modes

The last example is a custom designed display list with two graphics modes split by a row of expanded text. Whenever you decide to design any custom screen it is best to lay out the design on paper, and translate it into a sequence of mode lines. Once you have looked up the number of scan lines required for each mode line, you must double check the line count so that it does not exceed 192 scan lines. You then translate the sequence of mode lines into a sequence of ANTIC mode bytes.

Our display will consist of sixteen mode lines or rows of GRAPHICS 5 (ANTIC 10) pixels followed by a row of enlarged GRAPHICS 2 (ANTIC 7) text, followed by fourteen mode lines or rows of GRAPHICS 3 (ANTIC 8) pixels. Since each of the GRAPHICS 5 pixels are four scan lines high, this portion of the screen requires 16 x 4 = 64 scan lines. The one line of GRAPHICS 2 text requires sixteen scan lines. GRAPHICS 3 mode lines are eight scan lines high. The fourteen rows at the bottom require 14 x 8 = 112 scan lines. This gives us a total of 192 scan lines.

(figure)

In BASIC it is sometimes easier to let the system set up the memory area for your screen and display list. Since you need to be careful that the screen memory requirements don't collide with the top of memory, you always choose a graphics mode that uses at least as much screen memory as the one you are custom designing. Obviously a GRAPHICS mode 5 screen is larger in memory than one that is partially GRAPHICS 5 and partially GRAPHICS 3. GRAPHICS 5 screens require 960 bytes of memory while GRAPHICS 3 screens require only 240 bytes.

The location of screen memory for any GRAPHICS mode can be found at locations 88 and 89. SCREEN = PEEK(88)+PEEK(89)*256. The individual values of the low byte and high bytes for a GRAPHICS 5 screen in a 40K+ machine are 160 and 155 respectively. This is the lowest address of screen memory corresponding to the upper left corner of the screen. Memory builds upwards towards the top of memory.

Each of our sixteen mode lines of GRAPHICS 5 pixels requires twenty bytes. Therefore that portion of the screen requires 16 x 20 = 320 bytes. If we add 320 bytes to the beginning of screen memory, the next byte (the beginning of our text memory) in low byte/high byte order is at:

    High Byte      Low Byte
     155            160
                    320
     ___            ___
     155            480       reduce to a value (0-255)

or   156            224
The reason for the apparently nonsensical decimal math is that when you complete the addition of 320 and 160 in the low order byte the resulting decimal value 480 is larger than the storage capacity of one byte (255 decimal or I I I I I I I I binary). The carry bit is set and the high order bit of the low byte is carried to the low order bit of the high byte. The resulting address is the beginning of text memory for our GRAPHICS 2 text. Since it requires only twenty bytes of display memory, the beginning of our GRAPHICS 3 memory is at 244 for the low byte and 156 for our high byte. With this information it is now possible for us to create a display list. That display list is shown below.

	112	Blank 8 lines
	112
	112
	74	\LMS Display ANTIC mode 10 (GR.5)
	160	|Screen memory starts at
	155	/160+(155*256)
	10	Display ANTIC mode 10
	10
	10
	10
	10
	10
	10
	10
	10
	10
	10
	10
	10
	10
	10
	71	LMS Display ANTIC mode 7 (GR.2)
	224	\Text memory starts at
	156	/224+(156*256)
	72	\LMS Display ANTIC mode 8 (GR.3)
	244	|Screen memory starts at
	156	/244+(156*256)
	8	Display ANTIC mode 8
	8
	8
	8
	8
	8
	8
	8
	8
	8
	8
	8
	65	\JVC (jump and Wait for VBLANK)
	104	|Address of top of display list
	155	/104+(155*256)

Great care should be taken when designing a display list. One of the most frequent sources for error is forgetting that the LMS instruction is your first mode line for a particular graphics type. Forgetting this will cause you to have too many scan lines. The second source of error is incorrectly calculating the address for display memory. Once you begin looking at the wrong portion of memory, nothing appears that you print, plot, or POKE to.

Plotting Points & Lines Using A Custom Design

Plotting GRAPHICS 5 pixels on the top portion of our display is straightforward. All that you need to do is choose a color register, then PLOT. But on the lower portions of the screen, the Operating System must first be told which graphics mode to plot in and where screen memory is located. The current display mode is stored in memory location 87. Many programmers use this location to fool the OS into thinking that it is in a different GRAPHICS mode by POKEing it with a number from 0 to 11. This value is the same as the BASIC graphics mode number. In addition, the lowest address of screen memory stored at locations 88 and 89 must be changed.

In our example, when we wanted to plot to the GRAPHICS 3 portion of the screen, we POKED a 3 into location 87. We then put the beginning of the screen address into locations 88 and 89. These are the same values as our LMS address for this portion of the screen. If you don't perform this operation the OS will incorrectly calculate the memory addresses to plot your pixel or line of pixels. Similarly the OS needs to be informed when we print our message in GRAPHICS mode 2 characters. A POSITION statement must also be included because the OS automatically does a position each time it plots. The #6 type print statement must be used because this is screen memory, not text memory.

In summary, the ability to design a custom display list is very valuable. It gives you flexiblity that is not available on other computer systems. By customizing the display you can give the screen a personality all your own.

Download DLIDEMO3.BAS (Saved BASIC)
Download / View DLIDEMO3.LST (Listed BASIC)


Return to Table of Contents | Previous Chapter | Next Chapter