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 SetANTIC 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 ModifiersANTIC 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.
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 InstructionsThe 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 ListLet 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 ModesYou 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 WindowIn 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)
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)
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.
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 DesignPlotting
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
|