Atari Display List

by Craig Patchett

This article will attempt to explain enough about the ATARI display list so that you will be able to design your own custom graphics modes. Even if you are not interested in such applications, the information provided should give you some interesting insights into the operation of your machine.

In order to understand anything that your ATARI does to your television screen, it's important to understand what your television does to your television screen. To create an image on the screen, the television sends out an electron beam that scans the screen from left to right and top to bottom, much like you would scan a page while reading. When this beam hits the phosphor that coats the inside of the screen surface, the phosphor glows. The television regulates how strong the beam is, which in turn determines how bright the phosphor glows (a colour television is slightly more complex, with three different coloured phosphors and three beams, but one beam is sufficient for our purposes). The problem is that the phosphor will only glow for a fraction of a second after the beam hits it. This means that the beam must move very quickly and constantly redraw the screen in order for an image to be retained. It is for this reason that graphics information must be stored in a computer's memory, as well as on the screen (if you're interested, the screen is redrawn every sixtieth of a second). Now for the important stuff. Each line the electron beam scans on its way from top to bottom is called a scan line (makes sense, right?). As far as the ATARI is concerned, 262 such scan lines make up the screen. Of these 262 lines, however, only 192 are completely visible, and thus are the only ones used (these 192 make up the "box" you see in GRAPHICS 0). It is possible, however, to use more than 192 scan lines, as we will see later.

The information presented so far has only explained the operation of your television set. What about that of your computer? How does it go about relaying its data to the screen? After all, you certainly don't have to worry about updating the screen sixty times a second yourself. The unsung hero responsible for doing this dirty work is a little chip called ANTIC. Like the 6502 (the big chip), ANTIC is a microprocessor, which means that if you give it a program, it will give you results. The difference between the 6502 and ANTIC is that the 6502 gives you numbers, while ANTIC gives you graphics.

The program for ANTIC, believe it or not, is called the "display list". Like any program, the display list consists of a series of commands, or instructions. These instructions tell ANTIC exactly what to do with the screen. Luckily for us, ANTIC has only three basic kinds of instructions that we need be concerned with. Before I go over them, let me explain the difference between two similar terms:

· scan line is as high as the electron beam.

· mode line may be from one to sixteen lines high, depending on the type of mode. For example, a GRAPHICS 0 mode line is eight scan lines high, while a GRAPHICS 2 mode line is sixteen, and a GRAPHICS 8 is one.

With these differences in mind, let's take our first look at the ANTIC instructions:

MOD n - make the next line a graphics mode n line (the n does not always correspond to a BASIC graphics mode).

BLK n - make the next n scan lines blank (i.e. turn off the electron beam for n scan lines).

JVB addr - jump to addr and wait for the end of the next vertical blank (vertical blank is the time during which the electron beam returns from the bottom of the screen to the top after it has finished drawing the screen. Thus it occurs every sixtieth of a second).

Before we go into any detail on these instructions, let's take a look at what a typical display list would took like:

BEGIN BLK 8 *we first skip 24 scan lines, due
BLK 8  to the forementioned problem
BLK 8  of some lines not being entirely visible.*
MOD 2 *next, we want 24 mode 0 lines*
MOD 2
"
"
"
MOD 2
JVB BEGIN *finally, we want to go back to the beginning of our list and wait until it's time to start redrawing the screen.*

As you can see, the principle behind the display list is relatively simple. Keeping this in mind, let's take a look at some of the finer details.

You may be wondering what numbers in the MOD instruction correspond to the different BASIC graphics modes. ANTIC recognizes a total of fourteen graphics modes, nine of which are directly accessible from BASIC. The following chart will give the pertinent information for each of the fourteen. I won't go into detail on any of the new modes in this article, but will rather leave them for -you to play with after the article is over:

Mode
Number
Basic
Mode
Type #
Colors
Scan line per
mode line
Characters
per line
2 0 TEXT 2 8 40
3 NONE TEXT 2 10 40
4 NONE TEXT 4 8 40
5 NONE TEXT 4 16 40
6 1 TEXT 5 8 20
7 2 TEXT 5 16 20
8 3 GRAPHICS 4 8 40
9 4 GRAPHICS 2 4 80
10 5 GRAPHICS 4 4 80
11 6 GRAPHICS 2 2 160
12 NONE GRAPHICS 2 1 160
13 7 GRAPHICS 4 2 160
14 NONE GRAPHICS 4 1 160
15 8 GRAPHICS 2 1 320

When we go to put the display list into memory, we will represent the MOD n instruction with the mode number. Thus MOD 2 would translate to a 2.

Representation of the other two ANTIC instructions in memory is just as simple. The BLK n is represented by the number 16*(n1). Thus BLK 8 would translate to a 16*(8-1) = 16*7 = 112. Finally, the JVB addr instruction is represented by three numbers, or bytes as they are more commonly referred to. The first byte tells ANTIC that this instruction is a jump, and is always a 65. The second and third bytes tell ANTIC the address to jump to. They are the "low byte" and "high byte" of the actual address, in that order (the high byte of addr = INT(addr/256) and the low byte = addr-256*(the high byte). So 2561, for example, would have high byte = 10, low byte = I).

Finally (ok, so I lied before), there is a special kind of MOD instruction, called LMS, that tells ANTIC where in memory the graphics information is stored (LMS stands for Load Memory Scan). Usually there is only one LMS instruction in a display list, and it takes the place of the first MOD instruction. You could, however, use as many of them as you like (keeping in mind that each one takes the place of a MOD), and thus have different pieces of the graphics memory in different places. For our purposes, however, one will almost always suffice. In any case, a LMS instruction, like a jump, consists of three bytes. The first byte is just the mode number of the MOD that is being replaced, plus sixty-four (Ie. a MOD 2 LMS would translate to a 2+64 = 66). Like the jump instruction, the second and third bytes represent the low and high bytes of the address, where this time the address is that of the beginning of the graphics memory area.

Now that we (hopefully) have all our numbers straight, let's take another look at our sample display list. We'll assume that the display list begins at memory location 25824, and graphics memory begins at memory location 25888 (these numbers are just examples. We'll see how to get the real numbers, easily, later on).

OLD NEW
BEGIN BLK 8 112
BLK 8 112
BLK 8 112
MOD 2 (LMS) 66
32
11 (11*256+32=25888)
MOD 2 2
" "
" "
" "
MOD 2 2
JVB BEGIN 65
244
10 (10*256+224=25824)

(Chart 1)

We're now ready to begin custom designing our own graphics mode. The good news is that we don't have to do a lot of work setting up the display list we'll just make some changes to one that BASIC sets up for us. This means not having to worry about figuring out addresses. The bad news is that we do have to do some work in deciding exactly what our graphics mode will look like. The main thing is to make sure that our custom mode uses no more than 192 lines (we can use less if we like, but the screen will look smaller than usual). Use Chart 1 to determine how many scan lines your custom mode will use. For example, if we want to mix BASIC modes 0, 1, 2, and 7, and we decide that we want three lines of mode 0, four of mode 1, and two of mode 2, then we have a total of 3*8 + 4*8 + 2*16 = 88 scan lines so far. That leaves us with 192-88 = 104 scan lines for mode 7, so we can have 104/2 = 52 lines of mode 7.

Surprise! That's all it takes to design our custom mode. Putting it into the ATARI is almost as easy. The first step is to get BASIC to set up a graphics mode (i.e. display list and graphics memory) that we can use to make changes to. We don this with a GRAPHICS n+ 16, where n is, the BASIC graphics mode that uses the most memory/screen of all the modes we are mixing. The chart summarizes the different memory/screen requirements:

ANTIC
MODE
BASIC
MODE
MEMORY/
SCREEN(BYTES)
2 0 960
3 NONE 760
4 NONE 960
5 NONE 480
6 1 480
7 2 240
8 3 240
9 4 480
10 5 960
11 6 1920
12 NONE 3840
13 7 3840
14 NONE 7680
15 8 7680

(Chart 2)

So, for example, out of BASIC modes 0, 2, and 7, 7 has the largest memory/screen requirement so we would use a GRAPHICS 23 to start things off (note that if we were using ANTIC mode 12 instead of BASIC mode 7, we would still use a GRAPHICS 23).

Now BASIC has set up a display list and graphics memory area for us. We must go in and modify the display list. But how do we know where the display list is? It just so happens (I can afford to be smug about this) that memory locations 560 and 561 point to it. They hold the low and high bytes of the address of the beginning of the display list. We'll use a variable DISPLAY= PEEK(560)+2 5 6 *PEEK(5 6 1) to hold that address. So we know that locations DISPLAY, DISPLAY+1, and DISPLAY+2 hold BLK 8 instructions (check for yourself by PEEKing them). For our example, DISPLAY+3 holds a MOD 13 LMS instruction (remember, ANTIC mode 13 = BASIC mode 7). But we want the first line to be a MOD 2 (or BASIC mode 0) LMS instruction, so we have to change it. A simple POKE DISPLAY+3,66 takes care of this (remember, again, that MOD 2 LMS = 66), since BASIC already took care of the LMS address at locations DISPLAY+4, DISPLAY+5 when it set the display list up. Our program so far, then, looks like this:

100 GRAPHICS 23
110 DISPLAY=PEEK(560)+256*PEEK (561)
120 POKE DISPLAY+3,66

We want two more mode 0 lines, so we add:

130 POKE DISPLAY+2,2:POKE DISPLAY+7,2

Next we want four lines of mode 1:

140 POKE DISPLAY+8,6:POKE DISPLAY+9,6:POKE DISPLAY+10,6: POKE DISPLAY+11,6

And two more lines of mode two:

150POKE DISPLAY+ 12,7:POKE DISPLAY+13,7

Finally, we want fifty-two lines of mode 7. But we set up a mode 7 display list when we did our GRAPHICS 23, so we don't have to change anything for our mode 7 lines. We do, however, have to reposition the JVB instruction. Since we have a total of sixty-one MOD instructions (3+4+2+52) plus three BLK instructions plus two more bytes for the LMS address, our JVB has to begin at memory location DISPLAY +(61+3 +2) = DISPLAY+66. Remembering that locations 560 and 561 already hold the low and high bytes for the address of the beginning of the display list, we can simply do the following (remember that JVB = 65):

160 POKE DISPLAY+66,65:POKE DISPLAY+67,PEEK(560):POKE DISPLAY+68,PEEK(561)

So as not to confuse ANTIC while we are making our changes, we'll turn it off while we make them, and then turn it back on after we're done:

115 POKE 559,0
170 POKE 559,34

And, believe it or not, we now have a custom designed graphics mode (before you run the program, put in 1000 GOTO 1000, since the ATARI thinks that it's in a full screen mode and will go back to GRAPHICS 0 if you don't)! If you want to get rid of the blue band in the mode 0 lines, use a SETCOLOR 2,0,0 instruction.

Now that we have our custom mode, what do we do with it (keep those thought to yourself)? Remember that the ATARI still things it has a GRAPHICS 7 mode set up, so any time we try to POSITION, PRINT, PLOT, or DRAWTO, it will assume we want to do it in a GRAPHICS 7 environment. Getting around this problem is the "tough" part of custom modes, so-take a deep breath, relax, and read on.

The problem that we have to overcome is largely due to the fact that different modes use different amounts of memory per mode line. The following chart lists the differences:

ANTIC
MODE
BASIC
MODE
BYTES PER
MODE LINE
2 0 40
3 NONE 40
4 NONE 40
5 NONE 40
6 1 20
7 2 20
8 3 10
9 4 10
10 5 20
11 6 20
12 NONE 20
13 7 40
14 NONE 40
15 8 40

(Chart 3)

Before I continue, let me clear up one possible misconception you might have. ANTIC only takes care of displaying the graphics memory on the screen (i.e. controlling what it looks like). ANTIC does not handle any changes that are to be made to the graphics memory. With this in mind, you can see that the ATARI, with the exception of ANTIC, is completely oblivious to what our custom mode looks like. It still thinks it is dealing with a GRAPHICS 7 screen, and thus we will run into difficulties when we try to make changes to the text mode areas in our custom mode. Also, because of the difference in memory requirements of the different mode lines, trying to access the GRAPHICS 7 area will also give us problems. This is because the ATARI expects each line to be forty bytes long (the length of a GRAPHICS 7 line). Since we have a combination of forties and twenties in the text area, if we try and PLOT to the GRAPHICS 7 area, it will not PLOT where we want it to (try it). Also keep in mind that even if all the text mode lines were forty bytes/line, we would still run into problems (can you see why? Hint - PLOT X,Y will plot in the correct column, but not the correct row). As you can see, this is all very confusing. Don't worry too much if you don't completely understand. Luckily, the solution is relatively simple.

First of all, it's very easy to trick the ATARI into thinking that it's in a different mode. Memory location 87 holds the number of the correct BASIC mode. So if we want to make the ATARI believe that it's in another mode, we just POKE 87 with a new BASIC mode number. If we're dealing with an ANTIC mode that doesn't have a corresponding BASIC mode, then we use the closest BASIC mode in terms of type and bytes per mode line (BASIC 0 for ANTIC 3, 4, and 5, BASIC 6 for ANTIC 12, and BASIC 7 for ANTIC 14).

Now all we have to do is make it so that we can ignore whatever comes before the particular mode that we're interested in (what?). As we mentioned before, even after we straighten out the ATARI with respect to what mode we're using, it will still be confused as to where exactly that mode is on the screen, and therefore in memory (remember, it'll assume that the same mode takes up the whole screen). So how are we going to get around this? We'll fool the ATARI (again - and you always thought it was intelligent) into thinking that the top of the graphics mode area that we want to use is really the top of the screen. That way, the top left-hand corner of each mode area can be treated as position 0,0. Perhaps an easier way to think of this is to visualize each different mode area as being a separate, and smaller, screen. When we access one of these screens, we won't pay any attention to the others.

In order to pull this off, we have to know the address in graphics memory of each mode area, or "screen". Memory locations 88 and 89 are used by the ATARI to point to the beginning of graphics memory (88 holds the low byte, 89 the high). So we have a way of determining the address of the beginning of the first screen. We also know how much memory each screen takes up (remember, we know how many bytes per mode line there are). Thus we can figure out the addresses of the beginning of the other mode areas. Perhaps the best thing to do here is use our example:

180 SCREEN=PEEK+256*PEEK(89)

SCREEN
SCREEN=120
SCREEN=200
SCREEN=240
GR.0: 3 lines at 40 bytes/line = 120 bytes
GR.1: 4 lines at 20 bytes/line = 80 bytes
GR.2: 2 lines at 20 bytes/line = 40 bytes
GR.7

So we use:

190 SCREEN 1=SCREEN+ 120:SCREEN2 =SCREEN I +80:SCREEN7
=SCREEN2+40

Ok, we now have the addresses we need. How do we tell them to the ATARI? Surprise (don't you just love these surprises?) - locations 88 and 89 will do the trick, since they only specify where the ATARI thinks screen memory begins, not where it actually does (the LMS in the display list tells where it really begins). So, remembering that we first have to convert our addresses to low and high byte, let's do something to our example screen:

200 POKE 87,0:PRINT "LINE 1":PRINT "LINE 2":PRINT"LINE 3"
210 HI=INT(SCREEN1/256):LO=SCREEN 1-HI*256:POKE 88,LO: POKE 89,HI
220 POKE 87,1:POSITION 0,0:PRINT #6;"LINE 1":PRINT #6;"LINE 2": PRINT #6;"LINE 3":PRINT #6; "LINE 4"
230 HI=INT(SCREEN2/256):LO=SCREEN2-HI*256:POKE 88,LO: POKE 89,HI
240 POKE 87,2:POSITION 0,0:PRINT #6;"LINE 1":PRINT #6,"LINE 2"
250 HI=INT(SCREEN7/256):LO=SCREEN 7 HI* 25 6:POKE 88,LO: POKE 89,HI
260 POKE 87,7:COLOR 2:PLOT 0,0: DRAWTO 51,51

And there you have it! One genuine custom graphics mode in use.

Hopefully, if you've managed to read all the way through to here, you understand the display list and how the ATARI handles the screen at least a little better than you did when you started. Chances are that you're a little discouraged about the apparent complexity of designing a custom mode, especially with regard to accessing the different mode areas. The only thing I can suggest if this is the case if that you practice. Like anything new you learn, the more you put it to use, the easier it becomes. And in this case, the possible results are more than worth the effort.

MORE(?!)

Yes, there is one more thing. If you're going to use ANTIC modes 14 or 15, you may run into a problem. This problem is due to a minor limitation of ANTIC in that it has "difficulties" with large screen memories (specifically, screen memory can't cross a 4K boundary, if that makes any sense to you). In ANTIC modes 14 and 15, screen memory becomes large enough to cause problems. ANTIC's way around the problem is to have another LMS instruction halfway through the display list. All this does is keep ANTIC happy. There is no difference in the way the screen looks, and screen memory is still in one big chunk. The only time something goes wrong is when you attempt to make changes. And, unfortunately, there is no easy way around it. If you find yourself in this type of situation, you must take the following steps:

1. Find the second LMS in the display list.
2. Determine the address that it starts loading from (if you use a variable called LMS to point to the memory location of the second LMS instruction, then ADDRESS=PEEK(LMS+ 1 )+256 *PEEK (LMS+2) ).
3. If your screen memory does not end before this address, find the mode line that uses the address, and make the MOD instruction for that line an LMS instead (remember that the LMS will take tip three bytes instead of one, and don't forget to include the address).

In other words, it's a pain in the you-know-what, but hopefully you'll never encounter it - I seldom do. In the meantime, enjoy yourself and practice, practice, practice.